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