diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/cx25840/cx25840-audio.c | 65 | ||||
-rw-r--r-- | drivers/media/video/cx25840/cx25840-core.c | 219 | ||||
-rw-r--r-- | drivers/media/video/cx25840/cx25840-core.h | 1 | ||||
-rw-r--r-- | drivers/media/video/cx25840/cx25840-firmware.c | 5 |
4 files changed, 253 insertions, 37 deletions
diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c index 51fc0af01578..d6421e1e8f6a 100644 --- a/drivers/media/video/cx25840/cx25840-audio.c +++ b/drivers/media/video/cx25840/cx25840-audio.c | |||
@@ -32,11 +32,17 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) | |||
32 | 32 | ||
33 | /* common for all inputs and rates */ | 33 | /* common for all inputs and rates */ |
34 | /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */ | 34 | /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */ |
35 | cx25840_write(client, 0x127, 0x50); | 35 | if (!state->is_cx23885) |
36 | cx25840_write(client, 0x127, 0x50); | ||
36 | 37 | ||
37 | if (state->aud_input != CX25840_AUDIO_SERIAL) { | 38 | if (state->aud_input != CX25840_AUDIO_SERIAL) { |
38 | switch (freq) { | 39 | switch (freq) { |
39 | case 32000: | 40 | case 32000: |
41 | if (state->is_cx23885) { | ||
42 | /* We don't have register values | ||
43 | * so avoid destroying registers. */ | ||
44 | break; | ||
45 | } | ||
40 | /* VID_PLL and AUX_PLL */ | 46 | /* VID_PLL and AUX_PLL */ |
41 | cx25840_write4(client, 0x108, 0x1006040f); | 47 | cx25840_write4(client, 0x108, 0x1006040f); |
42 | 48 | ||
@@ -53,6 +59,11 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) | |||
53 | break; | 59 | break; |
54 | 60 | ||
55 | case 44100: | 61 | case 44100: |
62 | if (state->is_cx23885) { | ||
63 | /* We don't have register values | ||
64 | * so avoid destroying registers. */ | ||
65 | break; | ||
66 | } | ||
56 | /* VID_PLL and AUX_PLL */ | 67 | /* VID_PLL and AUX_PLL */ |
57 | cx25840_write4(client, 0x108, 0x1009040f); | 68 | cx25840_write4(client, 0x108, 0x1009040f); |
58 | 69 | ||
@@ -69,6 +80,11 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) | |||
69 | break; | 80 | break; |
70 | 81 | ||
71 | case 48000: | 82 | case 48000: |
83 | if (state->is_cx23885) { | ||
84 | /* We don't have register values | ||
85 | * so avoid destroying registers. */ | ||
86 | break; | ||
87 | } | ||
72 | /* VID_PLL and AUX_PLL */ | 88 | /* VID_PLL and AUX_PLL */ |
73 | cx25840_write4(client, 0x108, 0x100a040f); | 89 | cx25840_write4(client, 0x108, 0x100a040f); |
74 | 90 | ||
@@ -87,6 +103,11 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) | |||
87 | } else { | 103 | } else { |
88 | switch (freq) { | 104 | switch (freq) { |
89 | case 32000: | 105 | case 32000: |
106 | if (state->is_cx23885) { | ||
107 | /* We don't have register values | ||
108 | * so avoid destroying registers. */ | ||
109 | break; | ||
110 | } | ||
90 | /* VID_PLL and AUX_PLL */ | 111 | /* VID_PLL and AUX_PLL */ |
91 | cx25840_write4(client, 0x108, 0x1e08040f); | 112 | cx25840_write4(client, 0x108, 0x1e08040f); |
92 | 113 | ||
@@ -109,6 +130,12 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) | |||
109 | break; | 130 | break; |
110 | 131 | ||
111 | case 44100: | 132 | case 44100: |
133 | if (state->is_cx23885) { | ||
134 | /* We don't have register values | ||
135 | * so avoid destroying registers. */ | ||
136 | break; | ||
137 | } | ||
138 | |||
112 | /* VID_PLL and AUX_PLL */ | 139 | /* VID_PLL and AUX_PLL */ |
113 | cx25840_write4(client, 0x108, 0x1809040f); | 140 | cx25840_write4(client, 0x108, 0x1809040f); |
114 | 141 | ||
@@ -128,22 +155,33 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) | |||
128 | break; | 155 | break; |
129 | 156 | ||
130 | case 48000: | 157 | case 48000: |
131 | /* VID_PLL and AUX_PLL */ | 158 | if (!state->is_cx23885) { |
132 | cx25840_write4(client, 0x108, 0x180a040f); | 159 | /* VID_PLL and AUX_PLL */ |
160 | cx25840_write4(client, 0x108, 0x180a040f); | ||
133 | 161 | ||
134 | /* AUX_PLL_FRAC */ | 162 | /* AUX_PLL_FRAC */ |
135 | cx25840_write4(client, 0x110, 0x0098d6e5); | 163 | cx25840_write4(client, 0x110, 0x0098d6e5); |
164 | } | ||
136 | 165 | ||
137 | if (state->is_cx25836) | 166 | if (state->is_cx25836) |
138 | break; | 167 | break; |
139 | 168 | ||
140 | /* src1_ctl = 0x08010000 */ | 169 | if (!state->is_cx23885) { |
141 | cx25840_write4(client, 0x8f8, 0x08018000); | 170 | /* src1_ctl */ |
171 | cx25840_write4(client, 0x8f8, 0x08018000); | ||
142 | 172 | ||
143 | /* src3/4/6_ctl = 0x08020000 */ | 173 | /* src3/4/6_ctl */ |
144 | cx25840_write4(client, 0x900, 0x08015555); | 174 | cx25840_write4(client, 0x900, 0x08015555); |
145 | cx25840_write4(client, 0x904, 0x08015555); | 175 | cx25840_write4(client, 0x904, 0x08015555); |
146 | cx25840_write4(client, 0x90c, 0x08015555); | 176 | cx25840_write4(client, 0x90c, 0x08015555); |
177 | } else { | ||
178 | |||
179 | cx25840_write4(client, 0x8f8, 0x0801867c); | ||
180 | |||
181 | cx25840_write4(client, 0x900, 0x08014faa); | ||
182 | cx25840_write4(client, 0x904, 0x08014faa); | ||
183 | cx25840_write4(client, 0x90c, 0x08014faa); | ||
184 | } | ||
147 | break; | 185 | break; |
148 | } | 186 | } |
149 | } | 187 | } |
@@ -188,6 +226,11 @@ void cx25840_audio_set_path(struct i2c_client *client) | |||
188 | 226 | ||
189 | /* deassert soft reset */ | 227 | /* deassert soft reset */ |
190 | cx25840_and_or(client, 0x810, ~0x1, 0x00); | 228 | cx25840_and_or(client, 0x810, ~0x1, 0x00); |
229 | |||
230 | if (state->is_cx23885) { | ||
231 | /* Ensure the controller is running when we exit */ | ||
232 | cx25840_and_or(client, 0x803, ~0x10, 0x10); | ||
233 | } | ||
191 | } | 234 | } |
192 | 235 | ||
193 | static int get_volume(struct i2c_client *client) | 236 | static int get_volume(struct i2c_client *client) |
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 0d3d24aff504..756a1eeb274e 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c | |||
@@ -13,6 +13,8 @@ | |||
13 | * NTSC sliced VBI support by Christopher Neufeld <television@cneufeld.ca> | 13 | * NTSC sliced VBI support by Christopher Neufeld <television@cneufeld.ca> |
14 | * with additional fixes by Hans Verkuil <hverkuil@xs4all.nl>. | 14 | * with additional fixes by Hans Verkuil <hverkuil@xs4all.nl>. |
15 | * | 15 | * |
16 | * CX23885 support by Steven Toth <stoth@hauppauge.com>. | ||
17 | * | ||
16 | * This program is free software; you can redistribute it and/or | 18 | * This program is free software; you can redistribute it and/or |
17 | * modify it under the terms of the GNU General Public License | 19 | * modify it under the terms of the GNU General Public License |
18 | * as published by the Free Software Foundation; either version 2 | 20 | * as published by the Free Software Foundation; either version 2 |
@@ -255,6 +257,96 @@ static void cx25840_initialize(struct i2c_client *client) | |||
255 | cx25840_and_or(client, 0x803, ~0x10, 0x10); | 257 | cx25840_and_or(client, 0x803, ~0x10, 0x10); |
256 | } | 258 | } |
257 | 259 | ||
260 | static void cx23885_initialize(struct i2c_client *client) | ||
261 | { | ||
262 | DEFINE_WAIT(wait); | ||
263 | struct cx25840_state *state = i2c_get_clientdata(client); | ||
264 | struct workqueue_struct *q; | ||
265 | |||
266 | /* Internal Reset */ | ||
267 | cx25840_and_or(client, 0x102, ~0x01, 0x01); | ||
268 | cx25840_and_or(client, 0x102, ~0x01, 0x00); | ||
269 | |||
270 | /* Stop microcontroller */ | ||
271 | cx25840_and_or(client, 0x803, ~0x10, 0x00); | ||
272 | |||
273 | /* DIF in reset? */ | ||
274 | cx25840_write(client, 0x398, 0); | ||
275 | |||
276 | /* Trust the default xtal, no division */ | ||
277 | /* This changes for the cx23888 products */ | ||
278 | cx25840_write(client, 0x2, 0x76); | ||
279 | |||
280 | /* Bring down the regulator for AUX clk */ | ||
281 | cx25840_write(client, 0x1, 0x40); | ||
282 | |||
283 | /* Sys PLL frac */ | ||
284 | cx25840_write4(client, 0x11c, 0x01d1744c); | ||
285 | |||
286 | /* Sys PLL int */ | ||
287 | cx25840_write4(client, 0x118, 0x00000416); | ||
288 | |||
289 | /* Disable DIF bypass */ | ||
290 | cx25840_write4(client, 0x33c, 0x00000001); | ||
291 | |||
292 | /* DIF Src phase inc */ | ||
293 | cx25840_write4(client, 0x340, 0x0df7df83); | ||
294 | |||
295 | /* Vid PLL frac */ | ||
296 | cx25840_write4(client, 0x10c, 0x01b6db7b); | ||
297 | |||
298 | /* Vid PLL int */ | ||
299 | cx25840_write4(client, 0x108, 0x00000512); | ||
300 | |||
301 | /* Luma */ | ||
302 | cx25840_write4(client, 0x414, 0x00107d12); | ||
303 | |||
304 | /* Chroma */ | ||
305 | cx25840_write4(client, 0x420, 0x3d008282); | ||
306 | |||
307 | /* Aux PLL frac */ | ||
308 | cx25840_write4(client, 0x114, 0x017dbf48); | ||
309 | |||
310 | /* Aux PLL int */ | ||
311 | cx25840_write4(client, 0x110, 0x000a030e); | ||
312 | |||
313 | /* ADC2 input select */ | ||
314 | cx25840_write(client, 0x102, 0x10); | ||
315 | |||
316 | /* VIN1 & VIN5 */ | ||
317 | cx25840_write(client, 0x103, 0x11); | ||
318 | |||
319 | /* Enable format auto detect */ | ||
320 | cx25840_write(client, 0x400, 0); | ||
321 | /* Fast subchroma lock */ | ||
322 | /* White crush, Chroma AGC & Chroma Killer enabled */ | ||
323 | cx25840_write(client, 0x401, 0xe8); | ||
324 | |||
325 | /* Select AFE clock pad output source */ | ||
326 | cx25840_write(client, 0x144, 0x05); | ||
327 | |||
328 | /* Do the firmware load in a work handler to prevent. | ||
329 | Otherwise the kernel is blocked waiting for the | ||
330 | bit-banging i2c interface to finish uploading the | ||
331 | firmware. */ | ||
332 | INIT_WORK(&state->fw_work, cx25840_work_handler); | ||
333 | init_waitqueue_head(&state->fw_wait); | ||
334 | q = create_singlethread_workqueue("cx25840_fw"); | ||
335 | prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); | ||
336 | queue_work(q, &state->fw_work); | ||
337 | schedule(); | ||
338 | finish_wait(&state->fw_wait, &wait); | ||
339 | destroy_workqueue(q); | ||
340 | |||
341 | cx25840_vbi_setup(client); | ||
342 | |||
343 | /* (re)set input */ | ||
344 | set_input(client, state->vid_input, state->aud_input); | ||
345 | |||
346 | /* start microcontroller */ | ||
347 | cx25840_and_or(client, 0x803, ~0x10, 0x10); | ||
348 | } | ||
349 | |||
258 | /* ----------------------------------------------------------------------- */ | 350 | /* ----------------------------------------------------------------------- */ |
259 | 351 | ||
260 | static void input_change(struct i2c_client *client) | 352 | static void input_change(struct i2c_client *client) |
@@ -318,9 +410,22 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp | |||
318 | vid_input <= CX25840_COMPOSITE8); | 410 | vid_input <= CX25840_COMPOSITE8); |
319 | u8 reg; | 411 | u8 reg; |
320 | 412 | ||
321 | v4l_dbg(1, cx25840_debug, client, "decoder set video input %d, audio input %d\n", | 413 | v4l_dbg(1, cx25840_debug, client, |
322 | vid_input, aud_input); | 414 | "decoder set video input %d, audio input %d\n", |
415 | vid_input, aud_input); | ||
323 | 416 | ||
417 | if (vid_input >= CX25840_VIN1_CH1) { | ||
418 | v4l_dbg(1, cx25840_debug, client, "vid_input 0x%x\n", | ||
419 | vid_input); | ||
420 | reg = vid_input & 0xff; | ||
421 | if ((vid_input & CX25840_SVIDEO_ON) == CX25840_SVIDEO_ON) | ||
422 | is_composite = 0; | ||
423 | else | ||
424 | is_composite = 1; | ||
425 | |||
426 | v4l_dbg(1, cx25840_debug, client, "mux cfg 0x%x comp=%d\n", | ||
427 | reg, is_composite); | ||
428 | } else | ||
324 | if (is_composite) { | 429 | if (is_composite) { |
325 | reg = 0xf0 + (vid_input - CX25840_COMPOSITE1); | 430 | reg = 0xf0 + (vid_input - CX25840_COMPOSITE1); |
326 | } else { | 431 | } else { |
@@ -330,7 +435,8 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp | |||
330 | if ((vid_input & ~0xff0) || | 435 | if ((vid_input & ~0xff0) || |
331 | luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA4 || | 436 | luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA4 || |
332 | chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) { | 437 | chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) { |
333 | v4l_err(client, "0x%04x is not a valid video input!\n", vid_input); | 438 | v4l_err(client, "0x%04x is not a valid video input!\n", |
439 | vid_input); | ||
334 | return -EINVAL; | 440 | return -EINVAL; |
335 | } | 441 | } |
336 | reg = 0xf0 + ((luma - CX25840_SVIDEO_LUMA1) >> 4); | 442 | reg = 0xf0 + ((luma - CX25840_SVIDEO_LUMA1) >> 4); |
@@ -343,31 +449,49 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp | |||
343 | } | 449 | } |
344 | } | 450 | } |
345 | 451 | ||
346 | switch (aud_input) { | 452 | /* The caller has previously prepared the correct routing |
347 | case CX25840_AUDIO_SERIAL: | 453 | * configuration in reg (for the cx23885) so we have no |
348 | /* do nothing, use serial audio input */ | 454 | * need to attempt to flip bits for earlier av decoders. |
349 | break; | 455 | */ |
350 | case CX25840_AUDIO4: reg &= ~0x30; break; | 456 | if (!state->is_cx23885) { |
351 | case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break; | 457 | switch (aud_input) { |
352 | case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break; | 458 | case CX25840_AUDIO_SERIAL: |
353 | case CX25840_AUDIO7: reg &= ~0xc0; break; | 459 | /* do nothing, use serial audio input */ |
354 | case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break; | 460 | break; |
461 | case CX25840_AUDIO4: reg &= ~0x30; break; | ||
462 | case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break; | ||
463 | case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break; | ||
464 | case CX25840_AUDIO7: reg &= ~0xc0; break; | ||
465 | case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break; | ||
355 | 466 | ||
356 | default: | 467 | default: |
357 | v4l_err(client, "0x%04x is not a valid audio input!\n", aud_input); | 468 | v4l_err(client, "0x%04x is not a valid audio input!\n", |
358 | return -EINVAL; | 469 | aud_input); |
470 | return -EINVAL; | ||
471 | } | ||
359 | } | 472 | } |
360 | 473 | ||
361 | cx25840_write(client, 0x103, reg); | 474 | cx25840_write(client, 0x103, reg); |
475 | |||
362 | /* Set INPUT_MODE to Composite (0) or S-Video (1) */ | 476 | /* Set INPUT_MODE to Composite (0) or S-Video (1) */ |
363 | cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02); | 477 | cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02); |
364 | /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ | 478 | |
365 | cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); | 479 | if (!state->is_cx23885) { |
366 | /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */ | 480 | /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ |
367 | if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30) | 481 | cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); |
368 | cx25840_and_or(client, 0x102, ~0x4, 4); | 482 | /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2&CH3 */ |
369 | else | 483 | if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30) |
370 | cx25840_and_or(client, 0x102, ~0x4, 0); | 484 | cx25840_and_or(client, 0x102, ~0x4, 4); |
485 | else | ||
486 | cx25840_and_or(client, 0x102, ~0x4, 0); | ||
487 | } else { | ||
488 | if (is_composite) | ||
489 | /* ADC2 input select channel 2 */ | ||
490 | cx25840_and_or(client, 0x102, ~0x2, 0); | ||
491 | else | ||
492 | /* ADC2 input select channel 3 */ | ||
493 | cx25840_and_or(client, 0x102, ~0x2, 2); | ||
494 | } | ||
371 | 495 | ||
372 | state->vid_input = vid_input; | 496 | state->vid_input = vid_input; |
373 | state->aud_input = aud_input; | 497 | state->aud_input = aud_input; |
@@ -375,6 +499,25 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp | |||
375 | cx25840_audio_set_path(client); | 499 | cx25840_audio_set_path(client); |
376 | input_change(client); | 500 | input_change(client); |
377 | } | 501 | } |
502 | |||
503 | if (state->is_cx23885) { | ||
504 | /* Audio channel 1 src : Parallel 1 */ | ||
505 | cx25840_write(client, 0x124, 0x03); | ||
506 | |||
507 | /* Select AFE clock pad output source */ | ||
508 | cx25840_write(client, 0x144, 0x05); | ||
509 | |||
510 | /* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */ | ||
511 | cx25840_write(client, 0x914, 0xa0); | ||
512 | |||
513 | /* I2S_OUT_CTL: | ||
514 | * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 | ||
515 | * I2S_OUT_MASTER_MODE = Master | ||
516 | */ | ||
517 | cx25840_write(client, 0x918, 0xa0); | ||
518 | cx25840_write(client, 0x919, 0x01); | ||
519 | } | ||
520 | |||
378 | return 0; | 521 | return 0; |
379 | } | 522 | } |
380 | 523 | ||
@@ -853,6 +996,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, | |||
853 | state->is_initialized = 1; | 996 | state->is_initialized = 1; |
854 | if (state->is_cx25836) | 997 | if (state->is_cx25836) |
855 | cx25836_initialize(client); | 998 | cx25836_initialize(client); |
999 | else if (state->is_cx23885) | ||
1000 | cx23885_initialize(client); | ||
856 | else | 1001 | else |
857 | cx25840_initialize(client); | 1002 | cx25840_initialize(client); |
858 | } | 1003 | } |
@@ -870,6 +1015,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, | |||
870 | return -EINVAL; | 1015 | return -EINVAL; |
871 | if (!capable(CAP_SYS_ADMIN)) | 1016 | if (!capable(CAP_SYS_ADMIN)) |
872 | return -EPERM; | 1017 | return -EPERM; |
1018 | |||
873 | if (cmd == VIDIOC_DBG_G_REGISTER) | 1019 | if (cmd == VIDIOC_DBG_G_REGISTER) |
874 | reg->val = cx25840_read(client, reg->reg & 0x0fff); | 1020 | reg->val = cx25840_read(client, reg->reg & 0x0fff); |
875 | else | 1021 | else |
@@ -886,14 +1032,26 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, | |||
886 | 1032 | ||
887 | case VIDIOC_STREAMON: | 1033 | case VIDIOC_STREAMON: |
888 | v4l_dbg(1, cx25840_debug, client, "enable output\n"); | 1034 | v4l_dbg(1, cx25840_debug, client, "enable output\n"); |
889 | cx25840_write(client, 0x115, state->is_cx25836 ? 0x0c : 0x8c); | 1035 | if (state->is_cx23885) { |
890 | cx25840_write(client, 0x116, state->is_cx25836 ? 0x04 : 0x07); | 1036 | u8 v = (cx25840_read(client, 0x421) | 0x0b); |
1037 | cx25840_write(client, 0x421, v); | ||
1038 | } else { | ||
1039 | cx25840_write(client, 0x115, | ||
1040 | state->is_cx25836 ? 0x0c : 0x8c); | ||
1041 | cx25840_write(client, 0x116, | ||
1042 | state->is_cx25836 ? 0x04 : 0x07); | ||
1043 | } | ||
891 | break; | 1044 | break; |
892 | 1045 | ||
893 | case VIDIOC_STREAMOFF: | 1046 | case VIDIOC_STREAMOFF: |
894 | v4l_dbg(1, cx25840_debug, client, "disable output\n"); | 1047 | v4l_dbg(1, cx25840_debug, client, "disable output\n"); |
895 | cx25840_write(client, 0x115, 0x00); | 1048 | if (state->is_cx23885) { |
896 | cx25840_write(client, 0x116, 0x00); | 1049 | u8 v = cx25840_read(client, 0x421) & ~(0x0b); |
1050 | cx25840_write(client, 0x421, v); | ||
1051 | } else { | ||
1052 | cx25840_write(client, 0x115, 0x00); | ||
1053 | cx25840_write(client, 0x116, 0x00); | ||
1054 | } | ||
897 | break; | 1055 | break; |
898 | 1056 | ||
899 | case VIDIOC_LOG_STATUS: | 1057 | case VIDIOC_LOG_STATUS: |
@@ -1056,6 +1214,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, | |||
1056 | case VIDIOC_INT_RESET: | 1214 | case VIDIOC_INT_RESET: |
1057 | if (state->is_cx25836) | 1215 | if (state->is_cx25836) |
1058 | cx25836_initialize(client); | 1216 | cx25836_initialize(client); |
1217 | else if (state->is_cx23885) | ||
1218 | cx23885_initialize(client); | ||
1059 | else | 1219 | else |
1060 | cx25840_initialize(client); | 1220 | cx25840_initialize(client); |
1061 | break; | 1221 | break; |
@@ -1086,6 +1246,7 @@ static int cx25840_probe(struct i2c_client *client) | |||
1086 | 1246 | ||
1087 | device_id = cx25840_read(client, 0x101) << 8; | 1247 | device_id = cx25840_read(client, 0x101) << 8; |
1088 | device_id |= cx25840_read(client, 0x100); | 1248 | device_id |= cx25840_read(client, 0x100); |
1249 | v4l_dbg(1, cx25840_debug, client, "device_id = 0x%04x\n", device_id); | ||
1089 | 1250 | ||
1090 | /* The high byte of the device ID should be | 1251 | /* The high byte of the device ID should be |
1091 | * 0x83 for the cx2583x and 0x84 for the cx2584x */ | 1252 | * 0x83 for the cx2583x and 0x84 for the cx2584x */ |
@@ -1094,6 +1255,10 @@ static int cx25840_probe(struct i2c_client *client) | |||
1094 | } | 1255 | } |
1095 | else if ((device_id & 0xff00) == 0x8400) { | 1256 | else if ((device_id & 0xff00) == 0x8400) { |
1096 | id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf); | 1257 | id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf); |
1258 | } else if (device_id == 0x0000) { | ||
1259 | id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; | ||
1260 | } else if (device_id == 0x1313) { | ||
1261 | id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; | ||
1097 | } | 1262 | } |
1098 | else { | 1263 | else { |
1099 | v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); | 1264 | v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); |
@@ -1115,6 +1280,7 @@ static int cx25840_probe(struct i2c_client *client) | |||
1115 | i2c_set_clientdata(client, state); | 1280 | i2c_set_clientdata(client, state); |
1116 | state->c = client; | 1281 | state->c = client; |
1117 | state->is_cx25836 = ((device_id & 0xff00) == 0x8300); | 1282 | state->is_cx25836 = ((device_id & 0xff00) == 0x8300); |
1283 | state->is_cx23885 = (device_id == 0x0000) || (device_id == 0x1313); | ||
1118 | state->vid_input = CX25840_COMPOSITE7; | 1284 | state->vid_input = CX25840_COMPOSITE7; |
1119 | state->aud_input = CX25840_AUDIO8; | 1285 | state->aud_input = CX25840_AUDIO8; |
1120 | state->audclk_freq = 48000; | 1286 | state->audclk_freq = 48000; |
@@ -1124,6 +1290,7 @@ static int cx25840_probe(struct i2c_client *client) | |||
1124 | state->vbi_line_offset = 8; | 1290 | state->vbi_line_offset = 8; |
1125 | state->id = id; | 1291 | state->id = id; |
1126 | state->rev = device_id; | 1292 | state->rev = device_id; |
1293 | |||
1127 | return 0; | 1294 | return 0; |
1128 | } | 1295 | } |
1129 | 1296 | ||
diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h index ea669b1f084d..95093edc9186 100644 --- a/drivers/media/video/cx25840/cx25840-core.h +++ b/drivers/media/video/cx25840/cx25840-core.h | |||
@@ -47,6 +47,7 @@ struct cx25840_state { | |||
47 | u32 id; | 47 | u32 id; |
48 | u32 rev; | 48 | u32 rev; |
49 | int is_cx25836; | 49 | int is_cx25836; |
50 | int is_cx23885; | ||
50 | int is_initialized; | 51 | int is_initialized; |
51 | wait_queue_head_t fw_wait; /* wake up when the fw load is finished */ | 52 | wait_queue_head_t fw_wait; /* wake up when the fw load is finished */ |
52 | struct work_struct fw_work; /* work entry for fw load */ | 53 | struct work_struct fw_work; /* work entry for fw load */ |
diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c index e852024a5ea3..1ddf724a2c74 100644 --- a/drivers/media/video/cx25840/cx25840-firmware.c +++ b/drivers/media/video/cx25840/cx25840-firmware.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include "cx25840-core.h" | 24 | #include "cx25840-core.h" |
25 | 25 | ||
26 | #define FWFILE "v4l-cx25840.fw" | 26 | #define FWFILE "v4l-cx25840.fw" |
27 | #define FWFILE_CX23885 "v4l-cx23885-avcore-01.fw" | ||
27 | 28 | ||
28 | /* | 29 | /* |
29 | * Mike Isely <isely@pobox.com> - The FWSEND parameter controls the | 30 | * Mike Isely <isely@pobox.com> - The FWSEND parameter controls the |
@@ -92,10 +93,14 @@ static int fw_write(struct i2c_client *client, u8 * data, int size) | |||
92 | 93 | ||
93 | int cx25840_loadfw(struct i2c_client *client) | 94 | int cx25840_loadfw(struct i2c_client *client) |
94 | { | 95 | { |
96 | struct cx25840_state *state = i2c_get_clientdata(client); | ||
95 | const struct firmware *fw = NULL; | 97 | const struct firmware *fw = NULL; |
96 | u8 buffer[4], *ptr; | 98 | u8 buffer[4], *ptr; |
97 | int size, send, retval; | 99 | int size, send, retval; |
98 | 100 | ||
101 | if (state->is_cx23885) | ||
102 | firmware = FWFILE_CX23885; | ||
103 | |||
99 | if (request_firmware(&fw, firmware, FWDEV(client)) != 0) { | 104 | if (request_firmware(&fw, firmware, FWDEV(client)) != 0) { |
100 | v4l_err(client, "unable to open firmware %s\n", firmware); | 105 | v4l_err(client, "unable to open firmware %s\n", firmware); |
101 | return -EINVAL; | 106 | return -EINVAL; |