aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2011-09-23 08:30:01 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-09-23 08:32:35 -0400
commitbe304970850806abea880da95fbfb743a4d9f87d (patch)
treebd926b64bac6198dc05f07611025f56b1246e3ce /drivers/media/video
parent45dbf0db5ac974fb699fec39330d01642dff98dc (diff)
[media] move tm6000 to drivers/media/video
The serious bugs got fixed already. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video')
-rw-r--r--drivers/media/video/Kconfig2
-rw-r--r--drivers/media/video/Makefile1
-rw-r--r--drivers/media/video/tm6000/Kconfig33
-rw-r--r--drivers/media/video/tm6000/Makefile15
-rw-r--r--drivers/media/video/tm6000/tm6000-alsa.c513
-rw-r--r--drivers/media/video/tm6000/tm6000-cards.c1402
-rw-r--r--drivers/media/video/tm6000/tm6000-core.c965
-rw-r--r--drivers/media/video/tm6000/tm6000-dvb.c452
-rw-r--r--drivers/media/video/tm6000/tm6000-i2c.c340
-rw-r--r--drivers/media/video/tm6000/tm6000-input.c459
-rw-r--r--drivers/media/video/tm6000/tm6000-regs.h600
-rw-r--r--drivers/media/video/tm6000/tm6000-stds.c659
-rw-r--r--drivers/media/video/tm6000/tm6000-usb-isoc.h50
-rw-r--r--drivers/media/video/tm6000/tm6000-video.c1813
-rw-r--r--drivers/media/video/tm6000/tm6000.h398
15 files changed, 7702 insertions, 0 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 4a10086bb46..aed5b3d740c 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -1019,6 +1019,8 @@ source "drivers/media/video/tlg2300/Kconfig"
1019 1019
1020source "drivers/media/video/cx231xx/Kconfig" 1020source "drivers/media/video/cx231xx/Kconfig"
1021 1021
1022source "drivers/media/video/tm6000/Kconfig"
1023
1022source "drivers/media/video/usbvision/Kconfig" 1024source "drivers/media/video/usbvision/Kconfig"
1023 1025
1024source "drivers/media/video/et61x251/Kconfig" 1026source "drivers/media/video/et61x251/Kconfig"
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 0f0c6af58d8..11fff97e719 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -107,6 +107,7 @@ obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/
107obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ 107obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
108obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ 108obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
109obj-$(CONFIG_VIDEO_CPIA2) += cpia2/ 109obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
110obj-$(CONFIG_VIDEO_TM6000) += tm6000/
110obj-$(CONFIG_VIDEO_MXB) += mxb.o 111obj-$(CONFIG_VIDEO_MXB) += mxb.o
111obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o 112obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
112obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o 113obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
diff --git a/drivers/media/video/tm6000/Kconfig b/drivers/media/video/tm6000/Kconfig
new file mode 100644
index 00000000000..114eec8a630
--- /dev/null
+++ b/drivers/media/video/tm6000/Kconfig
@@ -0,0 +1,33 @@
1config VIDEO_TM6000
2 tristate "TV Master TM5600/6000/6010 driver"
3 depends on VIDEO_DEV && I2C && INPUT && RC_CORE && USB && EXPERIMENTAL
4 select VIDEO_TUNER
5 select MEDIA_TUNER_XC2028
6 select MEDIA_TUNER_XC5000
7 select VIDEOBUF_VMALLOC
8 help
9 Support for TM5600/TM6000/TM6010 USB Device
10
11 Since these cards have no MPEG decoder onboard, they transmit
12 only compressed MPEG data over the usb bus, so you need
13 an external software decoder to watch TV on your computer.
14
15 Say Y if you own such a device and want to use it.
16
17config VIDEO_TM6000_ALSA
18 tristate "TV Master TM5600/6000/6010 audio support"
19 depends on VIDEO_TM6000 && SND && EXPERIMENTAL
20 select SND_PCM
21 ---help---
22 This is a video4linux driver for direct (DMA) audio for
23 TM5600/TM6000/TM6010 USB Devices.
24
25 To compile this driver as a module, choose M here: the
26 module will be called tm6000-alsa.
27
28config VIDEO_TM6000_DVB
29 tristate "DVB Support for tm6000 based TV cards"
30 depends on VIDEO_TM6000 && DVB_CORE && USB && EXPERIMENTAL
31 select DVB_ZL10353
32 ---help---
33 This adds support for DVB cards based on the tm5600/tm6000 chip.
diff --git a/drivers/media/video/tm6000/Makefile b/drivers/media/video/tm6000/Makefile
new file mode 100644
index 00000000000..395515b4a88
--- /dev/null
+++ b/drivers/media/video/tm6000/Makefile
@@ -0,0 +1,15 @@
1tm6000-y := tm6000-cards.o \
2 tm6000-core.o \
3 tm6000-i2c.o \
4 tm6000-video.o \
5 tm6000-stds.o \
6 tm6000-input.o
7
8obj-$(CONFIG_VIDEO_TM6000) += tm6000.o
9obj-$(CONFIG_VIDEO_TM6000_ALSA) += tm6000-alsa.o
10obj-$(CONFIG_VIDEO_TM6000_DVB) += tm6000-dvb.o
11
12ccflags-y := -Idrivers/media/video
13ccflags-y += -Idrivers/media/common/tuners
14ccflags-y += -Idrivers/media/dvb/dvb-core
15ccflags-y += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/video/tm6000/tm6000-alsa.c b/drivers/media/video/tm6000/tm6000-alsa.c
new file mode 100644
index 00000000000..7d675c72fd4
--- /dev/null
+++ b/drivers/media/video/tm6000/tm6000-alsa.c
@@ -0,0 +1,513 @@
1/*
2 *
3 * Support for audio capture for tm5600/6000/6010
4 * (c) 2007-2008 Mauro Carvalho Chehab <mchehab@redhat.com>
5 *
6 * Based on cx88-alsa.c
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/device.h>
16#include <linux/interrupt.h>
17#include <linux/usb.h>
18#include <linux/slab.h>
19#include <linux/vmalloc.h>
20
21#include <linux/delay.h>
22#include <sound/core.h>
23#include <sound/pcm.h>
24#include <sound/pcm_params.h>
25#include <sound/control.h>
26#include <sound/initval.h>
27
28
29#include "tm6000.h"
30#include "tm6000-regs.h"
31
32#undef dprintk
33
34#define dprintk(level, fmt, arg...) do { \
35 if (debug >= level) \
36 printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg); \
37 } while (0)
38
39/****************************************************************************
40 Module global static vars
41 ****************************************************************************/
42
43static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
44
45static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
46
47module_param_array(enable, bool, NULL, 0444);
48MODULE_PARM_DESC(enable, "Enable tm6000x soundcard. default enabled.");
49
50module_param_array(index, int, NULL, 0444);
51MODULE_PARM_DESC(index, "Index value for tm6000x capture interface(s).");
52
53
54/****************************************************************************
55 Module macros
56 ****************************************************************************/
57
58MODULE_DESCRIPTION("ALSA driver module for tm5600/tm6000/tm6010 based TV cards");
59MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
60MODULE_LICENSE("GPL");
61MODULE_SUPPORTED_DEVICE("{{Trident,tm5600},"
62 "{{Trident,tm6000},"
63 "{{Trident,tm6010}");
64static unsigned int debug;
65module_param(debug, int, 0644);
66MODULE_PARM_DESC(debug, "enable debug messages");
67
68/****************************************************************************
69 Module specific funtions
70 ****************************************************************************/
71
72/*
73 * BOARD Specific: Sets audio DMA
74 */
75
76static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip)
77{
78 struct tm6000_core *core = chip->core;
79
80 dprintk(1, "Starting audio DMA\n");
81
82 /* Enables audio */
83 tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_IF, 0x40, 0x40);
84
85 tm6000_set_audio_bitrate(core, 48000);
86
87 return 0;
88}
89
90/*
91 * BOARD Specific: Resets audio DMA
92 */
93static int _tm6000_stop_audio_dma(struct snd_tm6000_card *chip)
94{
95 struct tm6000_core *core = chip->core;
96
97 dprintk(1, "Stopping audio DMA\n");
98
99 /* Disables audio */
100 tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_IF, 0x00, 0x40);
101
102 return 0;
103}
104
105static void dsp_buffer_free(struct snd_pcm_substream *substream)
106{
107 struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
108
109 dprintk(2, "Freeing buffer\n");
110
111 vfree(substream->runtime->dma_area);
112 substream->runtime->dma_area = NULL;
113 substream->runtime->dma_bytes = 0;
114}
115
116static int dsp_buffer_alloc(struct snd_pcm_substream *substream, int size)
117{
118 struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
119
120 dprintk(2, "Allocating buffer\n");
121
122 if (substream->runtime->dma_area) {
123 if (substream->runtime->dma_bytes > size)
124 return 0;
125
126 dsp_buffer_free(substream);
127 }
128
129 substream->runtime->dma_area = vmalloc(size);
130 if (!substream->runtime->dma_area)
131 return -ENOMEM;
132
133 substream->runtime->dma_bytes = size;
134
135 return 0;
136}
137
138
139/****************************************************************************
140 ALSA PCM Interface
141 ****************************************************************************/
142
143/*
144 * Digital hardware definition
145 */
146#define DEFAULT_FIFO_SIZE 4096
147
148static struct snd_pcm_hardware snd_tm6000_digital_hw = {
149 .info = SNDRV_PCM_INFO_MMAP |
150 SNDRV_PCM_INFO_INTERLEAVED |
151 SNDRV_PCM_INFO_BLOCK_TRANSFER |
152 SNDRV_PCM_INFO_MMAP_VALID,
153 .formats = SNDRV_PCM_FMTBIT_S16_LE,
154
155 .rates = SNDRV_PCM_RATE_CONTINUOUS,
156 .rate_min = 48000,
157 .rate_max = 48000,
158 .channels_min = 2,
159 .channels_max = 2,
160 .period_bytes_min = 64,
161 .period_bytes_max = 12544,
162 .periods_min = 1,
163 .periods_max = 98,
164 .buffer_bytes_max = 62720 * 8,
165};
166
167/*
168 * audio pcm capture open callback
169 */
170static int snd_tm6000_pcm_open(struct snd_pcm_substream *substream)
171{
172 struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
173 struct snd_pcm_runtime *runtime = substream->runtime;
174 int err;
175
176 err = snd_pcm_hw_constraint_pow2(runtime, 0,
177 SNDRV_PCM_HW_PARAM_PERIODS);
178 if (err < 0)
179 goto _error;
180
181 chip->substream = substream;
182
183 runtime->hw = snd_tm6000_digital_hw;
184
185 return 0;
186_error:
187 dprintk(1, "Error opening PCM!\n");
188 return err;
189}
190
191/*
192 * audio close callback
193 */
194static int snd_tm6000_close(struct snd_pcm_substream *substream)
195{
196 struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
197 struct tm6000_core *core = chip->core;
198
199 if (atomic_read(&core->stream_started) > 0) {
200 atomic_set(&core->stream_started, 0);
201 schedule_work(&core->wq_trigger);
202 }
203
204 return 0;
205}
206
207static int tm6000_fillbuf(struct tm6000_core *core, char *buf, int size)
208{
209 struct snd_tm6000_card *chip = core->adev;
210 struct snd_pcm_substream *substream = chip->substream;
211 struct snd_pcm_runtime *runtime;
212 int period_elapsed = 0;
213 unsigned int stride, buf_pos;
214 int length;
215
216 if (atomic_read(&core->stream_started) == 0)
217 return 0;
218
219 if (!size || !substream) {
220 dprintk(1, "substream was NULL\n");
221 return -EINVAL;
222 }
223
224 runtime = substream->runtime;
225 if (!runtime || !runtime->dma_area) {
226 dprintk(1, "runtime was NULL\n");
227 return -EINVAL;
228 }
229
230 buf_pos = chip->buf_pos;
231 stride = runtime->frame_bits >> 3;
232
233 if (stride == 0) {
234 dprintk(1, "stride is zero\n");
235 return -EINVAL;
236 }
237
238 length = size / stride;
239 if (length == 0) {
240 dprintk(1, "%s: length was zero\n", __func__);
241 return -EINVAL;
242 }
243
244 dprintk(1, "Copying %d bytes at %p[%d] - buf size=%d x %d\n", size,
245 runtime->dma_area, buf_pos,
246 (unsigned int)runtime->buffer_size, stride);
247
248 if (buf_pos + length >= runtime->buffer_size) {
249 unsigned int cnt = runtime->buffer_size - buf_pos;
250 memcpy(runtime->dma_area + buf_pos * stride, buf, cnt * stride);
251 memcpy(runtime->dma_area, buf + cnt * stride,
252 length * stride - cnt * stride);
253 } else
254 memcpy(runtime->dma_area + buf_pos * stride, buf,
255 length * stride);
256
257 snd_pcm_stream_lock(substream);
258
259 chip->buf_pos += length;
260 if (chip->buf_pos >= runtime->buffer_size)
261 chip->buf_pos -= runtime->buffer_size;
262
263 chip->period_pos += length;
264 if (chip->period_pos >= runtime->period_size) {
265 chip->period_pos -= runtime->period_size;
266 period_elapsed = 1;
267 }
268
269 snd_pcm_stream_unlock(substream);
270
271 if (period_elapsed)
272 snd_pcm_period_elapsed(substream);
273
274 return 0;
275}
276
277/*
278 * hw_params callback
279 */
280static int snd_tm6000_hw_params(struct snd_pcm_substream *substream,
281 struct snd_pcm_hw_params *hw_params)
282{
283 int size, rc;
284
285 size = params_period_bytes(hw_params) * params_periods(hw_params);
286
287 rc = dsp_buffer_alloc(substream, size);
288 if (rc < 0)
289 return rc;
290
291 return 0;
292}
293
294/*
295 * hw free callback
296 */
297static int snd_tm6000_hw_free(struct snd_pcm_substream *substream)
298{
299 struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
300 struct tm6000_core *core = chip->core;
301
302 if (atomic_read(&core->stream_started) > 0) {
303 atomic_set(&core->stream_started, 0);
304 schedule_work(&core->wq_trigger);
305 }
306
307 dsp_buffer_free(substream);
308 return 0;
309}
310
311/*
312 * prepare callback
313 */
314static int snd_tm6000_prepare(struct snd_pcm_substream *substream)
315{
316 struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
317
318 chip->buf_pos = 0;
319 chip->period_pos = 0;
320
321 return 0;
322}
323
324
325/*
326 * trigger callback
327 */
328static void audio_trigger(struct work_struct *work)
329{
330 struct tm6000_core *core = container_of(work, struct tm6000_core,
331 wq_trigger);
332 struct snd_tm6000_card *chip = core->adev;
333
334 if (atomic_read(&core->stream_started)) {
335 dprintk(1, "starting capture");
336 _tm6000_start_audio_dma(chip);
337 } else {
338 dprintk(1, "stopping capture");
339 _tm6000_stop_audio_dma(chip);
340 }
341}
342
343static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd)
344{
345 struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
346 struct tm6000_core *core = chip->core;
347 int err = 0;
348
349 switch (cmd) {
350 case SNDRV_PCM_TRIGGER_START:
351 atomic_set(&core->stream_started, 1);
352 break;
353 case SNDRV_PCM_TRIGGER_STOP:
354 atomic_set(&core->stream_started, 0);
355 break;
356 default:
357 err = -EINVAL;
358 break;
359 }
360 schedule_work(&core->wq_trigger);
361
362 return err;
363}
364/*
365 * pointer callback
366 */
367static snd_pcm_uframes_t snd_tm6000_pointer(struct snd_pcm_substream *substream)
368{
369 struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
370
371 return chip->buf_pos;
372}
373
374/*
375 * operators
376 */
377static struct snd_pcm_ops snd_tm6000_pcm_ops = {
378 .open = snd_tm6000_pcm_open,
379 .close = snd_tm6000_close,
380 .ioctl = snd_pcm_lib_ioctl,
381 .hw_params = snd_tm6000_hw_params,
382 .hw_free = snd_tm6000_hw_free,
383 .prepare = snd_tm6000_prepare,
384 .trigger = snd_tm6000_card_trigger,
385 .pointer = snd_tm6000_pointer,
386};
387
388/*
389 * create a PCM device
390 */
391
392/* FIXME: Control interface - How to control volume/mute? */
393
394/****************************************************************************
395 Basic Flow for Sound Devices
396 ****************************************************************************/
397
398/*
399 * Alsa Constructor - Component probe
400 */
401static int tm6000_audio_init(struct tm6000_core *dev)
402{
403 struct snd_card *card;
404 struct snd_tm6000_card *chip;
405 int rc;
406 static int devnr;
407 char component[14];
408 struct snd_pcm *pcm;
409
410 if (!dev)
411 return 0;
412
413 if (devnr >= SNDRV_CARDS)
414 return -ENODEV;
415
416 if (!enable[devnr])
417 return -ENOENT;
418
419 rc = snd_card_create(index[devnr], "tm6000", THIS_MODULE, 0, &card);
420 if (rc < 0) {
421 snd_printk(KERN_ERR "cannot create card instance %d\n", devnr);
422 return rc;
423 }
424 strcpy(card->driver, "tm6000-alsa");
425 strcpy(card->shortname, "TM5600/60x0");
426 sprintf(card->longname, "TM5600/60x0 Audio at bus %d device %d",
427 dev->udev->bus->busnum, dev->udev->devnum);
428
429 sprintf(component, "USB%04x:%04x",
430 le16_to_cpu(dev->udev->descriptor.idVendor),
431 le16_to_cpu(dev->udev->descriptor.idProduct));
432 snd_component_add(card, component);
433 snd_card_set_dev(card, &dev->udev->dev);
434
435 chip = kzalloc(sizeof(struct snd_tm6000_card), GFP_KERNEL);
436 if (!chip) {
437 rc = -ENOMEM;
438 goto error;
439 }
440
441 chip->core = dev;
442 chip->card = card;
443 dev->adev = chip;
444 spin_lock_init(&chip->reg_lock);
445
446 rc = snd_pcm_new(card, "TM6000 Audio", 0, 0, 1, &pcm);
447 if (rc < 0)
448 goto error_chip;
449
450 pcm->info_flags = 0;
451 pcm->private_data = chip;
452 strcpy(pcm->name, "Trident TM5600/60x0");
453
454 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops);
455
456 INIT_WORK(&dev->wq_trigger, audio_trigger);
457 rc = snd_card_register(card);
458 if (rc < 0)
459 goto error_chip;
460
461 dprintk(1, "Registered audio driver for %s\n", card->longname);
462
463 return 0;
464
465error_chip:
466 kfree(chip);
467 dev->adev = NULL;
468error:
469 snd_card_free(card);
470 return rc;
471}
472
473static int tm6000_audio_fini(struct tm6000_core *dev)
474{
475 struct snd_tm6000_card *chip = dev->adev;
476
477 if (!dev)
478 return 0;
479
480 if (!chip)
481 return 0;
482
483 if (!chip->card)
484 return 0;
485
486 snd_card_free(chip->card);
487 chip->card = NULL;
488 kfree(chip);
489 dev->adev = NULL;
490
491 return 0;
492}
493
494static struct tm6000_ops audio_ops = {
495 .type = TM6000_AUDIO,
496 .name = "TM6000 Audio Extension",
497 .init = tm6000_audio_init,
498 .fini = tm6000_audio_fini,
499 .fillbuf = tm6000_fillbuf,
500};
501
502static int __init tm6000_alsa_register(void)
503{
504 return tm6000_register_extension(&audio_ops);
505}
506
507static void __exit tm6000_alsa_unregister(void)
508{
509 tm6000_unregister_extension(&audio_ops);
510}
511
512module_init(tm6000_alsa_register);
513module_exit(tm6000_alsa_unregister);
diff --git a/drivers/media/video/tm6000/tm6000-cards.c b/drivers/media/video/tm6000/tm6000-cards.c
new file mode 100644
index 00000000000..ec2578a0fdf
--- /dev/null
+++ b/drivers/media/video/tm6000/tm6000-cards.c
@@ -0,0 +1,1402 @@
1/*
2 * tm6000-cards.c - driver for TM5600/TM6000/TM6010 USB video capture devices
3 *
4 * Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation version 2
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20#include <linux/init.h>
21#include <linux/module.h>
22#include <linux/pci.h>
23#include <linux/delay.h>
24#include <linux/i2c.h>
25#include <linux/usb.h>
26#include <linux/slab.h>
27#include <media/v4l2-common.h>
28#include <media/tuner.h>
29#include <media/tvaudio.h>
30#include <media/i2c-addr.h>
31#include <media/rc-map.h>
32
33#include "tm6000.h"
34#include "tm6000-regs.h"
35#include "tuner-xc2028.h"
36#include "xc5000.h"
37
38#define TM6000_BOARD_UNKNOWN 0
39#define TM5600_BOARD_GENERIC 1
40#define TM6000_BOARD_GENERIC 2
41#define TM6010_BOARD_GENERIC 3
42#define TM5600_BOARD_10MOONS_UT821 4
43#define TM5600_BOARD_10MOONS_UT330 5
44#define TM6000_BOARD_ADSTECH_DUAL_TV 6
45#define TM6000_BOARD_FREECOM_AND_SIMILAR 7
46#define TM6000_BOARD_ADSTECH_MINI_DUAL_TV 8
47#define TM6010_BOARD_HAUPPAUGE_900H 9
48#define TM6010_BOARD_BEHOLD_WANDER 10
49#define TM6010_BOARD_BEHOLD_VOYAGER 11
50#define TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE 12
51#define TM6010_BOARD_TWINHAN_TU501 13
52#define TM6010_BOARD_BEHOLD_WANDER_LITE 14
53#define TM6010_BOARD_BEHOLD_VOYAGER_LITE 15
54#define TM5600_BOARD_TERRATEC_GRABSTER 16
55
56#define is_generic(model) ((model == TM6000_BOARD_UNKNOWN) || \
57 (model == TM5600_BOARD_GENERIC) || \
58 (model == TM6000_BOARD_GENERIC) || \
59 (model == TM6010_BOARD_GENERIC))
60
61#define TM6000_MAXBOARDS 16
62static unsigned int card[] = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET };
63
64module_param_array(card, int, NULL, 0444);
65
66static unsigned long tm6000_devused;
67
68
69struct tm6000_board {
70 char *name;
71 char eename[16]; /* EEPROM name */
72 unsigned eename_size; /* size of EEPROM name */
73 unsigned eename_pos; /* Position where it appears at ROM */
74
75 struct tm6000_capabilities caps;
76
77 enum tm6000_devtype type; /* variant of the chipset */
78 int tuner_type; /* type of the tuner */
79 int tuner_addr; /* tuner address */
80 int demod_addr; /* demodulator address */
81
82 struct tm6000_gpio gpio;
83
84 struct tm6000_input vinput[3];
85 struct tm6000_input rinput;
86
87 char *ir_codes;
88};
89
90static struct tm6000_board tm6000_boards[] = {
91 [TM6000_BOARD_UNKNOWN] = {
92 .name = "Unknown tm6000 video grabber",
93 .caps = {
94 .has_tuner = 1,
95 .has_eeprom = 1,
96 },
97 .gpio = {
98 .tuner_reset = TM6000_GPIO_1,
99 },
100 .vinput = { {
101 .type = TM6000_INPUT_TV,
102 .vmux = TM6000_VMUX_VIDEO_B,
103 .amux = TM6000_AMUX_ADC1,
104 }, {
105 .type = TM6000_INPUT_COMPOSITE1,
106 .vmux = TM6000_VMUX_VIDEO_A,
107 .amux = TM6000_AMUX_ADC2,
108 }, {
109 .type = TM6000_INPUT_SVIDEO,
110 .vmux = TM6000_VMUX_VIDEO_AB,
111 .amux = TM6000_AMUX_ADC2,
112 },
113 },
114 },
115 [TM5600_BOARD_GENERIC] = {
116 .name = "Generic tm5600 board",
117 .type = TM5600,
118 .tuner_type = TUNER_XC2028,
119 .tuner_addr = 0xc2 >> 1,
120 .caps = {
121 .has_tuner = 1,
122 .has_eeprom = 1,
123 },
124 .gpio = {
125 .tuner_reset = TM6000_GPIO_1,
126 },
127 .vinput = { {
128 .type = TM6000_INPUT_TV,
129 .vmux = TM6000_VMUX_VIDEO_B,
130 .amux = TM6000_AMUX_ADC1,
131 }, {
132 .type = TM6000_INPUT_COMPOSITE1,
133 .vmux = TM6000_VMUX_VIDEO_A,
134 .amux = TM6000_AMUX_ADC2,
135 }, {
136 .type = TM6000_INPUT_SVIDEO,
137 .vmux = TM6000_VMUX_VIDEO_AB,
138 .amux = TM6000_AMUX_ADC2,
139 },
140 },
141 },
142 [TM6000_BOARD_GENERIC] = {
143 .name = "Generic tm6000 board",
144 .tuner_type = TUNER_XC2028,
145 .tuner_addr = 0xc2 >> 1,
146 .caps = {
147 .has_tuner = 1,
148 .has_eeprom = 1,
149 },
150 .gpio = {
151 .tuner_reset = TM6000_GPIO_1,
152 },
153 .vinput = { {
154 .type = TM6000_INPUT_TV,
155 .vmux = TM6000_VMUX_VIDEO_B,
156 .amux = TM6000_AMUX_ADC1,
157 }, {
158 .type = TM6000_INPUT_COMPOSITE1,
159 .vmux = TM6000_VMUX_VIDEO_A,
160 .amux = TM6000_AMUX_ADC2,
161 }, {
162 .type = TM6000_INPUT_SVIDEO,
163 .vmux = TM6000_VMUX_VIDEO_AB,
164 .amux = TM6000_AMUX_ADC2,
165 },
166 },
167 },
168 [TM6010_BOARD_GENERIC] = {
169 .name = "Generic tm6010 board",
170 .type = TM6010,
171 .tuner_type = TUNER_XC2028,
172 .tuner_addr = 0xc2 >> 1,
173 .demod_addr = 0x1e >> 1,
174 .caps = {
175 .has_tuner = 1,
176 .has_dvb = 1,
177 .has_zl10353 = 1,
178 .has_eeprom = 1,
179 .has_remote = 1,
180 },
181 .gpio = {
182 .tuner_reset = TM6010_GPIO_2,
183 .tuner_on = TM6010_GPIO_3,
184 .demod_reset = TM6010_GPIO_1,
185 .demod_on = TM6010_GPIO_4,
186 .power_led = TM6010_GPIO_7,
187 .dvb_led = TM6010_GPIO_5,
188 .ir = TM6010_GPIO_0,
189 },
190 .vinput = { {
191 .type = TM6000_INPUT_TV,
192 .vmux = TM6000_VMUX_VIDEO_B,
193 .amux = TM6000_AMUX_SIF1,
194 }, {
195 .type = TM6000_INPUT_COMPOSITE1,
196 .vmux = TM6000_VMUX_VIDEO_A,
197 .amux = TM6000_AMUX_ADC2,
198 }, {
199 .type = TM6000_INPUT_SVIDEO,
200 .vmux = TM6000_VMUX_VIDEO_AB,
201 .amux = TM6000_AMUX_ADC2,
202 },
203 },
204 },
205 [TM5600_BOARD_10MOONS_UT821] = {
206 .name = "10Moons UT 821",
207 .tuner_type = TUNER_XC2028,
208 .eename = { '1', '0', 'M', 'O', 'O', 'N', 'S', '5', '6', '0', '0', 0xff, 0x45, 0x5b},
209 .eename_size = 14,
210 .eename_pos = 0x14,
211 .type = TM5600,
212 .tuner_addr = 0xc2 >> 1,
213 .caps = {
214 .has_tuner = 1,
215 .has_eeprom = 1,
216 },
217 .gpio = {
218 .tuner_reset = TM6000_GPIO_1,
219 },
220 .vinput = { {
221 .type = TM6000_INPUT_TV,
222 .vmux = TM6000_VMUX_VIDEO_B,
223 .amux = TM6000_AMUX_ADC1,
224 }, {
225 .type = TM6000_INPUT_COMPOSITE1,
226 .vmux = TM6000_VMUX_VIDEO_A,
227 .amux = TM6000_AMUX_ADC2,
228 }, {
229 .type = TM6000_INPUT_SVIDEO,
230 .vmux = TM6000_VMUX_VIDEO_AB,
231 .amux = TM6000_AMUX_ADC2,
232 },
233 },
234 },
235 [TM5600_BOARD_10MOONS_UT330] = {
236 .name = "10Moons UT 330",
237 .tuner_type = TUNER_PHILIPS_FQ1216AME_MK4,
238 .tuner_addr = 0xc8 >> 1,
239 .caps = {
240 .has_tuner = 1,
241 .has_dvb = 0,
242 .has_zl10353 = 0,
243 .has_eeprom = 1,
244 },
245 .vinput = { {
246 .type = TM6000_INPUT_TV,
247 .vmux = TM6000_VMUX_VIDEO_B,
248 .amux = TM6000_AMUX_ADC1,
249 }, {
250 .type = TM6000_INPUT_COMPOSITE1,
251 .vmux = TM6000_VMUX_VIDEO_A,
252 .amux = TM6000_AMUX_ADC2,
253 }, {
254 .type = TM6000_INPUT_SVIDEO,
255 .vmux = TM6000_VMUX_VIDEO_AB,
256 .amux = TM6000_AMUX_ADC2,
257 },
258 },
259 },
260 [TM6000_BOARD_ADSTECH_DUAL_TV] = {
261 .name = "ADSTECH Dual TV USB",
262 .tuner_type = TUNER_XC2028,
263 .tuner_addr = 0xc8 >> 1,
264 .caps = {
265 .has_tuner = 1,
266 .has_tda9874 = 1,
267 .has_dvb = 1,
268 .has_zl10353 = 1,
269 .has_eeprom = 1,
270 },
271 .vinput = { {
272 .type = TM6000_INPUT_TV,
273 .vmux = TM6000_VMUX_VIDEO_B,
274 .amux = TM6000_AMUX_ADC1,
275 }, {
276 .type = TM6000_INPUT_COMPOSITE1,
277 .vmux = TM6000_VMUX_VIDEO_A,
278 .amux = TM6000_AMUX_ADC2,
279 }, {
280 .type = TM6000_INPUT_SVIDEO,
281 .vmux = TM6000_VMUX_VIDEO_AB,
282 .amux = TM6000_AMUX_ADC2,
283 },
284 },
285 },
286 [TM6000_BOARD_FREECOM_AND_SIMILAR] = {
287 .name = "Freecom Hybrid Stick / Moka DVB-T Receiver Dual",
288 .tuner_type = TUNER_XC2028, /* has a XC3028 */
289 .tuner_addr = 0xc2 >> 1,
290 .demod_addr = 0x1e >> 1,
291 .caps = {
292 .has_tuner = 1,
293 .has_dvb = 1,
294 .has_zl10353 = 1,
295 .has_eeprom = 0,
296 .has_remote = 1,
297 },
298 .gpio = {
299 .tuner_reset = TM6000_GPIO_4,
300 },
301 .vinput = { {
302 .type = TM6000_INPUT_TV,
303 .vmux = TM6000_VMUX_VIDEO_B,
304 .amux = TM6000_AMUX_ADC1,
305 }, {
306 .type = TM6000_INPUT_COMPOSITE1,
307 .vmux = TM6000_VMUX_VIDEO_A,
308 .amux = TM6000_AMUX_ADC2,
309 }, {
310 .type = TM6000_INPUT_SVIDEO,
311 .vmux = TM6000_VMUX_VIDEO_AB,
312 .amux = TM6000_AMUX_ADC2,
313 },
314 },
315 },
316 [TM6000_BOARD_ADSTECH_MINI_DUAL_TV] = {
317 .name = "ADSTECH Mini Dual TV USB",
318 .tuner_type = TUNER_XC2028, /* has a XC3028 */
319 .tuner_addr = 0xc8 >> 1,
320 .demod_addr = 0x1e >> 1,
321 .caps = {
322 .has_tuner = 1,
323 .has_dvb = 1,
324 .has_zl10353 = 1,
325 .has_eeprom = 0,
326 },
327 .gpio = {
328 .tuner_reset = TM6000_GPIO_4,
329 },
330 .vinput = { {
331 .type = TM6000_INPUT_TV,
332 .vmux = TM6000_VMUX_VIDEO_B,
333 .amux = TM6000_AMUX_ADC1,
334 }, {
335 .type = TM6000_INPUT_COMPOSITE1,
336 .vmux = TM6000_VMUX_VIDEO_A,
337 .amux = TM6000_AMUX_ADC2,
338 }, {
339 .type = TM6000_INPUT_SVIDEO,
340 .vmux = TM6000_VMUX_VIDEO_AB,
341 .amux = TM6000_AMUX_ADC2,
342 },
343 },
344 },
345 [TM6010_BOARD_HAUPPAUGE_900H] = {
346 .name = "Hauppauge WinTV HVR-900H / WinTV USB2-Stick",
347 .eename = { 'H', 0, 'V', 0, 'R', 0, '9', 0, '0', 0, '0', 0, 'H', 0 },
348 .eename_size = 14,
349 .eename_pos = 0x42,
350 .tuner_type = TUNER_XC2028, /* has a XC3028 */
351 .tuner_addr = 0xc2 >> 1,
352 .demod_addr = 0x1e >> 1,
353 .type = TM6010,
354 .caps = {
355 .has_tuner = 1,
356 .has_dvb = 1,
357 .has_zl10353 = 1,
358 .has_eeprom = 1,
359 .has_remote = 1,
360 },
361 .gpio = {
362 .tuner_reset = TM6010_GPIO_2,
363 .tuner_on = TM6010_GPIO_3,
364 .demod_reset = TM6010_GPIO_1,
365 .demod_on = TM6010_GPIO_4,
366 .power_led = TM6010_GPIO_7,
367 .dvb_led = TM6010_GPIO_5,
368 .ir = TM6010_GPIO_0,
369 },
370 .vinput = { {
371 .type = TM6000_INPUT_TV,
372 .vmux = TM6000_VMUX_VIDEO_B,
373 .amux = TM6000_AMUX_SIF1,
374 }, {
375 .type = TM6000_INPUT_COMPOSITE1,
376 .vmux = TM6000_VMUX_VIDEO_A,
377 .amux = TM6000_AMUX_ADC2,
378 }, {
379 .type = TM6000_INPUT_SVIDEO,
380 .vmux = TM6000_VMUX_VIDEO_AB,
381 .amux = TM6000_AMUX_ADC2,
382 },
383 },
384 },
385 [TM6010_BOARD_BEHOLD_WANDER] = {
386 .name = "Beholder Wander DVB-T/TV/FM USB2.0",
387 .tuner_type = TUNER_XC5000,
388 .tuner_addr = 0xc2 >> 1,
389 .demod_addr = 0x1e >> 1,
390 .type = TM6010,
391 .caps = {
392 .has_tuner = 1,
393 .has_dvb = 1,
394 .has_zl10353 = 1,
395 .has_eeprom = 1,
396 .has_remote = 1,
397 .has_radio = 1,
398 },
399 .gpio = {
400 .tuner_reset = TM6010_GPIO_0,
401 .demod_reset = TM6010_GPIO_1,
402 .power_led = TM6010_GPIO_6,
403 },
404 .vinput = { {
405 .type = TM6000_INPUT_TV,
406 .vmux = TM6000_VMUX_VIDEO_B,
407 .amux = TM6000_AMUX_SIF1,
408 }, {
409 .type = TM6000_INPUT_COMPOSITE1,
410 .vmux = TM6000_VMUX_VIDEO_A,
411 .amux = TM6000_AMUX_ADC2,
412 }, {
413 .type = TM6000_INPUT_SVIDEO,
414 .vmux = TM6000_VMUX_VIDEO_AB,
415 .amux = TM6000_AMUX_ADC2,
416 },
417 },
418 .rinput = {
419 .type = TM6000_INPUT_RADIO,
420 .amux = TM6000_AMUX_ADC1,
421 },
422 },
423 [TM6010_BOARD_BEHOLD_VOYAGER] = {
424 .name = "Beholder Voyager TV/FM USB2.0",
425 .tuner_type = TUNER_XC5000,
426 .tuner_addr = 0xc2 >> 1,
427 .type = TM6010,
428 .caps = {
429 .has_tuner = 1,
430 .has_dvb = 0,
431 .has_zl10353 = 0,
432 .has_eeprom = 1,
433 .has_remote = 1,
434 .has_radio = 1,
435 },
436 .gpio = {
437 .tuner_reset = TM6010_GPIO_0,
438 .power_led = TM6010_GPIO_6,
439 },
440 .vinput = { {
441 .type = TM6000_INPUT_TV,
442 .vmux = TM6000_VMUX_VIDEO_B,
443 .amux = TM6000_AMUX_SIF1,
444 }, {
445 .type = TM6000_INPUT_COMPOSITE1,
446 .vmux = TM6000_VMUX_VIDEO_A,
447 .amux = TM6000_AMUX_ADC2,
448 }, {
449 .type = TM6000_INPUT_SVIDEO,
450 .vmux = TM6000_VMUX_VIDEO_AB,
451 .amux = TM6000_AMUX_ADC2,
452 },
453 },
454 .rinput = {
455 .type = TM6000_INPUT_RADIO,
456 .amux = TM6000_AMUX_ADC1,
457 },
458 },
459 [TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = {
460 .name = "Terratec Cinergy Hybrid XE / Cinergy Hybrid-Stick",
461 .tuner_type = TUNER_XC2028, /* has a XC3028 */
462 .tuner_addr = 0xc2 >> 1,
463 .demod_addr = 0x1e >> 1,
464 .type = TM6010,
465 .caps = {
466 .has_tuner = 1,
467 .has_dvb = 1,
468 .has_zl10353 = 1,
469 .has_eeprom = 1,
470 .has_remote = 1,
471 .has_radio = 1,
472 },
473 .gpio = {
474 .tuner_reset = TM6010_GPIO_2,
475 .tuner_on = TM6010_GPIO_3,
476 .demod_reset = TM6010_GPIO_1,
477 .demod_on = TM6010_GPIO_4,
478 .power_led = TM6010_GPIO_7,
479 .dvb_led = TM6010_GPIO_5,
480 .ir = TM6010_GPIO_0,
481 },
482 .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
483 .vinput = { {
484 .type = TM6000_INPUT_TV,
485 .vmux = TM6000_VMUX_VIDEO_B,
486 .amux = TM6000_AMUX_SIF1,
487 }, {
488 .type = TM6000_INPUT_COMPOSITE1,
489 .vmux = TM6000_VMUX_VIDEO_A,
490 .amux = TM6000_AMUX_ADC2,
491 }, {
492 .type = TM6000_INPUT_SVIDEO,
493 .vmux = TM6000_VMUX_VIDEO_AB,
494 .amux = TM6000_AMUX_ADC2,
495 },
496 },
497 .rinput = {
498 .type = TM6000_INPUT_RADIO,
499 .amux = TM6000_AMUX_SIF1,
500 },
501 },
502 [TM5600_BOARD_TERRATEC_GRABSTER] = {
503 .name = "Terratec Grabster AV 150/250 MX",
504 .type = TM5600,
505 .tuner_type = TUNER_ABSENT,
506 .vinput = { {
507 .type = TM6000_INPUT_TV,
508 .vmux = TM6000_VMUX_VIDEO_B,
509 .amux = TM6000_AMUX_ADC1,
510 }, {
511 .type = TM6000_INPUT_COMPOSITE1,
512 .vmux = TM6000_VMUX_VIDEO_A,
513 .amux = TM6000_AMUX_ADC2,
514 }, {
515 .type = TM6000_INPUT_SVIDEO,
516 .vmux = TM6000_VMUX_VIDEO_AB,
517 .amux = TM6000_AMUX_ADC2,
518 },
519 },
520 },
521 [TM6010_BOARD_TWINHAN_TU501] = {
522 .name = "Twinhan TU501(704D1)",
523 .tuner_type = TUNER_XC2028, /* has a XC3028 */
524 .tuner_addr = 0xc2 >> 1,
525 .demod_addr = 0x1e >> 1,
526 .type = TM6010,
527 .caps = {
528 .has_tuner = 1,
529 .has_dvb = 1,
530 .has_zl10353 = 1,
531 .has_eeprom = 1,
532 .has_remote = 1,
533 },
534 .gpio = {
535 .tuner_reset = TM6010_GPIO_2,
536 .tuner_on = TM6010_GPIO_3,
537 .demod_reset = TM6010_GPIO_1,
538 .demod_on = TM6010_GPIO_4,
539 .power_led = TM6010_GPIO_7,
540 .dvb_led = TM6010_GPIO_5,
541 .ir = TM6010_GPIO_0,
542 },
543 .vinput = { {
544 .type = TM6000_INPUT_TV,
545 .vmux = TM6000_VMUX_VIDEO_B,
546 .amux = TM6000_AMUX_SIF1,
547 }, {
548 .type = TM6000_INPUT_COMPOSITE1,
549 .vmux = TM6000_VMUX_VIDEO_A,
550 .amux = TM6000_AMUX_ADC2,
551 }, {
552 .type = TM6000_INPUT_SVIDEO,
553 .vmux = TM6000_VMUX_VIDEO_AB,
554 .amux = TM6000_AMUX_ADC2,
555 },
556 },
557 },
558 [TM6010_BOARD_BEHOLD_WANDER_LITE] = {
559 .name = "Beholder Wander Lite DVB-T/TV/FM USB2.0",
560 .tuner_type = TUNER_XC5000,
561 .tuner_addr = 0xc2 >> 1,
562 .demod_addr = 0x1e >> 1,
563 .type = TM6010,
564 .caps = {
565 .has_tuner = 1,
566 .has_dvb = 1,
567 .has_zl10353 = 1,
568 .has_eeprom = 1,
569 .has_remote = 0,
570 .has_radio = 1,
571 },
572 .gpio = {
573 .tuner_reset = TM6010_GPIO_0,
574 .demod_reset = TM6010_GPIO_1,
575 .power_led = TM6010_GPIO_6,
576 },
577 .vinput = { {
578 .type = TM6000_INPUT_TV,
579 .vmux = TM6000_VMUX_VIDEO_B,
580 .amux = TM6000_AMUX_SIF1,
581 },
582 },
583 .rinput = {
584 .type = TM6000_INPUT_RADIO,
585 .amux = TM6000_AMUX_ADC1,
586 },
587 },
588 [TM6010_BOARD_BEHOLD_VOYAGER_LITE] = {
589 .name = "Beholder Voyager Lite TV/FM USB2.0",
590 .tuner_type = TUNER_XC5000,
591 .tuner_addr = 0xc2 >> 1,
592 .type = TM6010,
593 .caps = {
594 .has_tuner = 1,
595 .has_dvb = 0,
596 .has_zl10353 = 0,
597 .has_eeprom = 1,
598 .has_remote = 0,
599 .has_radio = 1,
600 },
601 .gpio = {
602 .tuner_reset = TM6010_GPIO_0,
603 .power_led = TM6010_GPIO_6,
604 },
605 .vinput = { {
606 .type = TM6000_INPUT_TV,
607 .vmux = TM6000_VMUX_VIDEO_B,
608 .amux = TM6000_AMUX_SIF1,
609 },
610 },
611 .rinput = {
612 .type = TM6000_INPUT_RADIO,
613 .amux = TM6000_AMUX_ADC1,
614 },
615 },
616};
617
618/* table of devices that work with this driver */
619static struct usb_device_id tm6000_id_table[] = {
620 { USB_DEVICE(0x6000, 0x0001), .driver_info = TM5600_BOARD_GENERIC },
621 { USB_DEVICE(0x6000, 0x0002), .driver_info = TM6010_BOARD_GENERIC },
622 { USB_DEVICE(0x06e1, 0xf332), .driver_info = TM6000_BOARD_ADSTECH_DUAL_TV },
623 { USB_DEVICE(0x14aa, 0x0620), .driver_info = TM6000_BOARD_FREECOM_AND_SIMILAR },
624 { USB_DEVICE(0x06e1, 0xb339), .driver_info = TM6000_BOARD_ADSTECH_MINI_DUAL_TV },
625 { USB_DEVICE(0x2040, 0x6600), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
626 { USB_DEVICE(0x2040, 0x6601), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
627 { USB_DEVICE(0x2040, 0x6610), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
628 { USB_DEVICE(0x2040, 0x6611), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
629 { USB_DEVICE(0x6000, 0xdec0), .driver_info = TM6010_BOARD_BEHOLD_WANDER },
630 { USB_DEVICE(0x6000, 0xdec1), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER },
631 { USB_DEVICE(0x0ccd, 0x0086), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
632 { USB_DEVICE(0x0ccd, 0x00A5), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
633 { USB_DEVICE(0x0ccd, 0x0079), .driver_info = TM5600_BOARD_TERRATEC_GRABSTER },
634 { USB_DEVICE(0x13d3, 0x3240), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
635 { USB_DEVICE(0x13d3, 0x3241), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
636 { USB_DEVICE(0x13d3, 0x3243), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
637 { USB_DEVICE(0x13d3, 0x3264), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
638 { USB_DEVICE(0x6000, 0xdec2), .driver_info = TM6010_BOARD_BEHOLD_WANDER_LITE },
639 { USB_DEVICE(0x6000, 0xdec3), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER_LITE },
640 { }
641};
642
643/* Control power led for show some activity */
644void tm6000_flash_led(struct tm6000_core *dev, u8 state)
645{
646 /* Power LED unconfigured */
647 if (!dev->gpio.power_led)
648 return;
649
650 /* ON Power LED */
651 if (state) {
652 switch (dev->model) {
653 case TM6010_BOARD_HAUPPAUGE_900H:
654 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
655 case TM6010_BOARD_TWINHAN_TU501:
656 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
657 dev->gpio.power_led, 0x00);
658 break;
659 case TM6010_BOARD_BEHOLD_WANDER:
660 case TM6010_BOARD_BEHOLD_VOYAGER:
661 case TM6010_BOARD_BEHOLD_WANDER_LITE:
662 case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
663 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
664 dev->gpio.power_led, 0x01);
665 break;
666 }
667 }
668 /* OFF Power LED */
669 else {
670 switch (dev->model) {
671 case TM6010_BOARD_HAUPPAUGE_900H:
672 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
673 case TM6010_BOARD_TWINHAN_TU501:
674 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
675 dev->gpio.power_led, 0x01);
676 break;
677 case TM6010_BOARD_BEHOLD_WANDER:
678 case TM6010_BOARD_BEHOLD_VOYAGER:
679 case TM6010_BOARD_BEHOLD_WANDER_LITE:
680 case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
681 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
682 dev->gpio.power_led, 0x00);
683 break;
684 }
685 }
686}
687
688/* Tuner callback to provide the proper gpio changes needed for xc5000 */
689int tm6000_xc5000_callback(void *ptr, int component, int command, int arg)
690{
691 int rc = 0;
692 struct tm6000_core *dev = ptr;
693
694 if (dev->tuner_type != TUNER_XC5000)
695 return 0;
696
697 switch (command) {
698 case XC5000_TUNER_RESET:
699 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
700 dev->gpio.tuner_reset, 0x01);
701 msleep(15);
702 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
703 dev->gpio.tuner_reset, 0x00);
704 msleep(15);
705 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
706 dev->gpio.tuner_reset, 0x01);
707 break;
708 }
709 return rc;
710}
711EXPORT_SYMBOL_GPL(tm6000_xc5000_callback);
712
713/* Tuner callback to provide the proper gpio changes needed for xc2028 */
714
715int tm6000_tuner_callback(void *ptr, int component, int command, int arg)
716{
717 int rc = 0;
718 struct tm6000_core *dev = ptr;
719
720 if (dev->tuner_type != TUNER_XC2028)
721 return 0;
722
723 switch (command) {
724 case XC2028_RESET_CLK:
725 tm6000_ir_wait(dev, 0);
726
727 tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
728 0x02, arg);
729 msleep(10);
730 rc = tm6000_i2c_reset(dev, 10);
731 break;
732 case XC2028_TUNER_RESET:
733 /* Reset codes during load firmware */
734 switch (arg) {
735 case 0:
736 /* newer tuner can faster reset */
737 switch (dev->model) {
738 case TM5600_BOARD_10MOONS_UT821:
739 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
740 dev->gpio.tuner_reset, 0x01);
741 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
742 0x300, 0x01);
743 msleep(10);
744 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
745 dev->gpio.tuner_reset, 0x00);
746 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
747 0x300, 0x00);
748 msleep(10);
749 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
750 dev->gpio.tuner_reset, 0x01);
751 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
752 0x300, 0x01);
753 break;
754 case TM6010_BOARD_HAUPPAUGE_900H:
755 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
756 case TM6010_BOARD_TWINHAN_TU501:
757 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
758 dev->gpio.tuner_reset, 0x01);
759 msleep(60);
760 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
761 dev->gpio.tuner_reset, 0x00);
762 msleep(75);
763 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
764 dev->gpio.tuner_reset, 0x01);
765 msleep(60);
766 break;
767 default:
768 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
769 dev->gpio.tuner_reset, 0x00);
770 msleep(130);
771 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
772 dev->gpio.tuner_reset, 0x01);
773 msleep(130);
774 break;
775 }
776
777 tm6000_ir_wait(dev, 1);
778 break;
779 case 1:
780 tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
781 0x02, 0x01);
782 msleep(10);
783 break;
784 case 2:
785 rc = tm6000_i2c_reset(dev, 100);
786 break;
787 }
788 break;
789 case XC2028_I2C_FLUSH:
790 tm6000_set_reg(dev, REQ_50_SET_START, 0, 0);
791 tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0);
792 break;
793 }
794 return rc;
795}
796EXPORT_SYMBOL_GPL(tm6000_tuner_callback);
797
798int tm6000_cards_setup(struct tm6000_core *dev)
799{
800 /*
801 * Board-specific initialization sequence. Handles all GPIO
802 * initialization sequences that are board-specific.
803 * Up to now, all found devices use GPIO1 and GPIO4 at the same way.
804 * Probably, they're all based on some reference device. Due to that,
805 * there's a common routine at the end to handle those GPIO's. Devices
806 * that use different pinups or init sequences can just return at
807 * the board-specific session.
808 */
809 switch (dev->model) {
810 case TM6010_BOARD_HAUPPAUGE_900H:
811 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
812 case TM6010_BOARD_TWINHAN_TU501:
813 case TM6010_BOARD_GENERIC:
814 /* Turn xceive 3028 on */
815 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.tuner_on, 0x01);
816 msleep(15);
817 /* Turn zarlink zl10353 on */
818 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
819 msleep(15);
820 /* Reset zarlink zl10353 */
821 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
822 msleep(50);
823 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
824 msleep(15);
825 /* Turn zarlink zl10353 off */
826 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x01);
827 msleep(15);
828 /* ir ? */
829 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.ir, 0x01);
830 msleep(15);
831 /* Power led on (blue) */
832 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x00);
833 msleep(15);
834 /* DVB led off (orange) */
835 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.dvb_led, 0x01);
836 msleep(15);
837 /* Turn zarlink zl10353 on */
838 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
839 msleep(15);
840 break;
841 case TM6010_BOARD_BEHOLD_WANDER:
842 case TM6010_BOARD_BEHOLD_WANDER_LITE:
843 /* Power led on (blue) */
844 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
845 msleep(15);
846 /* Reset zarlink zl10353 */
847 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
848 msleep(50);
849 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
850 msleep(15);
851 break;
852 case TM6010_BOARD_BEHOLD_VOYAGER:
853 case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
854 /* Power led on (blue) */
855 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
856 msleep(15);
857 break;
858 default:
859 break;
860 }
861
862 /*
863 * Default initialization. Most of the devices seem to use GPIO1
864 * and GPIO4.on the same way, so, this handles the common sequence
865 * used by most devices.
866 * If a device uses a different sequence or different GPIO pins for
867 * reset, just add the code at the board-specific part
868 */
869
870 if (dev->gpio.tuner_reset) {
871 int rc;
872 int i;
873
874 for (i = 0; i < 2; i++) {
875 rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
876 dev->gpio.tuner_reset, 0x00);
877 if (rc < 0) {
878 printk(KERN_ERR "Error %i doing tuner reset\n", rc);
879 return rc;
880 }
881
882 msleep(10); /* Just to be conservative */
883 rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
884 dev->gpio.tuner_reset, 0x01);
885 if (rc < 0) {
886 printk(KERN_ERR "Error %i doing tuner reset\n", rc);
887 return rc;
888 }
889 }
890 } else {
891 printk(KERN_ERR "Tuner reset is not configured\n");
892 return -1;
893 }
894
895 msleep(50);
896
897 return 0;
898};
899
900static void tm6000_config_tuner(struct tm6000_core *dev)
901{
902 struct tuner_setup tun_setup;
903
904 /* Load tuner module */
905 v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
906 "tuner", dev->tuner_addr, NULL);
907
908 memset(&tun_setup, 0, sizeof(tun_setup));
909 tun_setup.type = dev->tuner_type;
910 tun_setup.addr = dev->tuner_addr;
911
912 tun_setup.mode_mask = 0;
913 if (dev->caps.has_tuner)
914 tun_setup.mode_mask |= (T_ANALOG_TV | T_RADIO);
915
916 switch (dev->tuner_type) {
917 case TUNER_XC2028:
918 tun_setup.tuner_callback = tm6000_tuner_callback;
919 break;
920 case TUNER_XC5000:
921 tun_setup.tuner_callback = tm6000_xc5000_callback;
922 break;
923 }
924
925 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
926
927 switch (dev->tuner_type) {
928 case TUNER_XC2028: {
929 struct v4l2_priv_tun_config xc2028_cfg;
930 struct xc2028_ctrl ctl;
931
932 memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
933 memset(&ctl, 0, sizeof(ctl));
934
935 ctl.demod = XC3028_FE_ZARLINK456;
936
937 xc2028_cfg.tuner = TUNER_XC2028;
938 xc2028_cfg.priv = &ctl;
939
940 switch (dev->model) {
941 case TM6010_BOARD_HAUPPAUGE_900H:
942 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
943 case TM6010_BOARD_TWINHAN_TU501:
944 ctl.fname = "xc3028L-v36.fw";
945 break;
946 default:
947 if (dev->dev_type == TM6010)
948 ctl.fname = "xc3028-v27.fw";
949 else
950 ctl.fname = "xc3028-v24.fw";
951 }
952
953 printk(KERN_INFO "Setting firmware parameters for xc2028\n");
954 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
955 &xc2028_cfg);
956
957 }
958 break;
959 case TUNER_XC5000:
960 {
961 struct v4l2_priv_tun_config xc5000_cfg;
962 struct xc5000_config ctl = {
963 .i2c_address = dev->tuner_addr,
964 .if_khz = 4570,
965 .radio_input = XC5000_RADIO_FM1_MONO,
966 };
967
968 xc5000_cfg.tuner = TUNER_XC5000;
969 xc5000_cfg.priv = &ctl;
970
971 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
972 &xc5000_cfg);
973 }
974 break;
975 default:
976 printk(KERN_INFO "Unknown tuner type. Tuner is not configured.\n");
977 break;
978 }
979}
980
981static int fill_board_specific_data(struct tm6000_core *dev)
982{
983 int rc;
984
985 dev->dev_type = tm6000_boards[dev->model].type;
986 dev->tuner_type = tm6000_boards[dev->model].tuner_type;
987 dev->tuner_addr = tm6000_boards[dev->model].tuner_addr;
988
989 dev->gpio = tm6000_boards[dev->model].gpio;
990
991 dev->ir_codes = tm6000_boards[dev->model].ir_codes;
992
993 dev->demod_addr = tm6000_boards[dev->model].demod_addr;
994
995 dev->caps = tm6000_boards[dev->model].caps;
996
997 dev->vinput[0] = tm6000_boards[dev->model].vinput[0];
998 dev->vinput[1] = tm6000_boards[dev->model].vinput[1];
999 dev->vinput[2] = tm6000_boards[dev->model].vinput[2];
1000 dev->rinput = tm6000_boards[dev->model].rinput;
1001
1002 /* setup per-model quirks */
1003 switch (dev->model) {
1004 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
1005 dev->quirks |= TM6000_QUIRK_NO_USB_DELAY;
1006 break;
1007
1008 default:
1009 break;
1010 }
1011
1012 /* initialize hardware */
1013 rc = tm6000_init(dev);
1014 if (rc < 0)
1015 return rc;
1016
1017 return v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
1018}
1019
1020
1021static void use_alternative_detection_method(struct tm6000_core *dev)
1022{
1023 int i, model = -1;
1024
1025 if (!dev->eedata_size)
1026 return;
1027
1028 for (i = 0; i < ARRAY_SIZE(tm6000_boards); i++) {
1029 if (!tm6000_boards[i].eename_size)
1030 continue;
1031 if (dev->eedata_size < tm6000_boards[i].eename_pos +
1032 tm6000_boards[i].eename_size)
1033 continue;
1034
1035 if (!memcmp(&dev->eedata[tm6000_boards[i].eename_pos],
1036 tm6000_boards[i].eename,
1037 tm6000_boards[i].eename_size)) {
1038 model = i;
1039 break;
1040 }
1041 }
1042 if (model < 0) {
1043 printk(KERN_INFO "Device has eeprom but is currently unknown\n");
1044 return;
1045 }
1046
1047 dev->model = model;
1048
1049 printk(KERN_INFO "Device identified via eeprom as %s (type = %d)\n",
1050 tm6000_boards[model].name, model);
1051}
1052
1053static int tm6000_init_dev(struct tm6000_core *dev)
1054{
1055 struct v4l2_frequency f;
1056 int rc = 0;
1057
1058 mutex_init(&dev->lock);
1059 mutex_lock(&dev->lock);
1060
1061 if (!is_generic(dev->model)) {
1062 rc = fill_board_specific_data(dev);
1063 if (rc < 0)
1064 goto err;
1065
1066 /* register i2c bus */
1067 rc = tm6000_i2c_register(dev);
1068 if (rc < 0)
1069 goto err;
1070 } else {
1071 /* register i2c bus */
1072 rc = tm6000_i2c_register(dev);
1073 if (rc < 0)
1074 goto err;
1075
1076 use_alternative_detection_method(dev);
1077
1078 rc = fill_board_specific_data(dev);
1079 if (rc < 0)
1080 goto err;
1081 }
1082
1083 /* Default values for STD and resolutions */
1084 dev->width = 720;
1085 dev->height = 480;
1086 dev->norm = V4L2_STD_PAL_M;
1087
1088 /* Configure tuner */
1089 tm6000_config_tuner(dev);
1090
1091 /* Set video standard */
1092 v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
1093
1094 /* Set tuner frequency - also loads firmware on xc2028/xc3028 */
1095 f.tuner = 0;
1096 f.type = V4L2_TUNER_ANALOG_TV;
1097 f.frequency = 3092; /* 193.25 MHz */
1098 dev->freq = f.frequency;
1099 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
1100
1101 if (dev->caps.has_tda9874)
1102 v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
1103 "tvaudio", I2C_ADDR_TDA9874, NULL);
1104
1105 /* register and initialize V4L2 */
1106 rc = tm6000_v4l2_register(dev);
1107 if (rc < 0)
1108 goto err;
1109
1110 tm6000_add_into_devlist(dev);
1111 tm6000_init_extension(dev);
1112
1113 tm6000_ir_init(dev);
1114
1115 mutex_unlock(&dev->lock);
1116 return 0;
1117
1118err:
1119 mutex_unlock(&dev->lock);
1120 return rc;
1121}
1122
1123/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
1124#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
1125
1126static void get_max_endpoint(struct usb_device *udev,
1127 struct usb_host_interface *alt,
1128 char *msgtype,
1129 struct usb_host_endpoint *curr_e,
1130 struct tm6000_endpoint *tm_ep)
1131{
1132 u16 tmp = le16_to_cpu(curr_e->desc.wMaxPacketSize);
1133 unsigned int size = tmp & 0x7ff;
1134
1135 if (udev->speed == USB_SPEED_HIGH)
1136 size = size * hb_mult(tmp);
1137
1138 if (size > tm_ep->maxsize) {
1139 tm_ep->endp = curr_e;
1140 tm_ep->maxsize = size;
1141 tm_ep->bInterfaceNumber = alt->desc.bInterfaceNumber;
1142 tm_ep->bAlternateSetting = alt->desc.bAlternateSetting;
1143
1144 printk(KERN_INFO "tm6000: %s endpoint: 0x%02x (max size=%u bytes)\n",
1145 msgtype, curr_e->desc.bEndpointAddress,
1146 size);
1147 }
1148}
1149
1150/*
1151 * tm6000_usb_probe()
1152 * checks for supported devices
1153 */
1154static int tm6000_usb_probe(struct usb_interface *interface,
1155 const struct usb_device_id *id)
1156{
1157 struct usb_device *usbdev;
1158 struct tm6000_core *dev = NULL;
1159 int i, rc = 0;
1160 int nr = 0;
1161 char *speed;
1162
1163 usbdev = usb_get_dev(interface_to_usbdev(interface));
1164
1165 /* Selects the proper interface */
1166 rc = usb_set_interface(usbdev, 0, 1);
1167 if (rc < 0)
1168 goto err;
1169
1170 /* Check to see next free device and mark as used */
1171 nr = find_first_zero_bit(&tm6000_devused, TM6000_MAXBOARDS);
1172 if (nr >= TM6000_MAXBOARDS) {
1173 printk(KERN_ERR "tm6000: Supports only %i tm60xx boards.\n", TM6000_MAXBOARDS);
1174 usb_put_dev(usbdev);
1175 return -ENOMEM;
1176 }
1177
1178 /* Create and initialize dev struct */
1179 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1180 if (dev == NULL) {
1181 printk(KERN_ERR "tm6000" ": out of memory!\n");
1182 usb_put_dev(usbdev);
1183 return -ENOMEM;
1184 }
1185 spin_lock_init(&dev->slock);
1186 mutex_init(&dev->usb_lock);
1187
1188 /* Increment usage count */
1189 set_bit(nr, &tm6000_devused);
1190 snprintf(dev->name, 29, "tm6000 #%d", nr);
1191
1192 dev->model = id->driver_info;
1193 if (card[nr] < ARRAY_SIZE(tm6000_boards))
1194 dev->model = card[nr];
1195
1196 dev->udev = usbdev;
1197 dev->devno = nr;
1198
1199 switch (usbdev->speed) {
1200 case USB_SPEED_LOW:
1201 speed = "1.5";
1202 break;
1203 case USB_SPEED_UNKNOWN:
1204 case USB_SPEED_FULL:
1205 speed = "12";
1206 break;
1207 case USB_SPEED_HIGH:
1208 speed = "480";
1209 break;
1210 default:
1211 speed = "unknown";
1212 }
1213
1214 /* Get endpoints */
1215 for (i = 0; i < interface->num_altsetting; i++) {
1216 int ep;
1217
1218 for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) {
1219 struct usb_host_endpoint *e;
1220 int dir_out;
1221
1222 e = &interface->altsetting[i].endpoint[ep];
1223
1224 dir_out = ((e->desc.bEndpointAddress &
1225 USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
1226
1227 printk(KERN_INFO "tm6000: alt %d, interface %i, class %i\n",
1228 i,
1229 interface->altsetting[i].desc.bInterfaceNumber,
1230 interface->altsetting[i].desc.bInterfaceClass);
1231
1232 switch (e->desc.bmAttributes) {
1233 case USB_ENDPOINT_XFER_BULK:
1234 if (!dir_out) {
1235 get_max_endpoint(usbdev,
1236 &interface->altsetting[i],
1237 "Bulk IN", e,
1238 &dev->bulk_in);
1239 } else {
1240 get_max_endpoint(usbdev,
1241 &interface->altsetting[i],
1242 "Bulk OUT", e,
1243 &dev->bulk_out);
1244 }
1245 break;
1246 case USB_ENDPOINT_XFER_ISOC:
1247 if (!dir_out) {
1248 get_max_endpoint(usbdev,
1249 &interface->altsetting[i],
1250 "ISOC IN", e,
1251 &dev->isoc_in);
1252 } else {
1253 get_max_endpoint(usbdev,
1254 &interface->altsetting[i],
1255 "ISOC OUT", e,
1256 &dev->isoc_out);
1257 }
1258 break;
1259 case USB_ENDPOINT_XFER_INT:
1260 if (!dir_out) {
1261 get_max_endpoint(usbdev,
1262 &interface->altsetting[i],
1263 "INT IN", e,
1264 &dev->int_in);
1265 } else {
1266 get_max_endpoint(usbdev,
1267 &interface->altsetting[i],
1268 "INT OUT", e,
1269 &dev->int_out);
1270 }
1271 break;
1272 }
1273 }
1274 }
1275
1276
1277 printk(KERN_INFO "tm6000: New video device @ %s Mbps (%04x:%04x, ifnum %d)\n",
1278 speed,
1279 le16_to_cpu(dev->udev->descriptor.idVendor),
1280 le16_to_cpu(dev->udev->descriptor.idProduct),
1281 interface->altsetting->desc.bInterfaceNumber);
1282
1283/* check if the the device has the iso in endpoint at the correct place */
1284 if (!dev->isoc_in.endp) {
1285 printk(KERN_ERR "tm6000: probing error: no IN ISOC endpoint!\n");
1286 rc = -ENODEV;
1287
1288 goto err;
1289 }
1290
1291 /* save our data pointer in this interface device */
1292 usb_set_intfdata(interface, dev);
1293
1294 printk(KERN_INFO "tm6000: Found %s\n", tm6000_boards[dev->model].name);
1295
1296 rc = tm6000_init_dev(dev);
1297 if (rc < 0)
1298 goto err;
1299
1300 return 0;
1301
1302err:
1303 printk(KERN_ERR "tm6000: Error %d while registering\n", rc);
1304
1305 clear_bit(nr, &tm6000_devused);
1306 usb_put_dev(usbdev);
1307
1308 kfree(dev);
1309 return rc;
1310}
1311
1312/*
1313 * tm6000_usb_disconnect()
1314 * called when the device gets diconencted
1315 * video device will be unregistered on v4l2_close in case it is still open
1316 */
1317static void tm6000_usb_disconnect(struct usb_interface *interface)
1318{
1319 struct tm6000_core *dev = usb_get_intfdata(interface);
1320 usb_set_intfdata(interface, NULL);
1321
1322 if (!dev)
1323 return;
1324
1325 printk(KERN_INFO "tm6000: disconnecting %s\n", dev->name);
1326
1327 tm6000_ir_fini(dev);
1328
1329 if (dev->gpio.power_led) {
1330 switch (dev->model) {
1331 case TM6010_BOARD_HAUPPAUGE_900H:
1332 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
1333 case TM6010_BOARD_TWINHAN_TU501:
1334 /* Power led off */
1335 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
1336 dev->gpio.power_led, 0x01);
1337 msleep(15);
1338 break;
1339 case TM6010_BOARD_BEHOLD_WANDER:
1340 case TM6010_BOARD_BEHOLD_VOYAGER:
1341 case TM6010_BOARD_BEHOLD_WANDER_LITE:
1342 case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
1343 /* Power led off */
1344 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
1345 dev->gpio.power_led, 0x00);
1346 msleep(15);
1347 break;
1348 }
1349 }
1350 tm6000_v4l2_unregister(dev);
1351
1352 tm6000_i2c_unregister(dev);
1353
1354 v4l2_device_unregister(&dev->v4l2_dev);
1355
1356 dev->state |= DEV_DISCONNECTED;
1357
1358 usb_put_dev(dev->udev);
1359
1360 tm6000_close_extension(dev);
1361 tm6000_remove_from_devlist(dev);
1362
1363 clear_bit(dev->devno, &tm6000_devused);
1364 kfree(dev);
1365}
1366
1367static struct usb_driver tm6000_usb_driver = {
1368 .name = "tm6000",
1369 .probe = tm6000_usb_probe,
1370 .disconnect = tm6000_usb_disconnect,
1371 .id_table = tm6000_id_table,
1372};
1373
1374static int __init tm6000_module_init(void)
1375{
1376 int result;
1377
1378 printk(KERN_INFO "tm6000" " v4l2 driver version %d.%d.%d loaded\n",
1379 (TM6000_VERSION >> 16) & 0xff,
1380 (TM6000_VERSION >> 8) & 0xff, TM6000_VERSION & 0xff);
1381
1382 /* register this driver with the USB subsystem */
1383 result = usb_register(&tm6000_usb_driver);
1384 if (result)
1385 printk(KERN_ERR "tm6000"
1386 " usb_register failed. Error number %d.\n", result);
1387
1388 return result;
1389}
1390
1391static void __exit tm6000_module_exit(void)
1392{
1393 /* deregister at USB subsystem */
1394 usb_deregister(&tm6000_usb_driver);
1395}
1396
1397module_init(tm6000_module_init);
1398module_exit(tm6000_module_exit);
1399
1400MODULE_DESCRIPTION("Trident TVMaster TM5600/TM6000/TM6010 USB2 adapter");
1401MODULE_AUTHOR("Mauro Carvalho Chehab");
1402MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/tm6000/tm6000-core.c b/drivers/media/video/tm6000/tm6000-core.c
new file mode 100644
index 00000000000..9783616a0da
--- /dev/null
+++ b/drivers/media/video/tm6000/tm6000-core.c
@@ -0,0 +1,965 @@
1/*
2 * tm6000-core.c - driver for TM5600/TM6000/TM6010 USB video capture devices
3 *
4 * Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
5 *
6 * Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
7 * - DVB-T support
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation version 2
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23#include <linux/module.h>
24#include <linux/kernel.h>
25#include <linux/slab.h>
26#include <linux/usb.h>
27#include <linux/i2c.h>
28#include "tm6000.h"
29#include "tm6000-regs.h"
30#include <media/v4l2-common.h>
31#include <media/tuner.h>
32
33#define USB_TIMEOUT (5 * HZ) /* ms */
34
35int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req,
36 u16 value, u16 index, u8 *buf, u16 len)
37{
38 int ret, i;
39 unsigned int pipe;
40 u8 *data = NULL;
41
42 mutex_lock(&dev->usb_lock);
43
44 if (len)
45 data = kzalloc(len, GFP_KERNEL);
46
47 if (req_type & USB_DIR_IN)
48 pipe = usb_rcvctrlpipe(dev->udev, 0);
49 else {
50 pipe = usb_sndctrlpipe(dev->udev, 0);
51 memcpy(data, buf, len);
52 }
53
54 if (tm6000_debug & V4L2_DEBUG_I2C) {
55 printk(KERN_DEBUG "(dev %p, pipe %08x): ", dev->udev, pipe);
56
57 printk(KERN_CONT "%s: %02x %02x %02x %02x %02x %02x %02x %02x ",
58 (req_type & USB_DIR_IN) ? " IN" : "OUT",
59 req_type, req, value&0xff, value>>8, index&0xff,
60 index>>8, len&0xff, len>>8);
61
62 if (!(req_type & USB_DIR_IN)) {
63 printk(KERN_CONT ">>> ");
64 for (i = 0; i < len; i++)
65 printk(KERN_CONT " %02x", buf[i]);
66 printk(KERN_CONT "\n");
67 }
68 }
69
70 ret = usb_control_msg(dev->udev, pipe, req, req_type, value, index,
71 data, len, USB_TIMEOUT);
72
73 if (req_type & USB_DIR_IN)
74 memcpy(buf, data, len);
75
76 if (tm6000_debug & V4L2_DEBUG_I2C) {
77 if (ret < 0) {
78 if (req_type & USB_DIR_IN)
79 printk(KERN_DEBUG "<<< (len=%d)\n", len);
80
81 printk(KERN_CONT "%s: Error #%d\n", __func__, ret);
82 } else if (req_type & USB_DIR_IN) {
83 printk(KERN_CONT "<<< ");
84 for (i = 0; i < len; i++)
85 printk(KERN_CONT " %02x", buf[i]);
86 printk(KERN_CONT "\n");
87 }
88 }
89
90 kfree(data);
91 msleep(5);
92
93 mutex_unlock(&dev->usb_lock);
94 return ret;
95}
96
97int tm6000_set_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index)
98{
99 return
100 tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR,
101 req, value, index, NULL, 0);
102}
103EXPORT_SYMBOL_GPL(tm6000_set_reg);
104
105int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index)
106{
107 int rc;
108 u8 buf[1];
109
110 rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
111 value, index, buf, 1);
112
113 if (rc < 0)
114 return rc;
115
116 return *buf;
117}
118EXPORT_SYMBOL_GPL(tm6000_get_reg);
119
120int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value,
121 u16 index, u16 mask)
122{
123 int rc;
124 u8 buf[1];
125 u8 new_index;
126
127 rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
128 value, index, buf, 1);
129
130 if (rc < 0)
131 return rc;
132
133 new_index = (buf[0] & ~mask) | (index & mask);
134
135 if (new_index == index)
136 return 0;
137
138 return tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR,
139 req, value, new_index, NULL, 0);
140}
141EXPORT_SYMBOL_GPL(tm6000_set_reg_mask);
142
143int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index)
144{
145 int rc;
146 u8 buf[2];
147
148 rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
149 value, index, buf, 2);
150
151 if (rc < 0)
152 return rc;
153
154 return buf[1]|buf[0]<<8;
155}
156
157int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index)
158{
159 int rc;
160 u8 buf[4];
161
162 rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
163 value, index, buf, 4);
164
165 if (rc < 0)
166 return rc;
167
168 return buf[3] | buf[2] << 8 | buf[1] << 16 | buf[0] << 24;
169}
170
171int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep)
172{
173 int rc;
174
175 rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_CLK, 0);
176 if (rc < 0)
177 return rc;
178
179 msleep(tsleep);
180
181 rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_CLK, 1);
182 msleep(tsleep);
183
184 return rc;
185}
186
187void tm6000_set_fourcc_format(struct tm6000_core *dev)
188{
189 if (dev->dev_type == TM6010) {
190 int val;
191
192 val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_IF, 0) & 0xfc;
193 if (dev->fourcc == V4L2_PIX_FMT_UYVY)
194 tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_IF, val);
195 else
196 tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_IF, val | 1);
197 } else {
198 if (dev->fourcc == V4L2_PIX_FMT_UYVY)
199 tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0);
200 else
201 tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0x90);
202 }
203}
204
205static void tm6000_set_vbi(struct tm6000_core *dev)
206{
207 /*
208 * FIXME:
209 * VBI lines and start/end are different between 60Hz and 50Hz
210 * So, it is very likely that we need to change the config to
211 * something that takes it into account, doing something different
212 * if (dev->norm & V4L2_STD_525_60)
213 */
214
215 if (dev->dev_type == TM6010) {
216 tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01);
217 tm6000_set_reg(dev, TM6010_REQ07_R41_TELETEXT_VBI_CODE1, 0x27);
218 tm6000_set_reg(dev, TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55);
219 tm6000_set_reg(dev, TM6010_REQ07_R43_VBI_DATA_TYPE_LINE7, 0x66);
220 tm6000_set_reg(dev, TM6010_REQ07_R44_VBI_DATA_TYPE_LINE8, 0x66);
221 tm6000_set_reg(dev, TM6010_REQ07_R45_VBI_DATA_TYPE_LINE9, 0x66);
222 tm6000_set_reg(dev,
223 TM6010_REQ07_R46_VBI_DATA_TYPE_LINE10, 0x66);
224 tm6000_set_reg(dev,
225 TM6010_REQ07_R47_VBI_DATA_TYPE_LINE11, 0x66);
226 tm6000_set_reg(dev,
227 TM6010_REQ07_R48_VBI_DATA_TYPE_LINE12, 0x66);
228 tm6000_set_reg(dev,
229 TM6010_REQ07_R49_VBI_DATA_TYPE_LINE13, 0x66);
230 tm6000_set_reg(dev,
231 TM6010_REQ07_R4A_VBI_DATA_TYPE_LINE14, 0x66);
232 tm6000_set_reg(dev,
233 TM6010_REQ07_R4B_VBI_DATA_TYPE_LINE15, 0x66);
234 tm6000_set_reg(dev,
235 TM6010_REQ07_R4C_VBI_DATA_TYPE_LINE16, 0x66);
236 tm6000_set_reg(dev,
237 TM6010_REQ07_R4D_VBI_DATA_TYPE_LINE17, 0x66);
238 tm6000_set_reg(dev,
239 TM6010_REQ07_R4E_VBI_DATA_TYPE_LINE18, 0x66);
240 tm6000_set_reg(dev,
241 TM6010_REQ07_R4F_VBI_DATA_TYPE_LINE19, 0x66);
242 tm6000_set_reg(dev,
243 TM6010_REQ07_R50_VBI_DATA_TYPE_LINE20, 0x66);
244 tm6000_set_reg(dev,
245 TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x66);
246 tm6000_set_reg(dev,
247 TM6010_REQ07_R52_VBI_DATA_TYPE_LINE22, 0x66);
248 tm6000_set_reg(dev,
249 TM6010_REQ07_R53_VBI_DATA_TYPE_LINE23, 0x00);
250 tm6000_set_reg(dev,
251 TM6010_REQ07_R54_VBI_DATA_TYPE_RLINES, 0x00);
252 tm6000_set_reg(dev,
253 TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01);
254 tm6000_set_reg(dev,
255 TM6010_REQ07_R56_VBI_LOOP_FILTER_I_GAIN, 0x00);
256 tm6000_set_reg(dev,
257 TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02);
258 tm6000_set_reg(dev, TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35);
259 tm6000_set_reg(dev, TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0);
260 tm6000_set_reg(dev, TM6010_REQ07_R5A_VBI_TELETEXT_DTO1, 0x11);
261 tm6000_set_reg(dev, TM6010_REQ07_R5B_VBI_TELETEXT_DTO0, 0x4c);
262 tm6000_set_reg(dev, TM6010_REQ07_R40_TELETEXT_VBI_CODE0, 0x01);
263 tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00);
264 }
265}
266
267int tm6000_init_analog_mode(struct tm6000_core *dev)
268{
269 struct v4l2_frequency f;
270
271 if (dev->dev_type == TM6010) {
272 u8 active = TM6010_REQ07_RCC_ACTIVE_IF_AUDIO_ENABLE;
273
274 if (!dev->radio)
275 active |= TM6010_REQ07_RCC_ACTIVE_IF_VIDEO_ENABLE;
276
277 /* Enable video and audio */
278 tm6000_set_reg_mask(dev, TM6010_REQ07_RCC_ACTIVE_IF,
279 active, 0x60);
280 /* Disable TS input */
281 tm6000_set_reg_mask(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE,
282 0x00, 0x40);
283 } else {
284 /* Enables soft reset */
285 tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01);
286
287 if (dev->scaler)
288 /* Disable Hfilter and Enable TS Drop err */
289 tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x20);
290 else /* Enable Hfilter and disable TS Drop err */
291 tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x80);
292
293 tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x88);
294 tm6000_set_reg(dev, TM6000_REQ07_RDA_CLK_SEL, 0x23);
295 tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xc0);
296 tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xd8);
297 tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x06);
298 tm6000_set_reg(dev, TM6000_REQ07_RDF_PWDOWN_ACLK, 0x1f);
299
300 /* AP Software reset */
301 tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08);
302 tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00);
303
304 tm6000_set_fourcc_format(dev);
305
306 /* Disables soft reset */
307 tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00);
308 }
309 msleep(20);
310
311 /* Tuner firmware can now be loaded */
312
313 /*
314 * FIXME: This is a hack! xc3028 "sleeps" when no channel is detected
315 * for more than a few seconds. Not sure why, as this behavior does
316 * not happen on other devices with xc3028. So, I suspect that it
317 * is yet another bug at tm6000. After start sleeping, decoding
318 * doesn't start automatically. Instead, it requires some
319 * I2C commands to wake it up. As we want to have image at the
320 * beginning, we needed to add this hack. The better would be to
321 * discover some way to make tm6000 to wake up without this hack.
322 */
323 f.frequency = dev->freq;
324 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
325
326 msleep(100);
327 tm6000_set_standard(dev);
328 tm6000_set_vbi(dev);
329 tm6000_set_audio_bitrate(dev, 48000);
330
331 /* switch dvb led off */
332 if (dev->gpio.dvb_led) {
333 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
334 dev->gpio.dvb_led, 0x01);
335 }
336
337 return 0;
338}
339
340int tm6000_init_digital_mode(struct tm6000_core *dev)
341{
342 if (dev->dev_type == TM6010) {
343 /* Disable video and audio */
344 tm6000_set_reg_mask(dev, TM6010_REQ07_RCC_ACTIVE_IF,
345 0x00, 0x60);
346 /* Enable TS input */
347 tm6000_set_reg_mask(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE,
348 0x40, 0x40);
349 /* all power down, but not the digital data port */
350 tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, 0x28);
351 tm6000_set_reg(dev, TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xfc);
352 tm6000_set_reg(dev, TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0xff);
353 } else {
354 tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08);
355 tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00);
356 tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01);
357 tm6000_set_reg(dev, TM6000_REQ07_RDF_PWDOWN_ACLK, 0x08);
358 tm6000_set_reg(dev, TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x0c);
359 tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0xff);
360 tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0xd8);
361 tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x40);
362 tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0);
363 tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x09);
364 tm6000_set_reg(dev, TM6000_REQ07_RDA_CLK_SEL, 0x37);
365 tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xd8);
366 tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xc0);
367 tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x60);
368
369 tm6000_set_reg(dev, TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x0c);
370 tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0xff);
371 tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0x08);
372 msleep(50);
373
374 tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
375 msleep(50);
376 tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x01);
377 msleep(50);
378 tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
379 msleep(100);
380 }
381
382 /* switch dvb led on */
383 if (dev->gpio.dvb_led) {
384 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
385 dev->gpio.dvb_led, 0x00);
386 }
387
388 return 0;
389}
390EXPORT_SYMBOL(tm6000_init_digital_mode);
391
392struct reg_init {
393 u8 req;
394 u8 reg;
395 u8 val;
396};
397
398/* The meaning of those initializations are unknown */
399static struct reg_init tm6000_init_tab[] = {
400 /* REG VALUE */
401 { TM6000_REQ07_RDF_PWDOWN_ACLK, 0x1f },
402 { TM6010_REQ07_RFF_SOFT_RESET, 0x08 },
403 { TM6010_REQ07_RFF_SOFT_RESET, 0x00 },
404 { TM6010_REQ07_RD5_POWERSAVE, 0x4f },
405 { TM6000_REQ07_RDA_CLK_SEL, 0x23 },
406 { TM6000_REQ07_RDB_OUT_SEL, 0x08 },
407 { TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x00 },
408 { TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10 },
409 { TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00 },
410 { TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x00 },
411 { TM6000_REQ07_REB_VADC_AADC_MODE, 0x64 }, /* 48000 bits/sample, external input */
412 { TM6000_REQ07_REE_VADC_CTRL_SEL_CONTROL, 0xc2 },
413
414 { TM6010_REQ07_R3F_RESET, 0x01 }, /* Start of soft reset */
415 { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 },
416 { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x07 },
417 { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
418 { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 },
419 { TM6010_REQ07_R05_NOISE_THRESHOLD, 0x64 },
420 { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01 },
421 { TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0x82 },
422 { TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0x36 },
423 { TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0x50 },
424 { TM6010_REQ07_R0C_CHROMA_AGC_CONTROL, 0x6a },
425 { TM6010_REQ07_R11_AGC_PEAK_CONTROL, 0xc9 },
426 { TM6010_REQ07_R12_AGC_GATE_STARTH, 0x07 },
427 { TM6010_REQ07_R13_AGC_GATE_STARTL, 0x3b },
428 { TM6010_REQ07_R14_AGC_GATE_WIDTH, 0x47 },
429 { TM6010_REQ07_R15_AGC_BP_DELAY, 0x6f },
430 { TM6010_REQ07_R17_HLOOP_MAXSTATE, 0xcd },
431 { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
432 { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b },
433 { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 },
434 { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 },
435 { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
436 { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
437 { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
438 { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
439 { TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME, 0x3c },
440 { TM6010_REQ07_R21_HSYNC_PHASE_OFFSET, 0x3c },
441 { TM6010_REQ07_R2D_CHROMA_BURST_END, 0x48 },
442 { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 },
443 { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 },
444 { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 },
445 { TM6010_REQ07_R32_VSYNC_HLOCK_MIN, 0x74 },
446 { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c },
447 { TM6010_REQ07_R34_VSYNC_AGC_MIN, 0x74 },
448 { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
449 { TM6010_REQ07_R36_VSYNC_VBI_MIN, 0x7a },
450 { TM6010_REQ07_R37_VSYNC_VBI_MAX, 0x26 },
451 { TM6010_REQ07_R38_VSYNC_THRESHOLD, 0x40 },
452 { TM6010_REQ07_R39_VSYNC_TIME_CONSTANT, 0x0a },
453 { TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55 },
454 { TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x11 },
455 { TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01 },
456 { TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02 },
457 { TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35 },
458 { TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0 },
459 { TM6010_REQ07_R80_COMB_FILTER_TRESHOLD, 0x15 },
460 { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 },
461 { TM6010_REQ07_RC1_TRESHOLD, 0xd0 },
462 { TM6010_REQ07_RC3_HSTART1, 0x88 },
463 { TM6010_REQ07_R3F_RESET, 0x00 }, /* End of the soft reset */
464 { TM6010_REQ05_R18_IMASK7, 0x00 },
465};
466
467static struct reg_init tm6010_init_tab[] = {
468 { TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x00 },
469 { TM6010_REQ07_RC4_HSTART0, 0xa0 },
470 { TM6010_REQ07_RC6_HEND0, 0x40 },
471 { TM6010_REQ07_RCA_VEND0, 0x31 },
472 { TM6010_REQ07_RCC_ACTIVE_IF, 0xe1 },
473 { TM6010_REQ07_RE0_DVIDEO_SOURCE, 0x03 },
474 { TM6010_REQ07_RFE_POWER_DOWN, 0x7f },
475
476 { TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0 },
477 { TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4 },
478 { TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8 },
479 { TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x00 },
480 { TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2 },
481 { TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0 },
482 { TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2 },
483 { TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60 },
484 { TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc },
485
486 { TM6010_REQ07_R3F_RESET, 0x01 },
487 { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 },
488 { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x07 },
489 { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
490 { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 },
491 { TM6010_REQ07_R05_NOISE_THRESHOLD, 0x64 },
492 { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01 },
493 { TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0x82 },
494 { TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0x36 },
495 { TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0x50 },
496 { TM6010_REQ07_R0C_CHROMA_AGC_CONTROL, 0x6a },
497 { TM6010_REQ07_R11_AGC_PEAK_CONTROL, 0xc9 },
498 { TM6010_REQ07_R12_AGC_GATE_STARTH, 0x07 },
499 { TM6010_REQ07_R13_AGC_GATE_STARTL, 0x3b },
500 { TM6010_REQ07_R14_AGC_GATE_WIDTH, 0x47 },
501 { TM6010_REQ07_R15_AGC_BP_DELAY, 0x6f },
502 { TM6010_REQ07_R17_HLOOP_MAXSTATE, 0xcd },
503 { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
504 { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b },
505 { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 },
506 { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 },
507 { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
508 { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
509 { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
510 { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
511 { TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME, 0x3c },
512 { TM6010_REQ07_R21_HSYNC_PHASE_OFFSET, 0x3c },
513 { TM6010_REQ07_R2D_CHROMA_BURST_END, 0x48 },
514 { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 },
515 { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 },
516 { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 },
517 { TM6010_REQ07_R32_VSYNC_HLOCK_MIN, 0x74 },
518 { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c },
519 { TM6010_REQ07_R34_VSYNC_AGC_MIN, 0x74 },
520 { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
521 { TM6010_REQ07_R36_VSYNC_VBI_MIN, 0x7a },
522 { TM6010_REQ07_R37_VSYNC_VBI_MAX, 0x26 },
523 { TM6010_REQ07_R38_VSYNC_THRESHOLD, 0x40 },
524 { TM6010_REQ07_R39_VSYNC_TIME_CONSTANT, 0x0a },
525 { TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55 },
526 { TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x11 },
527 { TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01 },
528 { TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02 },
529 { TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35 },
530 { TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0 },
531 { TM6010_REQ07_R80_COMB_FILTER_TRESHOLD, 0x15 },
532 { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 },
533 { TM6010_REQ07_RC1_TRESHOLD, 0xd0 },
534 { TM6010_REQ07_RC3_HSTART1, 0x88 },
535 { TM6010_REQ07_R3F_RESET, 0x00 },
536
537 { TM6010_REQ05_R18_IMASK7, 0x00 },
538
539 { TM6010_REQ07_RD8_IR_LEADER1, 0xaa },
540 { TM6010_REQ07_RD8_IR_LEADER0, 0x30 },
541 { TM6010_REQ07_RD8_IR_PULSE_CNT1, 0x20 },
542 { TM6010_REQ07_RD8_IR_PULSE_CNT0, 0xd0 },
543 { REQ_04_EN_DISABLE_MCU_INT, 0x02, 0x00 },
544 { TM6010_REQ07_RD8_IR, 0x2f },
545
546 /* set remote wakeup key:any key wakeup */
547 { TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe },
548 { TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0xff },
549};
550
551int tm6000_init(struct tm6000_core *dev)
552{
553 int board, rc = 0, i, size;
554 struct reg_init *tab;
555
556 /* Check board revision */
557 board = tm6000_get_reg32(dev, REQ_40_GET_VERSION, 0, 0);
558 if (board >= 0) {
559 switch (board & 0xff) {
560 case 0xf3:
561 printk(KERN_INFO "Found tm6000\n");
562 if (dev->dev_type != TM6000)
563 dev->dev_type = TM6000;
564 break;
565 case 0xf4:
566 printk(KERN_INFO "Found tm6010\n");
567 if (dev->dev_type != TM6010)
568 dev->dev_type = TM6010;
569 break;
570 default:
571 printk(KERN_INFO "Unknown board version = 0x%08x\n", board);
572 }
573 } else
574 printk(KERN_ERR "Error %i while retrieving board version\n", board);
575
576 if (dev->dev_type == TM6010) {
577 tab = tm6010_init_tab;
578 size = ARRAY_SIZE(tm6010_init_tab);
579 } else {
580 tab = tm6000_init_tab;
581 size = ARRAY_SIZE(tm6000_init_tab);
582 }
583
584 /* Load board's initialization table */
585 for (i = 0; i < size; i++) {
586 rc = tm6000_set_reg(dev, tab[i].req, tab[i].reg, tab[i].val);
587 if (rc < 0) {
588 printk(KERN_ERR "Error %i while setting req %d, "
589 "reg %d to value %d\n", rc,
590 tab[i].req, tab[i].reg, tab[i].val);
591 return rc;
592 }
593 }
594
595 msleep(5); /* Just to be conservative */
596
597 rc = tm6000_cards_setup(dev);
598
599 return rc;
600}
601
602int tm6000_reset(struct tm6000_core *dev)
603{
604 int pipe;
605 int err;
606
607 msleep(500);
608
609 err = usb_set_interface(dev->udev, dev->isoc_in.bInterfaceNumber, 0);
610 if (err < 0) {
611 tm6000_err("failed to select interface %d, alt. setting 0\n",
612 dev->isoc_in.bInterfaceNumber);
613 return err;
614 }
615
616 err = usb_reset_configuration(dev->udev);
617 if (err < 0) {
618 tm6000_err("failed to reset configuration\n");
619 return err;
620 }
621
622 if ((dev->quirks & TM6000_QUIRK_NO_USB_DELAY) == 0)
623 msleep(5);
624
625 /*
626 * Not all devices have int_in defined
627 */
628 if (!dev->int_in.endp)
629 return 0;
630
631 err = usb_set_interface(dev->udev, dev->isoc_in.bInterfaceNumber, 2);
632 if (err < 0) {
633 tm6000_err("failed to select interface %d, alt. setting 2\n",
634 dev->isoc_in.bInterfaceNumber);
635 return err;
636 }
637
638 msleep(5);
639
640 pipe = usb_rcvintpipe(dev->udev,
641 dev->int_in.endp->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
642
643 err = usb_clear_halt(dev->udev, pipe);
644 if (err < 0) {
645 tm6000_err("usb_clear_halt failed: %d\n", err);
646 return err;
647 }
648
649 return 0;
650}
651
652int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate)
653{
654 int val = 0;
655 u8 areg_f0 = 0x60; /* ADC MCLK = 250 Fs */
656 u8 areg_0a = 0x91; /* SIF 48KHz */
657
658 switch (bitrate) {
659 case 48000:
660 areg_f0 = 0x60; /* ADC MCLK = 250 Fs */
661 areg_0a = 0x91; /* SIF 48KHz */
662 dev->audio_bitrate = bitrate;
663 break;
664 case 32000:
665 areg_f0 = 0x00; /* ADC MCLK = 375 Fs */
666 areg_0a = 0x90; /* SIF 32KHz */
667 dev->audio_bitrate = bitrate;
668 break;
669 default:
670 return -EINVAL;
671 }
672
673
674 /* enable I2S, if we use sif or external I2S device */
675 if (dev->dev_type == TM6010) {
676 val = tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, areg_0a);
677 if (val < 0)
678 return val;
679
680 val = tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
681 areg_f0, 0xf0);
682 if (val < 0)
683 return val;
684 } else {
685 val = tm6000_set_reg_mask(dev, TM6000_REQ07_REB_VADC_AADC_MODE,
686 areg_f0, 0xf0);
687 if (val < 0)
688 return val;
689 }
690 return 0;
691}
692EXPORT_SYMBOL_GPL(tm6000_set_audio_bitrate);
693
694int tm6000_set_audio_rinput(struct tm6000_core *dev)
695{
696 if (dev->dev_type == TM6010) {
697 /* Audio crossbar setting, default SIF1 */
698 u8 areg_f0;
699
700 switch (dev->rinput.amux) {
701 case TM6000_AMUX_SIF1:
702 case TM6000_AMUX_SIF2:
703 areg_f0 = 0x03;
704 break;
705 case TM6000_AMUX_ADC1:
706 areg_f0 = 0x00;
707 break;
708 case TM6000_AMUX_ADC2:
709 areg_f0 = 0x08;
710 break;
711 case TM6000_AMUX_I2S:
712 areg_f0 = 0x04;
713 break;
714 default:
715 printk(KERN_INFO "%s: audio input dosn't support\n",
716 dev->name);
717 return 0;
718 break;
719 }
720 /* Set audio input crossbar */
721 tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
722 areg_f0, 0x0f);
723 } else {
724 u8 areg_eb;
725 /* Audio setting, default LINE1 */
726 switch (dev->rinput.amux) {
727 case TM6000_AMUX_ADC1:
728 areg_eb = 0x00;
729 break;
730 case TM6000_AMUX_ADC2:
731 areg_eb = 0x04;
732 break;
733 default:
734 printk(KERN_INFO "%s: audio input dosn't support\n",
735 dev->name);
736 return 0;
737 break;
738 }
739 /* Set audio input */
740 tm6000_set_reg_mask(dev, TM6000_REQ07_REB_VADC_AADC_MODE,
741 areg_eb, 0x0f);
742 }
743 return 0;
744}
745
746static void tm6010_set_mute_sif(struct tm6000_core *dev, u8 mute)
747{
748 u8 mute_reg = 0;
749
750 if (mute)
751 mute_reg = 0x08;
752
753 tm6000_set_reg_mask(dev, TM6010_REQ08_R0A_A_I2S_MOD, mute_reg, 0x08);
754}
755
756static void tm6010_set_mute_adc(struct tm6000_core *dev, u8 mute)
757{
758 u8 mute_reg = 0;
759
760 if (mute)
761 mute_reg = 0x20;
762
763 if (dev->dev_type == TM6010) {
764 tm6000_set_reg_mask(dev, TM6010_REQ08_RF2_LEFT_CHANNEL_VOL,
765 mute_reg, 0x20);
766 tm6000_set_reg_mask(dev, TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL,
767 mute_reg, 0x20);
768 } else {
769 tm6000_set_reg_mask(dev, TM6000_REQ07_REC_VADC_AADC_LVOL,
770 mute_reg, 0x20);
771 tm6000_set_reg_mask(dev, TM6000_REQ07_RED_VADC_AADC_RVOL,
772 mute_reg, 0x20);
773 }
774}
775
776int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute)
777{
778 enum tm6000_mux mux;
779
780 if (dev->radio)
781 mux = dev->rinput.amux;
782 else
783 mux = dev->vinput[dev->input].amux;
784
785 switch (mux) {
786 case TM6000_AMUX_SIF1:
787 case TM6000_AMUX_SIF2:
788 if (dev->dev_type == TM6010)
789 tm6010_set_mute_sif(dev, mute);
790 else {
791 printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has"
792 " SIF audio inputs. Please check the %s"
793 " configuration.\n", dev->name);
794 return -EINVAL;
795 }
796 break;
797 case TM6000_AMUX_ADC1:
798 case TM6000_AMUX_ADC2:
799 tm6010_set_mute_adc(dev, mute);
800 break;
801 default:
802 return -EINVAL;
803 break;
804 }
805 return 0;
806}
807
808static void tm6010_set_volume_sif(struct tm6000_core *dev, int vol)
809{
810 u8 vol_reg;
811
812 vol_reg = vol & 0x0F;
813
814 if (vol < 0)
815 vol_reg |= 0x40;
816
817 tm6000_set_reg(dev, TM6010_REQ08_R07_A_LEFT_VOL, vol_reg);
818 tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, vol_reg);
819}
820
821static void tm6010_set_volume_adc(struct tm6000_core *dev, int vol)
822{
823 u8 vol_reg;
824
825 vol_reg = (vol + 0x10) & 0x1f;
826
827 if (dev->dev_type == TM6010) {
828 tm6000_set_reg(dev, TM6010_REQ08_RF2_LEFT_CHANNEL_VOL, vol_reg);
829 tm6000_set_reg(dev, TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL, vol_reg);
830 } else {
831 tm6000_set_reg(dev, TM6000_REQ07_REC_VADC_AADC_LVOL, vol_reg);
832 tm6000_set_reg(dev, TM6000_REQ07_RED_VADC_AADC_RVOL, vol_reg);
833 }
834}
835
836void tm6000_set_volume(struct tm6000_core *dev, int vol)
837{
838 enum tm6000_mux mux;
839
840 if (dev->radio) {
841 mux = dev->rinput.amux;
842 vol += 8; /* Offset to 0 dB */
843 } else
844 mux = dev->vinput[dev->input].amux;
845
846 switch (mux) {
847 case TM6000_AMUX_SIF1:
848 case TM6000_AMUX_SIF2:
849 if (dev->dev_type == TM6010)
850 tm6010_set_volume_sif(dev, vol);
851 else
852 printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has"
853 " SIF audio inputs. Please check the %s"
854 " configuration.\n", dev->name);
855 break;
856 case TM6000_AMUX_ADC1:
857 case TM6000_AMUX_ADC2:
858 tm6010_set_volume_adc(dev, vol);
859 break;
860 default:
861 break;
862 }
863}
864
865static LIST_HEAD(tm6000_devlist);
866static DEFINE_MUTEX(tm6000_devlist_mutex);
867
868/*
869 * tm6000_realease_resource()
870 */
871
872void tm6000_remove_from_devlist(struct tm6000_core *dev)
873{
874 mutex_lock(&tm6000_devlist_mutex);
875 list_del(&dev->devlist);
876 mutex_unlock(&tm6000_devlist_mutex);
877};
878
879void tm6000_add_into_devlist(struct tm6000_core *dev)
880{
881 mutex_lock(&tm6000_devlist_mutex);
882 list_add_tail(&dev->devlist, &tm6000_devlist);
883 mutex_unlock(&tm6000_devlist_mutex);
884};
885
886/*
887 * Extension interface
888 */
889
890static LIST_HEAD(tm6000_extension_devlist);
891
892int tm6000_call_fillbuf(struct tm6000_core *dev, enum tm6000_ops_type type,
893 char *buf, int size)
894{
895 struct tm6000_ops *ops = NULL;
896
897 /* FIXME: tm6000_extension_devlist_lock should be a spinlock */
898
899 if (!list_empty(&tm6000_extension_devlist)) {
900 list_for_each_entry(ops, &tm6000_extension_devlist, next) {
901 if (ops->fillbuf && ops->type == type)
902 ops->fillbuf(dev, buf, size);
903 }
904 }
905
906 return 0;
907}
908
909int tm6000_register_extension(struct tm6000_ops *ops)
910{
911 struct tm6000_core *dev = NULL;
912
913 mutex_lock(&tm6000_devlist_mutex);
914 list_add_tail(&ops->next, &tm6000_extension_devlist);
915 list_for_each_entry(dev, &tm6000_devlist, devlist) {
916 ops->init(dev);
917 printk(KERN_INFO "%s: Initialized (%s) extension\n",
918 dev->name, ops->name);
919 }
920 mutex_unlock(&tm6000_devlist_mutex);
921 return 0;
922}
923EXPORT_SYMBOL(tm6000_register_extension);
924
925void tm6000_unregister_extension(struct tm6000_ops *ops)
926{
927 struct tm6000_core *dev = NULL;
928
929 mutex_lock(&tm6000_devlist_mutex);
930 list_for_each_entry(dev, &tm6000_devlist, devlist)
931 ops->fini(dev);
932
933 printk(KERN_INFO "tm6000: Remove (%s) extension\n", ops->name);
934 list_del(&ops->next);
935 mutex_unlock(&tm6000_devlist_mutex);
936}
937EXPORT_SYMBOL(tm6000_unregister_extension);
938
939void tm6000_init_extension(struct tm6000_core *dev)
940{
941 struct tm6000_ops *ops = NULL;
942
943 mutex_lock(&tm6000_devlist_mutex);
944 if (!list_empty(&tm6000_extension_devlist)) {
945 list_for_each_entry(ops, &tm6000_extension_devlist, next) {
946 if (ops->init)
947 ops->init(dev);
948 }
949 }
950 mutex_unlock(&tm6000_devlist_mutex);
951}
952
953void tm6000_close_extension(struct tm6000_core *dev)
954{
955 struct tm6000_ops *ops = NULL;
956
957 mutex_lock(&tm6000_devlist_mutex);
958 if (!list_empty(&tm6000_extension_devlist)) {
959 list_for_each_entry(ops, &tm6000_extension_devlist, next) {
960 if (ops->fini)
961 ops->fini(dev);
962 }
963 }
964 mutex_unlock(&tm6000_devlist_mutex);
965}
diff --git a/drivers/media/video/tm6000/tm6000-dvb.c b/drivers/media/video/tm6000/tm6000-dvb.c
new file mode 100644
index 00000000000..5e6c129a4be
--- /dev/null
+++ b/drivers/media/video/tm6000/tm6000-dvb.c
@@ -0,0 +1,452 @@
1/*
2 * tm6000-dvb.c - dvb-t support for TM5600/TM6000/TM6010 USB video capture devices
3 *
4 * Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation version 2
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20#include <linux/kernel.h>
21#include <linux/slab.h>
22#include <linux/usb.h>
23
24#include "tm6000.h"
25#include "tm6000-regs.h"
26
27#include "zl10353.h"
28
29#include <media/tuner.h>
30
31#include "tuner-xc2028.h"
32#include "xc5000.h"
33
34MODULE_DESCRIPTION("DVB driver extension module for tm5600/6000/6010 based TV cards");
35MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
36MODULE_LICENSE("GPL");
37
38MODULE_SUPPORTED_DEVICE("{{Trident, tm5600},"
39 "{{Trident, tm6000},"
40 "{{Trident, tm6010}");
41
42static int debug;
43
44module_param(debug, int, 0644);
45MODULE_PARM_DESC(debug, "enable debug message");
46
47static inline void print_err_status(struct tm6000_core *dev,
48 int packet, int status)
49{
50 char *errmsg = "Unknown";
51
52 switch (status) {
53 case -ENOENT:
54 errmsg = "unlinked synchronuously";
55 break;
56 case -ECONNRESET:
57 errmsg = "unlinked asynchronuously";
58 break;
59 case -ENOSR:
60 errmsg = "Buffer error (overrun)";
61 break;
62 case -EPIPE:
63 errmsg = "Stalled (device not responding)";
64 break;
65 case -EOVERFLOW:
66 errmsg = "Babble (bad cable?)";
67 break;
68 case -EPROTO:
69 errmsg = "Bit-stuff error (bad cable?)";
70 break;
71 case -EILSEQ:
72 errmsg = "CRC/Timeout (could be anything)";
73 break;
74 case -ETIME:
75 errmsg = "Device does not respond";
76 break;
77 }
78 if (packet < 0) {
79 dprintk(dev, 1, "URB status %d [%s].\n",
80 status, errmsg);
81 } else {
82 dprintk(dev, 1, "URB packet %d, status %d [%s].\n",
83 packet, status, errmsg);
84 }
85}
86
87static void tm6000_urb_received(struct urb *urb)
88{
89 int ret;
90 struct tm6000_core *dev = urb->context;
91
92 if (urb->status != 0)
93 print_err_status(dev, 0, urb->status);
94 else if (urb->actual_length > 0)
95 dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer,
96 urb->actual_length);
97
98 if (dev->dvb->streams > 0) {
99 ret = usb_submit_urb(urb, GFP_ATOMIC);
100 if (ret < 0) {
101 printk(KERN_ERR "tm6000: error %s\n", __func__);
102 kfree(urb->transfer_buffer);
103 usb_free_urb(urb);
104 }
105 }
106}
107
108static int tm6000_start_stream(struct tm6000_core *dev)
109{
110 int ret;
111 unsigned int pipe, size;
112 struct tm6000_dvb *dvb = dev->dvb;
113
114 printk(KERN_INFO "tm6000: got start stream request %s\n", __func__);
115
116 if (dev->mode != TM6000_MODE_DIGITAL) {
117 tm6000_init_digital_mode(dev);
118 dev->mode = TM6000_MODE_DIGITAL;
119 }
120
121 dvb->bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
122 if (dvb->bulk_urb == NULL) {
123 printk(KERN_ERR "tm6000: couldn't allocate urb\n");
124 return -ENOMEM;
125 }
126
127 pipe = usb_rcvbulkpipe(dev->udev, dev->bulk_in.endp->desc.bEndpointAddress
128 & USB_ENDPOINT_NUMBER_MASK);
129
130 size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
131 size = size * 15; /* 512 x 8 or 12 or 15 */
132
133 dvb->bulk_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
134 if (dvb->bulk_urb->transfer_buffer == NULL) {
135 usb_free_urb(dvb->bulk_urb);
136 printk(KERN_ERR "tm6000: couldn't allocate transfer buffer!\n");
137 return -ENOMEM;
138 }
139
140 usb_fill_bulk_urb(dvb->bulk_urb, dev->udev, pipe,
141 dvb->bulk_urb->transfer_buffer,
142 size,
143 tm6000_urb_received, dev);
144
145 ret = usb_clear_halt(dev->udev, pipe);
146 if (ret < 0) {
147 printk(KERN_ERR "tm6000: error %i in %s during pipe reset\n",
148 ret, __func__);
149 return ret;
150 } else
151 printk(KERN_ERR "tm6000: pipe resetted\n");
152
153/* mutex_lock(&tm6000_driver.open_close_mutex); */
154 ret = usb_submit_urb(dvb->bulk_urb, GFP_KERNEL);
155
156/* mutex_unlock(&tm6000_driver.open_close_mutex); */
157 if (ret) {
158 printk(KERN_ERR "tm6000: submit of urb failed (error=%i)\n",
159 ret);
160
161 kfree(dvb->bulk_urb->transfer_buffer);
162 usb_free_urb(dvb->bulk_urb);
163 return ret;
164 }
165
166 return 0;
167}
168
169static void tm6000_stop_stream(struct tm6000_core *dev)
170{
171 struct tm6000_dvb *dvb = dev->dvb;
172
173 if (dvb->bulk_urb) {
174 printk(KERN_INFO "urb killing\n");
175 usb_kill_urb(dvb->bulk_urb);
176 printk(KERN_INFO "urb buffer free\n");
177 kfree(dvb->bulk_urb->transfer_buffer);
178 usb_free_urb(dvb->bulk_urb);
179 dvb->bulk_urb = NULL;
180 }
181}
182
183static int tm6000_start_feed(struct dvb_demux_feed *feed)
184{
185 struct dvb_demux *demux = feed->demux;
186 struct tm6000_core *dev = demux->priv;
187 struct tm6000_dvb *dvb = dev->dvb;
188 printk(KERN_INFO "tm6000: got start feed request %s\n", __func__);
189
190 mutex_lock(&dvb->mutex);
191 if (dvb->streams == 0) {
192 dvb->streams = 1;
193/* mutex_init(&tm6000_dev->streming_mutex); */
194 tm6000_start_stream(dev);
195 } else
196 ++(dvb->streams);
197 mutex_unlock(&dvb->mutex);
198
199 return 0;
200}
201
202static int tm6000_stop_feed(struct dvb_demux_feed *feed)
203{
204 struct dvb_demux *demux = feed->demux;
205 struct tm6000_core *dev = demux->priv;
206 struct tm6000_dvb *dvb = dev->dvb;
207
208 printk(KERN_INFO "tm6000: got stop feed request %s\n", __func__);
209
210 mutex_lock(&dvb->mutex);
211
212 printk(KERN_INFO "stream %#x\n", dvb->streams);
213 --(dvb->streams);
214 if (dvb->streams == 0) {
215 printk(KERN_INFO "stop stream\n");
216 tm6000_stop_stream(dev);
217/* mutex_destroy(&tm6000_dev->streaming_mutex); */
218 }
219 mutex_unlock(&dvb->mutex);
220/* mutex_destroy(&tm6000_dev->streaming_mutex); */
221
222 return 0;
223}
224
225static int tm6000_dvb_attach_frontend(struct tm6000_core *dev)
226{
227 struct tm6000_dvb *dvb = dev->dvb;
228
229 if (dev->caps.has_zl10353) {
230 struct zl10353_config config = {
231 .demod_address = dev->demod_addr,
232 .no_tuner = 1,
233 .parallel_ts = 1,
234 .if2 = 45700,
235 .disable_i2c_gate_ctrl = 1,
236 };
237
238 dvb->frontend = dvb_attach(zl10353_attach, &config,
239 &dev->i2c_adap);
240 } else {
241 printk(KERN_ERR "tm6000: no frontend defined for the device!\n");
242 return -1;
243 }
244
245 return (!dvb->frontend) ? -1 : 0;
246}
247
248DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
249
250static int register_dvb(struct tm6000_core *dev)
251{
252 int ret = -1;
253 struct tm6000_dvb *dvb = dev->dvb;
254
255 mutex_init(&dvb->mutex);
256
257 dvb->streams = 0;
258
259 /* attach the frontend */
260 ret = tm6000_dvb_attach_frontend(dev);
261 if (ret < 0) {
262 printk(KERN_ERR "tm6000: couldn't attach the frontend!\n");
263 goto err;
264 }
265
266 ret = dvb_register_adapter(&dvb->adapter, "Trident TVMaster 6000 DVB-T",
267 THIS_MODULE, &dev->udev->dev, adapter_nr);
268 dvb->adapter.priv = dev;
269
270 if (dvb->frontend) {
271 switch (dev->tuner_type) {
272 case TUNER_XC2028: {
273 struct xc2028_config cfg = {
274 .i2c_adap = &dev->i2c_adap,
275 .i2c_addr = dev->tuner_addr,
276 };
277
278 dvb->frontend->callback = tm6000_tuner_callback;
279 ret = dvb_register_frontend(&dvb->adapter, dvb->frontend);
280 if (ret < 0) {
281 printk(KERN_ERR
282 "tm6000: couldn't register frontend\n");
283 goto adapter_err;
284 }
285
286 if (!dvb_attach(xc2028_attach, dvb->frontend, &cfg)) {
287 printk(KERN_ERR "tm6000: couldn't register "
288 "frontend (xc3028)\n");
289 ret = -EINVAL;
290 goto frontend_err;
291 }
292 printk(KERN_INFO "tm6000: XC2028/3028 asked to be "
293 "attached to frontend!\n");
294 break;
295 }
296 case TUNER_XC5000: {
297 struct xc5000_config cfg = {
298 .i2c_address = dev->tuner_addr,
299 };
300
301 dvb->frontend->callback = tm6000_xc5000_callback;
302 ret = dvb_register_frontend(&dvb->adapter, dvb->frontend);
303 if (ret < 0) {
304 printk(KERN_ERR
305 "tm6000: couldn't register frontend\n");
306 goto adapter_err;
307 }
308
309 if (!dvb_attach(xc5000_attach, dvb->frontend, &dev->i2c_adap, &cfg)) {
310 printk(KERN_ERR "tm6000: couldn't register "
311 "frontend (xc5000)\n");
312 ret = -EINVAL;
313 goto frontend_err;
314 }
315 printk(KERN_INFO "tm6000: XC5000 asked to be "
316 "attached to frontend!\n");
317 break;
318 }
319 }
320 } else
321 printk(KERN_ERR "tm6000: no frontend found\n");
322
323 dvb->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING
324 | DMX_MEMORY_BASED_FILTERING;
325 dvb->demux.priv = dev;
326 dvb->demux.filternum = 8;
327 dvb->demux.feednum = 8;
328 dvb->demux.start_feed = tm6000_start_feed;
329 dvb->demux.stop_feed = tm6000_stop_feed;
330 dvb->demux.write_to_decoder = NULL;
331 ret = dvb_dmx_init(&dvb->demux);
332 if (ret < 0) {
333 printk(KERN_ERR "tm6000: dvb_dmx_init failed (errno = %d)\n", ret);
334 goto frontend_err;
335 }
336
337 dvb->dmxdev.filternum = dev->dvb->demux.filternum;
338 dvb->dmxdev.demux = &dev->dvb->demux.dmx;
339 dvb->dmxdev.capabilities = 0;
340
341 ret = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
342 if (ret < 0) {
343 printk(KERN_ERR "tm6000: dvb_dmxdev_init failed (errno = %d)\n", ret);
344 goto dvb_dmx_err;
345 }
346
347 return 0;
348
349dvb_dmx_err:
350 dvb_dmx_release(&dvb->demux);
351frontend_err:
352 if (dvb->frontend) {
353 dvb_frontend_detach(dvb->frontend);
354 dvb_unregister_frontend(dvb->frontend);
355 }
356adapter_err:
357 dvb_unregister_adapter(&dvb->adapter);
358err:
359 return ret;
360}
361
362static void unregister_dvb(struct tm6000_core *dev)
363{
364 struct tm6000_dvb *dvb = dev->dvb;
365
366 if (dvb->bulk_urb != NULL) {
367 struct urb *bulk_urb = dvb->bulk_urb;
368
369 kfree(bulk_urb->transfer_buffer);
370 bulk_urb->transfer_buffer = NULL;
371 usb_unlink_urb(bulk_urb);
372 usb_free_urb(bulk_urb);
373 }
374
375/* mutex_lock(&tm6000_driver.open_close_mutex); */
376 if (dvb->frontend) {
377 dvb_frontend_detach(dvb->frontend);
378 dvb_unregister_frontend(dvb->frontend);
379 }
380
381 dvb_dmxdev_release(&dvb->dmxdev);
382 dvb_dmx_release(&dvb->demux);
383 dvb_unregister_adapter(&dvb->adapter);
384 mutex_destroy(&dvb->mutex);
385/* mutex_unlock(&tm6000_driver.open_close_mutex); */
386}
387
388static int dvb_init(struct tm6000_core *dev)
389{
390 struct tm6000_dvb *dvb;
391 int rc;
392
393 if (!dev)
394 return 0;
395
396 if (!dev->caps.has_dvb)
397 return 0;
398
399 dvb = kzalloc(sizeof(struct tm6000_dvb), GFP_KERNEL);
400 if (!dvb) {
401 printk(KERN_INFO "Cannot allocate memory\n");
402 return -ENOMEM;
403 }
404
405 dev->dvb = dvb;
406
407 rc = register_dvb(dev);
408 if (rc < 0) {
409 kfree(dvb);
410 dev->dvb = NULL;
411 return 0;
412 }
413
414 return 0;
415}
416
417static int dvb_fini(struct tm6000_core *dev)
418{
419 if (!dev)
420 return 0;
421
422 if (!dev->caps.has_dvb)
423 return 0;
424
425 if (dev->dvb) {
426 unregister_dvb(dev);
427 kfree(dev->dvb);
428 dev->dvb = NULL;
429 }
430
431 return 0;
432}
433
434static struct tm6000_ops dvb_ops = {
435 .type = TM6000_DVB,
436 .name = "TM6000 dvb Extension",
437 .init = dvb_init,
438 .fini = dvb_fini,
439};
440
441static int __init tm6000_dvb_register(void)
442{
443 return tm6000_register_extension(&dvb_ops);
444}
445
446static void __exit tm6000_dvb_unregister(void)
447{
448 tm6000_unregister_extension(&dvb_ops);
449}
450
451module_init(tm6000_dvb_register);
452module_exit(tm6000_dvb_unregister);
diff --git a/drivers/media/video/tm6000/tm6000-i2c.c b/drivers/media/video/tm6000/tm6000-i2c.c
new file mode 100644
index 00000000000..0290bbf00c3
--- /dev/null
+++ b/drivers/media/video/tm6000/tm6000-i2c.c
@@ -0,0 +1,340 @@
1/*
2 * tm6000-i2c.c - driver for TM5600/TM6000/TM6010 USB video capture devices
3 *
4 * Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
5 *
6 * Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
7 * - Fix SMBus Read Byte command
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation version 2
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23#include <linux/module.h>
24#include <linux/kernel.h>
25#include <linux/usb.h>
26#include <linux/i2c.h>
27
28#include "tm6000.h"
29#include "tm6000-regs.h"
30#include <media/v4l2-common.h>
31#include <media/tuner.h>
32#include "tuner-xc2028.h"
33
34
35/* ----------------------------------------------------------- */
36
37static unsigned int i2c_debug;
38module_param(i2c_debug, int, 0644);
39MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
40
41#define i2c_dprintk(lvl, fmt, args...) if (i2c_debug >= lvl) do { \
42 printk(KERN_DEBUG "%s at %s: " fmt, \
43 dev->name, __func__, ##args); } while (0)
44
45static int tm6000_i2c_send_regs(struct tm6000_core *dev, unsigned char addr,
46 __u8 reg, char *buf, int len)
47{
48 int rc;
49 unsigned int tsleep;
50 unsigned int i2c_packet_limit = 16;
51
52 if (dev->dev_type == TM6010)
53 i2c_packet_limit = 64;
54
55 if (!buf)
56 return -1;
57
58 if (len < 1 || len > i2c_packet_limit) {
59 printk(KERN_ERR "Incorrect length of i2c packet = %d, limit set to %d\n",
60 len, i2c_packet_limit);
61 return -1;
62 }
63
64 /* capture mutex */
65 rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
66 USB_RECIP_DEVICE, REQ_16_SET_GET_I2C_WR1_RDN,
67 addr | reg << 8, 0, buf, len);
68
69 if (rc < 0) {
70 /* release mutex */
71 return rc;
72 }
73
74 /* Calculate delay time, 14000us for 64 bytes */
75 tsleep = ((len * 200) + 200 + 1000) / 1000;
76 msleep(tsleep);
77
78 /* release mutex */
79 return rc;
80}
81
82/* Generic read - doesn't work fine with 16bit registers */
83static int tm6000_i2c_recv_regs(struct tm6000_core *dev, unsigned char addr,
84 __u8 reg, char *buf, int len)
85{
86 int rc;
87 u8 b[2];
88 unsigned int i2c_packet_limit = 16;
89
90 if (dev->dev_type == TM6010)
91 i2c_packet_limit = 64;
92
93 if (!buf)
94 return -1;
95
96 if (len < 1 || len > i2c_packet_limit) {
97 printk(KERN_ERR "Incorrect length of i2c packet = %d, limit set to %d\n",
98 len, i2c_packet_limit);
99 return -1;
100 }
101
102 /* capture mutex */
103 if ((dev->caps.has_zl10353) && (dev->demod_addr << 1 == addr) && (reg % 2 == 0)) {
104 /*
105 * Workaround an I2C bug when reading from zl10353
106 */
107 reg -= 1;
108 len += 1;
109
110 rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
111 REQ_16_SET_GET_I2C_WR1_RDN, addr | reg << 8, 0, b, len);
112
113 *buf = b[1];
114 } else {
115 rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
116 REQ_16_SET_GET_I2C_WR1_RDN, addr | reg << 8, 0, buf, len);
117 }
118
119 /* release mutex */
120 return rc;
121}
122
123/*
124 * read from a 16bit register
125 * for example xc2028, xc3028 or xc3028L
126 */
127static int tm6000_i2c_recv_regs16(struct tm6000_core *dev, unsigned char addr,
128 __u16 reg, char *buf, int len)
129{
130 int rc;
131 unsigned char ureg;
132
133 if (!buf || len != 2)
134 return -1;
135
136 /* capture mutex */
137 if (dev->dev_type == TM6010) {
138 ureg = reg & 0xFF;
139 rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
140 USB_RECIP_DEVICE, REQ_16_SET_GET_I2C_WR1_RDN,
141 addr | (reg & 0xFF00), 0, &ureg, 1);
142
143 if (rc < 0) {
144 /* release mutex */
145 return rc;
146 }
147
148 msleep(1400 / 1000);
149 rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR |
150 USB_RECIP_DEVICE, REQ_35_AFTEK_TUNER_READ,
151 reg, 0, buf, len);
152 } else {
153 rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR |
154 USB_RECIP_DEVICE, REQ_14_SET_GET_I2C_WR2_RDN,
155 addr, reg, buf, len);
156 }
157
158 /* release mutex */
159 return rc;
160}
161
162static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap,
163 struct i2c_msg msgs[], int num)
164{
165 struct tm6000_core *dev = i2c_adap->algo_data;
166 int addr, rc, i, byte;
167
168 if (num <= 0)
169 return 0;
170 for (i = 0; i < num; i++) {
171 addr = (msgs[i].addr << 1) & 0xff;
172 i2c_dprintk(2, "%s %s addr=0x%x len=%d:",
173 (msgs[i].flags & I2C_M_RD) ? "read" : "write",
174 i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
175 if (msgs[i].flags & I2C_M_RD) {
176 /* read request without preceding register selection */
177 /*
178 * The TM6000 only supports a read transaction
179 * immediately after a 1 or 2 byte write to select
180 * a register. We cannot fulfil this request.
181 */
182 i2c_dprintk(2, " read without preceding write not"
183 " supported");
184 rc = -EOPNOTSUPP;
185 goto err;
186 } else if (i + 1 < num && msgs[i].len <= 2 &&
187 (msgs[i + 1].flags & I2C_M_RD) &&
188 msgs[i].addr == msgs[i + 1].addr) {
189 /* 1 or 2 byte write followed by a read */
190 if (i2c_debug >= 2)
191 for (byte = 0; byte < msgs[i].len; byte++)
192 printk(KERN_CONT " %02x", msgs[i].buf[byte]);
193 i2c_dprintk(2, "; joined to read %s len=%d:",
194 i == num - 2 ? "stop" : "nonstop",
195 msgs[i + 1].len);
196
197 if (msgs[i].len == 2) {
198 rc = tm6000_i2c_recv_regs16(dev, addr,
199 msgs[i].buf[0] << 8 | msgs[i].buf[1],
200 msgs[i + 1].buf, msgs[i + 1].len);
201 } else {
202 rc = tm6000_i2c_recv_regs(dev, addr, msgs[i].buf[0],
203 msgs[i + 1].buf, msgs[i + 1].len);
204 }
205
206 i++;
207
208 if (addr == dev->tuner_addr << 1) {
209 tm6000_set_reg(dev, REQ_50_SET_START, 0, 0);
210 tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0);
211 }
212 if (i2c_debug >= 2)
213 for (byte = 0; byte < msgs[i].len; byte++)
214 printk(KERN_CONT " %02x", msgs[i].buf[byte]);
215 } else {
216 /* write bytes */
217 if (i2c_debug >= 2)
218 for (byte = 0; byte < msgs[i].len; byte++)
219 printk(KERN_CONT " %02x", msgs[i].buf[byte]);
220 rc = tm6000_i2c_send_regs(dev, addr, msgs[i].buf[0],
221 msgs[i].buf + 1, msgs[i].len - 1);
222 }
223 if (i2c_debug >= 2)
224 printk(KERN_CONT "\n");
225 if (rc < 0)
226 goto err;
227 }
228
229 return num;
230err:
231 i2c_dprintk(2, " ERROR: %i\n", rc);
232 return rc;
233}
234
235static int tm6000_i2c_eeprom(struct tm6000_core *dev)
236{
237 int i, rc;
238 unsigned char *p = dev->eedata;
239 unsigned char bytes[17];
240
241 dev->i2c_client.addr = 0xa0 >> 1;
242 dev->eedata_size = 0;
243
244 bytes[16] = '\0';
245 for (i = 0; i < sizeof(dev->eedata); ) {
246 *p = i;
247 rc = tm6000_i2c_recv_regs(dev, 0xa0, i, p, 1);
248 if (rc < 1) {
249 if (p == dev->eedata)
250 goto noeeprom;
251 else {
252 printk(KERN_WARNING
253 "%s: i2c eeprom read error (err=%d)\n",
254 dev->name, rc);
255 }
256 return -EINVAL;
257 }
258 dev->eedata_size++;
259 p++;
260 if (0 == (i % 16))
261 printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
262 printk(KERN_CONT " %02x", dev->eedata[i]);
263 if ((dev->eedata[i] >= ' ') && (dev->eedata[i] <= 'z'))
264 bytes[i%16] = dev->eedata[i];
265 else
266 bytes[i%16] = '.';
267
268 i++;
269
270 if (0 == (i % 16)) {
271 bytes[16] = '\0';
272 printk(KERN_CONT " %s\n", bytes);
273 }
274 }
275 if (0 != (i%16)) {
276 bytes[i%16] = '\0';
277 for (i %= 16; i < 16; i++)
278 printk(KERN_CONT " ");
279 printk(KERN_CONT " %s\n", bytes);
280 }
281
282 return 0;
283
284noeeprom:
285 printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
286 dev->name, rc);
287 return -EINVAL;
288}
289
290/* ----------------------------------------------------------- */
291
292/*
293 * functionality()
294 */
295static u32 functionality(struct i2c_adapter *adap)
296{
297 return I2C_FUNC_SMBUS_EMUL;
298}
299
300static const struct i2c_algorithm tm6000_algo = {
301 .master_xfer = tm6000_i2c_xfer,
302 .functionality = functionality,
303};
304
305/* ----------------------------------------------------------- */
306
307/*
308 * tm6000_i2c_register()
309 * register i2c bus
310 */
311int tm6000_i2c_register(struct tm6000_core *dev)
312{
313 int rc;
314
315 dev->i2c_adap.owner = THIS_MODULE;
316 dev->i2c_adap.algo = &tm6000_algo;
317 dev->i2c_adap.dev.parent = &dev->udev->dev;
318 strlcpy(dev->i2c_adap.name, dev->name, sizeof(dev->i2c_adap.name));
319 dev->i2c_adap.algo_data = dev;
320 i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
321 rc = i2c_add_adapter(&dev->i2c_adap);
322 if (rc)
323 return rc;
324
325 dev->i2c_client.adapter = &dev->i2c_adap;
326 strlcpy(dev->i2c_client.name, "tm6000 internal", I2C_NAME_SIZE);
327 tm6000_i2c_eeprom(dev);
328
329 return 0;
330}
331
332/*
333 * tm6000_i2c_unregister()
334 * unregister i2c_bus
335 */
336int tm6000_i2c_unregister(struct tm6000_core *dev)
337{
338 i2c_del_adapter(&dev->i2c_adap);
339 return 0;
340}
diff --git a/drivers/media/video/tm6000/tm6000-input.c b/drivers/media/video/tm6000/tm6000-input.c
new file mode 100644
index 00000000000..405d12729d0
--- /dev/null
+++ b/drivers/media/video/tm6000/tm6000-input.c
@@ -0,0 +1,459 @@
1/*
2 * tm6000-input.c - driver for TM5600/TM6000/TM6010 USB video capture devices
3 *
4 * Copyright (C) 2010 Stefan Ringel <stefan.ringel@arcor.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation version 2
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20#include <linux/module.h>
21#include <linux/init.h>
22#include <linux/delay.h>
23
24#include <linux/input.h>
25#include <linux/usb.h>
26
27#include <media/rc-core.h>
28
29#include "tm6000.h"
30#include "tm6000-regs.h"
31
32static unsigned int ir_debug;
33module_param(ir_debug, int, 0644);
34MODULE_PARM_DESC(ir_debug, "enable debug message [IR]");
35
36static unsigned int enable_ir = 1;
37module_param(enable_ir, int, 0644);
38MODULE_PARM_DESC(enable_ir, "enable ir (default is enable)");
39
40/* number of 50ms for ON-OFF-ON power led */
41/* show IR activity */
42#define PWLED_OFF 2
43
44#undef dprintk
45
46#define dprintk(fmt, arg...) \
47 if (ir_debug) { \
48 printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
49 }
50
51struct tm6000_ir_poll_result {
52 u16 rc_data;
53};
54
55struct tm6000_IR {
56 struct tm6000_core *dev;
57 struct rc_dev *rc;
58 char name[32];
59 char phys[32];
60
61 /* poll expernal decoder */
62 int polling;
63 struct delayed_work work;
64 u8 wait:1;
65 u8 key:1;
66 u8 pwled:1;
67 u8 pwledcnt;
68 u16 key_addr;
69 struct urb *int_urb;
70 u8 *urb_data;
71
72 int (*get_key) (struct tm6000_IR *, struct tm6000_ir_poll_result *);
73
74 /* IR device properties */
75 u64 rc_type;
76};
77
78
79void tm6000_ir_wait(struct tm6000_core *dev, u8 state)
80{
81 struct tm6000_IR *ir = dev->ir;
82
83 if (!dev->ir)
84 return;
85
86 if (state)
87 ir->wait = 1;
88 else
89 ir->wait = 0;
90}
91
92
93static int tm6000_ir_config(struct tm6000_IR *ir)
94{
95 struct tm6000_core *dev = ir->dev;
96 u8 buf[10];
97 int rc;
98
99 switch (ir->rc_type) {
100 case RC_TYPE_NEC:
101 /* Setup IR decoder for NEC standard 12MHz system clock */
102 /* IR_LEADER_CNT = 0.9ms */
103 tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER1, 0xaa);
104 tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER0, 0x30);
105 /* IR_PULSE_CNT = 0.7ms */
106 tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT1, 0x20);
107 tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0xd0);
108 /* Remote WAKEUP = enable */
109 tm6000_set_reg(dev, TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe);
110 /* IR_WKUP_SEL = Low byte in decoded IR data */
111 tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0xff);
112 /* IR_WKU_ADD code */
113 tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_ADD, 0xff);
114 tm6000_flash_led(dev, 0);
115 msleep(100);
116 tm6000_flash_led(dev, 1);
117 break;
118 default:
119 /* hack */
120 buf[0] = 0xff;
121 buf[1] = 0xff;
122 buf[2] = 0xf2;
123 buf[3] = 0x2b;
124 buf[4] = 0x20;
125 buf[5] = 0x35;
126 buf[6] = 0x60;
127 buf[7] = 0x04;
128 buf[8] = 0xc0;
129 buf[9] = 0x08;
130
131 rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
132 USB_RECIP_DEVICE, REQ_00_SET_IR_VALUE, 0, 0, buf, 0x0a);
133 msleep(100);
134
135 if (rc < 0) {
136 printk(KERN_INFO "IR configuration failed");
137 return rc;
138 }
139 break;
140 }
141
142 return 0;
143}
144
145static void tm6000_ir_urb_received(struct urb *urb)
146{
147 struct tm6000_core *dev = urb->context;
148 struct tm6000_IR *ir = dev->ir;
149 int rc;
150
151 if (urb->status != 0)
152 printk(KERN_INFO "not ready\n");
153 else if (urb->actual_length > 0) {
154 memcpy(ir->urb_data, urb->transfer_buffer, urb->actual_length);
155
156 dprintk("data %02x %02x %02x %02x\n", ir->urb_data[0],
157 ir->urb_data[1], ir->urb_data[2], ir->urb_data[3]);
158
159 ir->key = 1;
160 }
161
162 rc = usb_submit_urb(urb, GFP_ATOMIC);
163}
164
165static int default_polling_getkey(struct tm6000_IR *ir,
166 struct tm6000_ir_poll_result *poll_result)
167{
168 struct tm6000_core *dev = ir->dev;
169 int rc;
170 u8 buf[2];
171
172 if (ir->wait && !&dev->int_in)
173 return 0;
174
175 if (&dev->int_in) {
176 switch (ir->rc_type) {
177 case RC_TYPE_RC5:
178 poll_result->rc_data = ir->urb_data[0];
179 break;
180 case RC_TYPE_NEC:
181 if (ir->urb_data[1] == ((ir->key_addr >> 8) & 0xff)) {
182 poll_result->rc_data = ir->urb_data[0]
183 | ir->urb_data[1] << 8;
184 }
185 break;
186 default:
187 poll_result->rc_data = ir->urb_data[0]
188 | ir->urb_data[1] << 8;
189 break;
190 }
191 } else {
192 tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0);
193 msleep(10);
194 tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 1);
195 msleep(10);
196
197 if (ir->rc_type == RC_TYPE_RC5) {
198 rc = tm6000_read_write_usb(dev, USB_DIR_IN |
199 USB_TYPE_VENDOR | USB_RECIP_DEVICE,
200 REQ_02_GET_IR_CODE, 0, 0, buf, 1);
201
202 msleep(10);
203
204 dprintk("read data=%02x\n", buf[0]);
205 if (rc < 0)
206 return rc;
207
208 poll_result->rc_data = buf[0];
209 } else {
210 rc = tm6000_read_write_usb(dev, USB_DIR_IN |
211 USB_TYPE_VENDOR | USB_RECIP_DEVICE,
212 REQ_02_GET_IR_CODE, 0, 0, buf, 2);
213
214 msleep(10);
215
216 dprintk("read data=%04x\n", buf[0] | buf[1] << 8);
217 if (rc < 0)
218 return rc;
219
220 poll_result->rc_data = buf[0] | buf[1] << 8;
221 }
222 if ((poll_result->rc_data & 0x00ff) != 0xff)
223 ir->key = 1;
224 }
225 return 0;
226}
227
228static void tm6000_ir_handle_key(struct tm6000_IR *ir)
229{
230 struct tm6000_core *dev = ir->dev;
231 int result;
232 struct tm6000_ir_poll_result poll_result;
233
234 /* read the registers containing the IR status */
235 result = ir->get_key(ir, &poll_result);
236 if (result < 0) {
237 printk(KERN_INFO "ir->get_key() failed %d\n", result);
238 return;
239 }
240
241 dprintk("ir->get_key result data=%04x\n", poll_result.rc_data);
242
243 if (ir->pwled) {
244 if (ir->pwledcnt >= PWLED_OFF) {
245 ir->pwled = 0;
246 ir->pwledcnt = 0;
247 tm6000_flash_led(dev, 1);
248 } else
249 ir->pwledcnt += 1;
250 }
251
252 if (ir->key) {
253 rc_keydown(ir->rc, poll_result.rc_data, 0);
254 ir->key = 0;
255 ir->pwled = 1;
256 ir->pwledcnt = 0;
257 tm6000_flash_led(dev, 0);
258 }
259 return;
260}
261
262static void tm6000_ir_work(struct work_struct *work)
263{
264 struct tm6000_IR *ir = container_of(work, struct tm6000_IR, work.work);
265
266 tm6000_ir_handle_key(ir);
267 schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
268}
269
270static int tm6000_ir_start(struct rc_dev *rc)
271{
272 struct tm6000_IR *ir = rc->priv;
273
274 INIT_DELAYED_WORK(&ir->work, tm6000_ir_work);
275 schedule_delayed_work(&ir->work, 0);
276
277 return 0;
278}
279
280static void tm6000_ir_stop(struct rc_dev *rc)
281{
282 struct tm6000_IR *ir = rc->priv;
283
284 cancel_delayed_work_sync(&ir->work);
285}
286
287static int tm6000_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
288{
289 struct tm6000_IR *ir = rc->priv;
290
291 if (!ir)
292 return 0;
293
294 if ((rc->rc_map.scan) && (rc_type == RC_TYPE_NEC))
295 ir->key_addr = ((rc->rc_map.scan[0].scancode >> 8) & 0xffff);
296
297 ir->get_key = default_polling_getkey;
298 ir->rc_type = rc_type;
299
300 tm6000_ir_config(ir);
301 /* TODO */
302 return 0;
303}
304
305int tm6000_ir_int_start(struct tm6000_core *dev)
306{
307 struct tm6000_IR *ir = dev->ir;
308 int pipe, size;
309 int err = -ENOMEM;
310
311
312 if (!ir)
313 return -ENODEV;
314
315 ir->int_urb = usb_alloc_urb(0, GFP_KERNEL);
316 if (!ir->int_urb)
317 return -ENOMEM;
318
319 pipe = usb_rcvintpipe(dev->udev,
320 dev->int_in.endp->desc.bEndpointAddress
321 & USB_ENDPOINT_NUMBER_MASK);
322
323 size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
324 dprintk("IR max size: %d\n", size);
325
326 ir->int_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
327 if (ir->int_urb->transfer_buffer == NULL) {
328 usb_free_urb(ir->int_urb);
329 return err;
330 }
331 dprintk("int interval: %d\n", dev->int_in.endp->desc.bInterval);
332 usb_fill_int_urb(ir->int_urb, dev->udev, pipe,
333 ir->int_urb->transfer_buffer, size,
334 tm6000_ir_urb_received, dev,
335 dev->int_in.endp->desc.bInterval);
336 err = usb_submit_urb(ir->int_urb, GFP_KERNEL);
337 if (err) {
338 kfree(ir->int_urb->transfer_buffer);
339 usb_free_urb(ir->int_urb);
340 return err;
341 }
342 ir->urb_data = kzalloc(size, GFP_KERNEL);
343
344 return 0;
345}
346
347void tm6000_ir_int_stop(struct tm6000_core *dev)
348{
349 struct tm6000_IR *ir = dev->ir;
350
351 if (!ir)
352 return;
353
354 usb_kill_urb(ir->int_urb);
355 kfree(ir->int_urb->transfer_buffer);
356 usb_free_urb(ir->int_urb);
357 ir->int_urb = NULL;
358 kfree(ir->urb_data);
359 ir->urb_data = NULL;
360}
361
362int tm6000_ir_init(struct tm6000_core *dev)
363{
364 struct tm6000_IR *ir;
365 struct rc_dev *rc;
366 int err = -ENOMEM;
367
368 if (!enable_ir)
369 return -ENODEV;
370
371 if (!dev->caps.has_remote)
372 return 0;
373
374 if (!dev->ir_codes)
375 return 0;
376
377 ir = kzalloc(sizeof(*ir), GFP_KERNEL);
378 rc = rc_allocate_device();
379 if (!ir || !rc)
380 goto out;
381
382 /* record handles to ourself */
383 ir->dev = dev;
384 dev->ir = ir;
385 ir->rc = rc;
386
387 /* input einrichten */
388 rc->allowed_protos = RC_TYPE_RC5 | RC_TYPE_NEC;
389 rc->priv = ir;
390 rc->change_protocol = tm6000_ir_change_protocol;
391 rc->open = tm6000_ir_start;
392 rc->close = tm6000_ir_stop;
393 rc->driver_type = RC_DRIVER_SCANCODE;
394
395 ir->polling = 50;
396 ir->pwled = 0;
397 ir->pwledcnt = 0;
398
399
400 snprintf(ir->name, sizeof(ir->name), "tm5600/60x0 IR (%s)",
401 dev->name);
402
403 usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
404 strlcat(ir->phys, "/input0", sizeof(ir->phys));
405
406 tm6000_ir_change_protocol(rc, RC_TYPE_UNKNOWN);
407
408 rc->input_name = ir->name;
409 rc->input_phys = ir->phys;
410 rc->input_id.bustype = BUS_USB;
411 rc->input_id.version = 1;
412 rc->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
413 rc->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
414 rc->map_name = dev->ir_codes;
415 rc->driver_name = "tm6000";
416 rc->dev.parent = &dev->udev->dev;
417
418 if (&dev->int_in) {
419 dprintk("IR over int\n");
420
421 err = tm6000_ir_int_start(dev);
422
423 if (err)
424 goto out;
425 }
426
427 /* ir register */
428 err = rc_register_device(rc);
429 if (err)
430 goto out;
431
432 return 0;
433
434out:
435 dev->ir = NULL;
436 rc_free_device(rc);
437 kfree(ir);
438 return err;
439}
440
441int tm6000_ir_fini(struct tm6000_core *dev)
442{
443 struct tm6000_IR *ir = dev->ir;
444
445 /* skip detach on non attached board */
446
447 if (!ir)
448 return 0;
449
450 rc_unregister_device(ir->rc);
451
452 if (ir->int_urb)
453 tm6000_ir_int_stop(dev);
454
455 kfree(ir);
456 dev->ir = NULL;
457
458 return 0;
459}
diff --git a/drivers/media/video/tm6000/tm6000-regs.h b/drivers/media/video/tm6000/tm6000-regs.h
new file mode 100644
index 00000000000..7f491b6de93
--- /dev/null
+++ b/drivers/media/video/tm6000/tm6000-regs.h
@@ -0,0 +1,600 @@
1/*
2 * tm6000-regs.h - driver for TM5600/TM6000/TM6010 USB video capture devices
3 *
4 * Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation version 2
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20/*
21 * Define TV Master TM5600/TM6000/TM6010 Request codes
22 */
23#define REQ_00_SET_IR_VALUE 0
24#define REQ_01_SET_WAKEUP_IRCODE 1
25#define REQ_02_GET_IR_CODE 2
26#define REQ_03_SET_GET_MCU_PIN 3
27#define REQ_04_EN_DISABLE_MCU_INT 4
28#define REQ_05_SET_GET_USBREG 5
29 /* Write: RegNum, Value, 0 */
30 /* Read : RegNum, Value, 1, RegStatus */
31#define REQ_06_SET_GET_USBREG_BIT 6
32#define REQ_07_SET_GET_AVREG 7
33 /* Write: RegNum, Value, 0 */
34 /* Read : RegNum, Value, 1, RegStatus */
35#define REQ_08_SET_GET_AVREG_BIT 8
36#define REQ_09_SET_GET_TUNER_FQ 9
37#define REQ_10_SET_TUNER_SYSTEM 10
38#define REQ_11_SET_EEPROM_ADDR 11
39#define REQ_12_SET_GET_EEPROMBYTE 12
40#define REQ_13_GET_EEPROM_SEQREAD 13
41#define REQ_14_SET_GET_I2C_WR2_RDN 14
42#define REQ_15_SET_GET_I2CBYTE 15
43 /* Write: Subaddr, Slave Addr, value, 0 */
44 /* Read : Subaddr, Slave Addr, value, 1 */
45#define REQ_16_SET_GET_I2C_WR1_RDN 16
46 /* Subaddr, Slave Addr, 0, length */
47#define REQ_17_SET_GET_I2CFP 17
48 /* Write: Slave Addr, register, value */
49 /* Read : Slave Addr, register, 2, data */
50#define REQ_20_DATA_TRANSFER 20
51#define REQ_30_I2C_WRITE 30
52#define REQ_31_I2C_READ 31
53#define REQ_35_AFTEK_TUNER_READ 35
54#define REQ_40_GET_VERSION 40
55#define REQ_50_SET_START 50
56#define REQ_51_SET_STOP 51
57#define REQ_52_TRANSMIT_DATA 52
58#define REQ_53_SPI_INITIAL 53
59#define REQ_54_SPI_SETSTART 54
60#define REQ_55_SPI_INOUTDATA 55
61#define REQ_56_SPI_SETSTOP 56
62
63/*
64 * Define TV Master TM5600/TM6000/TM6010 GPIO lines
65 */
66
67#define TM6000_GPIO_CLK 0x101
68#define TM6000_GPIO_DATA 0x100
69
70#define TM6000_GPIO_1 0x102
71#define TM6000_GPIO_2 0x103
72#define TM6000_GPIO_3 0x104
73#define TM6000_GPIO_4 0x300
74#define TM6000_GPIO_5 0x301
75#define TM6000_GPIO_6 0x304
76#define TM6000_GPIO_7 0x305
77
78/* tm6010 defines GPIO with different values */
79#define TM6010_GPIO_0 0x0102
80#define TM6010_GPIO_1 0x0103
81#define TM6010_GPIO_2 0x0104
82#define TM6010_GPIO_3 0x0105
83#define TM6010_GPIO_4 0x0106
84#define TM6010_GPIO_5 0x0107
85#define TM6010_GPIO_6 0x0300
86#define TM6010_GPIO_7 0x0301
87#define TM6010_GPIO_9 0x0305
88/*
89 * Define TV Master TM5600/TM6000/TM6010 URB message codes and length
90 */
91
92enum {
93 TM6000_URB_MSG_VIDEO = 1,
94 TM6000_URB_MSG_AUDIO,
95 TM6000_URB_MSG_VBI,
96 TM6000_URB_MSG_PTS,
97 TM6000_URB_MSG_ERR,
98};
99
100/* Define specific TM6000 Video decoder registers */
101#define TM6000_REQ07_RD8_TEST_SEL 0x07, 0xd8
102#define TM6000_REQ07_RD9_A_SIM_SEL 0x07, 0xd9
103#define TM6000_REQ07_RDA_CLK_SEL 0x07, 0xda
104#define TM6000_REQ07_RDB_OUT_SEL 0x07, 0xdb
105#define TM6000_REQ07_RDC_NSEL_I2S 0x07, 0xdc
106#define TM6000_REQ07_RDD_GPIO2_MDRV 0x07, 0xdd
107#define TM6000_REQ07_RDE_GPIO1_MDRV 0x07, 0xde
108#define TM6000_REQ07_RDF_PWDOWN_ACLK 0x07, 0xdf
109#define TM6000_REQ07_RE0_VADC_REF_CTL 0x07, 0xe0
110#define TM6000_REQ07_RE1_VADC_DACLIMP 0x07, 0xe1
111#define TM6000_REQ07_RE2_VADC_STATUS_CTL 0x07, 0xe2
112#define TM6000_REQ07_RE3_VADC_INP_LPF_SEL1 0x07, 0xe3
113#define TM6000_REQ07_RE4_VADC_TARGET1 0x07, 0xe4
114#define TM6000_REQ07_RE5_VADC_INP_LPF_SEL2 0x07, 0xe5
115#define TM6000_REQ07_RE6_VADC_TARGET2 0x07, 0xe6
116#define TM6000_REQ07_RE7_VADC_AGAIN_CTL 0x07, 0xe7
117#define TM6000_REQ07_RE8_VADC_PWDOWN_CTL 0x07, 0xe8
118#define TM6000_REQ07_RE9_VADC_INPUT_CTL1 0x07, 0xe9
119#define TM6000_REQ07_REA_VADC_INPUT_CTL2 0x07, 0xea
120#define TM6000_REQ07_REB_VADC_AADC_MODE 0x07, 0xeb
121#define TM6000_REQ07_REC_VADC_AADC_LVOL 0x07, 0xec
122#define TM6000_REQ07_RED_VADC_AADC_RVOL 0x07, 0xed
123#define TM6000_REQ07_REE_VADC_CTRL_SEL_CONTROL 0x07, 0xee
124#define TM6000_REQ07_REF_VADC_GAIN_MAP_CTL 0x07, 0xef
125#define TM6000_REQ07_RFD_BIST_ERR_VST_LOW 0x07, 0xfd
126#define TM6000_REQ07_RFE_BIST_ERR_VST_HIGH 0x07, 0xfe
127
128/* Define TM6000/TM6010 Video decoder registers */
129#define TM6010_REQ07_R00_VIDEO_CONTROL0 0x07, 0x00
130#define TM6010_REQ07_R01_VIDEO_CONTROL1 0x07, 0x01
131#define TM6010_REQ07_R02_VIDEO_CONTROL2 0x07, 0x02
132#define TM6010_REQ07_R03_YC_SEP_CONTROL 0x07, 0x03
133#define TM6010_REQ07_R04_LUMA_HAGC_CONTROL 0x07, 0x04
134#define TM6010_REQ07_R05_NOISE_THRESHOLD 0x07, 0x05
135#define TM6010_REQ07_R06_AGC_GATE_THRESHOLD 0x07, 0x06
136#define TM6010_REQ07_R07_OUTPUT_CONTROL 0x07, 0x07
137#define TM6010_REQ07_R08_LUMA_CONTRAST_ADJ 0x07, 0x08
138#define TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ 0x07, 0x09
139#define TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ 0x07, 0x0a
140#define TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ 0x07, 0x0b
141#define TM6010_REQ07_R0C_CHROMA_AGC_CONTROL 0x07, 0x0c
142#define TM6010_REQ07_R0D_CHROMA_KILL_LEVEL 0x07, 0x0d
143#define TM6010_REQ07_R0F_CHROMA_AUTO_POSITION 0x07, 0x0f
144#define TM6010_REQ07_R10_AGC_PEAK_NOMINAL 0x07, 0x10
145#define TM6010_REQ07_R11_AGC_PEAK_CONTROL 0x07, 0x11
146#define TM6010_REQ07_R12_AGC_GATE_STARTH 0x07, 0x12
147#define TM6010_REQ07_R13_AGC_GATE_STARTL 0x07, 0x13
148#define TM6010_REQ07_R14_AGC_GATE_WIDTH 0x07, 0x14
149#define TM6010_REQ07_R15_AGC_BP_DELAY 0x07, 0x15
150#define TM6010_REQ07_R16_LOCK_COUNT 0x07, 0x16
151#define TM6010_REQ07_R17_HLOOP_MAXSTATE 0x07, 0x17
152#define TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3 0x07, 0x18
153#define TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2 0x07, 0x19
154#define TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1 0x07, 0x1a
155#define TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0 0x07, 0x1b
156#define TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3 0x07, 0x1c
157#define TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2 0x07, 0x1d
158#define TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1 0x07, 0x1e
159#define TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0 0x07, 0x1f
160#define TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME 0x07, 0x20
161#define TM6010_REQ07_R21_HSYNC_PHASE_OFFSET 0x07, 0x21
162#define TM6010_REQ07_R22_HSYNC_PLL_START_TIME 0x07, 0x22
163#define TM6010_REQ07_R23_HSYNC_PLL_END_TIME 0x07, 0x23
164#define TM6010_REQ07_R24_HSYNC_TIP_START_TIME 0x07, 0x24
165#define TM6010_REQ07_R25_HSYNC_TIP_END_TIME 0x07, 0x25
166#define TM6010_REQ07_R26_HSYNC_RISING_EDGE_START 0x07, 0x26
167#define TM6010_REQ07_R27_HSYNC_RISING_EDGE_END 0x07, 0x27
168#define TM6010_REQ07_R28_BACKPORCH_START 0x07, 0x28
169#define TM6010_REQ07_R29_BACKPORCH_END 0x07, 0x29
170#define TM6010_REQ07_R2A_HSYNC_FILTER_START 0x07, 0x2a
171#define TM6010_REQ07_R2B_HSYNC_FILTER_END 0x07, 0x2b
172#define TM6010_REQ07_R2C_CHROMA_BURST_START 0x07, 0x2c
173#define TM6010_REQ07_R2D_CHROMA_BURST_END 0x07, 0x2d
174#define TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART 0x07, 0x2e
175#define TM6010_REQ07_R2F_ACTIVE_VIDEO_HWIDTH 0x07, 0x2f
176#define TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART 0x07, 0x30
177#define TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT 0x07, 0x31
178#define TM6010_REQ07_R32_VSYNC_HLOCK_MIN 0x07, 0x32
179#define TM6010_REQ07_R33_VSYNC_HLOCK_MAX 0x07, 0x33
180#define TM6010_REQ07_R34_VSYNC_AGC_MIN 0x07, 0x34
181#define TM6010_REQ07_R35_VSYNC_AGC_MAX 0x07, 0x35
182#define TM6010_REQ07_R36_VSYNC_VBI_MIN 0x07, 0x36
183#define TM6010_REQ07_R37_VSYNC_VBI_MAX 0x07, 0x37
184#define TM6010_REQ07_R38_VSYNC_THRESHOLD 0x07, 0x38
185#define TM6010_REQ07_R39_VSYNC_TIME_CONSTANT 0x07, 0x39
186#define TM6010_REQ07_R3A_STATUS1 0x07, 0x3a
187#define TM6010_REQ07_R3B_STATUS2 0x07, 0x3b
188#define TM6010_REQ07_R3C_STATUS3 0x07, 0x3c
189#define TM6010_REQ07_R3F_RESET 0x07, 0x3f
190#define TM6010_REQ07_R40_TELETEXT_VBI_CODE0 0x07, 0x40
191#define TM6010_REQ07_R41_TELETEXT_VBI_CODE1 0x07, 0x41
192#define TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL 0x07, 0x42
193#define TM6010_REQ07_R43_VBI_DATA_TYPE_LINE7 0x07, 0x43
194#define TM6010_REQ07_R44_VBI_DATA_TYPE_LINE8 0x07, 0x44
195#define TM6010_REQ07_R45_VBI_DATA_TYPE_LINE9 0x07, 0x45
196#define TM6010_REQ07_R46_VBI_DATA_TYPE_LINE10 0x07, 0x46
197#define TM6010_REQ07_R47_VBI_DATA_TYPE_LINE11 0x07, 0x47
198#define TM6010_REQ07_R48_VBI_DATA_TYPE_LINE12 0x07, 0x48
199#define TM6010_REQ07_R49_VBI_DATA_TYPE_LINE13 0x07, 0x49
200#define TM6010_REQ07_R4A_VBI_DATA_TYPE_LINE14 0x07, 0x4a
201#define TM6010_REQ07_R4B_VBI_DATA_TYPE_LINE15 0x07, 0x4b
202#define TM6010_REQ07_R4C_VBI_DATA_TYPE_LINE16 0x07, 0x4c
203#define TM6010_REQ07_R4D_VBI_DATA_TYPE_LINE17 0x07, 0x4d
204#define TM6010_REQ07_R4E_VBI_DATA_TYPE_LINE18 0x07, 0x4e
205#define TM6010_REQ07_R4F_VBI_DATA_TYPE_LINE19 0x07, 0x4f
206#define TM6010_REQ07_R50_VBI_DATA_TYPE_LINE20 0x07, 0x50
207#define TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21 0x07, 0x51
208#define TM6010_REQ07_R52_VBI_DATA_TYPE_LINE22 0x07, 0x52
209#define TM6010_REQ07_R53_VBI_DATA_TYPE_LINE23 0x07, 0x53
210#define TM6010_REQ07_R54_VBI_DATA_TYPE_RLINES 0x07, 0x54
211#define TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN 0x07, 0x55
212#define TM6010_REQ07_R56_VBI_LOOP_FILTER_I_GAIN 0x07, 0x56
213#define TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN 0x07, 0x57
214#define TM6010_REQ07_R58_VBI_CAPTION_DTO1 0x07, 0x58
215#define TM6010_REQ07_R59_VBI_CAPTION_DTO0 0x07, 0x59
216#define TM6010_REQ07_R5A_VBI_TELETEXT_DTO1 0x07, 0x5a
217#define TM6010_REQ07_R5B_VBI_TELETEXT_DTO0 0x07, 0x5b
218#define TM6010_REQ07_R5C_VBI_WSS625_DTO1 0x07, 0x5c
219#define TM6010_REQ07_R5D_VBI_WSS625_DTO0 0x07, 0x5d
220#define TM6010_REQ07_R5E_VBI_CAPTION_FRAME_START 0x07, 0x5e
221#define TM6010_REQ07_R5F_VBI_WSS625_FRAME_START 0x07, 0x5f
222#define TM6010_REQ07_R60_TELETEXT_FRAME_START 0x07, 0x60
223#define TM6010_REQ07_R61_VBI_CCDATA1 0x07, 0x61
224#define TM6010_REQ07_R62_VBI_CCDATA2 0x07, 0x62
225#define TM6010_REQ07_R63_VBI_WSS625_DATA1 0x07, 0x63
226#define TM6010_REQ07_R64_VBI_WSS625_DATA2 0x07, 0x64
227#define TM6010_REQ07_R65_VBI_DATA_STATUS 0x07, 0x65
228#define TM6010_REQ07_R66_VBI_CAPTION_START 0x07, 0x66
229#define TM6010_REQ07_R67_VBI_WSS625_START 0x07, 0x67
230#define TM6010_REQ07_R68_VBI_TELETEXT_START 0x07, 0x68
231#define TM6010_REQ07_R70_HSYNC_DTO_INC_STATUS3 0x07, 0x70
232#define TM6010_REQ07_R71_HSYNC_DTO_INC_STATUS2 0x07, 0x71
233#define TM6010_REQ07_R72_HSYNC_DTO_INC_STATUS1 0x07, 0x72
234#define TM6010_REQ07_R73_HSYNC_DTO_INC_STATUS0 0x07, 0x73
235#define TM6010_REQ07_R74_CHROMA_DTO_INC_STATUS3 0x07, 0x74
236#define TM6010_REQ07_R75_CHROMA_DTO_INC_STATUS2 0x07, 0x75
237#define TM6010_REQ07_R76_CHROMA_DTO_INC_STATUS1 0x07, 0x76
238#define TM6010_REQ07_R77_CHROMA_DTO_INC_STATUS0 0x07, 0x77
239#define TM6010_REQ07_R78_AGC_AGAIN_STATUS 0x07, 0x78
240#define TM6010_REQ07_R79_AGC_DGAIN_STATUS 0x07, 0x79
241#define TM6010_REQ07_R7A_CHROMA_MAG_STATUS 0x07, 0x7a
242#define TM6010_REQ07_R7B_CHROMA_GAIN_STATUS1 0x07, 0x7b
243#define TM6010_REQ07_R7C_CHROMA_GAIN_STATUS0 0x07, 0x7c
244#define TM6010_REQ07_R7D_CORDIC_FREQ_STATUS 0x07, 0x7d
245#define TM6010_REQ07_R7F_STATUS_NOISE 0x07, 0x7f
246#define TM6010_REQ07_R80_COMB_FILTER_TRESHOLD 0x07, 0x80
247#define TM6010_REQ07_R82_COMB_FILTER_CONFIG 0x07, 0x82
248#define TM6010_REQ07_R83_CHROMA_LOCK_CONFIG 0x07, 0x83
249#define TM6010_REQ07_R84_NOISE_NTSC_C 0x07, 0x84
250#define TM6010_REQ07_R85_NOISE_PAL_C 0x07, 0x85
251#define TM6010_REQ07_R86_NOISE_PHASE_C 0x07, 0x86
252#define TM6010_REQ07_R87_NOISE_PHASE_Y 0x07, 0x87
253#define TM6010_REQ07_R8A_CHROMA_LOOPFILTER_STATE 0x07, 0x8a
254#define TM6010_REQ07_R8B_CHROMA_HRESAMPLER 0x07, 0x8b
255#define TM6010_REQ07_R8D_CPUMP_DELAY_ADJ 0x07, 0x8d
256#define TM6010_REQ07_R8E_CPUMP_ADJ 0x07, 0x8e
257#define TM6010_REQ07_R8F_CPUMP_DELAY 0x07, 0x8f
258
259/* Define TM6000/TM6010 Miscellaneous registers */
260#define TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE 0x07, 0xc0
261#define TM6010_REQ07_RC1_TRESHOLD 0x07, 0xc1
262#define TM6010_REQ07_RC2_HSYNC_WIDTH 0x07, 0xc2
263#define TM6010_REQ07_RC3_HSTART1 0x07, 0xc3
264#define TM6010_REQ07_RC4_HSTART0 0x07, 0xc4
265#define TM6010_REQ07_RC5_HEND1 0x07, 0xc5
266#define TM6010_REQ07_RC6_HEND0 0x07, 0xc6
267#define TM6010_REQ07_RC7_VSTART1 0x07, 0xc7
268#define TM6010_REQ07_RC8_VSTART0 0x07, 0xc8
269#define TM6010_REQ07_RC9_VEND1 0x07, 0xc9
270#define TM6010_REQ07_RCA_VEND0 0x07, 0xca
271#define TM6010_REQ07_RCB_DELAY 0x07, 0xcb
272/* ONLY for TM6010 */
273#define TM6010_REQ07_RCC_ACTIVE_IF 0x07, 0xcc
274#define TM6010_REQ07_RCC_ACTIVE_IF_VIDEO_ENABLE (1 << 5)
275#define TM6010_REQ07_RCC_ACTIVE_IF_AUDIO_ENABLE (1 << 6)
276#define TM6010_REQ07_RD0_USB_PERIPHERY_CONTROL 0x07, 0xd0
277#define TM6010_REQ07_RD1_ADDR_FOR_REQ1 0x07, 0xd1
278#define TM6010_REQ07_RD2_ADDR_FOR_REQ2 0x07, 0xd2
279#define TM6010_REQ07_RD3_ADDR_FOR_REQ3 0x07, 0xd3
280#define TM6010_REQ07_RD4_ADDR_FOR_REQ4 0x07, 0xd4
281#define TM6010_REQ07_RD5_POWERSAVE 0x07, 0xd5
282#define TM6010_REQ07_RD6_ENDP_REQ1_REQ2 0x07, 0xd6
283#define TM6010_REQ07_RD7_ENDP_REQ3_REQ4 0x07, 0xd7
284/* ONLY for TM6010 */
285#define TM6010_REQ07_RD8_IR 0x07, 0xd8
286/* ONLY for TM6010 */
287#define TM6010_REQ07_RD8_IR_BSIZE 0x07, 0xd9
288/* ONLY for TM6010 */
289#define TM6010_REQ07_RD8_IR_WAKEUP_SEL 0x07, 0xda
290/* ONLY for TM6010 */
291#define TM6010_REQ07_RD8_IR_WAKEUP_ADD 0x07, 0xdb
292/* ONLY for TM6010 */
293#define TM6010_REQ07_RD8_IR_LEADER1 0x07, 0xdc
294/* ONLY for TM6010 */
295#define TM6010_REQ07_RD8_IR_LEADER0 0x07, 0xdd
296/* ONLY for TM6010 */
297#define TM6010_REQ07_RD8_IR_PULSE_CNT1 0x07, 0xde
298/* ONLY for TM6010 */
299#define TM6010_REQ07_RD8_IR_PULSE_CNT0 0x07, 0xdf
300/* ONLY for TM6010 */
301#define TM6010_REQ07_RE0_DVIDEO_SOURCE 0x07, 0xe0
302/* ONLY for TM6010 */
303#define TM6010_REQ07_RE0_DVIDEO_SOURCE_IF 0x07, 0xe1
304/* ONLY for TM6010 */
305#define TM6010_REQ07_RE2_OUT_SEL2 0x07, 0xe2
306/* ONLY for TM6010 */
307#define TM6010_REQ07_RE3_OUT_SEL1 0x07, 0xe3
308/* ONLY for TM6010 */
309#define TM6010_REQ07_RE4_OUT_SEL0 0x07, 0xe4
310/* ONLY for TM6010 */
311#define TM6010_REQ07_RE5_REMOTE_WAKEUP 0x07, 0xe5
312/* ONLY for TM6010 */
313#define TM6010_REQ07_RE7_PUB_GPIO 0x07, 0xe7
314/* ONLY for TM6010 */
315#define TM6010_REQ07_RE8_TYPESEL_MOS_I2S 0x07, 0xe8
316/* ONLY for TM6010 */
317#define TM6010_REQ07_RE9_TYPESEL_MOS_TS 0x07, 0xe9
318/* ONLY for TM6010 */
319#define TM6010_REQ07_REA_TYPESEL_MOS_CCIR 0x07, 0xea
320/* ONLY for TM6010 */
321#define TM6010_REQ07_RF0_BIST_CRC_RESULT0 0x07, 0xf0
322/* ONLY for TM6010 */
323#define TM6010_REQ07_RF1_BIST_CRC_RESULT1 0x07, 0xf1
324/* ONLY for TM6010 */
325#define TM6010_REQ07_RF2_BIST_CRC_RESULT2 0x07, 0xf2
326/* ONLY for TM6010 */
327#define TM6010_REQ07_RF3_BIST_CRC_RESULT3 0x07, 0xf3
328/* ONLY for TM6010 */
329#define TM6010_REQ07_RF4_BIST_ERR_VST2 0x07, 0xf4
330/* ONLY for TM6010 */
331#define TM6010_REQ07_RF5_BIST_ERR_VST1 0x07, 0xf5
332/* ONLY for TM6010 */
333#define TM6010_REQ07_RF6_BIST_ERR_VST0 0x07, 0xf6
334/* ONLY for TM6010 */
335#define TM6010_REQ07_RF7_BIST 0x07, 0xf7
336/* ONLY for TM6010 */
337#define TM6010_REQ07_RFE_POWER_DOWN 0x07, 0xfe
338#define TM6010_REQ07_RFF_SOFT_RESET 0x07, 0xff
339
340/* Define TM6000/TM6010 USB registers */
341#define TM6010_REQ05_R00_MAIN_CTRL 0x05, 0x00
342#define TM6010_REQ05_R01_DEVADDR 0x05, 0x01
343#define TM6010_REQ05_R02_TEST 0x05, 0x02
344#define TM6010_REQ05_R04_SOFN0 0x05, 0x04
345#define TM6010_REQ05_R05_SOFN1 0x05, 0x05
346#define TM6010_REQ05_R06_SOFTM0 0x05, 0x06
347#define TM6010_REQ05_R07_SOFTM1 0x05, 0x07
348#define TM6010_REQ05_R08_PHY_TEST 0x05, 0x08
349#define TM6010_REQ05_R09_VCTL 0x05, 0x09
350#define TM6010_REQ05_R0A_VSTA 0x05, 0x0a
351#define TM6010_REQ05_R0B_CX_CFG 0x05, 0x0b
352#define TM6010_REQ05_R0C_ENDP0_REG0 0x05, 0x0c
353#define TM6010_REQ05_R10_GMASK 0x05, 0x10
354#define TM6010_REQ05_R11_IMASK0 0x05, 0x11
355#define TM6010_REQ05_R12_IMASK1 0x05, 0x12
356#define TM6010_REQ05_R13_IMASK2 0x05, 0x13
357#define TM6010_REQ05_R14_IMASK3 0x05, 0x14
358#define TM6010_REQ05_R15_IMASK4 0x05, 0x15
359#define TM6010_REQ05_R16_IMASK5 0x05, 0x16
360#define TM6010_REQ05_R17_IMASK6 0x05, 0x17
361#define TM6010_REQ05_R18_IMASK7 0x05, 0x18
362#define TM6010_REQ05_R19_ZEROP0 0x05, 0x19
363#define TM6010_REQ05_R1A_ZEROP1 0x05, 0x1a
364#define TM6010_REQ05_R1C_FIFO_EMP0 0x05, 0x1c
365#define TM6010_REQ05_R1D_FIFO_EMP1 0x05, 0x1d
366#define TM6010_REQ05_R20_IRQ_GROUP 0x05, 0x20
367#define TM6010_REQ05_R21_IRQ_SOURCE0 0x05, 0x21
368#define TM6010_REQ05_R22_IRQ_SOURCE1 0x05, 0x22
369#define TM6010_REQ05_R23_IRQ_SOURCE2 0x05, 0x23
370#define TM6010_REQ05_R24_IRQ_SOURCE3 0x05, 0x24
371#define TM6010_REQ05_R25_IRQ_SOURCE4 0x05, 0x25
372#define TM6010_REQ05_R26_IRQ_SOURCE5 0x05, 0x26
373#define TM6010_REQ05_R27_IRQ_SOURCE6 0x05, 0x27
374#define TM6010_REQ05_R28_IRQ_SOURCE7 0x05, 0x28
375#define TM6010_REQ05_R29_SEQ_ERR0 0x05, 0x29
376#define TM6010_REQ05_R2A_SEQ_ERR1 0x05, 0x2a
377#define TM6010_REQ05_R2B_SEQ_ABORT0 0x05, 0x2b
378#define TM6010_REQ05_R2C_SEQ_ABORT1 0x05, 0x2c
379#define TM6010_REQ05_R2D_TX_ZERO0 0x05, 0x2d
380#define TM6010_REQ05_R2E_TX_ZERO1 0x05, 0x2e
381#define TM6010_REQ05_R2F_IDLE_CNT 0x05, 0x2f
382#define TM6010_REQ05_R30_FNO_P1 0x05, 0x30
383#define TM6010_REQ05_R31_FNO_P2 0x05, 0x31
384#define TM6010_REQ05_R32_FNO_P3 0x05, 0x32
385#define TM6010_REQ05_R33_FNO_P4 0x05, 0x33
386#define TM6010_REQ05_R34_FNO_P5 0x05, 0x34
387#define TM6010_REQ05_R35_FNO_P6 0x05, 0x35
388#define TM6010_REQ05_R36_FNO_P7 0x05, 0x36
389#define TM6010_REQ05_R37_FNO_P8 0x05, 0x37
390#define TM6010_REQ05_R38_FNO_P9 0x05, 0x38
391#define TM6010_REQ05_R30_FNO_P10 0x05, 0x39
392#define TM6010_REQ05_R30_FNO_P11 0x05, 0x3a
393#define TM6010_REQ05_R30_FNO_P12 0x05, 0x3b
394#define TM6010_REQ05_R30_FNO_P13 0x05, 0x3c
395#define TM6010_REQ05_R30_FNO_P14 0x05, 0x3d
396#define TM6010_REQ05_R30_FNO_P15 0x05, 0x3e
397#define TM6010_REQ05_R40_IN_MAXPS_LOW1 0x05, 0x40
398#define TM6010_REQ05_R41_IN_MAXPS_HIGH1 0x05, 0x41
399#define TM6010_REQ05_R42_IN_MAXPS_LOW2 0x05, 0x42
400#define TM6010_REQ05_R43_IN_MAXPS_HIGH2 0x05, 0x43
401#define TM6010_REQ05_R44_IN_MAXPS_LOW3 0x05, 0x44
402#define TM6010_REQ05_R45_IN_MAXPS_HIGH3 0x05, 0x45
403#define TM6010_REQ05_R46_IN_MAXPS_LOW4 0x05, 0x46
404#define TM6010_REQ05_R47_IN_MAXPS_HIGH4 0x05, 0x47
405#define TM6010_REQ05_R48_IN_MAXPS_LOW5 0x05, 0x48
406#define TM6010_REQ05_R49_IN_MAXPS_HIGH5 0x05, 0x49
407#define TM6010_REQ05_R4A_IN_MAXPS_LOW6 0x05, 0x4a
408#define TM6010_REQ05_R4B_IN_MAXPS_HIGH6 0x05, 0x4b
409#define TM6010_REQ05_R4C_IN_MAXPS_LOW7 0x05, 0x4c
410#define TM6010_REQ05_R4D_IN_MAXPS_HIGH7 0x05, 0x4d
411#define TM6010_REQ05_R4E_IN_MAXPS_LOW8 0x05, 0x4e
412#define TM6010_REQ05_R4F_IN_MAXPS_HIGH8 0x05, 0x4f
413#define TM6010_REQ05_R50_IN_MAXPS_LOW9 0x05, 0x50
414#define TM6010_REQ05_R51_IN_MAXPS_HIGH9 0x05, 0x51
415#define TM6010_REQ05_R40_IN_MAXPS_LOW10 0x05, 0x52
416#define TM6010_REQ05_R41_IN_MAXPS_HIGH10 0x05, 0x53
417#define TM6010_REQ05_R40_IN_MAXPS_LOW11 0x05, 0x54
418#define TM6010_REQ05_R41_IN_MAXPS_HIGH11 0x05, 0x55
419#define TM6010_REQ05_R40_IN_MAXPS_LOW12 0x05, 0x56
420#define TM6010_REQ05_R41_IN_MAXPS_HIGH12 0x05, 0x57
421#define TM6010_REQ05_R40_IN_MAXPS_LOW13 0x05, 0x58
422#define TM6010_REQ05_R41_IN_MAXPS_HIGH13 0x05, 0x59
423#define TM6010_REQ05_R40_IN_MAXPS_LOW14 0x05, 0x5a
424#define TM6010_REQ05_R41_IN_MAXPS_HIGH14 0x05, 0x5b
425#define TM6010_REQ05_R40_IN_MAXPS_LOW15 0x05, 0x5c
426#define TM6010_REQ05_R41_IN_MAXPS_HIGH15 0x05, 0x5d
427#define TM6010_REQ05_R60_OUT_MAXPS_LOW1 0x05, 0x60
428#define TM6010_REQ05_R61_OUT_MAXPS_HIGH1 0x05, 0x61
429#define TM6010_REQ05_R62_OUT_MAXPS_LOW2 0x05, 0x62
430#define TM6010_REQ05_R63_OUT_MAXPS_HIGH2 0x05, 0x63
431#define TM6010_REQ05_R64_OUT_MAXPS_LOW3 0x05, 0x64
432#define TM6010_REQ05_R65_OUT_MAXPS_HIGH3 0x05, 0x65
433#define TM6010_REQ05_R66_OUT_MAXPS_LOW4 0x05, 0x66
434#define TM6010_REQ05_R67_OUT_MAXPS_HIGH4 0x05, 0x67
435#define TM6010_REQ05_R68_OUT_MAXPS_LOW5 0x05, 0x68
436#define TM6010_REQ05_R69_OUT_MAXPS_HIGH5 0x05, 0x69
437#define TM6010_REQ05_R6A_OUT_MAXPS_LOW6 0x05, 0x6a
438#define TM6010_REQ05_R6B_OUT_MAXPS_HIGH6 0x05, 0x6b
439#define TM6010_REQ05_R6C_OUT_MAXPS_LOW7 0x05, 0x6c
440#define TM6010_REQ05_R6D_OUT_MAXPS_HIGH7 0x05, 0x6d
441#define TM6010_REQ05_R6E_OUT_MAXPS_LOW8 0x05, 0x6e
442#define TM6010_REQ05_R6F_OUT_MAXPS_HIGH8 0x05, 0x6f
443#define TM6010_REQ05_R70_OUT_MAXPS_LOW9 0x05, 0x70
444#define TM6010_REQ05_R71_OUT_MAXPS_HIGH9 0x05, 0x71
445#define TM6010_REQ05_R60_OUT_MAXPS_LOW10 0x05, 0x72
446#define TM6010_REQ05_R61_OUT_MAXPS_HIGH10 0x05, 0x73
447#define TM6010_REQ05_R60_OUT_MAXPS_LOW11 0x05, 0x74
448#define TM6010_REQ05_R61_OUT_MAXPS_HIGH11 0x05, 0x75
449#define TM6010_REQ05_R60_OUT_MAXPS_LOW12 0x05, 0x76
450#define TM6010_REQ05_R61_OUT_MAXPS_HIGH12 0x05, 0x77
451#define TM6010_REQ05_R60_OUT_MAXPS_LOW13 0x05, 0x78
452#define TM6010_REQ05_R61_OUT_MAXPS_HIGH13 0x05, 0x79
453#define TM6010_REQ05_R60_OUT_MAXPS_LOW14 0x05, 0x7a
454#define TM6010_REQ05_R61_OUT_MAXPS_HIGH14 0x05, 0x7b
455#define TM6010_REQ05_R60_OUT_MAXPS_LOW15 0x05, 0x7c
456#define TM6010_REQ05_R61_OUT_MAXPS_HIGH15 0x05, 0x7d
457#define TM6010_REQ05_R80_FIFO0 0x05, 0x80
458#define TM6010_REQ05_R81_FIFO1 0x05, 0x81
459#define TM6010_REQ05_R82_FIFO2 0x05, 0x82
460#define TM6010_REQ05_R83_FIFO3 0x05, 0x83
461#define TM6010_REQ05_R84_FIFO4 0x05, 0x84
462#define TM6010_REQ05_R85_FIFO5 0x05, 0x85
463#define TM6010_REQ05_R86_FIFO6 0x05, 0x86
464#define TM6010_REQ05_R87_FIFO7 0x05, 0x87
465#define TM6010_REQ05_R88_FIFO8 0x05, 0x88
466#define TM6010_REQ05_R89_FIFO9 0x05, 0x89
467#define TM6010_REQ05_R81_FIFO10 0x05, 0x8a
468#define TM6010_REQ05_R81_FIFO11 0x05, 0x8b
469#define TM6010_REQ05_R81_FIFO12 0x05, 0x8c
470#define TM6010_REQ05_R81_FIFO13 0x05, 0x8d
471#define TM6010_REQ05_R81_FIFO14 0x05, 0x8e
472#define TM6010_REQ05_R81_FIFO15 0x05, 0x8f
473#define TM6010_REQ05_R90_CFG_FIFO0 0x05, 0x90
474#define TM6010_REQ05_R91_CFG_FIFO1 0x05, 0x91
475#define TM6010_REQ05_R92_CFG_FIFO2 0x05, 0x92
476#define TM6010_REQ05_R93_CFG_FIFO3 0x05, 0x93
477#define TM6010_REQ05_R94_CFG_FIFO4 0x05, 0x94
478#define TM6010_REQ05_R95_CFG_FIFO5 0x05, 0x95
479#define TM6010_REQ05_R96_CFG_FIFO6 0x05, 0x96
480#define TM6010_REQ05_R97_CFG_FIFO7 0x05, 0x97
481#define TM6010_REQ05_R98_CFG_FIFO8 0x05, 0x98
482#define TM6010_REQ05_R99_CFG_FIFO9 0x05, 0x99
483#define TM6010_REQ05_R91_CFG_FIFO10 0x05, 0x9a
484#define TM6010_REQ05_R91_CFG_FIFO11 0x05, 0x9b
485#define TM6010_REQ05_R91_CFG_FIFO12 0x05, 0x9c
486#define TM6010_REQ05_R91_CFG_FIFO13 0x05, 0x9d
487#define TM6010_REQ05_R91_CFG_FIFO14 0x05, 0x9e
488#define TM6010_REQ05_R91_CFG_FIFO15 0x05, 0x9f
489#define TM6010_REQ05_RA0_CTL_FIFO0 0x05, 0xa0
490#define TM6010_REQ05_RA1_CTL_FIFO1 0x05, 0xa1
491#define TM6010_REQ05_RA2_CTL_FIFO2 0x05, 0xa2
492#define TM6010_REQ05_RA3_CTL_FIFO3 0x05, 0xa3
493#define TM6010_REQ05_RA4_CTL_FIFO4 0x05, 0xa4
494#define TM6010_REQ05_RA5_CTL_FIFO5 0x05, 0xa5
495#define TM6010_REQ05_RA6_CTL_FIFO6 0x05, 0xa6
496#define TM6010_REQ05_RA7_CTL_FIFO7 0x05, 0xa7
497#define TM6010_REQ05_RA8_CTL_FIFO8 0x05, 0xa8
498#define TM6010_REQ05_RA9_CTL_FIFO9 0x05, 0xa9
499#define TM6010_REQ05_RA1_CTL_FIFO10 0x05, 0xaa
500#define TM6010_REQ05_RA1_CTL_FIFO11 0x05, 0xab
501#define TM6010_REQ05_RA1_CTL_FIFO12 0x05, 0xac
502#define TM6010_REQ05_RA1_CTL_FIFO13 0x05, 0xad
503#define TM6010_REQ05_RA1_CTL_FIFO14 0x05, 0xae
504#define TM6010_REQ05_RA1_CTL_FIFO15 0x05, 0xaf
505#define TM6010_REQ05_RB0_BC_LOW_FIFO0 0x05, 0xb0
506#define TM6010_REQ05_RB1_BC_LOW_FIFO1 0x05, 0xb1
507#define TM6010_REQ05_RB2_BC_LOW_FIFO2 0x05, 0xb2
508#define TM6010_REQ05_RB3_BC_LOW_FIFO3 0x05, 0xb3
509#define TM6010_REQ05_RB4_BC_LOW_FIFO4 0x05, 0xb4
510#define TM6010_REQ05_RB5_BC_LOW_FIFO5 0x05, 0xb5
511#define TM6010_REQ05_RB6_BC_LOW_FIFO6 0x05, 0xb6
512#define TM6010_REQ05_RB7_BC_LOW_FIFO7 0x05, 0xb7
513#define TM6010_REQ05_RB8_BC_LOW_FIFO8 0x05, 0xb8
514#define TM6010_REQ05_RB9_BC_LOW_FIFO9 0x05, 0xb9
515#define TM6010_REQ05_RB1_BC_LOW_FIFO10 0x05, 0xba
516#define TM6010_REQ05_RB1_BC_LOW_FIFO11 0x05, 0xbb
517#define TM6010_REQ05_RB1_BC_LOW_FIFO12 0x05, 0xbc
518#define TM6010_REQ05_RB1_BC_LOW_FIFO13 0x05, 0xbd
519#define TM6010_REQ05_RB1_BC_LOW_FIFO14 0x05, 0xbe
520#define TM6010_REQ05_RB1_BC_LOW_FIFO15 0x05, 0xbf
521#define TM6010_REQ05_RC0_DATA_FIFO0 0x05, 0xc0
522#define TM6010_REQ05_RC4_DATA_FIFO1 0x05, 0xc4
523#define TM6010_REQ05_RC8_DATA_FIFO2 0x05, 0xc8
524#define TM6010_REQ05_RCC_DATA_FIFO3 0x05, 0xcc
525#define TM6010_REQ05_RD0_DATA_FIFO4 0x05, 0xd0
526#define TM6010_REQ05_RD4_DATA_FIFO5 0x05, 0xd4
527#define TM6010_REQ05_RD8_DATA_FIFO6 0x05, 0xd8
528#define TM6010_REQ05_RDC_DATA_FIFO7 0x05, 0xdc
529#define TM6010_REQ05_RE0_DATA_FIFO8 0x05, 0xe0
530#define TM6010_REQ05_RE4_DATA_FIFO9 0x05, 0xe4
531#define TM6010_REQ05_RC4_DATA_FIFO10 0x05, 0xe8
532#define TM6010_REQ05_RC4_DATA_FIFO11 0x05, 0xec
533#define TM6010_REQ05_RC4_DATA_FIFO12 0x05, 0xf0
534#define TM6010_REQ05_RC4_DATA_FIFO13 0x05, 0xf4
535#define TM6010_REQ05_RC4_DATA_FIFO14 0x05, 0xf8
536#define TM6010_REQ05_RC4_DATA_FIFO15 0x05, 0xfc
537
538/* Define TM6010 Audio decoder registers */
539/* This core available only in TM6010 */
540#define TM6010_REQ08_R00_A_VERSION 0x08, 0x00
541#define TM6010_REQ08_R01_A_INIT 0x08, 0x01
542#define TM6010_REQ08_R02_A_FIX_GAIN_CTRL 0x08, 0x02
543#define TM6010_REQ08_R03_A_AUTO_GAIN_CTRL 0x08, 0x03
544#define TM6010_REQ08_R04_A_SIF_AMP_CTRL 0x08, 0x04
545#define TM6010_REQ08_R05_A_STANDARD_MOD 0x08, 0x05
546#define TM6010_REQ08_R06_A_SOUND_MOD 0x08, 0x06
547#define TM6010_REQ08_R07_A_LEFT_VOL 0x08, 0x07
548#define TM6010_REQ08_R08_A_RIGHT_VOL 0x08, 0x08
549#define TM6010_REQ08_R09_A_MAIN_VOL 0x08, 0x09
550#define TM6010_REQ08_R0A_A_I2S_MOD 0x08, 0x0a
551#define TM6010_REQ08_R0B_A_ASD_THRES1 0x08, 0x0b
552#define TM6010_REQ08_R0C_A_ASD_THRES2 0x08, 0x0c
553#define TM6010_REQ08_R0D_A_AMD_THRES 0x08, 0x0d
554#define TM6010_REQ08_R0E_A_MONO_THRES1 0x08, 0x0e
555#define TM6010_REQ08_R0F_A_MONO_THRES2 0x08, 0x0f
556#define TM6010_REQ08_R10_A_MUTE_THRES1 0x08, 0x10
557#define TM6010_REQ08_R11_A_MUTE_THRES2 0x08, 0x11
558#define TM6010_REQ08_R12_A_AGC_U 0x08, 0x12
559#define TM6010_REQ08_R13_A_AGC_ERR_T 0x08, 0x13
560#define TM6010_REQ08_R14_A_AGC_GAIN_INIT 0x08, 0x14
561#define TM6010_REQ08_R15_A_AGC_STEP_THR 0x08, 0x15
562#define TM6010_REQ08_R16_A_AGC_GAIN_MAX 0x08, 0x16
563#define TM6010_REQ08_R17_A_AGC_GAIN_MIN 0x08, 0x17
564#define TM6010_REQ08_R18_A_TR_CTRL 0x08, 0x18
565#define TM6010_REQ08_R19_A_FH_2FH_GAIN 0x08, 0x19
566#define TM6010_REQ08_R1A_A_NICAM_SER_MAX 0x08, 0x1a
567#define TM6010_REQ08_R1B_A_NICAM_SER_MIN 0x08, 0x1b
568#define TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT 0x08, 0x1e
569#define TM6010_REQ08_R1F_A_TEST_INTF_SEL 0x08, 0x1f
570#define TM6010_REQ08_R20_A_TEST_PIN_SEL 0x08, 0x20
571#define TM6010_REQ08_R21_A_AGC_ERR 0x08, 0x21
572#define TM6010_REQ08_R22_A_AGC_GAIN 0x08, 0x22
573#define TM6010_REQ08_R23_A_NICAM_INFO 0x08, 0x23
574#define TM6010_REQ08_R24_A_SER 0x08, 0x24
575#define TM6010_REQ08_R25_A_C1_AMP 0x08, 0x25
576#define TM6010_REQ08_R26_A_C2_AMP 0x08, 0x26
577#define TM6010_REQ08_R27_A_NOISE_AMP 0x08, 0x27
578#define TM6010_REQ08_R28_A_AUDIO_MODE_RES 0x08, 0x28
579
580/* Define TM6010 Video ADC registers */
581#define TM6010_REQ08_RE0_ADC_REF 0x08, 0xe0
582#define TM6010_REQ08_RE1_DAC_CLMP 0x08, 0xe1
583#define TM6010_REQ08_RE2_POWER_DOWN_CTRL1 0x08, 0xe2
584#define TM6010_REQ08_RE3_ADC_IN1_SEL 0x08, 0xe3
585#define TM6010_REQ08_RE4_ADC_IN2_SEL 0x08, 0xe4
586#define TM6010_REQ08_RE5_GAIN_PARAM 0x08, 0xe5
587#define TM6010_REQ08_RE6_POWER_DOWN_CTRL2 0x08, 0xe6
588#define TM6010_REQ08_RE7_REG_GAIN_Y 0x08, 0xe7
589#define TM6010_REQ08_RE8_REG_GAIN_C 0x08, 0xe8
590#define TM6010_REQ08_RE9_BIAS_CTRL 0x08, 0xe9
591#define TM6010_REQ08_REA_BUFF_DRV_CTRL 0x08, 0xea
592#define TM6010_REQ08_REB_SIF_GAIN_CTRL 0x08, 0xeb
593#define TM6010_REQ08_REC_REVERSE_YC_CTRL 0x08, 0xec
594#define TM6010_REQ08_RED_GAIN_SEL 0x08, 0xed
595
596/* Define TM6010 Audio ADC registers */
597#define TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG 0x08, 0xf0
598#define TM6010_REQ08_RF1_AADC_POWER_DOWN 0x08, 0xf1
599#define TM6010_REQ08_RF2_LEFT_CHANNEL_VOL 0x08, 0xf2
600#define TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL 0x08, 0xf3
diff --git a/drivers/media/video/tm6000/tm6000-stds.c b/drivers/media/video/tm6000/tm6000-stds.c
new file mode 100644
index 00000000000..9a4145dc3d8
--- /dev/null
+++ b/drivers/media/video/tm6000/tm6000-stds.c
@@ -0,0 +1,659 @@
1/*
2 * tm6000-stds.c - driver for TM5600/TM6000/TM6010 USB video capture devices
3 *
4 * Copyright (C) 2007 Mauro Carvalho Chehab <mchehab@redhat.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation version 2
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20#include <linux/module.h>
21#include <linux/kernel.h>
22#include "tm6000.h"
23#include "tm6000-regs.h"
24
25static unsigned int tm6010_a_mode;
26module_param(tm6010_a_mode, int, 0644);
27MODULE_PARM_DESC(tm6010_a_mode, "set tm6010 sif audio mode");
28
29struct tm6000_reg_settings {
30 unsigned char req;
31 unsigned char reg;
32 unsigned char value;
33};
34
35
36struct tm6000_std_settings {
37 v4l2_std_id id;
38 struct tm6000_reg_settings *common;
39};
40
41static struct tm6000_reg_settings composite_pal_m[] = {
42 { TM6010_REQ07_R3F_RESET, 0x01 },
43 { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x04 },
44 { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e },
45 { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
46 { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 },
47 { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 },
48 { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
49 { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83 },
50 { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a },
51 { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe0 },
52 { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
53 { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
54 { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
55 { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
56 { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 },
57 { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x20 },
58 { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 },
59 { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c },
60 { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
61 { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 },
62 { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f },
63 { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc },
64 { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
65 { TM6010_REQ07_R3F_RESET, 0x00 },
66 { 0, 0, 0 }
67};
68
69static struct tm6000_reg_settings composite_pal_nc[] = {
70 { TM6010_REQ07_R3F_RESET, 0x01 },
71 { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x36 },
72 { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e },
73 { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
74 { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02 },
75 { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 },
76 { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
77 { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91 },
78 { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f },
79 { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x0c },
80 { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
81 { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
82 { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
83 { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
84 { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c },
85 { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c },
86 { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 },
87 { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c },
88 { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
89 { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 },
90 { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f },
91 { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc },
92 { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
93 { TM6010_REQ07_R3F_RESET, 0x00 },
94 { 0, 0, 0 }
95};
96
97static struct tm6000_reg_settings composite_pal[] = {
98 { TM6010_REQ07_R3F_RESET, 0x01 },
99 { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x32 },
100 { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e },
101 { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
102 { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02 },
103 { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 },
104 { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25 },
105 { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5 },
106 { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63 },
107 { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x50 },
108 { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
109 { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
110 { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
111 { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
112 { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c },
113 { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c },
114 { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 },
115 { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c },
116 { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
117 { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 },
118 { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f },
119 { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc },
120 { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
121 { TM6010_REQ07_R3F_RESET, 0x00 },
122 { 0, 0, 0 }
123};
124
125static struct tm6000_reg_settings composite_secam[] = {
126 { TM6010_REQ07_R3F_RESET, 0x01 },
127 { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x38 },
128 { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e },
129 { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
130 { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02 },
131 { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 },
132 { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24 },
133 { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92 },
134 { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8 },
135 { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed },
136 { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
137 { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
138 { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
139 { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
140 { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c },
141 { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c },
142 { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 },
143 { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c },
144 { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18 },
145 { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 },
146 { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xff },
147 { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
148 { TM6010_REQ07_R3F_RESET, 0x00 },
149 { 0, 0, 0 }
150};
151
152static struct tm6000_reg_settings composite_ntsc[] = {
153 { TM6010_REQ07_R3F_RESET, 0x01 },
154 { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 },
155 { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f },
156 { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
157 { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 },
158 { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 },
159 { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
160 { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b },
161 { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 },
162 { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 },
163 { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
164 { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
165 { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
166 { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
167 { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 },
168 { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 },
169 { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 },
170 { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c },
171 { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
172 { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 },
173 { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f },
174 { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdd },
175 { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
176 { TM6010_REQ07_R3F_RESET, 0x00 },
177 { 0, 0, 0 }
178};
179
180static struct tm6000_std_settings composite_stds[] = {
181 { .id = V4L2_STD_PAL_M, .common = composite_pal_m, },
182 { .id = V4L2_STD_PAL_Nc, .common = composite_pal_nc, },
183 { .id = V4L2_STD_PAL, .common = composite_pal, },
184 { .id = V4L2_STD_SECAM, .common = composite_secam, },
185 { .id = V4L2_STD_NTSC, .common = composite_ntsc, },
186};
187
188static struct tm6000_reg_settings svideo_pal_m[] = {
189 { TM6010_REQ07_R3F_RESET, 0x01 },
190 { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x05 },
191 { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e },
192 { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
193 { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04 },
194 { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 },
195 { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
196 { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83 },
197 { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a },
198 { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe0 },
199 { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
200 { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
201 { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
202 { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
203 { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 },
204 { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 },
205 { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 },
206 { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c },
207 { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
208 { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 },
209 { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f },
210 { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc },
211 { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
212 { TM6010_REQ07_R3F_RESET, 0x00 },
213 { 0, 0, 0 }
214};
215
216static struct tm6000_reg_settings svideo_pal_nc[] = {
217 { TM6010_REQ07_R3F_RESET, 0x01 },
218 { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x37 },
219 { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e },
220 { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
221 { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04 },
222 { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 },
223 { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
224 { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91 },
225 { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f },
226 { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x0c },
227 { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
228 { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
229 { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
230 { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
231 { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 },
232 { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 },
233 { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 },
234 { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c },
235 { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
236 { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 },
237 { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f },
238 { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc },
239 { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
240 { TM6010_REQ07_R3F_RESET, 0x00 },
241 { 0, 0, 0 }
242};
243
244static struct tm6000_reg_settings svideo_pal[] = {
245 { TM6010_REQ07_R3F_RESET, 0x01 },
246 { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x33 },
247 { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e },
248 { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
249 { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04 },
250 { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x30 },
251 { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25 },
252 { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5 },
253 { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63 },
254 { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x50 },
255 { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
256 { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
257 { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
258 { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
259 { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c },
260 { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2a },
261 { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 },
262 { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c },
263 { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
264 { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 },
265 { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f },
266 { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc },
267 { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
268 { TM6010_REQ07_R3F_RESET, 0x00 },
269 { 0, 0, 0 }
270};
271
272static struct tm6000_reg_settings svideo_secam[] = {
273 { TM6010_REQ07_R3F_RESET, 0x01 },
274 { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x39 },
275 { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e },
276 { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
277 { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03 },
278 { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 },
279 { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24 },
280 { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92 },
281 { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8 },
282 { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed },
283 { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
284 { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
285 { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
286 { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
287 { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c },
288 { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2a },
289 { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 },
290 { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c },
291 { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18 },
292 { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 },
293 { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xff },
294 { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
295 { TM6010_REQ07_R3F_RESET, 0x00 },
296 { 0, 0, 0 }
297};
298
299static struct tm6000_reg_settings svideo_ntsc[] = {
300 { TM6010_REQ07_R3F_RESET, 0x01 },
301 { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x01 },
302 { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f },
303 { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
304 { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03 },
305 { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x30 },
306 { TM6010_REQ07_R17_HLOOP_MAXSTATE, 0x8b },
307 { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
308 { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b },
309 { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 },
310 { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 },
311 { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
312 { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
313 { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
314 { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
315 { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 },
316 { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 },
317 { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 },
318 { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c },
319 { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
320 { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 },
321 { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f },
322 { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdd },
323 { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
324 { TM6010_REQ07_R3F_RESET, 0x00 },
325 { 0, 0, 0 }
326};
327
328static struct tm6000_std_settings svideo_stds[] = {
329 { .id = V4L2_STD_PAL_M, .common = svideo_pal_m, },
330 { .id = V4L2_STD_PAL_Nc, .common = svideo_pal_nc, },
331 { .id = V4L2_STD_PAL, .common = svideo_pal, },
332 { .id = V4L2_STD_SECAM, .common = svideo_secam, },
333 { .id = V4L2_STD_NTSC, .common = svideo_ntsc, },
334};
335
336static int tm6000_set_audio_std(struct tm6000_core *dev)
337{
338 uint8_t areg_02 = 0x04; /* GC1 Fixed gain 0dB */
339 uint8_t areg_05 = 0x01; /* Auto 4.5 = M Japan, Auto 6.5 = DK */
340 uint8_t areg_06 = 0x02; /* Auto de-emphasis, mannual channel mode */
341 uint8_t nicam_flag = 0; /* No NICAM */
342
343 if (dev->radio) {
344 tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00);
345 tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, 0x04);
346 tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00);
347 tm6000_set_reg(dev, TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0x80);
348 tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, 0x0c);
349 /* set mono or stereo */
350 if (dev->amode == V4L2_TUNER_MODE_MONO)
351 tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x00);
352 else if (dev->amode == V4L2_TUNER_MODE_STEREO)
353 tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x02);
354 tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x18);
355 tm6000_set_reg(dev, TM6010_REQ08_R0C_A_ASD_THRES2, 0x0a);
356 tm6000_set_reg(dev, TM6010_REQ08_R0D_A_AMD_THRES, 0x40);
357 tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe);
358 tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13);
359 tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80);
360 tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, 0xff);
361 return 0;
362 }
363
364 switch (tm6010_a_mode) {
365 /* auto */
366 case 0:
367 switch (dev->norm) {
368 case V4L2_STD_NTSC_M_KR:
369 areg_05 |= 0x00;
370 break;
371 case V4L2_STD_NTSC_M_JP:
372 areg_05 |= 0x40;
373 break;
374 case V4L2_STD_NTSC_M:
375 case V4L2_STD_PAL_M:
376 case V4L2_STD_PAL_N:
377 areg_05 |= 0x20;
378 break;
379 case V4L2_STD_PAL_Nc:
380 areg_05 |= 0x60;
381 break;
382 case V4L2_STD_SECAM_L:
383 areg_05 |= 0x00;
384 break;
385 case V4L2_STD_DK:
386 areg_05 |= 0x10;
387 break;
388 }
389 break;
390 /* A2 */
391 case 1:
392 switch (dev->norm) {
393 case V4L2_STD_B:
394 case V4L2_STD_GH:
395 areg_05 = 0x05;
396 break;
397 case V4L2_STD_DK:
398 areg_05 = 0x09;
399 break;
400 }
401 break;
402 /* NICAM */
403 case 2:
404 switch (dev->norm) {
405 case V4L2_STD_B:
406 case V4L2_STD_GH:
407 areg_05 = 0x07;
408 break;
409 case V4L2_STD_DK:
410 areg_05 = 0x06;
411 break;
412 case V4L2_STD_PAL_I:
413 areg_05 = 0x08;
414 break;
415 case V4L2_STD_SECAM_L:
416 areg_05 = 0x0a;
417 areg_02 = 0x02;
418 break;
419 }
420 nicam_flag = 1;
421 break;
422 /* other */
423 case 3:
424 switch (dev->norm) {
425 /* DK3_A2 */
426 case V4L2_STD_DK:
427 areg_05 = 0x0b;
428 break;
429 /* Korea */
430 case V4L2_STD_NTSC_M_KR:
431 areg_05 = 0x04;
432 break;
433 /* EIAJ */
434 case V4L2_STD_NTSC_M_JP:
435 areg_05 = 0x03;
436 break;
437 default:
438 areg_05 = 0x02;
439 break;
440 }
441 break;
442 }
443
444 tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00);
445 tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, areg_02);
446 tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00);
447 tm6000_set_reg(dev, TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0xa0);
448 tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, areg_05);
449 tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, areg_06);
450 tm6000_set_reg(dev, TM6010_REQ08_R07_A_LEFT_VOL, 0x00);
451 tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, 0x00);
452 tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x08);
453 tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0x91);
454 tm6000_set_reg(dev, TM6010_REQ08_R0B_A_ASD_THRES1, 0x20);
455 tm6000_set_reg(dev, TM6010_REQ08_R0C_A_ASD_THRES2, 0x12);
456 tm6000_set_reg(dev, TM6010_REQ08_R0D_A_AMD_THRES, 0x20);
457 tm6000_set_reg(dev, TM6010_REQ08_R0E_A_MONO_THRES1, 0xf0);
458 tm6000_set_reg(dev, TM6010_REQ08_R0F_A_MONO_THRES2, 0x80);
459 tm6000_set_reg(dev, TM6010_REQ08_R10_A_MUTE_THRES1, 0xc0);
460 tm6000_set_reg(dev, TM6010_REQ08_R11_A_MUTE_THRES2, 0x80);
461 tm6000_set_reg(dev, TM6010_REQ08_R12_A_AGC_U, 0x12);
462 tm6000_set_reg(dev, TM6010_REQ08_R13_A_AGC_ERR_T, 0xfe);
463 tm6000_set_reg(dev, TM6010_REQ08_R14_A_AGC_GAIN_INIT, 0x20);
464 tm6000_set_reg(dev, TM6010_REQ08_R15_A_AGC_STEP_THR, 0x14);
465 tm6000_set_reg(dev, TM6010_REQ08_R16_A_AGC_GAIN_MAX, 0xfe);
466 tm6000_set_reg(dev, TM6010_REQ08_R17_A_AGC_GAIN_MIN, 0x01);
467 tm6000_set_reg(dev, TM6010_REQ08_R18_A_TR_CTRL, 0xa0);
468 tm6000_set_reg(dev, TM6010_REQ08_R19_A_FH_2FH_GAIN, 0x32);
469 tm6000_set_reg(dev, TM6010_REQ08_R1A_A_NICAM_SER_MAX, 0x64);
470 tm6000_set_reg(dev, TM6010_REQ08_R1B_A_NICAM_SER_MIN, 0x20);
471 tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1c, 0x00);
472 tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1d, 0x00);
473 tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13);
474 tm6000_set_reg(dev, TM6010_REQ08_R1F_A_TEST_INTF_SEL, 0x00);
475 tm6000_set_reg(dev, TM6010_REQ08_R20_A_TEST_PIN_SEL, 0x00);
476 tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80);
477
478 return 0;
479}
480
481void tm6000_get_std_res(struct tm6000_core *dev)
482{
483 /* Currently, those are the only supported resoltions */
484 if (dev->norm & V4L2_STD_525_60)
485 dev->height = 480;
486 else
487 dev->height = 576;
488
489 dev->width = 720;
490}
491
492static int tm6000_load_std(struct tm6000_core *dev, struct tm6000_reg_settings *set)
493{
494 int i, rc;
495
496 /* Load board's initialization table */
497 for (i = 0; set[i].req; i++) {
498 rc = tm6000_set_reg(dev, set[i].req, set[i].reg, set[i].value);
499 if (rc < 0) {
500 printk(KERN_ERR "Error %i while setting "
501 "req %d, reg %d to value %d\n",
502 rc, set[i].req, set[i].reg, set[i].value);
503 return rc;
504 }
505 }
506
507 return 0;
508}
509
510int tm6000_set_standard(struct tm6000_core *dev)
511{
512 struct tm6000_input *input;
513 int i, rc = 0;
514 u8 reg_07_fe = 0x8a;
515 u8 reg_08_f1 = 0xfc;
516 u8 reg_08_e2 = 0xf0;
517 u8 reg_08_e6 = 0x0f;
518
519 tm6000_get_std_res(dev);
520
521 if (!dev->radio)
522 input = &dev->vinput[dev->input];
523 else
524 input = &dev->rinput;
525
526 if (dev->dev_type == TM6010) {
527 switch (input->vmux) {
528 case TM6000_VMUX_VIDEO_A:
529 tm6000_set_reg(dev, TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4);
530 tm6000_set_reg(dev, TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1);
531 tm6000_set_reg(dev, TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0);
532 tm6000_set_reg(dev, TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2);
533 tm6000_set_reg(dev, TM6010_REQ08_RED_GAIN_SEL, 0xe8);
534 reg_07_fe |= 0x01;
535 break;
536 case TM6000_VMUX_VIDEO_B:
537 tm6000_set_reg(dev, TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8);
538 tm6000_set_reg(dev, TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1);
539 tm6000_set_reg(dev, TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0);
540 tm6000_set_reg(dev, TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2);
541 tm6000_set_reg(dev, TM6010_REQ08_RED_GAIN_SEL, 0xe8);
542 reg_07_fe |= 0x01;
543 break;
544 case TM6000_VMUX_VIDEO_AB:
545 tm6000_set_reg(dev, TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc);
546 tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8);
547 reg_08_e6 = 0x00;
548 tm6000_set_reg(dev, TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2);
549 tm6000_set_reg(dev, TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0);
550 tm6000_set_reg(dev, TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2);
551 tm6000_set_reg(dev, TM6010_REQ08_RED_GAIN_SEL, 0xe0);
552 break;
553 default:
554 break;
555 }
556 switch (input->amux) {
557 case TM6000_AMUX_ADC1:
558 tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
559 0x00, 0x0f);
560 break;
561 case TM6000_AMUX_ADC2:
562 tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
563 0x08, 0x0f);
564 break;
565 case TM6000_AMUX_SIF1:
566 reg_08_e2 |= 0x02;
567 reg_08_e6 = 0x08;
568 reg_07_fe |= 0x40;
569 reg_08_f1 |= 0x02;
570 tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3);
571 tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
572 0x02, 0x0f);
573 break;
574 case TM6000_AMUX_SIF2:
575 reg_08_e2 |= 0x02;
576 reg_08_e6 = 0x08;
577 reg_07_fe |= 0x40;
578 reg_08_f1 |= 0x02;
579 tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf7);
580 tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
581 0x02, 0x0f);
582 break;
583 default:
584 break;
585 }
586 tm6000_set_reg(dev, TM6010_REQ08_RE2_POWER_DOWN_CTRL1, reg_08_e2);
587 tm6000_set_reg(dev, TM6010_REQ08_RE6_POWER_DOWN_CTRL2, reg_08_e6);
588 tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, reg_08_f1);
589 tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, reg_07_fe);
590 } else {
591 switch (input->vmux) {
592 case TM6000_VMUX_VIDEO_A:
593 tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10);
594 tm6000_set_reg(dev, TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00);
595 tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x0f);
596 tm6000_set_reg(dev,
597 REQ_03_SET_GET_MCU_PIN, input->v_gpio, 0);
598 break;
599 case TM6000_VMUX_VIDEO_B:
600 tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x00);
601 tm6000_set_reg(dev, TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00);
602 tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x0f);
603 tm6000_set_reg(dev,
604 REQ_03_SET_GET_MCU_PIN, input->v_gpio, 0);
605 break;
606 case TM6000_VMUX_VIDEO_AB:
607 tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10);
608 tm6000_set_reg(dev, TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x10);
609 tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x00);
610 tm6000_set_reg(dev,
611 REQ_03_SET_GET_MCU_PIN, input->v_gpio, 1);
612 break;
613 default:
614 break;
615 }
616 switch (input->amux) {
617 case TM6000_AMUX_ADC1:
618 tm6000_set_reg_mask(dev,
619 TM6000_REQ07_REB_VADC_AADC_MODE, 0x00, 0x0f);
620 break;
621 case TM6000_AMUX_ADC2:
622 tm6000_set_reg_mask(dev,
623 TM6000_REQ07_REB_VADC_AADC_MODE, 0x04, 0x0f);
624 break;
625 default:
626 break;
627 }
628 }
629 if (input->type == TM6000_INPUT_SVIDEO) {
630 for (i = 0; i < ARRAY_SIZE(svideo_stds); i++) {
631 if (dev->norm & svideo_stds[i].id) {
632 rc = tm6000_load_std(dev, svideo_stds[i].common);
633 goto ret;
634 }
635 }
636 return -EINVAL;
637 } else {
638 for (i = 0; i < ARRAY_SIZE(composite_stds); i++) {
639 if (dev->norm & composite_stds[i].id) {
640 rc = tm6000_load_std(dev, composite_stds[i].common);
641 goto ret;
642 }
643 }
644 return -EINVAL;
645 }
646
647ret:
648 if (rc < 0)
649 return rc;
650
651 if ((dev->dev_type == TM6010) &&
652 ((input->amux == TM6000_AMUX_SIF1) ||
653 (input->amux == TM6000_AMUX_SIF2)))
654 tm6000_set_audio_std(dev);
655
656 msleep(40);
657
658 return 0;
659}
diff --git a/drivers/media/video/tm6000/tm6000-usb-isoc.h b/drivers/media/video/tm6000/tm6000-usb-isoc.h
new file mode 100644
index 00000000000..99d15a55aa0
--- /dev/null
+++ b/drivers/media/video/tm6000/tm6000-usb-isoc.h
@@ -0,0 +1,50 @@
1/*
2 * tm6000-buf.c - driver for TM5600/TM6000/TM6010 USB video capture devices
3 *
4 * Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation version 2
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20#include <linux/videodev2.h>
21
22#define TM6000_URB_MSG_LEN 180
23
24struct usb_isoc_ctl {
25 /* max packet size of isoc transaction */
26 int max_pkt_size;
27
28 /* number of allocated urbs */
29 int num_bufs;
30
31 /* urb for isoc transfers */
32 struct urb **urb;
33
34 /* transfer buffers for isoc transfer */
35 char **transfer_buffer;
36
37 /* Last buffer command and region */
38 u8 cmd;
39 int pos, size, pktsize;
40
41 /* Last field: ODD or EVEN? */
42 int vfield, field;
43
44 /* Stores incomplete commands */
45 u32 tmp_buf;
46 int tmp_buf_len;
47
48 /* Stores already requested buffers */
49 struct tm6000_buffer *buf;
50};
diff --git a/drivers/media/video/tm6000/tm6000-video.c b/drivers/media/video/tm6000/tm6000-video.c
new file mode 100644
index 00000000000..1e5ace0b5d1
--- /dev/null
+++ b/drivers/media/video/tm6000/tm6000-video.c
@@ -0,0 +1,1813 @@
1/*
2 * tm6000-video.c - driver for TM5600/TM6000/TM6010 USB video capture devices
3 *
4 * Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
5 *
6 * Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
7 * - Fixed module load/unload
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation version 2
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23#include <linux/module.h>
24#include <linux/delay.h>
25#include <linux/errno.h>
26#include <linux/fs.h>
27#include <linux/kernel.h>
28#include <linux/slab.h>
29#include <linux/mm.h>
30#include <linux/ioport.h>
31#include <linux/init.h>
32#include <linux/sched.h>
33#include <linux/random.h>
34#include <linux/usb.h>
35#include <linux/videodev2.h>
36#include <media/v4l2-ioctl.h>
37#include <media/tuner.h>
38#include <linux/interrupt.h>
39#include <linux/kthread.h>
40#include <linux/highmem.h>
41#include <linux/freezer.h>
42
43#include "tm6000-regs.h"
44#include "tm6000.h"
45
46#define BUFFER_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */
47
48/* Limits minimum and default number of buffers */
49#define TM6000_MIN_BUF 4
50#define TM6000_DEF_BUF 8
51
52#define TM6000_MAX_ISO_PACKETS 46 /* Max number of ISO packets */
53
54/* Declare static vars that will be used as parameters */
55static unsigned int vid_limit = 16; /* Video memory limit, in Mb */
56static int video_nr = -1; /* /dev/videoN, -1 for autodetect */
57static int radio_nr = -1; /* /dev/radioN, -1 for autodetect */
58
59/* Debug level */
60int tm6000_debug;
61EXPORT_SYMBOL_GPL(tm6000_debug);
62
63static const struct v4l2_queryctrl no_ctrl = {
64 .name = "42",
65 .flags = V4L2_CTRL_FLAG_DISABLED,
66};
67
68/* supported controls */
69static struct v4l2_queryctrl tm6000_qctrl[] = {
70 {
71 .id = V4L2_CID_BRIGHTNESS,
72 .type = V4L2_CTRL_TYPE_INTEGER,
73 .name = "Brightness",
74 .minimum = 0,
75 .maximum = 255,
76 .step = 1,
77 .default_value = 54,
78 .flags = 0,
79 }, {
80 .id = V4L2_CID_CONTRAST,
81 .type = V4L2_CTRL_TYPE_INTEGER,
82 .name = "Contrast",
83 .minimum = 0,
84 .maximum = 255,
85 .step = 0x1,
86 .default_value = 119,
87 .flags = 0,
88 }, {
89 .id = V4L2_CID_SATURATION,
90 .type = V4L2_CTRL_TYPE_INTEGER,
91 .name = "Saturation",
92 .minimum = 0,
93 .maximum = 255,
94 .step = 0x1,
95 .default_value = 112,
96 .flags = 0,
97 }, {
98 .id = V4L2_CID_HUE,
99 .type = V4L2_CTRL_TYPE_INTEGER,
100 .name = "Hue",
101 .minimum = -128,
102 .maximum = 127,
103 .step = 0x1,
104 .default_value = 0,
105 .flags = 0,
106 },
107 /* --- audio --- */
108 {
109 .id = V4L2_CID_AUDIO_MUTE,
110 .name = "Mute",
111 .minimum = 0,
112 .maximum = 1,
113 .type = V4L2_CTRL_TYPE_BOOLEAN,
114 }, {
115 .id = V4L2_CID_AUDIO_VOLUME,
116 .name = "Volume",
117 .minimum = -15,
118 .maximum = 15,
119 .step = 1,
120 .default_value = 0,
121 .type = V4L2_CTRL_TYPE_INTEGER,
122 }
123};
124
125static const unsigned int CTRLS = ARRAY_SIZE(tm6000_qctrl);
126static int qctl_regs[ARRAY_SIZE(tm6000_qctrl)];
127
128static struct tm6000_fmt format[] = {
129 {
130 .name = "4:2:2, packed, YVY2",
131 .fourcc = V4L2_PIX_FMT_YUYV,
132 .depth = 16,
133 }, {
134 .name = "4:2:2, packed, UYVY",
135 .fourcc = V4L2_PIX_FMT_UYVY,
136 .depth = 16,
137 }, {
138 .name = "A/V + VBI mux packet",
139 .fourcc = V4L2_PIX_FMT_TM6000,
140 .depth = 16,
141 }
142};
143
144static const struct v4l2_queryctrl *ctrl_by_id(unsigned int id)
145{
146 unsigned int i;
147
148 for (i = 0; i < CTRLS; i++)
149 if (tm6000_qctrl[i].id == id)
150 return tm6000_qctrl+i;
151 return NULL;
152}
153
154/* ------------------------------------------------------------------
155 * DMA and thread functions
156 * ------------------------------------------------------------------
157 */
158
159#define norm_maxw(a) 720
160#define norm_maxh(a) 576
161
162#define norm_minw(a) norm_maxw(a)
163#define norm_minh(a) norm_maxh(a)
164
165/*
166 * video-buf generic routine to get the next available buffer
167 */
168static inline void get_next_buf(struct tm6000_dmaqueue *dma_q,
169 struct tm6000_buffer **buf)
170{
171 struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
172 char *outp;
173
174 if (list_empty(&dma_q->active)) {
175 dprintk(dev, V4L2_DEBUG_QUEUE, "No active queue to serve\n");
176 *buf = NULL;
177 return;
178 }
179
180 *buf = list_entry(dma_q->active.next,
181 struct tm6000_buffer, vb.queue);
182
183 /* Cleans up buffer - Useful for testing for frame/URB loss */
184 outp = videobuf_to_vmalloc(&(*buf)->vb);
185
186 return;
187}
188
189/*
190 * Announces that a buffer were filled and request the next
191 */
192static inline void buffer_filled(struct tm6000_core *dev,
193 struct tm6000_dmaqueue *dma_q,
194 struct tm6000_buffer *buf)
195{
196 /* Advice that buffer was filled */
197 dprintk(dev, V4L2_DEBUG_ISOC, "[%p/%d] wakeup\n", buf, buf->vb.i);
198 buf->vb.state = VIDEOBUF_DONE;
199 buf->vb.field_count++;
200 do_gettimeofday(&buf->vb.ts);
201
202 list_del(&buf->vb.queue);
203 wake_up(&buf->vb.done);
204}
205
206/*
207 * Identify the tm5600/6000 buffer header type and properly handles
208 */
209static int copy_streams(u8 *data, unsigned long len,
210 struct urb *urb)
211{
212 struct tm6000_dmaqueue *dma_q = urb->context;
213 struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
214 u8 *ptr = data, *endp = data+len, c;
215 unsigned long header = 0;
216 int rc = 0;
217 unsigned int cmd, cpysize, pktsize, size, field, block, line, pos = 0;
218 struct tm6000_buffer *vbuf = NULL;
219 char *voutp = NULL;
220 unsigned int linewidth;
221
222 if (!dev->radio) {
223 /* get video buffer */
224 get_next_buf(dma_q, &vbuf);
225
226 if (!vbuf)
227 return rc;
228 voutp = videobuf_to_vmalloc(&vbuf->vb);
229
230 if (!voutp)
231 return 0;
232 }
233
234 for (ptr = data; ptr < endp;) {
235 if (!dev->isoc_ctl.cmd) {
236 /* Header */
237 if (dev->isoc_ctl.tmp_buf_len > 0) {
238 /* from last urb or packet */
239 header = dev->isoc_ctl.tmp_buf;
240 if (4 - dev->isoc_ctl.tmp_buf_len > 0) {
241 memcpy((u8 *)&header +
242 dev->isoc_ctl.tmp_buf_len,
243 ptr,
244 4 - dev->isoc_ctl.tmp_buf_len);
245 ptr += 4 - dev->isoc_ctl.tmp_buf_len;
246 }
247 dev->isoc_ctl.tmp_buf_len = 0;
248 } else {
249 if (ptr + 3 >= endp) {
250 /* have incomplete header */
251 dev->isoc_ctl.tmp_buf_len = endp - ptr;
252 memcpy(&dev->isoc_ctl.tmp_buf, ptr,
253 dev->isoc_ctl.tmp_buf_len);
254 return rc;
255 }
256 /* Seek for sync */
257 for (; ptr < endp - 3; ptr++) {
258 if (*(ptr + 3) == 0x47)
259 break;
260 }
261 /* Get message header */
262 header = *(unsigned long *)ptr;
263 ptr += 4;
264 }
265
266 /* split the header fields */
267 c = (header >> 24) & 0xff;
268 size = ((header & 0x7e) << 1);
269 if (size > 0)
270 size -= 4;
271 block = (header >> 7) & 0xf;
272 field = (header >> 11) & 0x1;
273 line = (header >> 12) & 0x1ff;
274 cmd = (header >> 21) & 0x7;
275 /* Validates haeder fields */
276 if (size > TM6000_URB_MSG_LEN)
277 size = TM6000_URB_MSG_LEN;
278 pktsize = TM6000_URB_MSG_LEN;
279 /*
280 * calculate position in buffer and change the buffer
281 */
282 switch (cmd) {
283 case TM6000_URB_MSG_VIDEO:
284 if (!dev->radio) {
285 if ((dev->isoc_ctl.vfield != field) &&
286 (field == 1)) {
287 /*
288 * Announces that a new buffer
289 * were filled
290 */
291 buffer_filled(dev, dma_q, vbuf);
292 dprintk(dev, V4L2_DEBUG_ISOC,
293 "new buffer filled\n");
294 get_next_buf(dma_q, &vbuf);
295 if (!vbuf)
296 return rc;
297 voutp = videobuf_to_vmalloc(&vbuf->vb);
298 if (!voutp)
299 return rc;
300 memset(voutp, 0, vbuf->vb.size);
301 }
302 linewidth = vbuf->vb.width << 1;
303 pos = ((line << 1) - field - 1) *
304 linewidth + block * TM6000_URB_MSG_LEN;
305 /* Don't allow to write out of the buffer */
306 if (pos + size > vbuf->vb.size)
307 cmd = TM6000_URB_MSG_ERR;
308 dev->isoc_ctl.vfield = field;
309 }
310 break;
311 case TM6000_URB_MSG_VBI:
312 break;
313 case TM6000_URB_MSG_AUDIO:
314 case TM6000_URB_MSG_PTS:
315 size = pktsize; /* Size is always 180 bytes */
316 break;
317 }
318 } else {
319 /* Continue the last copy */
320 cmd = dev->isoc_ctl.cmd;
321 size = dev->isoc_ctl.size;
322 pos = dev->isoc_ctl.pos;
323 pktsize = dev->isoc_ctl.pktsize;
324 field = dev->isoc_ctl.field;
325 }
326 cpysize = (endp - ptr > size) ? size : endp - ptr;
327 if (cpysize) {
328 /* copy data in different buffers */
329 switch (cmd) {
330 case TM6000_URB_MSG_VIDEO:
331 /* Fills video buffer */
332 if (vbuf)
333 memcpy(&voutp[pos], ptr, cpysize);
334 break;
335 case TM6000_URB_MSG_AUDIO: {
336 int i;
337 for (i = 0; i < cpysize; i += 2)
338 swab16s((u16 *)(ptr + i));
339
340 tm6000_call_fillbuf(dev, TM6000_AUDIO, ptr, cpysize);
341 break;
342 }
343 case TM6000_URB_MSG_VBI:
344 /* Need some code to copy vbi buffer */
345 break;
346 case TM6000_URB_MSG_PTS: {
347 /* Need some code to copy pts */
348 u32 pts;
349 pts = *(u32 *)ptr;
350 dprintk(dev, V4L2_DEBUG_ISOC, "field %d, PTS %x",
351 field, pts);
352 break;
353 }
354 }
355 }
356 if (ptr + pktsize > endp) {
357 /*
358 * End of URB packet, but cmd processing is not
359 * complete. Preserve the state for a next packet
360 */
361 dev->isoc_ctl.pos = pos + cpysize;
362 dev->isoc_ctl.size = size - cpysize;
363 dev->isoc_ctl.cmd = cmd;
364 dev->isoc_ctl.field = field;
365 dev->isoc_ctl.pktsize = pktsize - (endp - ptr);
366 ptr += endp - ptr;
367 } else {
368 dev->isoc_ctl.cmd = 0;
369 ptr += pktsize;
370 }
371 }
372 return 0;
373}
374
375/*
376 * Identify the tm5600/6000 buffer header type and properly handles
377 */
378static int copy_multiplexed(u8 *ptr, unsigned long len,
379 struct urb *urb)
380{
381 struct tm6000_dmaqueue *dma_q = urb->context;
382 struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
383 unsigned int pos = dev->isoc_ctl.pos, cpysize;
384 int rc = 1;
385 struct tm6000_buffer *buf;
386 char *outp = NULL;
387
388 get_next_buf(dma_q, &buf);
389 if (buf)
390 outp = videobuf_to_vmalloc(&buf->vb);
391
392 if (!outp)
393 return 0;
394
395 while (len > 0) {
396 cpysize = min(len, buf->vb.size-pos);
397 memcpy(&outp[pos], ptr, cpysize);
398 pos += cpysize;
399 ptr += cpysize;
400 len -= cpysize;
401 if (pos >= buf->vb.size) {
402 pos = 0;
403 /* Announces that a new buffer were filled */
404 buffer_filled(dev, dma_q, buf);
405 dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n");
406 get_next_buf(dma_q, &buf);
407 if (!buf)
408 break;
409 outp = videobuf_to_vmalloc(&(buf->vb));
410 if (!outp)
411 return rc;
412 pos = 0;
413 }
414 }
415
416 dev->isoc_ctl.pos = pos;
417 return rc;
418}
419
420static inline void print_err_status(struct tm6000_core *dev,
421 int packet, int status)
422{
423 char *errmsg = "Unknown";
424
425 switch (status) {
426 case -ENOENT:
427 errmsg = "unlinked synchronuously";
428 break;
429 case -ECONNRESET:
430 errmsg = "unlinked asynchronuously";
431 break;
432 case -ENOSR:
433 errmsg = "Buffer error (overrun)";
434 break;
435 case -EPIPE:
436 errmsg = "Stalled (device not responding)";
437 break;
438 case -EOVERFLOW:
439 errmsg = "Babble (bad cable?)";
440 break;
441 case -EPROTO:
442 errmsg = "Bit-stuff error (bad cable?)";
443 break;
444 case -EILSEQ:
445 errmsg = "CRC/Timeout (could be anything)";
446 break;
447 case -ETIME:
448 errmsg = "Device does not respond";
449 break;
450 }
451 if (packet < 0) {
452 dprintk(dev, V4L2_DEBUG_QUEUE, "URB status %d [%s].\n",
453 status, errmsg);
454 } else {
455 dprintk(dev, V4L2_DEBUG_QUEUE, "URB packet %d, status %d [%s].\n",
456 packet, status, errmsg);
457 }
458}
459
460
461/*
462 * Controls the isoc copy of each urb packet
463 */
464static inline int tm6000_isoc_copy(struct urb *urb)
465{
466 struct tm6000_dmaqueue *dma_q = urb->context;
467 struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
468 int i, len = 0, rc = 1, status;
469 char *p;
470
471 if (urb->status < 0) {
472 print_err_status(dev, -1, urb->status);
473 return 0;
474 }
475
476 for (i = 0; i < urb->number_of_packets; i++) {
477 status = urb->iso_frame_desc[i].status;
478
479 if (status < 0) {
480 print_err_status(dev, i, status);
481 continue;
482 }
483
484 len = urb->iso_frame_desc[i].actual_length;
485
486 if (len > 0) {
487 p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
488 if (!urb->iso_frame_desc[i].status) {
489 if ((dev->fourcc) == V4L2_PIX_FMT_TM6000) {
490 rc = copy_multiplexed(p, len, urb);
491 if (rc <= 0)
492 return rc;
493 } else {
494 copy_streams(p, len, urb);
495 }
496 }
497 }
498 }
499 return rc;
500}
501
502/* ------------------------------------------------------------------
503 * URB control
504 * ------------------------------------------------------------------
505 */
506
507/*
508 * IRQ callback, called by URB callback
509 */
510static void tm6000_irq_callback(struct urb *urb)
511{
512 struct tm6000_dmaqueue *dma_q = urb->context;
513 struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
514 int i;
515
516 switch (urb->status) {
517 case 0:
518 case -ETIMEDOUT:
519 break;
520
521 case -ECONNRESET:
522 case -ENOENT:
523 case -ESHUTDOWN:
524 return;
525
526 default:
527 tm6000_err("urb completion error %d.\n", urb->status);
528 break;
529 }
530
531 spin_lock(&dev->slock);
532 tm6000_isoc_copy(urb);
533 spin_unlock(&dev->slock);
534
535 /* Reset urb buffers */
536 for (i = 0; i < urb->number_of_packets; i++) {
537 urb->iso_frame_desc[i].status = 0;
538 urb->iso_frame_desc[i].actual_length = 0;
539 }
540
541 urb->status = usb_submit_urb(urb, GFP_ATOMIC);
542 if (urb->status)
543 tm6000_err("urb resubmit failed (error=%i)\n",
544 urb->status);
545}
546
547/*
548 * Stop and Deallocate URBs
549 */
550static void tm6000_uninit_isoc(struct tm6000_core *dev)
551{
552 struct urb *urb;
553 int i;
554
555 dev->isoc_ctl.buf = NULL;
556 for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
557 urb = dev->isoc_ctl.urb[i];
558 if (urb) {
559 usb_kill_urb(urb);
560 usb_unlink_urb(urb);
561 if (dev->isoc_ctl.transfer_buffer[i]) {
562 usb_free_coherent(dev->udev,
563 urb->transfer_buffer_length,
564 dev->isoc_ctl.transfer_buffer[i],
565 urb->transfer_dma);
566 }
567 usb_free_urb(urb);
568 dev->isoc_ctl.urb[i] = NULL;
569 }
570 dev->isoc_ctl.transfer_buffer[i] = NULL;
571 }
572
573 kfree(dev->isoc_ctl.urb);
574 kfree(dev->isoc_ctl.transfer_buffer);
575
576 dev->isoc_ctl.urb = NULL;
577 dev->isoc_ctl.transfer_buffer = NULL;
578 dev->isoc_ctl.num_bufs = 0;
579}
580
581/*
582 * Allocate URBs and start IRQ
583 */
584static int tm6000_prepare_isoc(struct tm6000_core *dev)
585{
586 struct tm6000_dmaqueue *dma_q = &dev->vidq;
587 int i, j, sb_size, pipe, size, max_packets, num_bufs = 8;
588 struct urb *urb;
589
590 /* De-allocates all pending stuff */
591 tm6000_uninit_isoc(dev);
592 /* Stop interrupt USB pipe */
593 tm6000_ir_int_stop(dev);
594
595 usb_set_interface(dev->udev,
596 dev->isoc_in.bInterfaceNumber,
597 dev->isoc_in.bAlternateSetting);
598
599 /* Start interrupt USB pipe */
600 tm6000_ir_int_start(dev);
601
602 pipe = usb_rcvisocpipe(dev->udev,
603 dev->isoc_in.endp->desc.bEndpointAddress &
604 USB_ENDPOINT_NUMBER_MASK);
605
606 size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
607
608 if (size > dev->isoc_in.maxsize)
609 size = dev->isoc_in.maxsize;
610
611 dev->isoc_ctl.max_pkt_size = size;
612
613 max_packets = TM6000_MAX_ISO_PACKETS;
614 sb_size = max_packets * size;
615
616 dev->isoc_ctl.num_bufs = num_bufs;
617
618 dev->isoc_ctl.urb = kmalloc(sizeof(void *)*num_bufs, GFP_KERNEL);
619 if (!dev->isoc_ctl.urb) {
620 tm6000_err("cannot alloc memory for usb buffers\n");
621 return -ENOMEM;
622 }
623
624 dev->isoc_ctl.transfer_buffer = kmalloc(sizeof(void *)*num_bufs,
625 GFP_KERNEL);
626 if (!dev->isoc_ctl.transfer_buffer) {
627 tm6000_err("cannot allocate memory for usbtransfer\n");
628 kfree(dev->isoc_ctl.urb);
629 return -ENOMEM;
630 }
631
632 dprintk(dev, V4L2_DEBUG_QUEUE, "Allocating %d x %d packets"
633 " (%d bytes) of %d bytes each to handle %u size\n",
634 max_packets, num_bufs, sb_size,
635 dev->isoc_in.maxsize, size);
636
637 /* allocate urbs and transfer buffers */
638 for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
639 urb = usb_alloc_urb(max_packets, GFP_KERNEL);
640 if (!urb) {
641 tm6000_err("cannot alloc isoc_ctl.urb %i\n", i);
642 tm6000_uninit_isoc(dev);
643 usb_free_urb(urb);
644 return -ENOMEM;
645 }
646 dev->isoc_ctl.urb[i] = urb;
647
648 dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev,
649 sb_size, GFP_KERNEL, &urb->transfer_dma);
650 if (!dev->isoc_ctl.transfer_buffer[i]) {
651 tm6000_err("unable to allocate %i bytes for transfer"
652 " buffer %i%s\n",
653 sb_size, i,
654 in_interrupt() ? " while in int" : "");
655 tm6000_uninit_isoc(dev);
656 return -ENOMEM;
657 }
658 memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
659
660 usb_fill_bulk_urb(urb, dev->udev, pipe,
661 dev->isoc_ctl.transfer_buffer[i], sb_size,
662 tm6000_irq_callback, dma_q);
663 urb->interval = dev->isoc_in.endp->desc.bInterval;
664 urb->number_of_packets = max_packets;
665 urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
666
667 for (j = 0; j < max_packets; j++) {
668 urb->iso_frame_desc[j].offset = size * j;
669 urb->iso_frame_desc[j].length = size;
670 }
671 }
672
673 return 0;
674}
675
676static int tm6000_start_thread(struct tm6000_core *dev)
677{
678 struct tm6000_dmaqueue *dma_q = &dev->vidq;
679 int i;
680
681 dma_q->frame = 0;
682 dma_q->ini_jiffies = jiffies;
683
684 init_waitqueue_head(&dma_q->wq);
685
686 /* submit urbs and enables IRQ */
687 for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
688 int rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
689 if (rc) {
690 tm6000_err("submit of urb %i failed (error=%i)\n", i,
691 rc);
692 tm6000_uninit_isoc(dev);
693 return rc;
694 }
695 }
696
697 return 0;
698}
699
700/* ------------------------------------------------------------------
701 * Videobuf operations
702 * ------------------------------------------------------------------
703 */
704
705static int
706buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
707{
708 struct tm6000_fh *fh = vq->priv_data;
709
710 *size = fh->fmt->depth * fh->width * fh->height >> 3;
711 if (0 == *count)
712 *count = TM6000_DEF_BUF;
713
714 if (*count < TM6000_MIN_BUF)
715 *count = TM6000_MIN_BUF;
716
717 while (*size * *count > vid_limit * 1024 * 1024)
718 (*count)--;
719
720 return 0;
721}
722
723static void free_buffer(struct videobuf_queue *vq, struct tm6000_buffer *buf)
724{
725 struct tm6000_fh *fh = vq->priv_data;
726 struct tm6000_core *dev = fh->dev;
727 unsigned long flags;
728
729 if (in_interrupt())
730 BUG();
731
732 /* We used to wait for the buffer to finish here, but this didn't work
733 because, as we were keeping the state as VIDEOBUF_QUEUED,
734 videobuf_queue_cancel marked it as finished for us.
735 (Also, it could wedge forever if the hardware was misconfigured.)
736
737 This should be safe; by the time we get here, the buffer isn't
738 queued anymore. If we ever start marking the buffers as
739 VIDEOBUF_ACTIVE, it won't be, though.
740 */
741 spin_lock_irqsave(&dev->slock, flags);
742 if (dev->isoc_ctl.buf == buf)
743 dev->isoc_ctl.buf = NULL;
744 spin_unlock_irqrestore(&dev->slock, flags);
745
746 videobuf_vmalloc_free(&buf->vb);
747 buf->vb.state = VIDEOBUF_NEEDS_INIT;
748}
749
750static int
751buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
752 enum v4l2_field field)
753{
754 struct tm6000_fh *fh = vq->priv_data;
755 struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb);
756 struct tm6000_core *dev = fh->dev;
757 int rc = 0;
758
759 BUG_ON(NULL == fh->fmt);
760
761
762 /* FIXME: It assumes depth=2 */
763 /* The only currently supported format is 16 bits/pixel */
764 buf->vb.size = fh->fmt->depth*fh->width*fh->height >> 3;
765 if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
766 return -EINVAL;
767
768 if (buf->fmt != fh->fmt ||
769 buf->vb.width != fh->width ||
770 buf->vb.height != fh->height ||
771 buf->vb.field != field) {
772 buf->fmt = fh->fmt;
773 buf->vb.width = fh->width;
774 buf->vb.height = fh->height;
775 buf->vb.field = field;
776 buf->vb.state = VIDEOBUF_NEEDS_INIT;
777 }
778
779 if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
780 rc = videobuf_iolock(vq, &buf->vb, NULL);
781 if (rc != 0)
782 goto fail;
783 }
784
785 if (!dev->isoc_ctl.num_bufs) {
786 rc = tm6000_prepare_isoc(dev);
787 if (rc < 0)
788 goto fail;
789
790 rc = tm6000_start_thread(dev);
791 if (rc < 0)
792 goto fail;
793
794 }
795
796 buf->vb.state = VIDEOBUF_PREPARED;
797 return 0;
798
799fail:
800 free_buffer(vq, buf);
801 return rc;
802}
803
804static void
805buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
806{
807 struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb);
808 struct tm6000_fh *fh = vq->priv_data;
809 struct tm6000_core *dev = fh->dev;
810 struct tm6000_dmaqueue *vidq = &dev->vidq;
811
812 buf->vb.state = VIDEOBUF_QUEUED;
813 list_add_tail(&buf->vb.queue, &vidq->active);
814}
815
816static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb)
817{
818 struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb);
819
820 free_buffer(vq, buf);
821}
822
823static struct videobuf_queue_ops tm6000_video_qops = {
824 .buf_setup = buffer_setup,
825 .buf_prepare = buffer_prepare,
826 .buf_queue = buffer_queue,
827 .buf_release = buffer_release,
828};
829
830/* ------------------------------------------------------------------
831 * IOCTL handling
832 * ------------------------------------------------------------------
833 */
834
835static bool is_res_read(struct tm6000_core *dev, struct tm6000_fh *fh)
836{
837 /* Is the current fh handling it? if so, that's OK */
838 if (dev->resources == fh && dev->is_res_read)
839 return true;
840
841 return false;
842}
843
844static bool is_res_streaming(struct tm6000_core *dev, struct tm6000_fh *fh)
845{
846 /* Is the current fh handling it? if so, that's OK */
847 if (dev->resources == fh)
848 return true;
849
850 return false;
851}
852
853static bool res_get(struct tm6000_core *dev, struct tm6000_fh *fh,
854 bool is_res_read)
855{
856 /* Is the current fh handling it? if so, that's OK */
857 if (dev->resources == fh && dev->is_res_read == is_res_read)
858 return true;
859
860 /* is it free? */
861 if (dev->resources)
862 return false;
863
864 /* grab it */
865 dev->resources = fh;
866 dev->is_res_read = is_res_read;
867 dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: get\n");
868 return true;
869}
870
871static void res_free(struct tm6000_core *dev, struct tm6000_fh *fh)
872{
873 /* Is the current fh handling it? if so, that's OK */
874 if (dev->resources != fh)
875 return;
876
877 dev->resources = NULL;
878 dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: put\n");
879}
880
881/* ------------------------------------------------------------------
882 * IOCTL vidioc handling
883 * ------------------------------------------------------------------
884 */
885static int vidioc_querycap(struct file *file, void *priv,
886 struct v4l2_capability *cap)
887{
888 struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;
889
890 strlcpy(cap->driver, "tm6000", sizeof(cap->driver));
891 strlcpy(cap->card, "Trident TVMaster TM5600/6000/6010", sizeof(cap->card));
892 cap->version = TM6000_VERSION;
893 cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
894 V4L2_CAP_STREAMING |
895 V4L2_CAP_AUDIO |
896 V4L2_CAP_READWRITE;
897
898 if (dev->tuner_type != TUNER_ABSENT)
899 cap->capabilities |= V4L2_CAP_TUNER;
900
901 return 0;
902}
903
904static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
905 struct v4l2_fmtdesc *f)
906{
907 if (unlikely(f->index >= ARRAY_SIZE(format)))
908 return -EINVAL;
909
910 strlcpy(f->description, format[f->index].name, sizeof(f->description));
911 f->pixelformat = format[f->index].fourcc;
912 return 0;
913}
914
915static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
916 struct v4l2_format *f)
917{
918 struct tm6000_fh *fh = priv;
919
920 f->fmt.pix.width = fh->width;
921 f->fmt.pix.height = fh->height;
922 f->fmt.pix.field = fh->vb_vidq.field;
923 f->fmt.pix.pixelformat = fh->fmt->fourcc;
924 f->fmt.pix.bytesperline =
925 (f->fmt.pix.width * fh->fmt->depth) >> 3;
926 f->fmt.pix.sizeimage =
927 f->fmt.pix.height * f->fmt.pix.bytesperline;
928
929 return 0;
930}
931
932static struct tm6000_fmt *format_by_fourcc(unsigned int fourcc)
933{
934 unsigned int i;
935
936 for (i = 0; i < ARRAY_SIZE(format); i++)
937 if (format[i].fourcc == fourcc)
938 return format+i;
939 return NULL;
940}
941
942static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
943 struct v4l2_format *f)
944{
945 struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;
946 struct tm6000_fmt *fmt;
947 enum v4l2_field field;
948
949 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
950 if (NULL == fmt) {
951 dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Fourcc format (0x%08x)"
952 " invalid.\n", f->fmt.pix.pixelformat);
953 return -EINVAL;
954 }
955
956 field = f->fmt.pix.field;
957
958 if (field == V4L2_FIELD_ANY)
959 field = V4L2_FIELD_SEQ_TB;
960 else if (V4L2_FIELD_INTERLACED != field) {
961 dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Field type invalid.\n");
962 return -EINVAL;
963 }
964
965 tm6000_get_std_res(dev);
966
967 f->fmt.pix.width = dev->width;
968 f->fmt.pix.height = dev->height;
969
970 f->fmt.pix.width &= ~0x01;
971
972 f->fmt.pix.field = field;
973
974 f->fmt.pix.bytesperline =
975 (f->fmt.pix.width * fmt->depth) >> 3;
976 f->fmt.pix.sizeimage =
977 f->fmt.pix.height * f->fmt.pix.bytesperline;
978
979 return 0;
980}
981
982/*FIXME: This seems to be generic enough to be at videodev2 */
983static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
984 struct v4l2_format *f)
985{
986 struct tm6000_fh *fh = priv;
987 struct tm6000_core *dev = fh->dev;
988 int ret = vidioc_try_fmt_vid_cap(file, fh, f);
989 if (ret < 0)
990 return ret;
991
992 fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
993 fh->width = f->fmt.pix.width;
994 fh->height = f->fmt.pix.height;
995 fh->vb_vidq.field = f->fmt.pix.field;
996 fh->type = f->type;
997
998 dev->fourcc = f->fmt.pix.pixelformat;
999
1000 tm6000_set_fourcc_format(dev);
1001
1002 return 0;
1003}
1004
1005static int vidioc_reqbufs(struct file *file, void *priv,
1006 struct v4l2_requestbuffers *p)
1007{
1008 struct tm6000_fh *fh = priv;
1009
1010 return videobuf_reqbufs(&fh->vb_vidq, p);
1011}
1012
1013static int vidioc_querybuf(struct file *file, void *priv,
1014 struct v4l2_buffer *p)
1015{
1016 struct tm6000_fh *fh = priv;
1017
1018 return videobuf_querybuf(&fh->vb_vidq, p);
1019}
1020
1021static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
1022{
1023 struct tm6000_fh *fh = priv;
1024
1025 return videobuf_qbuf(&fh->vb_vidq, p);
1026}
1027
1028static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
1029{
1030 struct tm6000_fh *fh = priv;
1031
1032 return videobuf_dqbuf(&fh->vb_vidq, p,
1033 file->f_flags & O_NONBLOCK);
1034}
1035
1036static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
1037{
1038 struct tm6000_fh *fh = priv;
1039 struct tm6000_core *dev = fh->dev;
1040
1041 if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1042 return -EINVAL;
1043 if (i != fh->type)
1044 return -EINVAL;
1045
1046 if (!res_get(dev, fh, false))
1047 return -EBUSY;
1048 return videobuf_streamon(&fh->vb_vidq);
1049}
1050
1051static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
1052{
1053 struct tm6000_fh *fh = priv;
1054 struct tm6000_core *dev = fh->dev;
1055
1056 if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1057 return -EINVAL;
1058
1059 if (i != fh->type)
1060 return -EINVAL;
1061
1062 videobuf_streamoff(&fh->vb_vidq);
1063 res_free(dev, fh);
1064
1065 return 0;
1066}
1067
1068static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
1069{
1070 int rc = 0;
1071 struct tm6000_fh *fh = priv;
1072 struct tm6000_core *dev = fh->dev;
1073
1074 dev->norm = *norm;
1075 rc = tm6000_init_analog_mode(dev);
1076
1077 fh->width = dev->width;
1078 fh->height = dev->height;
1079
1080 if (rc < 0)
1081 return rc;
1082
1083 v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
1084
1085 return 0;
1086}
1087
1088static const char *iname[] = {
1089 [TM6000_INPUT_TV] = "Television",
1090 [TM6000_INPUT_COMPOSITE1] = "Composite 1",
1091 [TM6000_INPUT_COMPOSITE2] = "Composite 2",
1092 [TM6000_INPUT_SVIDEO] = "S-Video",
1093};
1094
1095static int vidioc_enum_input(struct file *file, void *priv,
1096 struct v4l2_input *i)
1097{
1098 struct tm6000_fh *fh = priv;
1099 struct tm6000_core *dev = fh->dev;
1100 unsigned int n;
1101
1102 n = i->index;
1103 if (n >= 3)
1104 return -EINVAL;
1105
1106 if (!dev->vinput[n].type)
1107 return -EINVAL;
1108
1109 i->index = n;
1110
1111 if (dev->vinput[n].type == TM6000_INPUT_TV)
1112 i->type = V4L2_INPUT_TYPE_TUNER;
1113 else
1114 i->type = V4L2_INPUT_TYPE_CAMERA;
1115
1116 strcpy(i->name, iname[dev->vinput[n].type]);
1117
1118 i->std = TM6000_STD;
1119
1120 return 0;
1121}
1122
1123static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
1124{
1125 struct tm6000_fh *fh = priv;
1126 struct tm6000_core *dev = fh->dev;
1127
1128 *i = dev->input;
1129
1130 return 0;
1131}
1132
1133static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
1134{
1135 struct tm6000_fh *fh = priv;
1136 struct tm6000_core *dev = fh->dev;
1137 int rc = 0;
1138
1139 if (i >= 3)
1140 return -EINVAL;
1141 if (!dev->vinput[i].type)
1142 return -EINVAL;
1143
1144 dev->input = i;
1145
1146 rc = vidioc_s_std(file, priv, &dev->vfd->current_norm);
1147
1148 return rc;
1149}
1150
1151/* --- controls ---------------------------------------------- */
1152static int vidioc_queryctrl(struct file *file, void *priv,
1153 struct v4l2_queryctrl *qc)
1154{
1155 int i;
1156
1157 for (i = 0; i < ARRAY_SIZE(tm6000_qctrl); i++)
1158 if (qc->id && qc->id == tm6000_qctrl[i].id) {
1159 memcpy(qc, &(tm6000_qctrl[i]),
1160 sizeof(*qc));
1161 return 0;
1162 }
1163
1164 return -EINVAL;
1165}
1166
1167static int vidioc_g_ctrl(struct file *file, void *priv,
1168 struct v4l2_control *ctrl)
1169{
1170 struct tm6000_fh *fh = priv;
1171 struct tm6000_core *dev = fh->dev;
1172 int val;
1173
1174 /* FIXME: Probably, those won't work! Maybe we need shadow regs */
1175 switch (ctrl->id) {
1176 case V4L2_CID_CONTRAST:
1177 val = tm6000_get_reg(dev, TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0);
1178 break;
1179 case V4L2_CID_BRIGHTNESS:
1180 val = tm6000_get_reg(dev, TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0);
1181 return 0;
1182 case V4L2_CID_SATURATION:
1183 val = tm6000_get_reg(dev, TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0);
1184 return 0;
1185 case V4L2_CID_HUE:
1186 val = tm6000_get_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, 0);
1187 return 0;
1188 case V4L2_CID_AUDIO_MUTE:
1189 val = dev->ctl_mute;
1190 return 0;
1191 case V4L2_CID_AUDIO_VOLUME:
1192 val = dev->ctl_volume;
1193 return 0;
1194 default:
1195 return -EINVAL;
1196 }
1197
1198 if (val < 0)
1199 return val;
1200
1201 ctrl->value = val;
1202
1203 return 0;
1204}
1205static int vidioc_s_ctrl(struct file *file, void *priv,
1206 struct v4l2_control *ctrl)
1207{
1208 struct tm6000_fh *fh = priv;
1209 struct tm6000_core *dev = fh->dev;
1210 u8 val = ctrl->value;
1211
1212 switch (ctrl->id) {
1213 case V4L2_CID_CONTRAST:
1214 tm6000_set_reg(dev, TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, val);
1215 return 0;
1216 case V4L2_CID_BRIGHTNESS:
1217 tm6000_set_reg(dev, TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, val);
1218 return 0;
1219 case V4L2_CID_SATURATION:
1220 tm6000_set_reg(dev, TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, val);
1221 return 0;
1222 case V4L2_CID_HUE:
1223 tm6000_set_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, val);
1224 return 0;
1225 case V4L2_CID_AUDIO_MUTE:
1226 dev->ctl_mute = val;
1227 tm6000_tvaudio_set_mute(dev, val);
1228 return 0;
1229 case V4L2_CID_AUDIO_VOLUME:
1230 dev->ctl_volume = val;
1231 tm6000_set_volume(dev, val);
1232 return 0;
1233 }
1234 return -EINVAL;
1235}
1236
1237static int vidioc_g_tuner(struct file *file, void *priv,
1238 struct v4l2_tuner *t)
1239{
1240 struct tm6000_fh *fh = priv;
1241 struct tm6000_core *dev = fh->dev;
1242
1243 if (unlikely(UNSET == dev->tuner_type))
1244 return -EINVAL;
1245 if (0 != t->index)
1246 return -EINVAL;
1247
1248 strcpy(t->name, "Television");
1249 t->type = V4L2_TUNER_ANALOG_TV;
1250 t->capability = V4L2_TUNER_CAP_NORM;
1251 t->rangehigh = 0xffffffffUL;
1252 t->rxsubchans = V4L2_TUNER_SUB_STEREO;
1253
1254 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
1255
1256 t->audmode = dev->amode;
1257
1258 return 0;
1259}
1260
1261static int vidioc_s_tuner(struct file *file, void *priv,
1262 struct v4l2_tuner *t)
1263{
1264 struct tm6000_fh *fh = priv;
1265 struct tm6000_core *dev = fh->dev;
1266
1267 if (UNSET == dev->tuner_type)
1268 return -EINVAL;
1269 if (0 != t->index)
1270 return -EINVAL;
1271
1272 dev->amode = t->audmode;
1273 dprintk(dev, 3, "audio mode: %x\n", t->audmode);
1274
1275 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
1276
1277 return 0;
1278}
1279
1280static int vidioc_g_frequency(struct file *file, void *priv,
1281 struct v4l2_frequency *f)
1282{
1283 struct tm6000_fh *fh = priv;
1284 struct tm6000_core *dev = fh->dev;
1285
1286 if (unlikely(UNSET == dev->tuner_type))
1287 return -EINVAL;
1288
1289 f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
1290 f->frequency = dev->freq;
1291
1292 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, f);
1293
1294 return 0;
1295}
1296
1297static int vidioc_s_frequency(struct file *file, void *priv,
1298 struct v4l2_frequency *f)
1299{
1300 struct tm6000_fh *fh = priv;
1301 struct tm6000_core *dev = fh->dev;
1302
1303 if (unlikely(UNSET == dev->tuner_type))
1304 return -EINVAL;
1305 if (unlikely(f->tuner != 0))
1306 return -EINVAL;
1307 if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type)
1308 return -EINVAL;
1309 if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
1310 return -EINVAL;
1311
1312 dev->freq = f->frequency;
1313 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f);
1314
1315 return 0;
1316}
1317
1318static int radio_querycap(struct file *file, void *priv,
1319 struct v4l2_capability *cap)
1320{
1321 struct tm6000_fh *fh = file->private_data;
1322 struct tm6000_core *dev = fh->dev;
1323
1324 strcpy(cap->driver, "tm6000");
1325 strlcpy(cap->card, dev->name, sizeof(dev->name));
1326 sprintf(cap->bus_info, "USB%04x:%04x",
1327 le16_to_cpu(dev->udev->descriptor.idVendor),
1328 le16_to_cpu(dev->udev->descriptor.idProduct));
1329 cap->version = dev->dev_type;
1330 cap->capabilities = V4L2_CAP_TUNER |
1331 V4L2_CAP_AUDIO |
1332 V4L2_CAP_RADIO |
1333 V4L2_CAP_READWRITE |
1334 V4L2_CAP_STREAMING;
1335
1336 return 0;
1337}
1338
1339static int radio_g_tuner(struct file *file, void *priv,
1340 struct v4l2_tuner *t)
1341{
1342 struct tm6000_fh *fh = file->private_data;
1343 struct tm6000_core *dev = fh->dev;
1344
1345 if (0 != t->index)
1346 return -EINVAL;
1347
1348 memset(t, 0, sizeof(*t));
1349 strcpy(t->name, "Radio");
1350 t->type = V4L2_TUNER_RADIO;
1351 t->rxsubchans = V4L2_TUNER_SUB_STEREO;
1352
1353 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
1354
1355 return 0;
1356}
1357
1358static int radio_s_tuner(struct file *file, void *priv,
1359 struct v4l2_tuner *t)
1360{
1361 struct tm6000_fh *fh = file->private_data;
1362 struct tm6000_core *dev = fh->dev;
1363
1364 if (0 != t->index)
1365 return -EINVAL;
1366
1367 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
1368
1369 return 0;
1370}
1371
1372static int radio_enum_input(struct file *file, void *priv,
1373 struct v4l2_input *i)
1374{
1375 struct tm6000_fh *fh = priv;
1376 struct tm6000_core *dev = fh->dev;
1377
1378 if (i->index != 0)
1379 return -EINVAL;
1380
1381 if (!dev->rinput.type)
1382 return -EINVAL;
1383
1384 strcpy(i->name, "Radio");
1385 i->type = V4L2_INPUT_TYPE_TUNER;
1386
1387 return 0;
1388}
1389
1390static int radio_g_input(struct file *filp, void *priv, unsigned int *i)
1391{
1392 struct tm6000_fh *fh = priv;
1393 struct tm6000_core *dev = fh->dev;
1394
1395 if (dev->input != 5)
1396 return -EINVAL;
1397
1398 *i = dev->input - 5;
1399
1400 return 0;
1401}
1402
1403static int radio_g_audio(struct file *file, void *priv,
1404 struct v4l2_audio *a)
1405{
1406 memset(a, 0, sizeof(*a));
1407 strcpy(a->name, "Radio");
1408 return 0;
1409}
1410
1411static int radio_s_audio(struct file *file, void *priv,
1412 struct v4l2_audio *a)
1413{
1414 return 0;
1415}
1416
1417static int radio_s_input(struct file *filp, void *priv, unsigned int i)
1418{
1419 struct tm6000_fh *fh = priv;
1420 struct tm6000_core *dev = fh->dev;
1421
1422 if (i)
1423 return -EINVAL;
1424
1425 if (!dev->rinput.type)
1426 return -EINVAL;
1427
1428 dev->input = i + 5;
1429
1430 return 0;
1431}
1432
1433static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm)
1434{
1435 return 0;
1436}
1437
1438static int radio_queryctrl(struct file *file, void *priv,
1439 struct v4l2_queryctrl *c)
1440{
1441 const struct v4l2_queryctrl *ctrl;
1442
1443 if (c->id < V4L2_CID_BASE ||
1444 c->id >= V4L2_CID_LASTP1)
1445 return -EINVAL;
1446 if (c->id == V4L2_CID_AUDIO_MUTE) {
1447 ctrl = ctrl_by_id(c->id);
1448 *c = *ctrl;
1449 } else
1450 *c = no_ctrl;
1451
1452 return 0;
1453}
1454
1455/* ------------------------------------------------------------------
1456 File operations for the device
1457 ------------------------------------------------------------------*/
1458
1459static int tm6000_open(struct file *file)
1460{
1461 struct video_device *vdev = video_devdata(file);
1462 struct tm6000_core *dev = video_drvdata(file);
1463 struct tm6000_fh *fh;
1464 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1465 int i, rc;
1466 int radio = 0;
1467
1468 dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: open called (dev=%s)\n",
1469 video_device_node_name(vdev));
1470
1471 switch (vdev->vfl_type) {
1472 case VFL_TYPE_GRABBER:
1473 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1474 break;
1475 case VFL_TYPE_VBI:
1476 type = V4L2_BUF_TYPE_VBI_CAPTURE;
1477 break;
1478 case VFL_TYPE_RADIO:
1479 radio = 1;
1480 break;
1481 }
1482
1483 /* If more than one user, mutex should be added */
1484 dev->users++;
1485
1486 dprintk(dev, V4L2_DEBUG_OPEN, "open dev=%s type=%s users=%d\n",
1487 video_device_node_name(vdev), v4l2_type_names[type],
1488 dev->users);
1489
1490 /* allocate + initialize per filehandle data */
1491 fh = kzalloc(sizeof(*fh), GFP_KERNEL);
1492 if (NULL == fh) {
1493 dev->users--;
1494 return -ENOMEM;
1495 }
1496
1497 file->private_data = fh;
1498 fh->dev = dev;
1499 fh->radio = radio;
1500 dev->radio = radio;
1501 fh->type = type;
1502 dev->fourcc = format[0].fourcc;
1503
1504 fh->fmt = format_by_fourcc(dev->fourcc);
1505
1506 tm6000_get_std_res(dev);
1507
1508 fh->width = dev->width;
1509 fh->height = dev->height;
1510
1511 dprintk(dev, V4L2_DEBUG_OPEN, "Open: fh=0x%08lx, dev=0x%08lx, "
1512 "dev->vidq=0x%08lx\n",
1513 (unsigned long)fh, (unsigned long)dev,
1514 (unsigned long)&dev->vidq);
1515 dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty "
1516 "queued=%d\n", list_empty(&dev->vidq.queued));
1517 dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty "
1518 "active=%d\n", list_empty(&dev->vidq.active));
1519
1520 /* initialize hardware on analog mode */
1521 rc = tm6000_init_analog_mode(dev);
1522 if (rc < 0)
1523 return rc;
1524
1525 if (dev->mode != TM6000_MODE_ANALOG) {
1526 /* Put all controls at a sane state */
1527 for (i = 0; i < ARRAY_SIZE(tm6000_qctrl); i++)
1528 qctl_regs[i] = tm6000_qctrl[i].default_value;
1529
1530 dev->mode = TM6000_MODE_ANALOG;
1531 }
1532
1533 if (!fh->radio) {
1534 videobuf_queue_vmalloc_init(&fh->vb_vidq, &tm6000_video_qops,
1535 NULL, &dev->slock,
1536 fh->type,
1537 V4L2_FIELD_INTERLACED,
1538 sizeof(struct tm6000_buffer), fh, &dev->lock);
1539 } else {
1540 dprintk(dev, V4L2_DEBUG_OPEN, "video_open: setting radio device\n");
1541 dev->input = 5;
1542 tm6000_set_audio_rinput(dev);
1543 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio);
1544 tm6000_prepare_isoc(dev);
1545 tm6000_start_thread(dev);
1546 }
1547
1548 return 0;
1549}
1550
1551static ssize_t
1552tm6000_read(struct file *file, char __user *data, size_t count, loff_t *pos)
1553{
1554 struct tm6000_fh *fh = file->private_data;
1555
1556 if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
1557 if (!res_get(fh->dev, fh, true))
1558 return -EBUSY;
1559
1560 return videobuf_read_stream(&fh->vb_vidq, data, count, pos, 0,
1561 file->f_flags & O_NONBLOCK);
1562 }
1563 return 0;
1564}
1565
1566static unsigned int
1567tm6000_poll(struct file *file, struct poll_table_struct *wait)
1568{
1569 struct tm6000_fh *fh = file->private_data;
1570 struct tm6000_buffer *buf;
1571
1572 if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
1573 return POLLERR;
1574
1575 if (!!is_res_streaming(fh->dev, fh))
1576 return POLLERR;
1577
1578 if (!is_res_read(fh->dev, fh)) {
1579 /* streaming capture */
1580 if (list_empty(&fh->vb_vidq.stream))
1581 return POLLERR;
1582 buf = list_entry(fh->vb_vidq.stream.next, struct tm6000_buffer, vb.stream);
1583 } else {
1584 /* read() capture */
1585 return videobuf_poll_stream(file, &fh->vb_vidq, wait);
1586 }
1587 poll_wait(file, &buf->vb.done, wait);
1588 if (buf->vb.state == VIDEOBUF_DONE ||
1589 buf->vb.state == VIDEOBUF_ERROR)
1590 return POLLIN | POLLRDNORM;
1591 return 0;
1592}
1593
1594static int tm6000_release(struct file *file)
1595{
1596 struct tm6000_fh *fh = file->private_data;
1597 struct tm6000_core *dev = fh->dev;
1598 struct video_device *vdev = video_devdata(file);
1599
1600 dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: close called (dev=%s, users=%d)\n",
1601 video_device_node_name(vdev), dev->users);
1602
1603 dev->users--;
1604
1605 res_free(dev, fh);
1606
1607 if (!dev->users) {
1608 int err;
1609
1610 tm6000_uninit_isoc(dev);
1611
1612 if (!fh->radio)
1613 videobuf_mmap_free(&fh->vb_vidq);
1614
1615 err = tm6000_reset(dev);
1616 if (err < 0)
1617 dev_err(&vdev->dev, "reset failed: %d\n", err);
1618 }
1619
1620 kfree(fh);
1621
1622 return 0;
1623}
1624
1625static int tm6000_mmap(struct file *file, struct vm_area_struct * vma)
1626{
1627 struct tm6000_fh *fh = file->private_data;
1628
1629 return videobuf_mmap_mapper(&fh->vb_vidq, vma);
1630}
1631
1632static struct v4l2_file_operations tm6000_fops = {
1633 .owner = THIS_MODULE,
1634 .open = tm6000_open,
1635 .release = tm6000_release,
1636 .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
1637 .read = tm6000_read,
1638 .poll = tm6000_poll,
1639 .mmap = tm6000_mmap,
1640};
1641
1642static const struct v4l2_ioctl_ops video_ioctl_ops = {
1643 .vidioc_querycap = vidioc_querycap,
1644 .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
1645 .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
1646 .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
1647 .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
1648 .vidioc_s_std = vidioc_s_std,
1649 .vidioc_enum_input = vidioc_enum_input,
1650 .vidioc_g_input = vidioc_g_input,
1651 .vidioc_s_input = vidioc_s_input,
1652 .vidioc_queryctrl = vidioc_queryctrl,
1653 .vidioc_g_ctrl = vidioc_g_ctrl,
1654 .vidioc_s_ctrl = vidioc_s_ctrl,
1655 .vidioc_g_tuner = vidioc_g_tuner,
1656 .vidioc_s_tuner = vidioc_s_tuner,
1657 .vidioc_g_frequency = vidioc_g_frequency,
1658 .vidioc_s_frequency = vidioc_s_frequency,
1659 .vidioc_streamon = vidioc_streamon,
1660 .vidioc_streamoff = vidioc_streamoff,
1661 .vidioc_reqbufs = vidioc_reqbufs,
1662 .vidioc_querybuf = vidioc_querybuf,
1663 .vidioc_qbuf = vidioc_qbuf,
1664 .vidioc_dqbuf = vidioc_dqbuf,
1665};
1666
1667static struct video_device tm6000_template = {
1668 .name = "tm6000",
1669 .fops = &tm6000_fops,
1670 .ioctl_ops = &video_ioctl_ops,
1671 .release = video_device_release,
1672 .tvnorms = TM6000_STD,
1673 .current_norm = V4L2_STD_NTSC_M,
1674};
1675
1676static const struct v4l2_file_operations radio_fops = {
1677 .owner = THIS_MODULE,
1678 .open = tm6000_open,
1679 .release = tm6000_release,
1680 .unlocked_ioctl = video_ioctl2,
1681};
1682
1683static const struct v4l2_ioctl_ops radio_ioctl_ops = {
1684 .vidioc_querycap = radio_querycap,
1685 .vidioc_g_tuner = radio_g_tuner,
1686 .vidioc_enum_input = radio_enum_input,
1687 .vidioc_g_audio = radio_g_audio,
1688 .vidioc_s_tuner = radio_s_tuner,
1689 .vidioc_s_audio = radio_s_audio,
1690 .vidioc_s_input = radio_s_input,
1691 .vidioc_s_std = radio_s_std,
1692 .vidioc_queryctrl = radio_queryctrl,
1693 .vidioc_g_input = radio_g_input,
1694 .vidioc_g_ctrl = vidioc_g_ctrl,
1695 .vidioc_s_ctrl = vidioc_s_ctrl,
1696 .vidioc_g_frequency = vidioc_g_frequency,
1697 .vidioc_s_frequency = vidioc_s_frequency,
1698};
1699
1700static struct video_device tm6000_radio_template = {
1701 .name = "tm6000",
1702 .fops = &radio_fops,
1703 .ioctl_ops = &radio_ioctl_ops,
1704};
1705
1706/* -----------------------------------------------------------------
1707 * Initialization and module stuff
1708 * ------------------------------------------------------------------
1709 */
1710
1711static struct video_device *vdev_init(struct tm6000_core *dev,
1712 const struct video_device
1713 *template, const char *type_name)
1714{
1715 struct video_device *vfd;
1716
1717 vfd = video_device_alloc();
1718 if (NULL == vfd)
1719 return NULL;
1720
1721 *vfd = *template;
1722 vfd->v4l2_dev = &dev->v4l2_dev;
1723 vfd->release = video_device_release;
1724 vfd->debug = tm6000_debug;
1725 vfd->lock = &dev->lock;
1726
1727 snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
1728
1729 video_set_drvdata(vfd, dev);
1730 return vfd;
1731}
1732
1733int tm6000_v4l2_register(struct tm6000_core *dev)
1734{
1735 int ret = -1;
1736
1737 dev->vfd = vdev_init(dev, &tm6000_template, "video");
1738
1739 if (!dev->vfd) {
1740 printk(KERN_INFO "%s: can't register video device\n",
1741 dev->name);
1742 return -ENOMEM;
1743 }
1744
1745 /* init video dma queues */
1746 INIT_LIST_HEAD(&dev->vidq.active);
1747 INIT_LIST_HEAD(&dev->vidq.queued);
1748
1749 ret = video_register_device(dev->vfd, VFL_TYPE_GRABBER, video_nr);
1750
1751 if (ret < 0) {
1752 printk(KERN_INFO "%s: can't register video device\n",
1753 dev->name);
1754 return ret;
1755 }
1756
1757 printk(KERN_INFO "%s: registered device %s\n",
1758 dev->name, video_device_node_name(dev->vfd));
1759
1760 if (dev->caps.has_radio) {
1761 dev->radio_dev = vdev_init(dev, &tm6000_radio_template,
1762 "radio");
1763 if (!dev->radio_dev) {
1764 printk(KERN_INFO "%s: can't register radio device\n",
1765 dev->name);
1766 return ret; /* FIXME release resource */
1767 }
1768
1769 ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
1770 radio_nr);
1771 if (ret < 0) {
1772 printk(KERN_INFO "%s: can't register radio device\n",
1773 dev->name);
1774 return ret; /* FIXME release resource */
1775 }
1776
1777 printk(KERN_INFO "%s: registered device %s\n",
1778 dev->name, video_device_node_name(dev->radio_dev));
1779 }
1780
1781 printk(KERN_INFO "Trident TVMaster TM5600/TM6000/TM6010 USB2 board (Load status: %d)\n", ret);
1782 return ret;
1783}
1784
1785int tm6000_v4l2_unregister(struct tm6000_core *dev)
1786{
1787 video_unregister_device(dev->vfd);
1788
1789 if (dev->radio_dev) {
1790 if (video_is_registered(dev->radio_dev))
1791 video_unregister_device(dev->radio_dev);
1792 else
1793 video_device_release(dev->radio_dev);
1794 dev->radio_dev = NULL;
1795 }
1796
1797 return 0;
1798}
1799
1800int tm6000_v4l2_exit(void)
1801{
1802 return 0;
1803}
1804
1805module_param(video_nr, int, 0);
1806MODULE_PARM_DESC(video_nr, "Allow changing video device number");
1807
1808module_param_named(debug, tm6000_debug, int, 0444);
1809MODULE_PARM_DESC(debug, "activates debug info");
1810
1811module_param(vid_limit, int, 0644);
1812MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
1813
diff --git a/drivers/media/video/tm6000/tm6000.h b/drivers/media/video/tm6000/tm6000.h
new file mode 100644
index 00000000000..2777e514eff
--- /dev/null
+++ b/drivers/media/video/tm6000/tm6000.h
@@ -0,0 +1,398 @@
1/*
2 * tm6000.h - driver for TM5600/TM6000/TM6010 USB video capture devices
3 *
4 * Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
5 *
6 * Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
7 * - DVB-T support
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation version 2
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23#include <linux/videodev2.h>
24#include <media/v4l2-common.h>
25#include <media/videobuf-vmalloc.h>
26#include "tm6000-usb-isoc.h"
27#include <linux/i2c.h>
28#include <linux/mutex.h>
29#include <media/v4l2-device.h>
30
31#include <linux/dvb/frontend.h>
32#include "dvb_demux.h"
33#include "dvb_frontend.h"
34#include "dmxdev.h"
35
36#define TM6000_VERSION KERNEL_VERSION(0, 0, 2)
37
38/* Inputs */
39enum tm6000_itype {
40 TM6000_INPUT_TV = 1,
41 TM6000_INPUT_COMPOSITE1,
42 TM6000_INPUT_COMPOSITE2,
43 TM6000_INPUT_SVIDEO,
44 TM6000_INPUT_DVB,
45 TM6000_INPUT_RADIO,
46};
47
48enum tm6000_mux {
49 TM6000_VMUX_VIDEO_A = 1,
50 TM6000_VMUX_VIDEO_B,
51 TM6000_VMUX_VIDEO_AB,
52 TM6000_AMUX_ADC1,
53 TM6000_AMUX_ADC2,
54 TM6000_AMUX_SIF1,
55 TM6000_AMUX_SIF2,
56 TM6000_AMUX_I2S,
57};
58
59enum tm6000_devtype {
60 TM6000 = 0,
61 TM5600,
62 TM6010,
63};
64
65struct tm6000_input {
66 enum tm6000_itype type;
67 enum tm6000_mux vmux;
68 enum tm6000_mux amux;
69 unsigned int v_gpio;
70 unsigned int a_gpio;
71};
72
73/* ------------------------------------------------------------------
74 * Basic structures
75 * ------------------------------------------------------------------
76 */
77
78struct tm6000_fmt {
79 char *name;
80 u32 fourcc; /* v4l2 format id */
81 int depth;
82};
83
84/* buffer for one video frame */
85struct tm6000_buffer {
86 /* common v4l buffer stuff -- must be first */
87 struct videobuf_buffer vb;
88
89 struct tm6000_fmt *fmt;
90};
91
92struct tm6000_dmaqueue {
93 struct list_head active;
94 struct list_head queued;
95
96 /* thread for generating video stream*/
97 struct task_struct *kthread;
98 wait_queue_head_t wq;
99 /* Counters to control fps rate */
100 int frame;
101 int ini_jiffies;
102};
103
104/* device states */
105enum tm6000_core_state {
106 DEV_INITIALIZED = 0x01,
107 DEV_DISCONNECTED = 0x02,
108 DEV_MISCONFIGURED = 0x04,
109};
110
111/* io methods */
112enum tm6000_io_method {
113 IO_NONE,
114 IO_READ,
115 IO_MMAP,
116};
117
118enum tm6000_mode {
119 TM6000_MODE_UNKNOWN = 0,
120 TM6000_MODE_ANALOG,
121 TM6000_MODE_DIGITAL,
122};
123
124struct tm6000_gpio {
125 int tuner_reset;
126 int tuner_on;
127 int demod_reset;
128 int demod_on;
129 int power_led;
130 int dvb_led;
131 int ir;
132};
133
134struct tm6000_capabilities {
135 unsigned int has_tuner:1;
136 unsigned int has_tda9874:1;
137 unsigned int has_dvb:1;
138 unsigned int has_zl10353:1;
139 unsigned int has_eeprom:1;
140 unsigned int has_remote:1;
141 unsigned int has_radio:1;
142};
143
144struct tm6000_dvb {
145 struct dvb_adapter adapter;
146 struct dvb_demux demux;
147 struct dvb_frontend *frontend;
148 struct dmxdev dmxdev;
149 unsigned int streams;
150 struct urb *bulk_urb;
151 struct mutex mutex;
152};
153
154struct snd_tm6000_card {
155 struct snd_card *card;
156 spinlock_t reg_lock;
157 struct tm6000_core *core;
158 struct snd_pcm_substream *substream;
159
160 /* temporary data for buffer fill processing */
161 unsigned buf_pos;
162 unsigned period_pos;
163};
164
165struct tm6000_endpoint {
166 struct usb_host_endpoint *endp;
167 __u8 bInterfaceNumber;
168 __u8 bAlternateSetting;
169 unsigned maxsize;
170};
171
172#define TM6000_QUIRK_NO_USB_DELAY (1 << 0)
173
174struct tm6000_core {
175 /* generic device properties */
176 char name[30]; /* name (including minor) of the device */
177 int model; /* index in the device_data struct */
178 int devno; /* marks the number of this device */
179 enum tm6000_devtype dev_type; /* type of device */
180 unsigned char eedata[256]; /* Eeprom data */
181 unsigned eedata_size; /* Size of the eeprom info */
182
183 v4l2_std_id norm; /* Current norm */
184 int width, height; /* Selected resolution */
185
186 enum tm6000_core_state state;
187
188 /* Device Capabilities*/
189 struct tm6000_capabilities caps;
190
191 /* Tuner configuration */
192 int tuner_type; /* type of the tuner */
193 int tuner_addr; /* tuner address */
194
195 struct tm6000_gpio gpio;
196
197 char *ir_codes;
198
199 __u8 radio;
200
201 /* Demodulator configuration */
202 int demod_addr; /* demodulator address */
203
204 int audio_bitrate;
205 /* i2c i/o */
206 struct i2c_adapter i2c_adap;
207 struct i2c_client i2c_client;
208
209
210 /* extension */
211 struct list_head devlist;
212
213 /* video for linux */
214 int users;
215
216 /* various device info */
217 struct tm6000_fh *resources; /* Points to fh that is streaming */
218 bool is_res_read;
219
220 struct video_device *vfd;
221 struct video_device *radio_dev;
222 struct tm6000_dmaqueue vidq;
223 struct v4l2_device v4l2_dev;
224
225 int input;
226 struct tm6000_input vinput[3]; /* video input */
227 struct tm6000_input rinput; /* radio input */
228
229 int freq;
230 unsigned int fourcc;
231
232 enum tm6000_mode mode;
233
234 int ctl_mute; /* audio */
235 int ctl_volume;
236 int amode;
237
238 /* DVB-T support */
239 struct tm6000_dvb *dvb;
240
241 /* audio support */
242 struct snd_tm6000_card *adev;
243 struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */
244 atomic_t stream_started; /* stream should be running if true */
245
246 struct tm6000_IR *ir;
247
248 /* locks */
249 struct mutex lock;
250 struct mutex usb_lock;
251
252 /* usb transfer */
253 struct usb_device *udev; /* the usb device */
254
255 struct tm6000_endpoint bulk_in, bulk_out, isoc_in, isoc_out;
256 struct tm6000_endpoint int_in, int_out;
257
258 /* scaler!=0 if scaler is active*/
259 int scaler;
260
261 /* Isoc control struct */
262 struct usb_isoc_ctl isoc_ctl;
263
264 spinlock_t slock;
265
266 unsigned long quirks;
267};
268
269enum tm6000_ops_type {
270 TM6000_AUDIO = 0x10,
271 TM6000_DVB = 0x20,
272};
273
274struct tm6000_ops {
275 struct list_head next;
276 char *name;
277 enum tm6000_ops_type type;
278 int (*init)(struct tm6000_core *);
279 int (*fini)(struct tm6000_core *);
280 int (*fillbuf)(struct tm6000_core *, char *buf, int size);
281};
282
283struct tm6000_fh {
284 struct tm6000_core *dev;
285 unsigned int radio;
286
287 /* video capture */
288 struct tm6000_fmt *fmt;
289 unsigned int width, height;
290 struct videobuf_queue vb_vidq;
291
292 enum v4l2_buf_type type;
293};
294
295#define TM6000_STD (V4L2_STD_PAL|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc| \
296 V4L2_STD_PAL_M|V4L2_STD_PAL_60|V4L2_STD_NTSC_M| \
297 V4L2_STD_NTSC_M_JP|V4L2_STD_SECAM)
298
299/* In tm6000-cards.c */
300
301int tm6000_tuner_callback(void *ptr, int component, int command, int arg);
302int tm6000_xc5000_callback(void *ptr, int component, int command, int arg);
303int tm6000_cards_setup(struct tm6000_core *dev);
304void tm6000_flash_led(struct tm6000_core *dev, u8 state);
305
306/* In tm6000-core.c */
307
308int tm6000_read_write_usb(struct tm6000_core *dev, u8 reqtype, u8 req,
309 u16 value, u16 index, u8 *buf, u16 len);
310int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index);
311int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index);
312int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index);
313int tm6000_set_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index);
314int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value,
315 u16 index, u16 mask);
316int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep);
317int tm6000_init(struct tm6000_core *dev);
318int tm6000_reset(struct tm6000_core *dev);
319
320int tm6000_init_analog_mode(struct tm6000_core *dev);
321int tm6000_init_digital_mode(struct tm6000_core *dev);
322int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate);
323int tm6000_set_audio_rinput(struct tm6000_core *dev);
324int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute);
325void tm6000_set_volume(struct tm6000_core *dev, int vol);
326
327int tm6000_v4l2_register(struct tm6000_core *dev);
328int tm6000_v4l2_unregister(struct tm6000_core *dev);
329int tm6000_v4l2_exit(void);
330void tm6000_set_fourcc_format(struct tm6000_core *dev);
331
332void tm6000_remove_from_devlist(struct tm6000_core *dev);
333void tm6000_add_into_devlist(struct tm6000_core *dev);
334int tm6000_register_extension(struct tm6000_ops *ops);
335void tm6000_unregister_extension(struct tm6000_ops *ops);
336void tm6000_init_extension(struct tm6000_core *dev);
337void tm6000_close_extension(struct tm6000_core *dev);
338int tm6000_call_fillbuf(struct tm6000_core *dev, enum tm6000_ops_type type,
339 char *buf, int size);
340
341
342/* In tm6000-stds.c */
343void tm6000_get_std_res(struct tm6000_core *dev);
344int tm6000_set_standard(struct tm6000_core *dev);
345
346/* In tm6000-i2c.c */
347int tm6000_i2c_register(struct tm6000_core *dev);
348int tm6000_i2c_unregister(struct tm6000_core *dev);
349
350/* In tm6000-queue.c */
351
352int tm6000_v4l2_mmap(struct file *filp, struct vm_area_struct *vma);
353
354int tm6000_vidioc_streamon(struct file *file, void *priv,
355 enum v4l2_buf_type i);
356int tm6000_vidioc_streamoff(struct file *file, void *priv,
357 enum v4l2_buf_type i);
358int tm6000_vidioc_reqbufs(struct file *file, void *priv,
359 struct v4l2_requestbuffers *rb);
360int tm6000_vidioc_querybuf(struct file *file, void *priv,
361 struct v4l2_buffer *b);
362int tm6000_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b);
363int tm6000_vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b);
364ssize_t tm6000_v4l2_read(struct file *filp, char __user * buf, size_t count,
365 loff_t *f_pos);
366unsigned int tm6000_v4l2_poll(struct file *file,
367 struct poll_table_struct *wait);
368int tm6000_queue_init(struct tm6000_core *dev);
369
370/* In tm6000-alsa.c */
371/*int tm6000_audio_init(struct tm6000_core *dev, int idx);*/
372
373/* In tm6000-input.c */
374int tm6000_ir_init(struct tm6000_core *dev);
375int tm6000_ir_fini(struct tm6000_core *dev);
376void tm6000_ir_wait(struct tm6000_core *dev, u8 state);
377int tm6000_ir_int_start(struct tm6000_core *dev);
378void tm6000_ir_int_stop(struct tm6000_core *dev);
379
380/* Debug stuff */
381
382extern int tm6000_debug;
383
384#define dprintk(dev, level, fmt, arg...) do {\
385 if (tm6000_debug & level) \
386 printk(KERN_INFO "(%lu) %s %s :"fmt, jiffies, \
387 dev->name, __func__ , ##arg); } while (0)
388
389#define V4L2_DEBUG_REG 0x0004
390#define V4L2_DEBUG_I2C 0x0008
391#define V4L2_DEBUG_QUEUE 0x0010
392#define V4L2_DEBUG_ISOC 0x0020
393#define V4L2_DEBUG_RES_LOCK 0x0040 /* Resource locking */
394#define V4L2_DEBUG_OPEN 0x0080 /* video open/close debug */
395
396#define tm6000_err(fmt, arg...) do {\
397 printk(KERN_ERR "tm6000 %s :"fmt, \
398 __func__ , ##arg); } while (0)