aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx25840
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/cx25840')
-rw-r--r--drivers/media/video/cx25840/cx25840-audio.c66
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c185
-rw-r--r--drivers/media/video/cx25840/cx25840-core.h1
-rw-r--r--drivers/media/video/cx25840/cx25840-firmware.c11
4 files changed, 191 insertions, 72 deletions
diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c
index 93d74bee292..2f846f5e0f9 100644
--- a/drivers/media/video/cx25840/cx25840-audio.c
+++ b/drivers/media/video/cx25840/cx25840-audio.c
@@ -32,7 +32,7 @@ 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 if (!state->is_cx23885) 35 if (!state->is_cx23885 && !state->is_cx231xx)
36 cx25840_write(client, 0x127, 0x50); 36 cx25840_write(client, 0x127, 0x50);
37 37
38 if (state->aud_input != CX25840_AUDIO_SERIAL) { 38 if (state->aud_input != CX25840_AUDIO_SERIAL) {
@@ -43,11 +43,14 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
43 * so avoid destroying registers. */ 43 * so avoid destroying registers. */
44 break; 44 break;
45 } 45 }
46 /* VID_PLL and AUX_PLL */
47 cx25840_write4(client, 0x108, 0x1006040f);
48 46
49 /* AUX_PLL_FRAC */ 47 if (!state->is_cx231xx) {
50 cx25840_write4(client, 0x110, 0x01bb39ee); 48 /* VID_PLL and AUX_PLL */
49 cx25840_write4(client, 0x108, 0x1006040f);
50
51 /* AUX_PLL_FRAC */
52 cx25840_write4(client, 0x110, 0x01bb39ee);
53 }
51 54
52 if (state->is_cx25836) 55 if (state->is_cx25836)
53 break; 56 break;
@@ -64,11 +67,14 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
64 * so avoid destroying registers. */ 67 * so avoid destroying registers. */
65 break; 68 break;
66 } 69 }
67 /* VID_PLL and AUX_PLL */
68 cx25840_write4(client, 0x108, 0x1009040f);
69 70
70 /* AUX_PLL_FRAC */ 71 if (!state->is_cx231xx) {
71 cx25840_write4(client, 0x110, 0x00ec6bd6); 72 /* VID_PLL and AUX_PLL */
73 cx25840_write4(client, 0x108, 0x1009040f);
74
75 /* AUX_PLL_FRAC */
76 cx25840_write4(client, 0x110, 0x00ec6bd6);
77 }
72 78
73 if (state->is_cx25836) 79 if (state->is_cx25836)
74 break; 80 break;
@@ -85,11 +91,14 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
85 * so avoid destroying registers. */ 91 * so avoid destroying registers. */
86 break; 92 break;
87 } 93 }
88 /* VID_PLL and AUX_PLL */
89 cx25840_write4(client, 0x108, 0x100a040f);
90 94
91 /* AUX_PLL_FRAC */ 95 if (!state->is_cx231xx) {
92 cx25840_write4(client, 0x110, 0x0098d6e5); 96 /* VID_PLL and AUX_PLL */
97 cx25840_write4(client, 0x108, 0x100a040f);
98
99 /* AUX_PLL_FRAC */
100 cx25840_write4(client, 0x110, 0x0098d6e5);
101 }
93 102
94 if (state->is_cx25836) 103 if (state->is_cx25836)
95 break; 104 break;
@@ -108,11 +117,14 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
108 * so avoid destroying registers. */ 117 * so avoid destroying registers. */
109 break; 118 break;
110 } 119 }
111 /* VID_PLL and AUX_PLL */
112 cx25840_write4(client, 0x108, 0x1e08040f);
113 120
114 /* AUX_PLL_FRAC */ 121 if (!state->is_cx231xx) {
115 cx25840_write4(client, 0x110, 0x012a0869); 122 /* VID_PLL and AUX_PLL */
123 cx25840_write4(client, 0x108, 0x1e08040f);
124
125 /* AUX_PLL_FRAC */
126 cx25840_write4(client, 0x110, 0x012a0869);
127 }
116 128
117 if (state->is_cx25836) 129 if (state->is_cx25836)
118 break; 130 break;
@@ -136,11 +148,14 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
136 break; 148 break;
137 } 149 }
138 150
139 /* VID_PLL and AUX_PLL */
140 cx25840_write4(client, 0x108, 0x1809040f);
141 151
142 /* AUX_PLL_FRAC */ 152 if (!state->is_cx231xx) {
143 cx25840_write4(client, 0x110, 0x00ec6bd6); 153 /* VID_PLL and AUX_PLL */
154 cx25840_write4(client, 0x108, 0x1809040f);
155
156 /* AUX_PLL_FRAC */
157 cx25840_write4(client, 0x110, 0x00ec6bd6);
158 }
144 159
145 if (state->is_cx25836) 160 if (state->is_cx25836)
146 break; 161 break;
@@ -155,7 +170,7 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
155 break; 170 break;
156 171
157 case 48000: 172 case 48000:
158 if (!state->is_cx23885) { 173 if (!state->is_cx23885 && !state->is_cx231xx) {
159 /* VID_PLL and AUX_PLL */ 174 /* VID_PLL and AUX_PLL */
160 cx25840_write4(client, 0x108, 0x180a040f); 175 cx25840_write4(client, 0x108, 0x180a040f);
161 176
@@ -166,7 +181,7 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
166 if (state->is_cx25836) 181 if (state->is_cx25836)
167 break; 182 break;
168 183
169 if (!state->is_cx23885) { 184 if (!state->is_cx23885 && !state->is_cx231xx) {
170 /* src1_ctl */ 185 /* src1_ctl */
171 cx25840_write4(client, 0x8f8, 0x08018000); 186 cx25840_write4(client, 0x8f8, 0x08018000);
172 187
@@ -227,10 +242,9 @@ void cx25840_audio_set_path(struct i2c_client *client)
227 /* deassert soft reset */ 242 /* deassert soft reset */
228 cx25840_and_or(client, 0x810, ~0x1, 0x00); 243 cx25840_and_or(client, 0x810, ~0x1, 0x00);
229 244
230 if (state->is_cx23885) { 245 /* Ensure the controller is running when we exit */
231 /* Ensure the controller is running when we exit */ 246 if (state->is_cx23885 || state->is_cx231xx)
232 cx25840_and_or(client, 0x803, ~0x10, 0x10); 247 cx25840_and_or(client, 0x803, ~0x10, 0x10);
233 }
234} 248}
235 249
236static int get_volume(struct i2c_client *client) 250static 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 737ee4ea883..0be51b65f09 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -345,6 +345,77 @@ static void cx23885_initialize(struct i2c_client *client)
345 345
346/* ----------------------------------------------------------------------- */ 346/* ----------------------------------------------------------------------- */
347 347
348static void cx231xx_initialize(struct i2c_client *client)
349{
350 DEFINE_WAIT(wait);
351 struct cx25840_state *state = to_state(i2c_get_clientdata(client));
352 struct workqueue_struct *q;
353
354 /* Internal Reset */
355 cx25840_and_or(client, 0x102, ~0x01, 0x01);
356 cx25840_and_or(client, 0x102, ~0x01, 0x00);
357
358 /* Stop microcontroller */
359 cx25840_and_or(client, 0x803, ~0x10, 0x00);
360
361 /* DIF in reset? */
362 cx25840_write(client, 0x398, 0);
363
364 /* Trust the default xtal, no division */
365 /* This changes for the cx23888 products */
366 cx25840_write(client, 0x2, 0x76);
367
368 /* Bring down the regulator for AUX clk */
369 cx25840_write(client, 0x1, 0x40);
370
371 /* Disable DIF bypass */
372 cx25840_write4(client, 0x33c, 0x00000001);
373
374 /* DIF Src phase inc */
375 cx25840_write4(client, 0x340, 0x0df7df83);
376
377 /* Luma */
378 cx25840_write4(client, 0x414, 0x00107d12);
379
380 /* Chroma */
381 cx25840_write4(client, 0x420, 0x3d008282);
382
383 /* ADC2 input select */
384 cx25840_write(client, 0x102, 0x10);
385
386 /* VIN1 & VIN5 */
387 cx25840_write(client, 0x103, 0x11);
388
389 /* Enable format auto detect */
390 cx25840_write(client, 0x400, 0);
391 /* Fast subchroma lock */
392 /* White crush, Chroma AGC & Chroma Killer enabled */
393 cx25840_write(client, 0x401, 0xe8);
394
395 /* Do the firmware load in a work handler to prevent.
396 Otherwise the kernel is blocked waiting for the
397 bit-banging i2c interface to finish uploading the
398 firmware. */
399 INIT_WORK(&state->fw_work, cx25840_work_handler);
400 init_waitqueue_head(&state->fw_wait);
401 q = create_singlethread_workqueue("cx25840_fw");
402 prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
403 queue_work(q, &state->fw_work);
404 schedule();
405 finish_wait(&state->fw_wait, &wait);
406 destroy_workqueue(q);
407
408 cx25840_std_setup(client);
409
410 /* (re)set input */
411 set_input(client, state->vid_input, state->aud_input);
412
413 /* start microcontroller */
414 cx25840_and_or(client, 0x803, ~0x10, 0x10);
415}
416
417/* ----------------------------------------------------------------------- */
418
348void cx25840_std_setup(struct i2c_client *client) 419void cx25840_std_setup(struct i2c_client *client)
349{ 420{
350 struct cx25840_state *state = to_state(i2c_get_clientdata(client)); 421 struct cx25840_state *state = to_state(i2c_get_clientdata(client));
@@ -414,39 +485,41 @@ void cx25840_std_setup(struct i2c_client *client)
414 } 485 }
415 486
416 /* DEBUG: Displays configured PLL frequency */ 487 /* DEBUG: Displays configured PLL frequency */
417 pll_int = cx25840_read(client, 0x108); 488 if (!state->is_cx231xx) {
418 pll_frac = cx25840_read4(client, 0x10c) & 0x1ffffff; 489 pll_int = cx25840_read(client, 0x108);
419 pll_post = cx25840_read(client, 0x109); 490 pll_frac = cx25840_read4(client, 0x10c) & 0x1ffffff;
420 v4l_dbg(1, cx25840_debug, client, 491 pll_post = cx25840_read(client, 0x109);
421 "PLL regs = int: %u, frac: %u, post: %u\n",
422 pll_int, pll_frac, pll_post);
423
424 if (pll_post) {
425 int fin, fsc;
426 int pll = (28636363L * ((((u64)pll_int) << 25L) + pll_frac)) >> 25L;
427
428 pll /= pll_post;
429 v4l_dbg(1, cx25840_debug, client, "PLL = %d.%06d MHz\n",
430 pll / 1000000, pll % 1000000);
431 v4l_dbg(1, cx25840_debug, client, "PLL/8 = %d.%06d MHz\n",
432 pll / 8000000, (pll / 8) % 1000000);
433
434 fin = ((u64)src_decimation * pll) >> 12;
435 v4l_dbg(1, cx25840_debug, client,
436 "ADC Sampling freq = %d.%06d MHz\n",
437 fin / 1000000, fin % 1000000);
438
439 fsc = (((u64)sc) * pll) >> 24L;
440 v4l_dbg(1, cx25840_debug, client, 492 v4l_dbg(1, cx25840_debug, client,
441 "Chroma sub-carrier freq = %d.%06d MHz\n", 493 "PLL regs = int: %u, frac: %u, post: %u\n",
442 fsc / 1000000, fsc % 1000000); 494 pll_int, pll_frac, pll_post);
443 495
444 v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, " 496 if (pll_post) {
445 "vblank %i, vactive %i, vblank656 %i, src_dec %i, " 497 int fin, fsc;
446 "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x, " 498 int pll = (28636363L * ((((u64)pll_int) << 25L) + pll_frac)) >> 25L;
447 "sc 0x%06x\n", 499
448 hblank, hactive, vblank, vactive, vblank656, 500 pll /= pll_post;
449 src_decimation, burst, luma_lpf, uv_lpf, comb, sc); 501 v4l_dbg(1, cx25840_debug, client, "PLL = %d.%06d MHz\n",
502 pll / 1000000, pll % 1000000);
503 v4l_dbg(1, cx25840_debug, client, "PLL/8 = %d.%06d MHz\n",
504 pll / 8000000, (pll / 8) % 1000000);
505
506 fin = ((u64)src_decimation * pll) >> 12;
507 v4l_dbg(1, cx25840_debug, client,
508 "ADC Sampling freq = %d.%06d MHz\n",
509 fin / 1000000, fin % 1000000);
510
511 fsc = (((u64)sc) * pll) >> 24L;
512 v4l_dbg(1, cx25840_debug, client,
513 "Chroma sub-carrier freq = %d.%06d MHz\n",
514 fsc / 1000000, fsc % 1000000);
515
516 v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, "
517 "vblank %i, vactive %i, vblank656 %i, src_dec %i, "
518 "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x, "
519 "sc 0x%06x\n",
520 hblank, hactive, vblank, vactive, vblank656,
521 src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
522 }
450 } 523 }
451 524
452 /* Sets horizontal blanking delay and active lines */ 525 /* Sets horizontal blanking delay and active lines */
@@ -596,7 +669,7 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
596 * configuration in reg (for the cx23885) so we have no 669 * configuration in reg (for the cx23885) so we have no
597 * need to attempt to flip bits for earlier av decoders. 670 * need to attempt to flip bits for earlier av decoders.
598 */ 671 */
599 if (!state->is_cx23885) { 672 if (!state->is_cx23885 && !state->is_cx231xx) {
600 switch (aud_input) { 673 switch (aud_input) {
601 case CX25840_AUDIO_SERIAL: 674 case CX25840_AUDIO_SERIAL:
602 /* do nothing, use serial audio input */ 675 /* do nothing, use serial audio input */
@@ -619,7 +692,7 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
619 /* Set INPUT_MODE to Composite (0) or S-Video (1) */ 692 /* Set INPUT_MODE to Composite (0) or S-Video (1) */
620 cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02); 693 cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02);
621 694
622 if (!state->is_cx23885) { 695 if (!state->is_cx23885 && !state->is_cx231xx) {
623 /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ 696 /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
624 cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); 697 cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
625 /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2&CH3 */ 698 /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2&CH3 */
@@ -659,6 +732,19 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
659 */ 732 */
660 cx25840_write(client, 0x918, 0xa0); 733 cx25840_write(client, 0x918, 0xa0);
661 cx25840_write(client, 0x919, 0x01); 734 cx25840_write(client, 0x919, 0x01);
735 } else if (state->is_cx231xx) {
736 /* Audio channel 1 src : Parallel 1 */
737 cx25840_write(client, 0x124, 0x03);
738
739 /* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */
740 cx25840_write(client, 0x914, 0xa0);
741
742 /* I2S_OUT_CTL:
743 * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1
744 * I2S_OUT_MASTER_MODE = Master
745 */
746 cx25840_write(client, 0x918, 0xa0);
747 cx25840_write(client, 0x919, 0x01);
662 } 748 }
663 749
664 return 0; 750 return 0;
@@ -1096,7 +1182,7 @@ static void log_audio_status(struct i2c_client *client)
1096 1182
1097/* ----------------------------------------------------------------------- */ 1183/* ----------------------------------------------------------------------- */
1098 1184
1099/* This init operation must be called to load the driver's firmware. 1185/* This load_fw operation must be called to load the driver's firmware.
1100 Without this the audio standard detection will fail and you will 1186 Without this the audio standard detection will fail and you will
1101 only get mono. 1187 only get mono.
1102 1188
@@ -1106,18 +1192,20 @@ static void log_audio_status(struct i2c_client *client)
1106 postponing it is that loading this firmware takes a long time (seconds) 1192 postponing it is that loading this firmware takes a long time (seconds)
1107 due to the slow i2c bus speed. So it will speed up the boot process if 1193 due to the slow i2c bus speed. So it will speed up the boot process if
1108 you can avoid loading the fw as long as the video device isn't used. */ 1194 you can avoid loading the fw as long as the video device isn't used. */
1109static int cx25840_init(struct v4l2_subdev *sd, u32 val) 1195static int cx25840_load_fw(struct v4l2_subdev *sd)
1110{ 1196{
1111 struct cx25840_state *state = to_state(sd); 1197 struct cx25840_state *state = to_state(sd);
1112 struct i2c_client *client = v4l2_get_subdevdata(sd); 1198 struct i2c_client *client = v4l2_get_subdevdata(sd);
1113 1199
1114 if (!state->is_initialized) { 1200 if (!state->is_initialized) {
1115 /* initialize on first use */ 1201 /* initialize and load firmware */
1116 state->is_initialized = 1; 1202 state->is_initialized = 1;
1117 if (state->is_cx25836) 1203 if (state->is_cx25836)
1118 cx25836_initialize(client); 1204 cx25836_initialize(client);
1119 else if (state->is_cx23885) 1205 else if (state->is_cx23885)
1120 cx23885_initialize(client); 1206 cx23885_initialize(client);
1207 else if (state->is_cx231xx)
1208 cx231xx_initialize(client);
1121 else 1209 else
1122 cx25840_initialize(client); 1210 cx25840_initialize(client);
1123 } 1211 }
@@ -1159,7 +1247,7 @@ static int cx25840_s_stream(struct v4l2_subdev *sd, int enable)
1159 v4l_dbg(1, cx25840_debug, client, "%s output\n", 1247 v4l_dbg(1, cx25840_debug, client, "%s output\n",
1160 enable ? "enable" : "disable"); 1248 enable ? "enable" : "disable");
1161 if (enable) { 1249 if (enable) {
1162 if (state->is_cx23885) { 1250 if (state->is_cx23885 || state->is_cx231xx) {
1163 u8 v = (cx25840_read(client, 0x421) | 0x0b); 1251 u8 v = (cx25840_read(client, 0x421) | 0x0b);
1164 cx25840_write(client, 0x421, v); 1252 cx25840_write(client, 0x421, v);
1165 } else { 1253 } else {
@@ -1169,7 +1257,7 @@ static int cx25840_s_stream(struct v4l2_subdev *sd, int enable)
1169 state->is_cx25836 ? 0x04 : 0x07); 1257 state->is_cx25836 ? 0x04 : 0x07);
1170 } 1258 }
1171 } else { 1259 } else {
1172 if (state->is_cx23885) { 1260 if (state->is_cx23885 || state->is_cx231xx) {
1173 u8 v = cx25840_read(client, 0x421) & ~(0x0b); 1261 u8 v = cx25840_read(client, 0x421) & ~(0x0b);
1174 cx25840_write(client, 0x421, v); 1262 cx25840_write(client, 0x421, v);
1175 } else { 1263 } else {
@@ -1234,22 +1322,24 @@ static int cx25840_s_radio(struct v4l2_subdev *sd)
1234 return 0; 1322 return 0;
1235} 1323}
1236 1324
1237static int cx25840_s_video_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route) 1325static int cx25840_s_video_routing(struct v4l2_subdev *sd,
1326 u32 input, u32 output, u32 config)
1238{ 1327{
1239 struct cx25840_state *state = to_state(sd); 1328 struct cx25840_state *state = to_state(sd);
1240 struct i2c_client *client = v4l2_get_subdevdata(sd); 1329 struct i2c_client *client = v4l2_get_subdevdata(sd);
1241 1330
1242 return set_input(client, route->input, state->aud_input); 1331 return set_input(client, input, state->aud_input);
1243} 1332}
1244 1333
1245static int cx25840_s_audio_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route) 1334static int cx25840_s_audio_routing(struct v4l2_subdev *sd,
1335 u32 input, u32 output, u32 config)
1246{ 1336{
1247 struct cx25840_state *state = to_state(sd); 1337 struct cx25840_state *state = to_state(sd);
1248 struct i2c_client *client = v4l2_get_subdevdata(sd); 1338 struct i2c_client *client = v4l2_get_subdevdata(sd);
1249 1339
1250 if (state->is_cx25836) 1340 if (state->is_cx25836)
1251 return -EINVAL; 1341 return -EINVAL;
1252 return set_input(client, state->vid_input, route->input); 1342 return set_input(client, state->vid_input, input);
1253} 1343}
1254 1344
1255static int cx25840_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) 1345static int cx25840_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
@@ -1350,6 +1440,8 @@ static int cx25840_reset(struct v4l2_subdev *sd, u32 val)
1350 cx25836_initialize(client); 1440 cx25836_initialize(client);
1351 else if (state->is_cx23885) 1441 else if (state->is_cx23885)
1352 cx23885_initialize(client); 1442 cx23885_initialize(client);
1443 else if (state->is_cx231xx)
1444 cx231xx_initialize(client);
1353 else 1445 else
1354 cx25840_initialize(client); 1446 cx25840_initialize(client);
1355 return 0; 1447 return 0;
@@ -1382,8 +1474,9 @@ static const struct v4l2_subdev_core_ops cx25840_core_ops = {
1382 .g_ctrl = cx25840_g_ctrl, 1474 .g_ctrl = cx25840_g_ctrl,
1383 .s_ctrl = cx25840_s_ctrl, 1475 .s_ctrl = cx25840_s_ctrl,
1384 .queryctrl = cx25840_queryctrl, 1476 .queryctrl = cx25840_queryctrl,
1477 .s_std = cx25840_s_std,
1385 .reset = cx25840_reset, 1478 .reset = cx25840_reset,
1386 .init = cx25840_init, 1479 .load_fw = cx25840_load_fw,
1387#ifdef CONFIG_VIDEO_ADV_DEBUG 1480#ifdef CONFIG_VIDEO_ADV_DEBUG
1388 .g_register = cx25840_g_register, 1481 .g_register = cx25840_g_register,
1389 .s_register = cx25840_s_register, 1482 .s_register = cx25840_s_register,
@@ -1392,7 +1485,6 @@ static const struct v4l2_subdev_core_ops cx25840_core_ops = {
1392 1485
1393static const struct v4l2_subdev_tuner_ops cx25840_tuner_ops = { 1486static const struct v4l2_subdev_tuner_ops cx25840_tuner_ops = {
1394 .s_frequency = cx25840_s_frequency, 1487 .s_frequency = cx25840_s_frequency,
1395 .s_std = cx25840_s_std,
1396 .s_radio = cx25840_s_radio, 1488 .s_radio = cx25840_s_radio,
1397 .g_tuner = cx25840_g_tuner, 1489 .g_tuner = cx25840_g_tuner,
1398 .s_tuner = cx25840_s_tuner, 1490 .s_tuner = cx25840_s_tuner,
@@ -1449,6 +1541,8 @@ static int cx25840_probe(struct i2c_client *client,
1449 id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; 1541 id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
1450 } else if (device_id == 0x1313) { 1542 } else if (device_id == 0x1313) {
1451 id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; 1543 id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
1544 } else if ((device_id & 0xfff0) == 0x5A30) {
1545 id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf);
1452 } 1546 }
1453 else { 1547 else {
1454 v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); 1548 v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n");
@@ -1471,6 +1565,7 @@ static int cx25840_probe(struct i2c_client *client,
1471 state->c = client; 1565 state->c = client;
1472 state->is_cx25836 = ((device_id & 0xff00) == 0x8300); 1566 state->is_cx25836 = ((device_id & 0xff00) == 0x8300);
1473 state->is_cx23885 = (device_id == 0x0000) || (device_id == 0x1313); 1567 state->is_cx23885 = (device_id == 0x0000) || (device_id == 0x1313);
1568 state->is_cx231xx = (device_id == 0x5a3e);
1474 state->vid_input = CX25840_COMPOSITE7; 1569 state->vid_input = CX25840_COMPOSITE7;
1475 state->aud_input = CX25840_AUDIO8; 1570 state->aud_input = CX25840_AUDIO8;
1476 state->audclk_freq = 48000; 1571 state->audclk_freq = 48000;
diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h
index 9ad0eb86ecf..814b5653699 100644
--- a/drivers/media/video/cx25840/cx25840-core.h
+++ b/drivers/media/video/cx25840/cx25840-core.h
@@ -50,6 +50,7 @@ struct cx25840_state {
50 u32 rev; 50 u32 rev;
51 int is_cx25836; 51 int is_cx25836;
52 int is_cx23885; 52 int is_cx23885;
53 int is_cx231xx;
53 int is_initialized; 54 int is_initialized;
54 wait_queue_head_t fw_wait; /* wake up when the fw load is finished */ 55 wait_queue_head_t fw_wait; /* wake up when the fw load is finished */
55 struct work_struct fw_work; /* work entry for fw load */ 56 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 0b2dceb7410..0df53b0d75d 100644
--- a/drivers/media/video/cx25840/cx25840-firmware.c
+++ b/drivers/media/video/cx25840/cx25840-firmware.c
@@ -25,6 +25,7 @@
25 25
26#define FWFILE "v4l-cx25840.fw" 26#define FWFILE "v4l-cx25840.fw"
27#define FWFILE_CX23885 "v4l-cx23885-avcore-01.fw" 27#define FWFILE_CX23885 "v4l-cx23885-avcore-01.fw"
28#define FWFILE_CX231XX "v4l-cx231xx-avcore-01.fw"
28 29
29/* 30/*
30 * Mike Isely <isely@pobox.com> - The FWSEND parameter controls the 31 * Mike Isely <isely@pobox.com> - The FWSEND parameter controls the
@@ -96,9 +97,17 @@ int cx25840_loadfw(struct i2c_client *client)
96 u8 buffer[FWSEND]; 97 u8 buffer[FWSEND];
97 const u8 *ptr; 98 const u8 *ptr;
98 int size, retval; 99 int size, retval;
100 int MAX_BUF_SIZE = FWSEND;
99 101
100 if (state->is_cx23885) 102 if (state->is_cx23885)
101 firmware = FWFILE_CX23885; 103 firmware = FWFILE_CX23885;
104 else if (state->is_cx231xx)
105 firmware = FWFILE_CX231XX;
106
107 if ((state->is_cx231xx) && MAX_BUF_SIZE > 16) {
108 v4l_err(client, " Firmware download size changed to 16 bytes max length\n");
109 MAX_BUF_SIZE = 16; /* cx231xx cannot accept more than 16 bytes at a time */
110 }
102 111
103 if (request_firmware(&fw, firmware, FWDEV(client)) != 0) { 112 if (request_firmware(&fw, firmware, FWDEV(client)) != 0) {
104 v4l_err(client, "unable to open firmware %s\n", firmware); 113 v4l_err(client, "unable to open firmware %s\n", firmware);
@@ -113,7 +122,7 @@ int cx25840_loadfw(struct i2c_client *client)
113 size = fw->size; 122 size = fw->size;
114 ptr = fw->data; 123 ptr = fw->data;
115 while (size > 0) { 124 while (size > 0) {
116 int len = min(FWSEND - 2, size); 125 int len = min(MAX_BUF_SIZE - 2, size);
117 126
118 memcpy(buffer + 2, ptr, len); 127 memcpy(buffer + 2, ptr, len);
119 128