• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/drivers/staging/tm6000/
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	static int   ini = 0, last = 0, n = 0;
41	u8	     *data = NULL;
42
43	if (len)
44		data = kzalloc(len, GFP_KERNEL);
45
46
47	if (req_type & USB_DIR_IN)
48		pipe = usb_rcvctrlpipe(dev->udev, 0);
49	else {
50		pipe = usb_sndctrlpipe(dev->udev, 0);
51		memcpy(data, buf, len);
52	}
53
54	if (tm6000_debug & V4L2_DEBUG_I2C) {
55		if (!ini)
56			last = ini = jiffies;
57
58		printk("%06i (dev %p, pipe %08x): ", n, dev->udev, pipe);
59
60		printk("%s: %06u ms %06u ms %02x %02x %02x %02x %02x %02x %02x %02x ",
61			(req_type & USB_DIR_IN) ? " IN" : "OUT",
62			jiffies_to_msecs(jiffies-last),
63			jiffies_to_msecs(jiffies-ini),
64			req_type, req, value&0xff, value>>8, index&0xff,
65			index>>8, len&0xff, len>>8);
66		last = jiffies;
67		n++;
68
69		if (!(req_type & USB_DIR_IN)) {
70			printk(">>> ");
71			for (i = 0; i < len; i++)
72				printk(" %02x", buf[i]);
73		printk("\n");
74		}
75	}
76
77	ret = usb_control_msg(dev->udev, pipe, req, req_type, value, index,
78			      data, len, USB_TIMEOUT);
79
80	if (req_type &  USB_DIR_IN)
81		memcpy(buf, data, len);
82
83	if (tm6000_debug & V4L2_DEBUG_I2C) {
84		if (ret < 0) {
85			if (req_type &  USB_DIR_IN)
86				printk("<<< (len=%d)\n", len);
87
88			printk("%s: Error #%d\n", __FUNCTION__, ret);
89		} else if (req_type &  USB_DIR_IN) {
90			printk("<<< ");
91			for (i = 0; i < len; i++)
92				printk(" %02x", buf[i]);
93			printk("\n");
94		}
95	}
96
97	kfree(data);
98
99	msleep(5);
100
101	return ret;
102}
103
104int tm6000_set_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index)
105{
106	return
107		tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR,
108				      req, value, index, NULL, 0);
109}
110EXPORT_SYMBOL_GPL(tm6000_set_reg);
111
112int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index)
113{
114	int rc;
115	u8 buf[1];
116
117	rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
118					value, index, buf, 1);
119
120	if (rc < 0)
121		return rc;
122
123	return *buf;
124}
125EXPORT_SYMBOL_GPL(tm6000_get_reg);
126
127int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index)
128{
129	int rc;
130	u8 buf[2];
131
132	rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
133					value, index, buf, 2);
134
135	if (rc < 0)
136		return rc;
137
138	return buf[1]|buf[0]<<8;
139}
140
141int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index)
142{
143	int rc;
144	u8 buf[4];
145
146	rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
147					value, index, buf, 4);
148
149	if (rc < 0)
150		return rc;
151
152	return buf[3] | buf[2] << 8 | buf[1] << 16 | buf[0] << 24;
153}
154
155int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep)
156{
157	int rc;
158
159	rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_CLK, 0);
160	if (rc < 0)
161		return rc;
162
163	msleep(tsleep);
164
165	rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_CLK, 1);
166	msleep(tsleep);
167
168	return rc;
169}
170
171void tm6000_set_fourcc_format(struct tm6000_core *dev)
172{
173	if (dev->dev_type == TM6010) {
174		int val;
175
176		val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0) & 0xfc;
177		if (dev->fourcc == V4L2_PIX_FMT_UYVY)
178			tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val);
179		else
180			tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val | 1);
181	} else {
182		if (dev->fourcc == V4L2_PIX_FMT_UYVY)
183			tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0);
184		else
185			tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0x90);
186	}
187}
188
189int tm6000_init_analog_mode(struct tm6000_core *dev)
190{
191	if (dev->dev_type == TM6010) {
192		int val;
193
194		/* Enable video */
195		val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0);
196		val |= 0x60;
197		tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val);
198		val = tm6000_get_reg(dev,
199			TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0);
200		val &= ~0x40;
201		tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, val);
202
203		/* Init teletext */
204		tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01);
205		tm6000_set_reg(dev, TM6010_REQ07_R41_TELETEXT_VBI_CODE1, 0x27);
206		tm6000_set_reg(dev, TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55);
207		tm6000_set_reg(dev, TM6010_REQ07_R43_VBI_DATA_TYPE_LINE7, 0x66);
208		tm6000_set_reg(dev, TM6010_REQ07_R44_VBI_DATA_TYPE_LINE8, 0x66);
209		tm6000_set_reg(dev, TM6010_REQ07_R45_VBI_DATA_TYPE_LINE9, 0x66);
210		tm6000_set_reg(dev,
211			TM6010_REQ07_R46_VBI_DATA_TYPE_LINE10, 0x66);
212		tm6000_set_reg(dev,
213			TM6010_REQ07_R47_VBI_DATA_TYPE_LINE11, 0x66);
214		tm6000_set_reg(dev,
215			TM6010_REQ07_R48_VBI_DATA_TYPE_LINE12, 0x66);
216		tm6000_set_reg(dev,
217			TM6010_REQ07_R49_VBI_DATA_TYPE_LINE13, 0x66);
218		tm6000_set_reg(dev,
219			TM6010_REQ07_R4A_VBI_DATA_TYPE_LINE14, 0x66);
220		tm6000_set_reg(dev,
221			TM6010_REQ07_R4B_VBI_DATA_TYPE_LINE15, 0x66);
222		tm6000_set_reg(dev,
223			TM6010_REQ07_R4C_VBI_DATA_TYPE_LINE16, 0x66);
224		tm6000_set_reg(dev,
225			TM6010_REQ07_R4D_VBI_DATA_TYPE_LINE17, 0x66);
226		tm6000_set_reg(dev,
227			TM6010_REQ07_R4E_VBI_DATA_TYPE_LINE18, 0x66);
228		tm6000_set_reg(dev,
229			TM6010_REQ07_R4F_VBI_DATA_TYPE_LINE19, 0x66);
230		tm6000_set_reg(dev,
231			TM6010_REQ07_R50_VBI_DATA_TYPE_LINE20, 0x66);
232		tm6000_set_reg(dev,
233			TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x66);
234		tm6000_set_reg(dev,
235			TM6010_REQ07_R52_VBI_DATA_TYPE_LINE22, 0x66);
236		tm6000_set_reg(dev,
237			TM6010_REQ07_R53_VBI_DATA_TYPE_LINE23, 0x00);
238		tm6000_set_reg(dev,
239			TM6010_REQ07_R54_VBI_DATA_TYPE_RLINES, 0x00);
240		tm6000_set_reg(dev,
241			TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01);
242		tm6000_set_reg(dev,
243			TM6010_REQ07_R56_VBI_LOOP_FILTER_I_GAIN, 0x00);
244		tm6000_set_reg(dev,
245			TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02);
246		tm6000_set_reg(dev, TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35);
247		tm6000_set_reg(dev, TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0);
248		tm6000_set_reg(dev, TM6010_REQ07_R5A_VBI_TELETEXT_DTO1, 0x11);
249		tm6000_set_reg(dev, TM6010_REQ07_R5B_VBI_TELETEXT_DTO0, 0x4c);
250		tm6000_set_reg(dev, TM6010_REQ07_R40_TELETEXT_VBI_CODE0, 0x01);
251		tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00);
252
253
254		/* Init audio */
255		tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00);
256		tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, 0x04);
257		tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00);
258		tm6000_set_reg(dev, TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0xa0);
259		tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, 0x05);
260		tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x06);
261		tm6000_set_reg(dev, TM6010_REQ08_R07_A_LEFT_VOL, 0x00);
262		tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, 0x00);
263		tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x08);
264		tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0x91);
265		tm6000_set_reg(dev, TM6010_REQ08_R0B_A_ASD_THRES1, 0x20);
266		tm6000_set_reg(dev, TM6010_REQ08_R0C_A_ASD_THRES2, 0x12);
267		tm6000_set_reg(dev, TM6010_REQ08_R0D_A_AMD_THRES, 0x20);
268		tm6000_set_reg(dev, TM6010_REQ08_R0E_A_MONO_THRES1, 0xf0);
269		tm6000_set_reg(dev, TM6010_REQ08_R0F_A_MONO_THRES2, 0x80);
270		tm6000_set_reg(dev, TM6010_REQ08_R10_A_MUTE_THRES1, 0xc0);
271		tm6000_set_reg(dev, TM6010_REQ08_R11_A_MUTE_THRES2, 0x80);
272		tm6000_set_reg(dev, TM6010_REQ08_R12_A_AGC_U, 0x12);
273		tm6000_set_reg(dev, TM6010_REQ08_R13_A_AGC_ERR_T, 0xfe);
274		tm6000_set_reg(dev, TM6010_REQ08_R14_A_AGC_GAIN_INIT, 0x20);
275		tm6000_set_reg(dev, TM6010_REQ08_R15_A_AGC_STEP_THR, 0x14);
276		tm6000_set_reg(dev, TM6010_REQ08_R16_A_AGC_GAIN_MAX, 0xfe);
277		tm6000_set_reg(dev, TM6010_REQ08_R17_A_AGC_GAIN_MIN, 0x01);
278		tm6000_set_reg(dev, TM6010_REQ08_R18_A_TR_CTRL, 0xa0);
279		tm6000_set_reg(dev, TM6010_REQ08_R19_A_FH_2FH_GAIN, 0x32);
280		tm6000_set_reg(dev, TM6010_REQ08_R1A_A_NICAM_SER_MAX, 0x64);
281		tm6000_set_reg(dev, TM6010_REQ08_R1B_A_NICAM_SER_MIN, 0x20);
282		tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1c, 0x00);
283		tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1d, 0x00);
284		tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13);
285		tm6000_set_reg(dev, TM6010_REQ08_R1F_A_TEST_INTF_SEL, 0x00);
286		tm6000_set_reg(dev, TM6010_REQ08_R20_A_TEST_PIN_SEL, 0x00);
287		tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3);
288		tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x00);
289		tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80);
290
291	} else {
292		/* Enables soft reset */
293		tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01);
294
295		if (dev->scaler)
296			tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x20);
297		else	/* Enable Hfilter and disable TS Drop err */
298			tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x80);
299
300		tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x88);
301		tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0x23);
302		tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xc0);
303		tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xd8);
304		tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x06);
305		tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0x1f);
306
307		/* AP Software reset */
308		tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08);
309		tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00);
310
311		tm6000_set_fourcc_format(dev);
312
313		/* Disables soft reset */
314		tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00);
315
316		/* E3: Select input 0 - TV tuner */
317		tm6000_set_reg(dev, TM6010_REQ07_RE3_OUT_SEL1, 0x00);
318		tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xeb, 0x60);
319
320		/* This controls input */
321		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_2, 0x0);
322		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_3, 0x01);
323	}
324	msleep(20);
325
326	/* Tuner firmware can now be loaded */
327
328	struct v4l2_frequency f;
329	mutex_lock(&dev->lock);
330	f.frequency = dev->freq;
331	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
332	mutex_unlock(&dev->lock);
333
334	msleep(100);
335	tm6000_set_standard(dev, &dev->norm);
336	tm6000_set_audio_bitrate(dev, 48000);
337
338	/* switch dvb led off */
339	if (dev->gpio.dvb_led) {
340		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
341			dev->gpio.dvb_led, 0x01);
342	}
343
344	return 0;
345}
346
347int tm6000_init_digital_mode(struct tm6000_core *dev)
348{
349	if (dev->dev_type == TM6010) {
350		int val;
351		u8 buf[2];
352
353		/* digital init */
354		val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0);
355		val &= ~0x60;
356		tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val);
357		val = tm6000_get_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0);
358		val |= 0x40;
359		tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, val);
360		tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, 0x28);
361		tm6000_set_reg(dev, TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xfc);
362		tm6000_set_reg(dev, TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0xff);
363		tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe);
364		tm6000_read_write_usb(dev, 0xc0, 0x0e, 0x00c2, 0x0008, buf, 2);
365		printk(KERN_INFO"buf %#x %#x\n", buf[0], buf[1]);
366	} else  {
367		tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08);
368		tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00);
369		tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01);
370		tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0x08);
371		tm6000_set_reg(dev, TM6010_REQ07_RE2_OUT_SEL2, 0x0c);
372		tm6000_set_reg(dev, TM6010_REQ07_RE8_TYPESEL_MOS_I2S, 0xff);
373		tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0x00eb, 0xd8);
374		tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x40);
375		tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0);
376		tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x09);
377		tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0x37);
378		tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xd8);
379		tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xc0);
380		tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x60);
381
382		tm6000_set_reg(dev, TM6010_REQ07_RE2_OUT_SEL2, 0x0c);
383		tm6000_set_reg(dev, TM6010_REQ07_RE8_TYPESEL_MOS_I2S, 0xff);
384		tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0x00eb, 0x08);
385		msleep(50);
386
387		tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
388		msleep(50);
389		tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x01);
390		msleep(50);
391		tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
392		msleep(100);
393	}
394
395	/* switch dvb led on */
396	if (dev->gpio.dvb_led) {
397		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
398			dev->gpio.dvb_led, 0x00);
399	}
400
401	return 0;
402}
403EXPORT_SYMBOL(tm6000_init_digital_mode);
404
405struct reg_init {
406	u8 req;
407	u8 reg;
408	u8 val;
409};
410
411/* The meaning of those initializations are unknown */
412struct reg_init tm6000_init_tab[] = {
413	/* REG  VALUE */
414	{ TM6010_REQ07_RD8_IR_PULSE_CNT0, 0x1f },
415	{ TM6010_REQ07_RFF_SOFT_RESET, 0x08 },
416	{ TM6010_REQ07_RFF_SOFT_RESET, 0x00 },
417	{ TM6010_REQ07_RD5_POWERSAVE, 0x4f },
418	{ TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0x23 },
419	{ TM6010_REQ07_RD8_IR_WAKEUP_ADD, 0x08 },
420	{ TM6010_REQ07_RE2_OUT_SEL2, 0x00 },
421	{ TM6010_REQ07_RE3_OUT_SEL1, 0x10 },
422	{ TM6010_REQ07_RE5_REMOTE_WAKEUP, 0x00 },
423	{ TM6010_REQ07_RE8_TYPESEL_MOS_I2S, 0x00 },
424	{ REQ_07_SET_GET_AVREG,  0xeb, 0x64 },		/* 48000 bits/sample, external input */
425	{ REQ_07_SET_GET_AVREG,  0xee, 0xc2 },
426	{ TM6010_REQ07_R3F_RESET, 0x01 },		/* Start of soft reset */
427	{ TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 },
428	{ TM6010_REQ07_R01_VIDEO_CONTROL1, 0x07 },
429	{ TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
430	{ TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 },
431	{ TM6010_REQ07_R05_NOISE_THRESHOLD, 0x64 },
432	{ TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01 },
433	{ TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0x82 },
434	{ TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0x36 },
435	{ TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0x50 },
436	{ TM6010_REQ07_R0C_CHROMA_AGC_CONTROL, 0x6a },
437	{ TM6010_REQ07_R11_AGC_PEAK_CONTROL, 0xc9 },
438	{ TM6010_REQ07_R12_AGC_GATE_STARTH, 0x07 },
439	{ TM6010_REQ07_R13_AGC_GATE_STARTL, 0x3b },
440	{ TM6010_REQ07_R14_AGC_GATE_WIDTH, 0x47 },
441	{ TM6010_REQ07_R15_AGC_BP_DELAY, 0x6f },
442	{ TM6010_REQ07_R17_HLOOP_MAXSTATE, 0xcd },
443	{ TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
444	{ TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b },
445	{ TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 },
446	{ TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 },
447	{ TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
448	{ TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
449	{ TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
450	{ TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
451	{ TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME, 0x3c },
452	{ TM6010_REQ07_R21_HSYNC_PHASE_OFFSET, 0x3c },
453	{ TM6010_REQ07_R2D_CHROMA_BURST_END, 0x48 },
454	{ TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 },
455	{ TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 },
456	{ TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 },
457	{ TM6010_REQ07_R32_VSYNC_HLOCK_MIN, 0x74 },
458	{ TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c },
459	{ TM6010_REQ07_R34_VSYNC_AGC_MIN, 0x74 },
460	{ TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
461	{ TM6010_REQ07_R36_VSYNC_VBI_MIN, 0x7a },
462	{ TM6010_REQ07_R37_VSYNC_VBI_MAX, 0x26 },
463	{ TM6010_REQ07_R38_VSYNC_THRESHOLD, 0x40 },
464	{ TM6010_REQ07_R39_VSYNC_TIME_CONSTANT, 0x0a },
465	{ TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55 },
466	{ TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x11 },
467	{ TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01 },
468	{ TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02 },
469	{ TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35 },
470	{ TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0 },
471	{ TM6010_REQ07_R80_COMB_FILTER_TRESHOLD, 0x15 },
472	{ TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 },
473	{ TM6010_REQ07_RC1_TRESHOLD, 0xd0 },
474	{ TM6010_REQ07_RC3_HSTART1, 0x88 },
475	{ TM6010_REQ07_R3F_RESET, 0x00 },		/* End of the soft reset */
476	{ TM6010_REQ05_R18_IMASK7, 0x00 },
477};
478
479struct reg_init tm6010_init_tab[] = {
480	{ TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x00 },
481	{ TM6010_REQ07_RC4_HSTART0, 0xa0 },
482	{ TM6010_REQ07_RC6_HEND0, 0x40 },
483	{ TM6010_REQ07_RCA_VEND0, 0x31 },
484	{ TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0xe1 },
485	{ TM6010_REQ07_RE0_DVIDEO_SOURCE, 0x03 },
486	{ TM6010_REQ07_RFE_POWER_DOWN, 0x7f },
487
488	{ TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0 },
489	{ TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4 },
490	{ TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8 },
491	{ TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x00 },
492	{ TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2 },
493	{ TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0 },
494	{ TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2 },
495	{ TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60 },
496	{ TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc },
497
498	{ TM6010_REQ07_R3F_RESET, 0x01 },
499	{ TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 },
500	{ TM6010_REQ07_R01_VIDEO_CONTROL1, 0x07 },
501	{ TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
502	{ TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 },
503	{ TM6010_REQ07_R05_NOISE_THRESHOLD, 0x64 },
504	{ TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01 },
505	{ TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0x82 },
506	{ TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0x36 },
507	{ TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0x50 },
508	{ TM6010_REQ07_R0C_CHROMA_AGC_CONTROL, 0x6a },
509	{ TM6010_REQ07_R11_AGC_PEAK_CONTROL, 0xc9 },
510	{ TM6010_REQ07_R12_AGC_GATE_STARTH, 0x07 },
511	{ TM6010_REQ07_R13_AGC_GATE_STARTL, 0x3b },
512	{ TM6010_REQ07_R14_AGC_GATE_WIDTH, 0x47 },
513	{ TM6010_REQ07_R15_AGC_BP_DELAY, 0x6f },
514	{ TM6010_REQ07_R17_HLOOP_MAXSTATE, 0xcd },
515	{ TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
516	{ TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b },
517	{ TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 },
518	{ TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 },
519	{ TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
520	{ TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
521	{ TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
522	{ TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
523	{ TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME, 0x3c },
524	{ TM6010_REQ07_R21_HSYNC_PHASE_OFFSET, 0x3c },
525	{ TM6010_REQ07_R2D_CHROMA_BURST_END, 0x48 },
526	{ TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 },
527	{ TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 },
528	{ TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 },
529	{ TM6010_REQ07_R32_VSYNC_HLOCK_MIN, 0x74 },
530	{ TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c },
531	{ TM6010_REQ07_R34_VSYNC_AGC_MIN, 0x74 },
532	{ TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
533	{ TM6010_REQ07_R36_VSYNC_VBI_MIN, 0x7a },
534	{ TM6010_REQ07_R37_VSYNC_VBI_MAX, 0x26 },
535	{ TM6010_REQ07_R38_VSYNC_THRESHOLD, 0x40 },
536	{ TM6010_REQ07_R39_VSYNC_TIME_CONSTANT, 0x0a },
537	{ TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55 },
538	{ TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x11 },
539	{ TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01 },
540	{ TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02 },
541	{ TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35 },
542	{ TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0 },
543	{ TM6010_REQ07_R80_COMB_FILTER_TRESHOLD, 0x15 },
544	{ TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 },
545	{ TM6010_REQ07_RC1_TRESHOLD, 0xd0 },
546	{ TM6010_REQ07_RC3_HSTART1, 0x88 },
547	{ TM6010_REQ07_R3F_RESET, 0x00 },
548
549	{ TM6010_REQ05_R18_IMASK7, 0x00 },
550
551	{ TM6010_REQ07_RD8_IR_LEADER1, 0xaa },
552	{ TM6010_REQ07_RD8_IR_LEADER0, 0x30 },
553	{ TM6010_REQ07_RD8_IR_PULSE_CNT1, 0x20 },
554	{ TM6010_REQ07_RD8_IR_PULSE_CNT0, 0xd0 },
555	{ REQ_04_EN_DISABLE_MCU_INT, 0x02, 0x00 },
556	{ TM6010_REQ07_RD8_IR, 0x2f },
557
558	/* set remote wakeup key:any key wakeup */
559	{ TM6010_REQ07_RE5_REMOTE_WAKEUP,  0xfe },
560	{ TM6010_REQ07_RD8_IR_WAKEUP_SEL,  0xff },
561};
562
563int tm6000_init(struct tm6000_core *dev)
564{
565	int board, rc = 0, i, size;
566	struct reg_init *tab;
567
568	if (dev->dev_type == TM6010) {
569		tab = tm6010_init_tab;
570		size = ARRAY_SIZE(tm6010_init_tab);
571	} else {
572		tab = tm6000_init_tab;
573		size = ARRAY_SIZE(tm6000_init_tab);
574	}
575
576	/* Load board's initialization table */
577	for (i = 0; i < size; i++) {
578		rc = tm6000_set_reg(dev, tab[i].req, tab[i].reg, tab[i].val);
579		if (rc < 0) {
580			printk(KERN_ERR "Error %i while setting req %d, "
581					"reg %d to value %d\n", rc,
582					tab[i].req, tab[i].reg, tab[i].val);
583			return rc;
584		}
585	}
586
587	msleep(5); /* Just to be conservative */
588
589	/* Check board version - maybe 10Moons specific */
590	board = tm6000_get_reg32(dev, REQ_40_GET_VERSION, 0, 0);
591	if (board >= 0)
592		printk(KERN_INFO "Board version = 0x%08x\n", board);
593	else
594		printk(KERN_ERR "Error %i while retrieving board version\n", board);
595
596	rc = tm6000_cards_setup(dev);
597
598	return rc;
599}
600
601int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate)
602{
603	int val;
604
605	if (dev->dev_type == TM6010) {
606		val = tm6000_get_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0);
607		if (val < 0)
608			return val;
609		val = (val & 0xf0) | 0x1; /* 48 kHz, not muted */
610		val = tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, val);
611		if (val < 0)
612			return val;
613	}
614
615	val = tm6000_get_reg(dev, REQ_07_SET_GET_AVREG, 0xeb, 0x0);
616	if (val < 0)
617		return val;
618
619	val &= 0x0f;		/* Preserve the audio input control bits */
620	switch (bitrate) {
621	case 44100:
622		val |= 0xd0;
623		dev->audio_bitrate = bitrate;
624		break;
625	case 48000:
626		val |= 0x60;
627		dev->audio_bitrate = bitrate;
628		break;
629	}
630	val = tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xeb, val);
631
632	return val;
633}
634EXPORT_SYMBOL_GPL(tm6000_set_audio_bitrate);
635
636static LIST_HEAD(tm6000_devlist);
637static DEFINE_MUTEX(tm6000_devlist_mutex);
638
639/*
640 * tm6000_realease_resource()
641 */
642
643void tm6000_remove_from_devlist(struct tm6000_core *dev)
644{
645	mutex_lock(&tm6000_devlist_mutex);
646	list_del(&dev->devlist);
647	mutex_unlock(&tm6000_devlist_mutex);
648};
649
650void tm6000_add_into_devlist(struct tm6000_core *dev)
651{
652	mutex_lock(&tm6000_devlist_mutex);
653	list_add_tail(&dev->devlist, &tm6000_devlist);
654	mutex_unlock(&tm6000_devlist_mutex);
655};
656
657/*
658 * Extension interface
659 */
660
661static LIST_HEAD(tm6000_extension_devlist);
662static DEFINE_MUTEX(tm6000_extension_devlist_lock);
663
664int tm6000_call_fillbuf(struct tm6000_core *dev, enum tm6000_ops_type type,
665			char *buf, int size)
666{
667	struct tm6000_ops *ops = NULL;
668
669
670	if (!list_empty(&tm6000_extension_devlist)) {
671		list_for_each_entry(ops, &tm6000_extension_devlist, next) {
672			if (ops->fillbuf && ops->type == type)
673				ops->fillbuf(dev, buf, size);
674		}
675	}
676
677	return 0;
678}
679
680int tm6000_register_extension(struct tm6000_ops *ops)
681{
682	struct tm6000_core *dev = NULL;
683
684	mutex_lock(&tm6000_devlist_mutex);
685	mutex_lock(&tm6000_extension_devlist_lock);
686	list_add_tail(&ops->next, &tm6000_extension_devlist);
687	list_for_each_entry(dev, &tm6000_devlist, devlist) {
688		ops->init(dev);
689		printk(KERN_INFO "%s: Initialized (%s) extension\n",
690		       dev->name, ops->name);
691	}
692	mutex_unlock(&tm6000_extension_devlist_lock);
693	mutex_unlock(&tm6000_devlist_mutex);
694	return 0;
695}
696EXPORT_SYMBOL(tm6000_register_extension);
697
698void tm6000_unregister_extension(struct tm6000_ops *ops)
699{
700	struct tm6000_core *dev = NULL;
701
702	mutex_lock(&tm6000_devlist_mutex);
703	list_for_each_entry(dev, &tm6000_devlist, devlist) {
704		if (dev)
705			ops->fini(dev);
706	}
707
708	mutex_lock(&tm6000_extension_devlist_lock);
709	printk(KERN_INFO "tm6000: Remove (%s) extension\n", ops->name);
710	list_del(&ops->next);
711	mutex_unlock(&tm6000_extension_devlist_lock);
712	mutex_unlock(&tm6000_devlist_mutex);
713}
714EXPORT_SYMBOL(tm6000_unregister_extension);
715
716void tm6000_init_extension(struct tm6000_core *dev)
717{
718	struct tm6000_ops *ops = NULL;
719
720	mutex_lock(&tm6000_extension_devlist_lock);
721	if (!list_empty(&tm6000_extension_devlist)) {
722		list_for_each_entry(ops, &tm6000_extension_devlist, next) {
723			if (ops->init)
724				ops->init(dev);
725		}
726	}
727	mutex_unlock(&tm6000_extension_devlist_lock);
728}
729
730void tm6000_close_extension(struct tm6000_core *dev)
731{
732	struct tm6000_ops *ops = NULL;
733
734	mutex_lock(&tm6000_extension_devlist_lock);
735	if (!list_empty(&tm6000_extension_devlist)) {
736		list_for_each_entry(ops, &tm6000_extension_devlist, next) {
737			if (ops->fini)
738				ops->fini(dev);
739		}
740	}
741	mutex_unlock(&tm6000_extension_devlist_lock);
742}
743