diff options
Diffstat (limited to 'drivers/media/video/cx25840/cx25840-core.c')
-rw-r--r-- | drivers/media/video/cx25840/cx25840-core.c | 113 |
1 files changed, 105 insertions, 8 deletions
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 737ee4ea8830..9108f74c0f71 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c | |||
@@ -345,6 +345,81 @@ 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 | |||
378 | /* Luma */ | ||
379 | cx25840_write4(client, 0x414, 0x00107d12); | ||
380 | |||
381 | /* Chroma */ | ||
382 | cx25840_write4(client, 0x420, 0x3d008282); | ||
383 | |||
384 | |||
385 | |||
386 | /* ADC2 input select */ | ||
387 | cx25840_write(client, 0x102, 0x10); | ||
388 | |||
389 | /* VIN1 & VIN5 */ | ||
390 | cx25840_write(client, 0x103, 0x11); | ||
391 | |||
392 | /* Enable format auto detect */ | ||
393 | cx25840_write(client, 0x400, 0); | ||
394 | /* Fast subchroma lock */ | ||
395 | /* White crush, Chroma AGC & Chroma Killer enabled */ | ||
396 | cx25840_write(client, 0x401, 0xe8); | ||
397 | |||
398 | |||
399 | /* Do the firmware load in a work handler to prevent. | ||
400 | Otherwise the kernel is blocked waiting for the | ||
401 | bit-banging i2c interface to finish uploading the | ||
402 | firmware. */ | ||
403 | INIT_WORK(&state->fw_work, cx25840_work_handler); | ||
404 | init_waitqueue_head(&state->fw_wait); | ||
405 | q = create_singlethread_workqueue("cx25840_fw"); | ||
406 | prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); | ||
407 | queue_work(q, &state->fw_work); | ||
408 | schedule(); | ||
409 | finish_wait(&state->fw_wait, &wait); | ||
410 | destroy_workqueue(q); | ||
411 | |||
412 | cx25840_std_setup(client); | ||
413 | |||
414 | /* (re)set input */ | ||
415 | set_input(client, state->vid_input, state->aud_input); | ||
416 | |||
417 | /* start microcontroller */ | ||
418 | cx25840_and_or(client, 0x803, ~0x10, 0x10); | ||
419 | } | ||
420 | |||
421 | /* ----------------------------------------------------------------------- */ | ||
422 | |||
348 | void cx25840_std_setup(struct i2c_client *client) | 423 | void cx25840_std_setup(struct i2c_client *client) |
349 | { | 424 | { |
350 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | 425 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); |
@@ -414,6 +489,7 @@ void cx25840_std_setup(struct i2c_client *client) | |||
414 | } | 489 | } |
415 | 490 | ||
416 | /* DEBUG: Displays configured PLL frequency */ | 491 | /* DEBUG: Displays configured PLL frequency */ |
492 | if (!state->is_cx231xx) { | ||
417 | pll_int = cx25840_read(client, 0x108); | 493 | pll_int = cx25840_read(client, 0x108); |
418 | pll_frac = cx25840_read4(client, 0x10c) & 0x1ffffff; | 494 | pll_frac = cx25840_read4(client, 0x10c) & 0x1ffffff; |
419 | pll_post = cx25840_read(client, 0x109); | 495 | pll_post = cx25840_read(client, 0x109); |
@@ -448,6 +524,7 @@ void cx25840_std_setup(struct i2c_client *client) | |||
448 | hblank, hactive, vblank, vactive, vblank656, | 524 | hblank, hactive, vblank, vactive, vblank656, |
449 | src_decimation, burst, luma_lpf, uv_lpf, comb, sc); | 525 | src_decimation, burst, luma_lpf, uv_lpf, comb, sc); |
450 | } | 526 | } |
527 | } | ||
451 | 528 | ||
452 | /* Sets horizontal blanking delay and active lines */ | 529 | /* Sets horizontal blanking delay and active lines */ |
453 | cx25840_write(client, 0x470, hblank); | 530 | cx25840_write(client, 0x470, hblank); |
@@ -596,7 +673,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 | 673 | * configuration in reg (for the cx23885) so we have no |
597 | * need to attempt to flip bits for earlier av decoders. | 674 | * need to attempt to flip bits for earlier av decoders. |
598 | */ | 675 | */ |
599 | if (!state->is_cx23885) { | 676 | if (!state->is_cx23885 && !state->is_cx231xx) { |
600 | switch (aud_input) { | 677 | switch (aud_input) { |
601 | case CX25840_AUDIO_SERIAL: | 678 | case CX25840_AUDIO_SERIAL: |
602 | /* do nothing, use serial audio input */ | 679 | /* do nothing, use serial audio input */ |
@@ -619,7 +696,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) */ | 696 | /* Set INPUT_MODE to Composite (0) or S-Video (1) */ |
620 | cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02); | 697 | cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02); |
621 | 698 | ||
622 | if (!state->is_cx23885) { | 699 | if (!state->is_cx23885 && !state->is_cx231xx) { |
623 | /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ | 700 | /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ |
624 | cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); | 701 | 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 */ | 702 | /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2&CH3 */ |
@@ -659,6 +736,19 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp | |||
659 | */ | 736 | */ |
660 | cx25840_write(client, 0x918, 0xa0); | 737 | cx25840_write(client, 0x918, 0xa0); |
661 | cx25840_write(client, 0x919, 0x01); | 738 | cx25840_write(client, 0x919, 0x01); |
739 | } else if (state->is_cx231xx) { | ||
740 | /* Audio channel 1 src : Parallel 1 */ | ||
741 | cx25840_write(client, 0x124, 0x03); | ||
742 | |||
743 | /* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */ | ||
744 | cx25840_write(client, 0x914, 0xa0); | ||
745 | |||
746 | /* I2S_OUT_CTL: | ||
747 | * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 | ||
748 | * I2S_OUT_MASTER_MODE = Master | ||
749 | */ | ||
750 | cx25840_write(client, 0x918, 0xa0); | ||
751 | cx25840_write(client, 0x919, 0x01); | ||
662 | } | 752 | } |
663 | 753 | ||
664 | return 0; | 754 | return 0; |
@@ -719,7 +809,7 @@ static int set_v4lstd(struct i2c_client *client) | |||
719 | 809 | ||
720 | static int cx25840_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 810 | static int cx25840_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
721 | { | 811 | { |
722 | struct cx25840_state *state = to_state(sd); | 812 | struct cx25840_state *state = to_state(sd); |
723 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 813 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
724 | 814 | ||
725 | switch (ctrl->id) { | 815 | switch (ctrl->id) { |
@@ -786,7 +876,7 @@ static int cx25840_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
786 | 876 | ||
787 | static int cx25840_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 877 | static int cx25840_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
788 | { | 878 | { |
789 | struct cx25840_state *state = to_state(sd); | 879 | struct cx25840_state *state = to_state(sd); |
790 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 880 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
791 | 881 | ||
792 | switch (ctrl->id) { | 882 | switch (ctrl->id) { |
@@ -1118,6 +1208,8 @@ static int cx25840_init(struct v4l2_subdev *sd, u32 val) | |||
1118 | cx25836_initialize(client); | 1208 | cx25836_initialize(client); |
1119 | else if (state->is_cx23885) | 1209 | else if (state->is_cx23885) |
1120 | cx23885_initialize(client); | 1210 | cx23885_initialize(client); |
1211 | else if (state->is_cx231xx) | ||
1212 | cx231xx_initialize(client); | ||
1121 | else | 1213 | else |
1122 | cx25840_initialize(client); | 1214 | cx25840_initialize(client); |
1123 | } | 1215 | } |
@@ -1159,7 +1251,7 @@ static int cx25840_s_stream(struct v4l2_subdev *sd, int enable) | |||
1159 | v4l_dbg(1, cx25840_debug, client, "%s output\n", | 1251 | v4l_dbg(1, cx25840_debug, client, "%s output\n", |
1160 | enable ? "enable" : "disable"); | 1252 | enable ? "enable" : "disable"); |
1161 | if (enable) { | 1253 | if (enable) { |
1162 | if (state->is_cx23885) { | 1254 | if (state->is_cx23885 || state->is_cx231xx) { |
1163 | u8 v = (cx25840_read(client, 0x421) | 0x0b); | 1255 | u8 v = (cx25840_read(client, 0x421) | 0x0b); |
1164 | cx25840_write(client, 0x421, v); | 1256 | cx25840_write(client, 0x421, v); |
1165 | } else { | 1257 | } else { |
@@ -1169,7 +1261,7 @@ static int cx25840_s_stream(struct v4l2_subdev *sd, int enable) | |||
1169 | state->is_cx25836 ? 0x04 : 0x07); | 1261 | state->is_cx25836 ? 0x04 : 0x07); |
1170 | } | 1262 | } |
1171 | } else { | 1263 | } else { |
1172 | if (state->is_cx23885) { | 1264 | if (state->is_cx23885 || state->is_cx231xx) { |
1173 | u8 v = cx25840_read(client, 0x421) & ~(0x0b); | 1265 | u8 v = cx25840_read(client, 0x421) & ~(0x0b); |
1174 | cx25840_write(client, 0x421, v); | 1266 | cx25840_write(client, 0x421, v); |
1175 | } else { | 1267 | } else { |
@@ -1350,6 +1442,8 @@ static int cx25840_reset(struct v4l2_subdev *sd, u32 val) | |||
1350 | cx25836_initialize(client); | 1442 | cx25836_initialize(client); |
1351 | else if (state->is_cx23885) | 1443 | else if (state->is_cx23885) |
1352 | cx23885_initialize(client); | 1444 | cx23885_initialize(client); |
1445 | else if (state->is_cx231xx) | ||
1446 | cx231xx_initialize(client); | ||
1353 | else | 1447 | else |
1354 | cx25840_initialize(client); | 1448 | cx25840_initialize(client); |
1355 | return 0; | 1449 | return 0; |
@@ -1445,10 +1539,12 @@ static int cx25840_probe(struct i2c_client *client, | |||
1445 | } | 1539 | } |
1446 | else if ((device_id & 0xff00) == 0x8400) { | 1540 | else if ((device_id & 0xff00) == 0x8400) { |
1447 | id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf); | 1541 | id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf); |
1448 | } else if (device_id == 0x0000) { | 1542 | } /* else if (device_id == 0x0000) { |
1449 | id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; | 1543 | id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; |
1450 | } else if (device_id == 0x1313) { | 1544 | } */ else if (device_id == 0x1313) { |
1451 | id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; | 1545 | id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; |
1546 | } else if ((device_id & 0xfff0) == 0x5A30) { | ||
1547 | id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf); | ||
1452 | } | 1548 | } |
1453 | else { | 1549 | else { |
1454 | v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); | 1550 | v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); |
@@ -1471,6 +1567,7 @@ static int cx25840_probe(struct i2c_client *client, | |||
1471 | state->c = client; | 1567 | state->c = client; |
1472 | state->is_cx25836 = ((device_id & 0xff00) == 0x8300); | 1568 | state->is_cx25836 = ((device_id & 0xff00) == 0x8300); |
1473 | state->is_cx23885 = (device_id == 0x0000) || (device_id == 0x1313); | 1569 | state->is_cx23885 = (device_id == 0x0000) || (device_id == 0x1313); |
1570 | state->is_cx231xx = (device_id == 0x5A3E); | ||
1474 | state->vid_input = CX25840_COMPOSITE7; | 1571 | state->vid_input = CX25840_COMPOSITE7; |
1475 | state->aud_input = CX25840_AUDIO8; | 1572 | state->aud_input = CX25840_AUDIO8; |
1476 | state->audclk_freq = 48000; | 1573 | state->audclk_freq = 48000; |