Commit | Line | Data |
---|---|---|
9701dc94 MCC |
1 | /* |
2 | tm6000-core.c - driver for TM5600/TM6000 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/module.h> | |
21 | #include <linux/kernel.h> | |
22 | #include <linux/usb.h> | |
23 | #include <linux/i2c.h> | |
24 | #include <linux/video_decoder.h> | |
25 | #include "tm6000.h" | |
26 | #include "tm6000-regs.h" | |
27 | #include <media/v4l2-common.h> | |
28 | #include <media/tuner.h> | |
29 | ||
30 | #ifdef HACK /* HACK */ | |
31 | #include "tm6000-hack.c" | |
32 | #endif | |
33 | ||
34 | #define USB_TIMEOUT 5*HZ /* ms */ | |
35 | ||
36 | int tm6000_read_write_usb (struct tm6000_core *dev, u8 req_type, u8 req, | |
37 | u16 value, u16 index, u8 *buf, u16 len) | |
38 | { | |
39 | int ret, i; | |
40 | unsigned int pipe; | |
41 | static int ini=0, last=0, n=0; | |
42 | u8 *data=NULL; | |
43 | ||
44 | if (len) | |
45 | data = kzalloc(len, GFP_KERNEL); | |
46 | ||
47 | ||
48 | if (req_type & USB_DIR_IN) | |
49 | pipe=usb_rcvctrlpipe(dev->udev, 0); | |
50 | else { | |
51 | pipe=usb_sndctrlpipe(dev->udev, 0); | |
52 | memcpy(data, buf, len); | |
53 | } | |
54 | ||
55 | if (tm6000_debug & V4L2_DEBUG_I2C) { | |
56 | if (!ini) | |
57 | last=ini=jiffies; | |
58 | ||
59 | printk("%06i (dev %p, pipe %08x): ", n, dev->udev, pipe); | |
60 | ||
61 | printk( "%s: %06u ms %06u ms %02x %02x %02x %02x %02x %02x %02x %02x ", | |
62 | (req_type & USB_DIR_IN)?" IN":"OUT", | |
63 | jiffies_to_msecs(jiffies-last), | |
64 | jiffies_to_msecs(jiffies-ini), | |
65 | req_type, req,value&0xff,value>>8, index&0xff, index>>8, | |
66 | len&0xff, len>>8); | |
67 | last=jiffies; | |
68 | n++; | |
69 | ||
70 | if ( !(req_type & USB_DIR_IN) ) { | |
71 | printk(">>> "); | |
72 | for (i=0;i<len;i++) { | |
73 | printk(" %02x",buf[i]); | |
74 | } | |
75 | printk("\n"); | |
76 | } | |
77 | } | |
78 | ||
79 | ret = usb_control_msg(dev->udev, pipe, req, req_type, value, index, data, | |
80 | len, USB_TIMEOUT); | |
81 | ||
82 | if (req_type & USB_DIR_IN) | |
83 | memcpy(buf, data, len); | |
84 | ||
85 | if (tm6000_debug & V4L2_DEBUG_I2C) { | |
86 | if (ret<0) { | |
87 | if (req_type & USB_DIR_IN) | |
88 | printk("<<< (len=%d)\n",len); | |
89 | ||
90 | printk("%s: Error #%d\n", __FUNCTION__, ret); | |
91 | } else if (req_type & USB_DIR_IN) { | |
92 | printk("<<< "); | |
93 | for (i=0;i<len;i++) { | |
94 | printk(" %02x",buf[i]); | |
95 | } | |
96 | printk("\n"); | |
97 | } | |
98 | } | |
99 | ||
100 | kfree(data); | |
101 | ||
102 | return ret; | |
103 | } | |
104 | ||
105 | int tm6000_set_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index) | |
106 | { | |
107 | return | |
108 | tm6000_read_write_usb (dev, USB_DIR_OUT | USB_TYPE_VENDOR, | |
109 | req, value, index, NULL, 0); | |
110 | } | |
111 | ||
112 | int 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 | } | |
125 | ||
126 | int tm6000_get_reg16 (struct tm6000_core *dev, u8 req, u16 value, u16 index) | |
127 | { | |
128 | int rc; | |
129 | u8 buf[2]; | |
130 | ||
131 | rc=tm6000_read_write_usb (dev, USB_DIR_IN | USB_TYPE_VENDOR, req, | |
132 | value, index, buf, 2); | |
133 | ||
134 | if (rc<0) | |
135 | return rc; | |
136 | ||
137 | return buf[1]|buf[0]<<8; | |
138 | } | |
139 | ||
140 | void tm6000_set_fourcc_format(struct tm6000_core *dev) | |
141 | { | |
142 | if (dev->fourcc==V4L2_PIX_FMT_UYVY) { | |
143 | /* Sets driver to UYUV */ | |
144 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xc1, 0xd0); | |
145 | } else { | |
146 | /* Sets driver to YUV2 */ | |
147 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xc1, 0x90); | |
148 | } | |
149 | } | |
150 | ||
151 | int tm6000_init_analog_mode (struct tm6000_core *dev) | |
152 | { | |
153 | ||
154 | /* Enables soft reset */ | |
155 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x3f, 0x01); | |
156 | ||
157 | if (dev->scaler) { | |
158 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xc0, 0x20); | |
159 | } else { | |
160 | /* Enable Hfilter and disable TS Drop err */ | |
161 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xc0, 0x80); | |
162 | } | |
163 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xc3, 0x88); | |
164 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xda, 0x23); | |
165 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xd1, 0xc0); | |
166 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xd2, 0xd8); | |
167 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xd6, 0x06); | |
168 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xdf, 0x1f); | |
169 | ||
170 | /* AP Software reset */ | |
171 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xff, 0x08); | |
172 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xff, 0x00); | |
173 | ||
174 | tm6000_set_fourcc_format(dev); | |
175 | ||
176 | /* Disables soft reset */ | |
177 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x3f, 0x00); | |
178 | ||
179 | /* E3: Select input 0 - TV tuner */ | |
180 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xe3, 0x00); | |
181 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xeb, 0x60); | |
182 | ||
183 | /* Tuner firmware can now be loaded */ | |
184 | ||
185 | tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_1, 0x00); | |
186 | msleep(11); | |
187 | ||
188 | /* This controls input */ | |
189 | tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_2, 0x0); | |
190 | tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_3, 0x01); | |
191 | msleep(20); | |
192 | ||
193 | /*FIXME: Hack!!! */ | |
194 | struct v4l2_frequency f; | |
195 | mutex_lock(&dev->lock); | |
196 | f.frequency=dev->freq; | |
197 | tm6000_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,&f); | |
198 | mutex_unlock(&dev->lock); | |
199 | ||
200 | msleep(100); | |
201 | tm6000_set_standard (dev, &dev->norm); | |
202 | tm6000_set_audio_bitrate (dev,48000); | |
203 | ||
204 | ||
205 | return 0; | |
206 | } | |
207 | ||
208 | ||
209 | /* The meaning of those initializations are unknown */ | |
210 | u8 init_tab[][2] = { | |
211 | /* REG VALUE */ | |
212 | { 0xdf, 0x1f }, | |
213 | { 0xff, 0x08 }, | |
214 | { 0xff, 0x00 }, | |
215 | { 0xd5, 0x4f }, | |
216 | { 0xda, 0x23 }, | |
217 | { 0xdb, 0x08 }, | |
218 | { 0xe2, 0x00 }, | |
219 | { 0xe3, 0x10 }, | |
220 | { 0xe5, 0x00 }, | |
221 | { 0xe8, 0x00 }, | |
222 | { 0xeb, 0x64 }, /* 48000 bits/sample, external input */ | |
223 | { 0xee, 0xc2 }, | |
224 | { 0x3f, 0x01 }, /* Start of soft reset */ | |
225 | { 0x00, 0x00 }, | |
226 | { 0x01, 0x07 }, | |
227 | { 0x02, 0x5f }, | |
228 | { 0x03, 0x00 }, | |
229 | { 0x05, 0x64 }, | |
230 | { 0x07, 0x01 }, | |
231 | { 0x08, 0x82 }, | |
232 | { 0x09, 0x36 }, | |
233 | { 0x0a, 0x50 }, | |
234 | { 0x0c, 0x6a }, | |
235 | { 0x11, 0xc9 }, | |
236 | { 0x12, 0x07 }, | |
237 | { 0x13, 0x3b }, | |
238 | { 0x14, 0x47 }, | |
239 | { 0x15, 0x6f }, | |
240 | { 0x17, 0xcd }, | |
241 | { 0x18, 0x1e }, | |
242 | { 0x19, 0x8b }, | |
243 | { 0x1a, 0xa2 }, | |
244 | { 0x1b, 0xe9 }, | |
245 | { 0x1c, 0x1c }, | |
246 | { 0x1d, 0xcc }, | |
247 | { 0x1e, 0xcc }, | |
248 | { 0x1f, 0xcd }, | |
249 | { 0x20, 0x3c }, | |
250 | { 0x21, 0x3c }, | |
251 | { 0x2d, 0x48 }, | |
252 | { 0x2e, 0x88 }, | |
253 | { 0x30, 0x22 }, | |
254 | { 0x31, 0x61 }, | |
255 | { 0x32, 0x74 }, | |
256 | { 0x33, 0x1c }, | |
257 | { 0x34, 0x74 }, | |
258 | { 0x35, 0x1c }, | |
259 | { 0x36, 0x7a }, | |
260 | { 0x37, 0x26 }, | |
261 | { 0x38, 0x40 }, | |
262 | { 0x39, 0x0a }, | |
263 | { 0x42, 0x55 }, | |
264 | { 0x51, 0x11 }, | |
265 | { 0x55, 0x01 }, | |
266 | { 0x57, 0x02 }, | |
267 | { 0x58, 0x35 }, | |
268 | { 0x59, 0xa0 }, | |
269 | { 0x80, 0x15 }, | |
270 | { 0x82, 0x42 }, | |
271 | { 0xc1, 0xd0 }, | |
272 | { 0xc3, 0x88 }, | |
273 | { 0x3f, 0x00 }, /* End of the soft reset */ | |
274 | }; | |
275 | ||
276 | int tm6000_init (struct tm6000_core *dev) | |
277 | { | |
278 | int board, rc=0, i; | |
279 | ||
280 | #ifdef HACK /* HACK */ | |
281 | init_tm6000(dev); | |
282 | return 0; | |
283 | #else | |
284 | ||
285 | /* Load board's initialization table */ | |
286 | for (i=0; i< ARRAY_SIZE(init_tab); i++) { | |
287 | rc= tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, | |
288 | init_tab[i][0],init_tab[i][1]); | |
289 | if (rc<0) { | |
290 | printk (KERN_ERR "Error %i while setting reg %d to value %d\n", | |
291 | rc, init_tab[i][0],init_tab[i][1]); | |
292 | return rc; | |
293 | } | |
294 | } | |
295 | ||
296 | /* Check board version - maybe 10Moons specific */ | |
297 | board=tm6000_get_reg16 (dev, 0x40, 0, 0); | |
298 | if (board >=0) { | |
299 | printk (KERN_INFO "Board version = 0x%04x\n",board); | |
300 | } else { | |
301 | printk (KERN_ERR "Error %i while retrieving board version\n",board); | |
302 | } | |
303 | ||
304 | tm6000_set_reg (dev, REQ_05_SET_GET_USBREG, 0x18, 0x00); | |
305 | msleep(5); /* Just to be conservative */ | |
306 | ||
307 | /* Reset GPIO1. Maybe, this is 10 Moons specific */ | |
308 | for (i=0; i< 3; i++) { | |
309 | rc=tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_1, 0); | |
310 | if (rc<0) { | |
311 | printk (KERN_ERR "Error %i doing GPIO1 reset\n",rc); | |
312 | return rc; | |
313 | } | |
314 | ||
315 | msleep(10); /* Just to be conservative */ | |
316 | rc=tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_1, 1); | |
317 | if (rc<0) { | |
318 | printk (KERN_ERR "Error %i doing GPIO1 reset\n",rc); | |
319 | return rc; | |
320 | } | |
321 | ||
322 | if (!i) | |
323 | rc=tm6000_get_reg16(dev, 0x40,0,0); | |
324 | } | |
325 | return 0; | |
326 | ||
327 | #endif /* HACK */ | |
328 | } | |
329 | ||
330 | #define tm6000_wrt(dev,req,reg,val, data...) \ | |
331 | { const static u8 _val[] = data; \ | |
332 | tm6000_read_write_usb(dev,USB_DIR_OUT | USB_TYPE_VENDOR, \ | |
333 | req,reg, val, (u8 *) _val, ARRAY_SIZE(_val)); \ | |
334 | } | |
335 | ||
336 | /* | |
337 | TM5600/6000 register values to set video standards. | |
338 | There's an adjust, common to all, for composite video | |
339 | Additional adjustments are required for S-Video, based on std. | |
340 | ||
341 | Standards values for TV S-Video Changes | |
342 | REG PAL PAL_M PAL_N SECAM NTSC Comp. PAL PAL_M PAL_N SECAM NTSC | |
343 | 0xdf 0x1f 0x1f 0x1f 0x1f 0x1f | |
344 | 0xe2 0x00 0x00 0x00 0x00 0x00 | |
345 | 0xe8 0x0f 0x0f 0x0f 0x0f 0x0f 0x00 0x00 0x00 0x00 0x00 | |
346 | 0xeb 0x60 0x60 0x60 0x60 0x60 0x64 0x64 0x64 0x64 0x64 0x64 | |
347 | 0xd5 0x5f 0x5f 0x5f 0x4f 0x4f 0x4f 0x4f 0x4f 0x4f 0x4f | |
348 | 0xe3 0x00 0x00 0x00 0x00 0x00 0x10 0x10 0x10 0x10 0x10 0x10 | |
349 | 0xe5 0x00 0x00 0x00 0x00 0x00 0x10 0x10 0x10 0x10 0x10 | |
350 | 0x3f 0x01 0x01 0x01 0x01 0x01 | |
351 | 0x00 0x32 0x04 0x36 0x38 0x00 0x33 0x05 0x37 0x39 0x01 | |
352 | 0x01 0x0e 0x0e 0x0e 0x0e 0x0f | |
353 | 0x02 0x5f 0x5f 0x5f 0x5f 0x5f | |
354 | 0x03 0x02 0x00 0x02 0x02 0x00 0x04 0x04 0x04 0x03 0x03 | |
355 | 0x07 0x01 0x01 0x01 0x01 0x01 0x00 0x00 | |
356 | 0x17 0xcd 0xcd 0xcd 0xcd 0xcd 0x8b | |
357 | 0x18 0x25 0x1e 0x1e 0x24 0x1e | |
358 | 0x19 0xd5 0x83 0x91 0x92 0x8b | |
359 | 0x1a 0x63 0x0a 0x1f 0xe8 0xa2 | |
360 | 0x1b 0x50 0xe0 0x0c 0xed 0xe9 | |
361 | 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c | |
362 | 0x1d 0xcc 0xcc 0xcc 0xcc 0xcc | |
363 | 0x1e 0xcc 0xcc 0xcc 0xcc 0xcc | |
364 | 0x1f 0xcd 0xcd 0xcd 0xcd 0xcd | |
365 | 0x2e 0x8c 0x88 0x8c 0x8c 0x88 0x88 | |
366 | 0x30 0x2c 0x20 0x2c 0x2c 0x22 0x2a 0x22 0x22 0x2a | |
367 | 0x31 0xc1 0x61 0xc1 0xc1 0x61 | |
368 | 0x33 0x0c 0x0c 0x0c 0x2c 0x1c | |
369 | 0x35 0x1c 0x1c 0x1c 0x18 0x1c | |
370 | 0x82 0x52 0x52 0x52 0x42 0x42 | |
371 | 0x04 0xdc 0xdc 0xdc 0xdd | |
372 | 0x0d 0x07 0x07 0x07 0x87 0x07 | |
373 | 0x3f 0x00 0x00 0x00 0x00 0x00 | |
374 | */ | |
375 | ||
376 | int tm6000_set_standard (struct tm6000_core *dev, v4l2_std_id *norm) | |
377 | { | |
378 | dev->norm=*norm; | |
379 | ||
380 | /* HACK: Should use, instead, the common code!!! */ | |
381 | if (*norm & V4L2_STD_PAL_M) { | |
382 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xdf, 0x1f); | |
383 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xe2, 0x00); | |
384 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xe8, 0x0f); | |
385 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xeb, 0x60); | |
386 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xd5, 0x5f); | |
387 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xe3, 0x00); | |
388 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xe5, 0x00); | |
389 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x3f, 0x01); | |
390 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00, 0x04); | |
391 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x01, 0x0e); | |
392 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x02, 0x5f); | |
393 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x03, 0x00); | |
394 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x07, 0x01); | |
395 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x18, 0x1e); | |
396 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x19, 0x83); | |
397 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x1a, 0x0a); | |
398 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x1b, 0xe0); | |
399 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x1c, 0x1c); | |
400 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x1d, 0xcc); | |
401 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x1e, 0xcc); | |
402 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x1f, 0xcd); | |
403 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x2e, 0x88); | |
404 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x30, 0x20); | |
405 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x31, 0x61); | |
406 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x33, 0x0c); | |
407 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x35, 0x1c); | |
408 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x82, 0x52); | |
409 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x04, 0xdc); | |
410 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x0d, 0x07); | |
411 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x3f, 0x00); | |
412 | return 0; | |
413 | } | |
414 | ||
415 | /* */ | |
416 | // tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x02, 0x01); | |
417 | // tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x02, 0x00); | |
418 | ||
419 | /* Set registers common to all standards */ | |
420 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xdf, 0x1f); | |
421 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xe2, 0x00); | |
422 | ||
423 | switch (dev->input) { | |
424 | case TM6000_INPUT_TV: | |
425 | /* Seems to disable ADC2 - needed for TV and RCA */ | |
426 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xe8, 0x0f); | |
427 | ||
428 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xeb, 0x60); | |
429 | ||
430 | if (*norm & V4L2_STD_PAL) { | |
431 | /* Enable UV_FLT_EN */ | |
432 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xd5, 0x5f); | |
433 | } else { | |
434 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xd5, 0x4f); | |
435 | } | |
436 | ||
437 | /* E3: Select input 0 */ | |
438 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xe3, 0x00); | |
439 | ||
440 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xe5, 0x10); | |
441 | ||
442 | break; | |
443 | case TM6000_INPUT_COMPOSITE: | |
444 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xeb, 0x64); | |
445 | /* E3: Select input 1 */ | |
446 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xe3, 0x10); | |
447 | break; | |
448 | case TM6000_INPUT_SVIDEO: | |
449 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xe8, 0x00); | |
450 | ||
451 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xeb, 0x64); | |
452 | ||
453 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xd5, 0x4f); | |
454 | /* E3: Select input 1 */ | |
455 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xe3, 0x10); | |
456 | ||
457 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xe5, 0x10); | |
458 | ||
459 | break; | |
460 | } | |
461 | ||
462 | /* Software reset */ | |
463 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x3f, 0x01); | |
464 | ||
465 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x02, 0x5f); | |
466 | ||
467 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x07, 0x01); | |
468 | // tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x17, 0xcd); | |
469 | ||
470 | /* Horizontal Sync DTO = 0x1ccccccd */ | |
471 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x1c, 0x1c); | |
472 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x1d, 0xcc); | |
473 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x1e, 0xcc); | |
474 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x1f, 0xcd); | |
475 | ||
476 | /* Vertical Height */ | |
477 | if (*norm & V4L2_STD_525_60) { | |
478 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x31, 0x61); | |
479 | } else { | |
480 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x31, 0xc1); | |
481 | } | |
482 | ||
483 | /* Horizontal Length */ | |
484 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x2f, 640/8); | |
485 | ||
486 | if (*norm & V4L2_STD_PAL) { | |
487 | /* Common to All PAL Standards */ | |
488 | ||
489 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x01, 0x0e); | |
490 | ||
491 | /* Vsync Hsinc Lockout End */ | |
492 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x33, 0x0c); | |
493 | ||
494 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x35, 0x1c); | |
495 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x82, 0x52); | |
496 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x04, 0xdc); | |
497 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x0d, 0x07); | |
498 | if (*norm & V4L2_STD_PAL_M) { | |
499 | ||
500 | /* Chroma DTO */ | |
501 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x18, 0x1e); | |
502 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x19, 0x83); | |
503 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x1a, 0x0a); | |
504 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x1b, 0xe0); | |
505 | ||
506 | /* Active Video Horiz Start Time */ | |
507 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x2e, 0x88); | |
508 | ||
509 | if (dev->input==TM6000_INPUT_SVIDEO) { | |
510 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00, 0x05); | |
511 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x03, 0x04); | |
512 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x30, 0x22); | |
513 | } else { | |
514 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00, 0x04); | |
515 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x03, 0x00); | |
516 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x30, 0x20); | |
517 | } | |
518 | } else if (*norm & V4L2_STD_PAL_N) { | |
519 | /* Chroma DTO */ | |
520 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x18, 0x1e); | |
521 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x19, 0x91); | |
522 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x1a, 0x1f); | |
523 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x1b, 0x0c); | |
524 | ||
525 | if (dev->input==TM6000_INPUT_SVIDEO) { | |
526 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00, 0x37); | |
527 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x03, 0x04); | |
528 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x2e, 0x88); | |
529 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x30, 0x22); | |
530 | } else { | |
531 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00, 0x36); | |
532 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x03, 0x02); | |
533 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x2e, 0x8c); | |
534 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x30, 0x2c); | |
535 | } | |
536 | } else { // Other PAL standards | |
537 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x18, 0x25); | |
538 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x19, 0xd5); | |
539 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x1a, 0x63); | |
540 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x1b, 0x50); | |
541 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x2e, 0x8c); | |
542 | ||
543 | if (dev->input==TM6000_INPUT_SVIDEO) { | |
544 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00, 0x33); | |
545 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x03, 0x04); | |
546 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x30, 0x2a); | |
547 | ||
548 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x30, 0x2c); | |
549 | } else { | |
550 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00, 0x32); | |
551 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x03, 0x02); | |
552 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x30, 0x2c); | |
553 | } | |
554 | } | |
555 | } if (*norm & V4L2_STD_SECAM) { | |
556 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x01, 0x0e); | |
557 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x18, 0x24); | |
558 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x19, 0x92); | |
559 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x1a, 0xe8); | |
560 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x1b, 0xed); | |
561 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x2e, 0x8c); | |
562 | ||
563 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x33, 0x2c); | |
564 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x35, 0x18); | |
565 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x82, 0x42); | |
566 | // Register 0x04 is not initialized on SECAM | |
567 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x0d, 0x87); | |
568 | ||
569 | if (dev->input==TM6000_INPUT_SVIDEO) { | |
570 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00, 0x39); | |
571 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x03, 0x03); | |
572 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x30, 0x2a); | |
573 | } else { | |
574 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00, 0x38); | |
575 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x03, 0x02); | |
576 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x30, 0x2c); | |
577 | } | |
578 | } else { /* NTSC */ | |
579 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x01, 0x0f); | |
580 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x18, 0x1e); | |
581 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x19, 0x8b); | |
582 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x1a, 0xa2); | |
583 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x1b, 0xe9); | |
584 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x2e, 0x88); | |
585 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x30, 0x22); | |
586 | ||
587 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x33, 0x1c); | |
588 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x35, 0x1c); | |
589 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x82, 0x42); | |
590 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x0d, 0x07); | |
591 | if (dev->input==TM6000_INPUT_SVIDEO) { | |
592 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00, 0x01); | |
593 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x03, 0x03); | |
594 | ||
595 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x07, 0x00); | |
596 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x17, 0x8b); | |
597 | } else { | |
598 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00, 0x00); | |
599 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x03, 0x00); | |
600 | } | |
601 | } | |
602 | ||
603 | ||
604 | /* End of software reset */ | |
605 | tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x3f, 0x00); | |
606 | ||
607 | msleep(40); | |
608 | ||
609 | return 0; | |
610 | } | |
611 | ||
612 | int tm6000_set_audio_bitrate (struct tm6000_core *dev, int bitrate) | |
613 | { | |
614 | int val; | |
615 | ||
616 | val=tm6000_get_reg (dev, REQ_07_SET_GET_AVREG, 0xeb, 0x0); | |
617 | printk("Original value=%d\n",val); | |
618 | if (val<0) | |
619 | return val; | |
620 | ||
621 | val &= 0x0f; /* Preserve the audio input control bits */ | |
622 | switch (bitrate) { | |
623 | case 44100: | |
624 | val|=0xd0; | |
625 | break; | |
626 | case 48000: | |
627 | val|=0x60; | |
628 | break; | |
629 | } | |
630 | val=tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xeb, val); | |
631 | ||
632 | return val; | |
633 | } |