diff options
Diffstat (limited to 'firmware/drivers/audio/wm8978.c')
-rw-r--r-- | firmware/drivers/audio/wm8978.c | 130 |
1 files changed, 128 insertions, 2 deletions
diff --git a/firmware/drivers/audio/wm8978.c b/firmware/drivers/audio/wm8978.c index c50500356a..f392c21d4c 100644 --- a/firmware/drivers/audio/wm8978.c +++ b/firmware/drivers/audio/wm8978.c | |||
@@ -227,8 +227,9 @@ void audiohw_postinit(void) | |||
227 | wmc_write(WMC_DAC_CONTROL, WMC_DACOSR_128 | WMC_AMUTE); | 227 | wmc_write(WMC_DAC_CONTROL, WMC_DACOSR_128 | WMC_AMUTE); |
228 | 228 | ||
229 | /* Specific to HW clocking */ | 229 | /* Specific to HW clocking */ |
230 | wmc_write(WMC_CLOCK_GEN_CTRL, WMC_MCLKDIV_1_5 | WMC_BCLKDIV_8 | WMC_MS); | 230 | wmc_write_masked(WMC_CLOCK_GEN_CTRL, WMC_BCLKDIV_4 | WMC_MS, |
231 | wmc_write(WMC_ADDITIONAL_CTRL, WMC_SR_48KHZ); /* 44.1 */ | 231 | WMC_BCLKDIV | WMC_MS | WMC_CLKSEL); |
232 | audiohw_set_frequency(HW_SAMPR_DEFAULT); | ||
232 | 233 | ||
233 | /* ADC silenced */ | 234 | /* ADC silenced */ |
234 | wmc_write_masked(WMC_LEFT_ADC_DIGITAL_VOL, 0x00, WMC_DVOL); | 235 | wmc_write_masked(WMC_LEFT_ADC_DIGITAL_VOL, 0x00, WMC_DVOL); |
@@ -354,6 +355,131 @@ void audiohw_mute(bool mute) | |||
354 | } | 355 | } |
355 | } | 356 | } |
356 | 357 | ||
358 | void audiohw_set_frequency(int sampling_control) | ||
359 | { | ||
360 | /* For 16.9344MHz MCLK */ | ||
361 | static const struct | ||
362 | { | ||
363 | uint32_t plln : 8; | ||
364 | uint32_t pllk0 : 6; | ||
365 | uint32_t pllk1 : 9; | ||
366 | uint32_t pllk2 : 9; | ||
367 | unsigned char mclkdiv; | ||
368 | unsigned char filter; | ||
369 | } sctrl_table[HW_NUM_FREQ] = | ||
370 | { | ||
371 | [HW_FREQ_8] = /* PLL = 65.536MHz */ | ||
372 | { | ||
373 | .plln = WMC_PLLNw(7) | WMC_PLL_PRESCALE, | ||
374 | .pllk0 = WMC_PLLK_23_18w(12414886 >> 18), | ||
375 | .pllk1 = WMC_PLLK_17_9w(12414886 >> 9), | ||
376 | .pllk2 = WMC_PLLK_8_0w(12414886 >> 0), | ||
377 | .mclkdiv = WMC_MCLKDIV_8, /* 2.0480 MHz */ | ||
378 | .filter = WMC_SR_8KHZ, | ||
379 | }, | ||
380 | [HW_FREQ_11] = /* PLL = off */ | ||
381 | { | ||
382 | .mclkdiv = WMC_MCLKDIV_6, /* 2.8224 MHz */ | ||
383 | .filter = WMC_SR_12KHZ, | ||
384 | }, | ||
385 | [HW_FREQ_12] = /* PLL = 73.728 MHz */ | ||
386 | { | ||
387 | .plln = WMC_PLLNw(8) | WMC_PLL_PRESCALE, | ||
388 | .pllk0 = WMC_PLLK_23_18w(11869595 >> 18), | ||
389 | .pllk1 = WMC_PLLK_17_9w(11869595 >> 9), | ||
390 | .pllk2 = WMC_PLLK_8_0w(11869595 >> 0), | ||
391 | .mclkdiv = WMC_MCLKDIV_6, /* 3.0720 MHz */ | ||
392 | .filter = WMC_SR_12KHZ, | ||
393 | }, | ||
394 | [HW_FREQ_16] = /* PLL = 65.536MHz */ | ||
395 | { | ||
396 | .plln = WMC_PLLNw(7) | WMC_PLL_PRESCALE, | ||
397 | .pllk0 = WMC_PLLK_23_18w(12414886 >> 18), | ||
398 | .pllk1 = WMC_PLLK_17_9w(12414886 >> 9), | ||
399 | .pllk2 = WMC_PLLK_8_0w(12414886 >> 0), | ||
400 | .mclkdiv = WMC_MCLKDIV_4, /* 4.0960 MHz */ | ||
401 | .filter = WMC_SR_16KHZ, | ||
402 | }, | ||
403 | [HW_FREQ_22] = /* PLL = off */ | ||
404 | { | ||
405 | .mclkdiv = WMC_MCLKDIV_3, /* 5.6448 MHz */ | ||
406 | .filter = WMC_SR_24KHZ, | ||
407 | }, | ||
408 | [HW_FREQ_24] = /* PLL = 73.728 MHz */ | ||
409 | { | ||
410 | .plln = WMC_PLLNw(8) | WMC_PLL_PRESCALE, | ||
411 | .pllk0 = WMC_PLLK_23_18w(11869595 >> 18), | ||
412 | .pllk1 = WMC_PLLK_17_9w(11869595 >> 9), | ||
413 | .pllk2 = WMC_PLLK_8_0w(11869595 >> 0), | ||
414 | .mclkdiv = WMC_MCLKDIV_3, /* 6.1440 MHz */ | ||
415 | .filter = WMC_SR_24KHZ, | ||
416 | }, | ||
417 | [HW_FREQ_32] = /* PLL = 65.536MHz */ | ||
418 | { | ||
419 | .plln = WMC_PLLNw(7) | WMC_PLL_PRESCALE, | ||
420 | .pllk0 = WMC_PLLK_23_18w(12414886 >> 18), | ||
421 | .pllk1 = WMC_PLLK_17_9w(12414886 >> 9), | ||
422 | .pllk2 = WMC_PLLK_8_0w(12414886 >> 0), | ||
423 | .mclkdiv = WMC_MCLKDIV_2, /* 8.1920 MHz */ | ||
424 | .filter = WMC_SR_32KHZ, | ||
425 | }, | ||
426 | [HW_FREQ_44] = /* PLL = off */ | ||
427 | { | ||
428 | .mclkdiv = WMC_MCLKDIV_1_5, /* 11.2896 MHz */ | ||
429 | .filter = WMC_SR_48KHZ, | ||
430 | }, | ||
431 | [HW_FREQ_48] = /* PLL = 73.728 MHz */ | ||
432 | { | ||
433 | .plln = WMC_PLLNw(8) | WMC_PLL_PRESCALE, | ||
434 | .pllk0 = WMC_PLLK_23_18w(11869595 >> 18), | ||
435 | .pllk1 = WMC_PLLK_17_9w(11869595 >> 9), | ||
436 | .pllk2 = WMC_PLLK_8_0w(11869595 >> 0), | ||
437 | .mclkdiv = WMC_MCLKDIV_1_5, /* 12.2880 MHz */ | ||
438 | .filter = WMC_SR_48KHZ, | ||
439 | }, | ||
440 | }; | ||
441 | |||
442 | unsigned int plln; | ||
443 | unsigned int mclkdiv; | ||
444 | |||
445 | if ((unsigned)sampling_control >= ARRAYLEN(sctrl_table)) | ||
446 | sampling_control = HW_FREQ_DEFAULT; | ||
447 | |||
448 | |||
449 | /* Setup filters. */ | ||
450 | wmc_write(WMC_ADDITIONAL_CTRL, | ||
451 | sctrl_table[sampling_control].filter); | ||
452 | |||
453 | plln = sctrl_table[sampling_control].plln; | ||
454 | mclkdiv = sctrl_table[sampling_control].mclkdiv; | ||
455 | |||
456 | if (plln != 0) | ||
457 | { | ||
458 | /* Using PLL to generate SYSCLK */ | ||
459 | |||
460 | /* Program PLL. */ | ||
461 | wmc_write(WMC_PLL_N, plln); | ||
462 | wmc_write(WMC_PLLK_23_18, sctrl_table[sampling_control].pllk0); | ||
463 | wmc_write(WMC_PLLK_17_9, sctrl_table[sampling_control].pllk1); | ||
464 | wmc_write(WMC_PLLK_8_0, sctrl_table[sampling_control].pllk2); | ||
465 | |||
466 | /* Turn on PLL. */ | ||
467 | wmc_set(WMC_POWER_MANAGEMENT1, WMC_PLLEN); | ||
468 | |||
469 | /* Switch to PLL and set divider. */ | ||
470 | wmc_write_masked(WMC_CLOCK_GEN_CTRL, mclkdiv | WMC_CLKSEL, | ||
471 | WMC_MCLKDIV | WMC_CLKSEL); | ||
472 | } | ||
473 | else | ||
474 | { | ||
475 | /* Switch away from PLL and set MCLKDIV. */ | ||
476 | wmc_write_masked(WMC_CLOCK_GEN_CTRL, mclkdiv, | ||
477 | WMC_MCLKDIV | WMC_CLKSEL); | ||
478 | |||
479 | /* Turn off PLL. */ | ||
480 | wmc_clear(WMC_POWER_MANAGEMENT1, WMC_PLLEN); | ||
481 | } | ||
482 | } | ||
357 | 483 | ||
358 | #ifdef HAVE_RECORDING | 484 | #ifdef HAVE_RECORDING |
359 | /* TODO */ | 485 | /* TODO */ |