aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx25840
diff options
context:
space:
mode:
authorSteven Toth <stoth@hauppauge.com>2008-01-09 23:22:39 -0500
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-01-25 16:04:47 -0500
commitf234081bc564c69eb0e2cd4e957ad1cbae4a6144 (patch)
tree4dd6400872df3f73e4f4b63c7303564fe3264c1d /drivers/media/video/cx25840
parentd05051c82e0e8ff748e9c9a06a061bda3ad656e5 (diff)
V4L/DVB (7002): cx25840: Add basic CX23885 AVCore support
The cx23885/7/8 PCIe bridge has an internal AVCore modelled on the cx2584x family. Many of the registers positions are identical but some moved. The register values are also different because the different bridges run at different clock rates. Signed-off-by: Steven Toth <stoth@hauppauge.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/cx25840')
-rw-r--r--drivers/media/video/cx25840/cx25840-audio.c65
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c219
-rw-r--r--drivers/media/video/cx25840/cx25840-core.h1
-rw-r--r--drivers/media/video/cx25840/cx25840-firmware.c5
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
193static int get_volume(struct i2c_client *client) 236static 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
260static 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
260static void input_change(struct i2c_client *client) 352static 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
93int cx25840_loadfw(struct i2c_client *client) 94int 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;