aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-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;