diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2006-01-09 12:25:41 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@brturbo.com.br> | 2006-01-09 12:25:41 -0500 |
commit | 3578d3dd0b1e468a44a76a83efe90476a854625d (patch) | |
tree | 2cd544f2aae9844821afdf90308048a800e961a1 /drivers/media/video/saa7115.c | |
parent | 21fa715e67fe57e404d7f5f39b7f18016db9e4b6 (diff) |
V4L/DVB (3214): Calculate the saa7115 AMCLK regs instead of using fixed values
- Calculate the audio master clock registers from the actual
frequencies. This simplifies the code and it also prepares
for adding CGC2 support.
- VIDIOC_INT_AUDIO_CLOCK_FREQ now receives an u32 instead of
an enum. It is more generic and actually easier to implement.
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br>
Diffstat (limited to 'drivers/media/video/saa7115.c')
-rw-r--r-- | drivers/media/video/saa7115.c | 155 |
1 files changed, 36 insertions, 119 deletions
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index b175389d9f43..3e4e5584c5d0 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/i2c.h> | 39 | #include <linux/i2c.h> |
40 | #include <linux/videodev2.h> | 40 | #include <linux/videodev2.h> |
41 | #include <media/v4l2-common.h> | 41 | #include <media/v4l2-common.h> |
42 | #include <asm/div64.h> | ||
42 | 43 | ||
43 | MODULE_DESCRIPTION("Philips SAA7114/SAA7115 video decoder driver"); | 44 | MODULE_DESCRIPTION("Philips SAA7114/SAA7115 video decoder driver"); |
44 | MODULE_AUTHOR("Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, Hans Verkuil"); | 45 | MODULE_AUTHOR("Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, Hans Verkuil"); |
@@ -78,7 +79,7 @@ struct saa7115_state { | |||
78 | int hue; | 79 | int hue; |
79 | int sat; | 80 | int sat; |
80 | enum v4l2_chip_ident ident; | 81 | enum v4l2_chip_ident ident; |
81 | enum v4l2_audio_clock_freq audclk_freq; | 82 | u32 audclk_freq; |
82 | }; | 83 | }; |
83 | 84 | ||
84 | /* ----------------------------------------------------------------------- */ | 85 | /* ----------------------------------------------------------------------- */ |
@@ -469,80 +470,6 @@ static const unsigned char saa7115_init_misc[] = { | |||
469 | 0x00, 0x00 | 470 | 0x00, 0x00 |
470 | }; | 471 | }; |
471 | 472 | ||
472 | /* ============== SAA7715 AUDIO settings ============= */ | ||
473 | |||
474 | /* 48.0 kHz */ | ||
475 | static const unsigned char saa7115_cfg_48_audio[] = { | ||
476 | 0x34, 0xce, | ||
477 | 0x35, 0xfb, | ||
478 | 0x36, 0x30, | ||
479 | 0x00, 0x00 | ||
480 | }; | ||
481 | |||
482 | /* 44.1 kHz */ | ||
483 | static const unsigned char saa7115_cfg_441_audio[] = { | ||
484 | 0x34, 0xf2, | ||
485 | 0x35, 0x00, | ||
486 | 0x36, 0x2d, | ||
487 | 0x00, 0x00 | ||
488 | }; | ||
489 | |||
490 | /* 32.0 kHz */ | ||
491 | static const unsigned char saa7115_cfg_32_audio[] = { | ||
492 | 0x34, 0xdf, | ||
493 | 0x35, 0xa7, | ||
494 | 0x36, 0x20, | ||
495 | 0x00, 0x00 | ||
496 | }; | ||
497 | |||
498 | /* 48.0 kHz 60hz */ | ||
499 | static const unsigned char saa7115_cfg_60hz_48_audio[] = { | ||
500 | 0x30, 0xcd, | ||
501 | 0x31, 0x20, | ||
502 | 0x32, 0x03, | ||
503 | 0x00, 0x00 | ||
504 | }; | ||
505 | |||
506 | /* 48.0 kHz 50hz */ | ||
507 | static const unsigned char saa7115_cfg_50hz_48_audio[] = { | ||
508 | 0x30, 0x00, | ||
509 | 0x31, 0xc0, | ||
510 | 0x32, 0x03, | ||
511 | 0x00, 0x00 | ||
512 | }; | ||
513 | |||
514 | /* 44.1 kHz 60hz */ | ||
515 | static const unsigned char saa7115_cfg_60hz_441_audio[] = { | ||
516 | 0x30, 0xbc, | ||
517 | 0x31, 0xdf, | ||
518 | 0x32, 0x02, | ||
519 | 0x00, 0x00 | ||
520 | }; | ||
521 | |||
522 | /* 44.1 kHz 50hz */ | ||
523 | static const unsigned char saa7115_cfg_50hz_441_audio[] = { | ||
524 | 0x30, 0x00, | ||
525 | 0x31, 0x72, | ||
526 | 0x32, 0x03, | ||
527 | 0x00, 0x00 | ||
528 | }; | ||
529 | |||
530 | /* 32.0 kHz 60hz */ | ||
531 | static const unsigned char saa7115_cfg_60hz_32_audio[] = { | ||
532 | 0x30, 0xde, | ||
533 | 0x31, 0x15, | ||
534 | 0x32, 0x02, | ||
535 | 0x00, 0x00 | ||
536 | }; | ||
537 | |||
538 | /* 32.0 kHz 50hz */ | ||
539 | static const unsigned char saa7115_cfg_50hz_32_audio[] = { | ||
540 | 0x30, 0x00, | ||
541 | 0x31, 0x80, | ||
542 | 0x32, 0x02, | ||
543 | 0x00, 0x00 | ||
544 | }; | ||
545 | |||
546 | static int saa7115_odd_parity(u8 c) | 473 | static int saa7115_odd_parity(u8 c) |
547 | { | 474 | { |
548 | c ^= (c >> 4); | 475 | c ^= (c >> 4); |
@@ -627,40 +554,38 @@ static int saa7115_decode_wss(u8 * p) | |||
627 | } | 554 | } |
628 | 555 | ||
629 | 556 | ||
630 | static int saa7115_set_audio_clock_freq(struct i2c_client *client, enum v4l2_audio_clock_freq freq) | 557 | static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq) |
631 | { | 558 | { |
632 | struct saa7115_state *state = i2c_get_clientdata(client); | 559 | struct saa7115_state *state = i2c_get_clientdata(client); |
560 | u32 acpf; | ||
561 | u32 acni; | ||
562 | u32 hz; | ||
563 | u64 f; | ||
633 | 564 | ||
634 | saa7115_dbg("set audio clock freq: %d\n", freq); | 565 | saa7115_dbg("set audio clock freq: %d\n", freq); |
635 | switch (freq) { | 566 | |
636 | case V4L2_AUDCLK_32_KHZ: | 567 | /* sanity check */ |
637 | saa7115_writeregs(client, saa7115_cfg_32_audio); | 568 | if (freq < 32000 || freq > 48000) |
638 | if (state->std & V4L2_STD_525_60) { | 569 | return -EINVAL; |
639 | saa7115_writeregs(client, saa7115_cfg_60hz_32_audio); | 570 | |
640 | } else { | 571 | /* hz is the refresh rate times 100 */ |
641 | saa7115_writeregs(client, saa7115_cfg_50hz_32_audio); | 572 | hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000; |
642 | } | 573 | /* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */ |
643 | break; | 574 | acpf = (25600 * freq) / hz; |
644 | case V4L2_AUDCLK_441_KHZ: | 575 | /* acni = (256 * freq * 2^23) / crystal_frequency = |
645 | saa7115_writeregs(client, saa7115_cfg_441_audio); | 576 | (freq * 2^(8+23)) / crystal_frequency = |
646 | if (state->std & V4L2_STD_525_60) { | 577 | (freq << 31) / 32.11 MHz */ |
647 | saa7115_writeregs(client, saa7115_cfg_60hz_441_audio); | 578 | f = freq; |
648 | } else { | 579 | f = f << 31; |
649 | saa7115_writeregs(client, saa7115_cfg_50hz_441_audio); | 580 | do_div(f, 32110000); |
650 | } | 581 | acni = f; |
651 | break; | 582 | |
652 | case V4L2_AUDCLK_48_KHZ: | 583 | saa7115_write(client, 0x30, acpf & 0xff); |
653 | saa7115_writeregs(client, saa7115_cfg_48_audio); | 584 | saa7115_write(client, 0x31, (acpf >> 8) & 0xff); |
654 | if (state->std & V4L2_STD_525_60) { | 585 | saa7115_write(client, 0x32, (acpf >> 16) & 0x03); |
655 | saa7115_writeregs(client, saa7115_cfg_60hz_48_audio); | 586 | saa7115_write(client, 0x34, acni & 0xff); |
656 | } else { | 587 | saa7115_write(client, 0x35, (acni >> 8) & 0xff); |
657 | saa7115_writeregs(client, saa7115_cfg_50hz_48_audio); | 588 | saa7115_write(client, 0x36, (acni >> 16) & 0x3f); |
658 | } | ||
659 | break; | ||
660 | default: | ||
661 | saa7115_dbg("invalid audio setting %d\n", freq); | ||
662 | return -EINVAL; | ||
663 | } | ||
664 | state->audclk_freq = freq; | 589 | state->audclk_freq = freq; |
665 | return 0; | 590 | return 0; |
666 | } | 591 | } |
@@ -773,24 +698,17 @@ static v4l2_std_id saa7115_get_v4lstd(struct i2c_client *client) | |||
773 | static void saa7115_log_status(struct i2c_client *client) | 698 | static void saa7115_log_status(struct i2c_client *client) |
774 | { | 699 | { |
775 | struct saa7115_state *state = i2c_get_clientdata(client); | 700 | struct saa7115_state *state = i2c_get_clientdata(client); |
776 | char *audfreq = "undefined"; | ||
777 | int reg1e, reg1f; | 701 | int reg1e, reg1f; |
778 | int signalOk; | 702 | int signalOk; |
779 | int vcr; | 703 | int vcr; |
780 | 704 | ||
781 | switch (state->audclk_freq) { | 705 | saa7115_info("Audio frequency: %d Hz\n", state->audclk_freq); |
782 | case V4L2_AUDCLK_32_KHZ: audfreq = "32 kHz"; break; | ||
783 | case V4L2_AUDCLK_441_KHZ: audfreq = "44.1 kHz"; break; | ||
784 | case V4L2_AUDCLK_48_KHZ: audfreq = "48 kHz"; break; | ||
785 | } | ||
786 | |||
787 | saa7115_info("Audio frequency: %s\n", audfreq); | ||
788 | if (client->name[6] == '4') { | 706 | if (client->name[6] == '4') { |
789 | /* status for the saa7114 */ | 707 | /* status for the saa7114 */ |
790 | reg1f = saa7115_read(client, 0x1f); | 708 | reg1f = saa7115_read(client, 0x1f); |
791 | signalOk = (reg1f & 0xc1) == 0x81; | 709 | signalOk = (reg1f & 0xc1) == 0x81; |
792 | saa7115_info("Video signal: %s\n", signalOk ? "ok" : "bad"); | 710 | saa7115_info("Video signal: %s\n", signalOk ? "ok" : "bad"); |
793 | saa7115_info("Frequency: %s\n", (reg1f & 0x20) ? "60Hz" : "50Hz"); | 711 | saa7115_info("Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz"); |
794 | return; | 712 | return; |
795 | } | 713 | } |
796 | 714 | ||
@@ -807,7 +725,7 @@ static void saa7115_log_status(struct i2c_client *client) | |||
807 | saa7115_info("Input: Composite %d\n", state->input); | 725 | saa7115_info("Input: Composite %d\n", state->input); |
808 | } | 726 | } |
809 | saa7115_info("Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad"); | 727 | saa7115_info("Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad"); |
810 | saa7115_info("Frequency: %s\n", (reg1f & 0x20) ? "60Hz" : "50Hz"); | 728 | saa7115_info("Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz"); |
811 | 729 | ||
812 | switch (reg1e & 0x03) { | 730 | switch (reg1e & 0x03) { |
813 | case 1: | 731 | case 1: |
@@ -1108,7 +1026,7 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar | |||
1108 | return saa7115_get_v4lfmt(client, (struct v4l2_format *)arg); | 1026 | return saa7115_get_v4lfmt(client, (struct v4l2_format *)arg); |
1109 | 1027 | ||
1110 | case VIDIOC_INT_AUDIO_CLOCK_FREQ: | 1028 | case VIDIOC_INT_AUDIO_CLOCK_FREQ: |
1111 | return saa7115_set_audio_clock_freq(client, *(enum v4l2_audio_clock_freq *)arg); | 1029 | return saa7115_set_audio_clock_freq(client, *(u32 *)arg); |
1112 | 1030 | ||
1113 | case VIDIOC_G_TUNER: | 1031 | case VIDIOC_G_TUNER: |
1114 | { | 1032 | { |
@@ -1307,7 +1225,7 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind) | |||
1307 | state->hue = 0; | 1225 | state->hue = 0; |
1308 | state->sat = 64; | 1226 | state->sat = 64; |
1309 | state->ident = (chip_id == 4) ? V4L2_IDENT_SAA7114 : V4L2_IDENT_SAA7115; | 1227 | state->ident = (chip_id == 4) ? V4L2_IDENT_SAA7114 : V4L2_IDENT_SAA7115; |
1310 | state->audclk_freq = V4L2_AUDCLK_48_KHZ; | 1228 | state->audclk_freq = 48000; |
1311 | 1229 | ||
1312 | saa7115_dbg("writing init values\n"); | 1230 | saa7115_dbg("writing init values\n"); |
1313 | 1231 | ||
@@ -1317,8 +1235,7 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind) | |||
1317 | saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x); | 1235 | saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x); |
1318 | saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y); | 1236 | saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y); |
1319 | saa7115_writeregs(client, saa7115_cfg_60hz_video); | 1237 | saa7115_writeregs(client, saa7115_cfg_60hz_video); |
1320 | saa7115_writeregs(client, saa7115_cfg_48_audio); | 1238 | saa7115_set_audio_clock_freq(client, state->audclk_freq); |
1321 | saa7115_writeregs(client, saa7115_cfg_60hz_48_audio); | ||
1322 | saa7115_writeregs(client, saa7115_cfg_reset_scaler); | 1239 | saa7115_writeregs(client, saa7115_cfg_reset_scaler); |
1323 | 1240 | ||
1324 | i2c_attach_client(client); | 1241 | i2c_attach_client(client); |