diff options
Diffstat (limited to 'drivers/media/video/cx25840')
-rw-r--r-- | drivers/media/video/cx25840/cx25840-audio.c | 66 | ||||
-rw-r--r-- | drivers/media/video/cx25840/cx25840-core.c | 185 | ||||
-rw-r--r-- | drivers/media/video/cx25840/cx25840-core.h | 1 | ||||
-rw-r--r-- | drivers/media/video/cx25840/cx25840-firmware.c | 11 |
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 | ||
236 | static int get_volume(struct i2c_client *client) | 250 | 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 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 | ||
348 | static 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 | |||
348 | void cx25840_std_setup(struct i2c_client *client) | 419 | void 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. */ |
1109 | static int cx25840_init(struct v4l2_subdev *sd, u32 val) | 1195 | static 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 | ||
1237 | static int cx25840_s_video_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route) | 1325 | static 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 | ||
1245 | static int cx25840_s_audio_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route) | 1334 | static 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 | ||
1255 | static int cx25840_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) | 1345 | static 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 | ||
1393 | static const struct v4l2_subdev_tuner_ops cx25840_tuner_ops = { | 1486 | static 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 | ||