summaryrefslogtreecommitdiff
path: root/firmware/drivers/audio/wm8978.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/audio/wm8978.c')
-rw-r--r--firmware/drivers/audio/wm8978.c130
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
358void 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 */