diff options
Diffstat (limited to 'drivers/media/video/saa7115.c')
-rw-r--r-- | drivers/media/video/saa7115.c | 51 |
1 files changed, 43 insertions, 8 deletions
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index dceebc0b1250..edea9e3d2dca 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c | |||
@@ -72,6 +72,10 @@ struct saa7115_state { | |||
72 | int sat; | 72 | int sat; |
73 | enum v4l2_chip_ident ident; | 73 | enum v4l2_chip_ident ident; |
74 | u32 audclk_freq; | 74 | u32 audclk_freq; |
75 | u32 crystal_freq; | ||
76 | u8 ucgc; | ||
77 | u8 cgcdiv; | ||
78 | u8 apll; | ||
75 | }; | 79 | }; |
76 | 80 | ||
77 | /* ----------------------------------------------------------------------- */ | 81 | /* ----------------------------------------------------------------------- */ |
@@ -375,10 +379,6 @@ static const unsigned char saa7113_init_auto_input[] = { | |||
375 | }; | 379 | }; |
376 | 380 | ||
377 | static const unsigned char saa7115_init_misc[] = { | 381 | static const unsigned char saa7115_init_misc[] = { |
378 | 0x38, 0x03, /* audio stuff */ | ||
379 | 0x39, 0x10, | ||
380 | 0x3a, 0x08, | ||
381 | |||
382 | 0x81, 0x01, /* reg 0x15,0x16 define blanking window */ | 382 | 0x81, 0x01, /* reg 0x15,0x16 define blanking window */ |
383 | 0x82, 0x00, | 383 | 0x82, 0x00, |
384 | 0x83, 0x01, /* I port settings */ | 384 | 0x83, 0x01, /* I port settings */ |
@@ -584,6 +584,7 @@ static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq) | |||
584 | u32 acni; | 584 | u32 acni; |
585 | u32 hz; | 585 | u32 hz; |
586 | u64 f; | 586 | u64 f; |
587 | u8 acc = 0; /* reg 0x3a, audio clock control */ | ||
587 | 588 | ||
588 | v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq); | 589 | v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq); |
589 | 590 | ||
@@ -591,18 +592,34 @@ static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq) | |||
591 | if (freq < 32000 || freq > 48000) | 592 | if (freq < 32000 || freq > 48000) |
592 | return -EINVAL; | 593 | return -EINVAL; |
593 | 594 | ||
595 | /* The saa7113 has no audio clock */ | ||
596 | if (state->ident == V4L2_IDENT_SAA7113) | ||
597 | return 0; | ||
598 | |||
594 | /* hz is the refresh rate times 100 */ | 599 | /* hz is the refresh rate times 100 */ |
595 | hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000; | 600 | hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000; |
596 | /* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */ | 601 | /* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */ |
597 | acpf = (25600 * freq) / hz; | 602 | acpf = (25600 * freq) / hz; |
598 | /* acni = (256 * freq * 2^23) / crystal_frequency = | 603 | /* acni = (256 * freq * 2^23) / crystal_frequency = |
599 | (freq * 2^(8+23)) / crystal_frequency = | 604 | (freq * 2^(8+23)) / crystal_frequency = |
600 | (freq << 31) / 32.11 MHz */ | 605 | (freq << 31) / crystal_frequency */ |
601 | f = freq; | 606 | f = freq; |
602 | f = f << 31; | 607 | f = f << 31; |
603 | do_div(f, 32110000); | 608 | do_div(f, state->crystal_freq); |
604 | acni = f; | 609 | acni = f; |
610 | if (state->ucgc) { | ||
611 | acpf = acpf * state->cgcdiv / 16; | ||
612 | acni = acni * state->cgcdiv / 16; | ||
613 | acc = 0x80; | ||
614 | if (state->cgcdiv == 3) | ||
615 | acc |= 0x40; | ||
616 | } | ||
617 | if (state->apll) | ||
618 | acc |= 0x08; | ||
605 | 619 | ||
620 | saa7115_write(client, 0x38, 0x03); | ||
621 | saa7115_write(client, 0x39, 0x10); | ||
622 | saa7115_write(client, 0x3a, acc); | ||
606 | saa7115_write(client, 0x30, acpf & 0xff); | 623 | saa7115_write(client, 0x30, acpf & 0xff); |
607 | saa7115_write(client, 0x31, (acpf >> 8) & 0xff); | 624 | saa7115_write(client, 0x31, (acpf >> 8) & 0xff); |
608 | saa7115_write(client, 0x32, (acpf >> 16) & 0x03); | 625 | saa7115_write(client, 0x32, (acpf >> 16) & 0x03); |
@@ -1260,6 +1277,21 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar | |||
1260 | } | 1277 | } |
1261 | break; | 1278 | break; |
1262 | 1279 | ||
1280 | case VIDIOC_INT_S_CRYSTAL_FREQ: | ||
1281 | { | ||
1282 | struct v4l2_crystal_freq *freq = arg; | ||
1283 | |||
1284 | if (freq->freq != SAA7115_FREQ_32_11_MHZ && | ||
1285 | freq->freq != SAA7115_FREQ_24_576_MHZ) | ||
1286 | return -EINVAL; | ||
1287 | state->crystal_freq = freq->freq; | ||
1288 | state->cgcdiv = (freq->flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4; | ||
1289 | state->ucgc = (freq->flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0; | ||
1290 | state->apll = (freq->flags & SAA7115_FREQ_FL_APLL) ? 1 : 0; | ||
1291 | saa7115_set_audio_clock_freq(client, state->audclk_freq); | ||
1292 | break; | ||
1293 | } | ||
1294 | |||
1263 | case VIDIOC_INT_DECODE_VBI_LINE: | 1295 | case VIDIOC_INT_DECODE_VBI_LINE: |
1264 | saa7115_decode_vbi_line(client, arg); | 1296 | saa7115_decode_vbi_line(client, arg); |
1265 | break; | 1297 | break; |
@@ -1401,10 +1433,13 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind) | |||
1401 | v4l_dbg(1, debug, client, "writing init values\n"); | 1433 | v4l_dbg(1, debug, client, "writing init values\n"); |
1402 | 1434 | ||
1403 | /* init to 60hz/48khz */ | 1435 | /* init to 60hz/48khz */ |
1404 | if (state->ident == V4L2_IDENT_SAA7113) | 1436 | if (state->ident == V4L2_IDENT_SAA7113) { |
1437 | state->crystal_freq = SAA7115_FREQ_24_576_MHZ; | ||
1405 | saa7115_writeregs(client, saa7113_init_auto_input); | 1438 | saa7115_writeregs(client, saa7113_init_auto_input); |
1406 | else | 1439 | } else { |
1440 | state->crystal_freq = SAA7115_FREQ_32_11_MHZ; | ||
1407 | saa7115_writeregs(client, saa7115_init_auto_input); | 1441 | saa7115_writeregs(client, saa7115_init_auto_input); |
1442 | } | ||
1408 | saa7115_writeregs(client, saa7115_init_misc); | 1443 | saa7115_writeregs(client, saa7115_init_misc); |
1409 | saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x); | 1444 | saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x); |
1410 | saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y); | 1445 | saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y); |