void audiohw_postinit(void) { sleep(5*HZ/4); /* 7. Enable other mixers as required */ /* 8. Enable other outputs as required */ /* 9. Set remaining registers */ wmc_write(WMC_AUDIO_INTERFACE, WMC_WL_16 | WMC_FMT_I2S); wmc_write(WMC_DAC_CONTROL, WMC_DACOSR_128); /* No ADC, no HP filter, no popping */ wmc_clear(WMC_ADC_CONTROL, WMC_HPFEN); wmc_clear(WMC_LEFT_ADC_BOOST_CTRL, WMC_PGABOOSTL); wmc_clear(WMC_RIGHT_ADC_BOOST_CTRL, WMC_PGABOOSTR); /* Specific to HW clocking */ wmc_write_masked(WMC_CLOCK_GEN_CTRL, WMC_BCLKDIV_4 | WMC_MS, WMC_BCLKDIV | WMC_MS | WMC_CLKSEL); audiohw_set_frequency(HW_FREQ_DEFAULT); audiohw_enable_headphone_jack(true); }
void audiohw_preinit(void) { /* POWER UP SEQUENCE */ /* 1) Switch on power supplies. By default the WM codec is in Standby Mode, * the DAC is digitally muted and the Audio Interface and Outputs are * all OFF. */ wmcodec_write(RESET, RESET_RESET); /* 2) Set all required bits in the Power Down register (0Ch) to '0'; * EXCEPT the OUTPD bit, this should be set to '1' (Default). */ wmc_clear(PDCTRL, PDCTRL_DACPD | PDCTRL_POWEROFF); /* 3) Set required values in all other registers except 12h (Active). */ wmc_set(AINTFCE, 0); /* Set no bits - write init/shadow value */ wmc_set(AAPCTRL, AAPCTRL_DACSEL); wmc_write(SAMPCTRL, WMC_USB24_44100HZ); /* 4) Set the 'Active' bit in register 12h. */ codec_set_active(true); /* 5) The last write of the sequence should be setting OUTPD to '0' * (active) in register 0Ch, enabling the DAC signal path, free * of any significant power-up noise. */ wmc_clear(PDCTRL, PDCTRL_OUTPD); }
void audiohw_set_headphone_vol(int vol_l, int vol_r) { int prev_l = wmc_vol.vol_l; int prev_r = wmc_vol.vol_r; int dac_l, dac_r, hp_l, hp_r; int mix_l, mix_r, boost_l, boost_r; wmc_vol.vol_l = vol_l; wmc_vol.vol_r = vol_r; /* Mixers are synced to provide full volume range on both the analogue * and digital pathways */ get_headphone_levels(vol_l, &dac_l, &hp_l, &mix_l, &boost_l); get_headphone_levels(vol_r, &dac_r, &hp_r, &mix_r, &boost_r); wmc_vol.dac_l = dac_l; wmc_vol.dac_r = dac_r; sync_prescaler(); wmc_write_masked(WMC_LEFT_MIXER_CTRL, mix_l << WMC_BYPLMIXVOL_POS, WMC_BYPLMIXVOL); wmc_write_masked(WMC_LEFT_ADC_BOOST_CTRL, boost_l << WMC_L2_2BOOSTVOL_POS, WMC_L2_2BOOSTVOL); wmc_write_masked(WMC_LOUT1_HP_VOLUME_CTRL, hp_l, WMC_AVOL); wmc_write_masked(WMC_RIGHT_MIXER_CTRL, mix_r << WMC_BYPRMIXVOL_POS, WMC_BYPRMIXVOL); wmc_write_masked(WMC_RIGHT_ADC_BOOST_CTRL, boost_r << WMC_R2_2BOOSTVOL_POS, WMC_R2_2BOOSTVOL); wmc_write_masked(WMC_ROUT1_HP_VOLUME_CTRL, hp_r, WMC_AVOL); if (vol_l > 0) { /* Not muted and going up from mute level? */ if (prev_l <= 0 && !wmc_vol.ahw_mute) wmc_clear(WMC_LOUT1_HP_VOLUME_CTRL, WMC_MUTE); } else { /* Going to mute level? */ if (prev_l > 0) wmc_set(WMC_LOUT1_HP_VOLUME_CTRL, WMC_MUTE); } if (vol_r > 0) { /* Not muted and going up from mute level? */ if (prev_r <= 0 && !wmc_vol.ahw_mute) wmc_clear(WMC_ROUT1_HP_VOLUME_CTRL, WMC_MUTE); } else { /* Going to mute level? */ if (prev_r > 0) wmc_set(WMC_ROUT1_HP_VOLUME_CTRL, WMC_MUTE); } }
static void audiohw_mute(bool mute) { if (mute) { /* Set DACMU = 1 to soft-mute the audio DACs. */ wmc_set(DAPCTRL, DAPCTRL_DACMU); } else { /* Set DACMU = 0 to soft-un-mute the audio DACs. */ wmc_clear(DAPCTRL, DAPCTRL_DACMU); } }
static void audiohw_mute(bool mute) { wmc_vol.ahw_mute = mute; /* No DAC mute here, please - take care of each enabled output. */ if (mute) { wmc_set(WMC_LOUT1_HP_VOLUME_CTRL, WMC_MUTE); wmc_set(WMC_ROUT1_HP_VOLUME_CTRL, WMC_MUTE); } else { /* Unmute outputs not at mute level */ if (wmc_vol.vol_l > 0) wmc_clear(WMC_LOUT1_HP_VOLUME_CTRL, WMC_MUTE); if (wmc_vol.vol_r > 0) wmc_clear(WMC_ROUT1_HP_VOLUME_CTRL, WMC_MUTE); } }
void audiohw_set_frequency(int fsel) { extern const struct wmc_srctrl_entry wmc_srctrl_table[HW_NUM_FREQ]; unsigned int plln; unsigned int mclkdiv; if ((unsigned)fsel >= HW_NUM_FREQ) fsel = HW_FREQ_DEFAULT; /* Setup filters. */ wmc_write(WMC_ADDITIONAL_CTRL, wmc_srctrl_table[fsel].filter); plln = wmc_srctrl_table[fsel].plln; mclkdiv = wmc_srctrl_table[fsel].mclkdiv; if (plln != 0) { /* Using PLL to generate SYSCLK */ /* Program PLL. */ wmc_write(WMC_PLL_N, plln); wmc_write(WMC_PLL_K1, wmc_srctrl_table[fsel].pllk1); wmc_write(WMC_PLL_K2, wmc_srctrl_table[fsel].pllk2); wmc_write(WMC_PLL_K3, wmc_srctrl_table[fsel].pllk3); /* Turn on PLL. */ wmc_set(WMC_POWER_MANAGEMENT1, WMC_PLLEN); /* Switch to PLL and set divider. */ wmc_write_masked(WMC_CLOCK_GEN_CTRL, mclkdiv | WMC_CLKSEL, WMC_MCLKDIV | WMC_CLKSEL); } else { /* Switch away from PLL and set MCLKDIV. */ wmc_write_masked(WMC_CLOCK_GEN_CTRL, mclkdiv, WMC_MCLKDIV | WMC_CLKSEL); /* Turn off PLL. */ wmc_clear(WMC_POWER_MANAGEMENT1, WMC_PLLEN); } }
void audiohw_set_recsrc(int source, bool recording) { switch (source) { case AUDIO_SRC_PLAYBACK: /* Disable all audio paths but DAC */ /* Disable ADCs */ wmc_clear(WMC_ADC_CONTROL, WMC_HPFEN); wmc_clear(WMC_POWER_MANAGEMENT2, WMC_ADCENL | WMC_ADCENR); /* Disable bypass */ wmc_clear(WMC_LEFT_MIXER_CTRL, WMC_BYPL2LMIX); wmc_clear(WMC_RIGHT_MIXER_CTRL, WMC_BYPR2RMIX); /* Disable IP BOOSTMIX and PGA */ wmc_clear(WMC_POWER_MANAGEMENT2, WMC_INPPGAENL | WMC_INPPGAENR | WMC_BOOSTENL | WMC_BOOSTENR); wmc_clear(WMC_INPUT_CTRL, WMC_L2_2INPPGA | WMC_R2_2INPPGA | WMC_LIP2INPPGA | WMC_RIP2INPPGA | WMC_LIN2INPPGA | WMC_RIN2INPPGA); wmc_clear(WMC_LEFT_ADC_BOOST_CTRL, WMC_PGABOOSTL); wmc_clear(WMC_RIGHT_ADC_BOOST_CTRL, WMC_PGABOOSTR); break; case AUDIO_SRC_FMRADIO: if (recording) { /* Disable bypass */ wmc_clear(WMC_LEFT_MIXER_CTRL, WMC_BYPL2LMIX); wmc_clear(WMC_RIGHT_MIXER_CTRL, WMC_BYPR2RMIX); /* Enable ADCs, IP BOOSTMIX and PGA, route L/R2 through PGA */ wmc_set(WMC_POWER_MANAGEMENT2, WMC_ADCENL | WMC_ADCENR | WMC_BOOSTENL | WMC_BOOSTENR | WMC_INPPGAENL | WMC_INPPGAENR); wmc_set(WMC_ADC_CONTROL, WMC_ADCOSR | WMC_HPFEN); /* PGA at 0dB with +20dB boost */ wmc_write_masked(WMC_LEFT_INP_PGA_GAIN_CTRL, 0x10, WMC_AVOL); wmc_write_masked(WMC_RIGHT_INP_PGA_GAIN_CTRL, 0x10, WMC_AVOL); wmc_set(WMC_LEFT_ADC_BOOST_CTRL, WMC_PGABOOSTL); wmc_set(WMC_RIGHT_ADC_BOOST_CTRL, WMC_PGABOOSTR); /* Connect L/R2 inputs to PGA */ wmc_write_masked(WMC_INPUT_CTRL, WMC_L2_2INPPGA | WMC_R2_2INPPGA | WMC_LIN2INPPGA | WMC_RIN2INPPGA, WMC_L2_2INPPGA | WMC_R2_2INPPGA | WMC_LIP2INPPGA | WMC_RIP2INPPGA | WMC_LIN2INPPGA | WMC_RIN2INPPGA); } else { /* Disable PGA and ADC, enable IP BOOSTMIX, route L/R2 directly to * IP BOOSTMIX */ wmc_clear(WMC_ADC_CONTROL, WMC_HPFEN); wmc_write_masked(WMC_POWER_MANAGEMENT2, WMC_BOOSTENL | WMC_BOOSTENR, WMC_BOOSTENL | WMC_BOOSTENR | WMC_INPPGAENL | WMC_INPPGAENR | WMC_ADCENL | WMC_ADCENR); wmc_clear(WMC_INPUT_CTRL, WMC_L2_2INPPGA | WMC_R2_2INPPGA | WMC_LIP2INPPGA | WMC_RIP2INPPGA | WMC_LIN2INPPGA | WMC_RIN2INPPGA); wmc_clear(WMC_LEFT_ADC_BOOST_CTRL, WMC_PGABOOSTL); wmc_clear(WMC_RIGHT_ADC_BOOST_CTRL, WMC_PGABOOSTR); /* Enable bypass to L/R mixers */ wmc_set(WMC_LEFT_MIXER_CTRL, WMC_BYPL2LMIX); wmc_set(WMC_RIGHT_MIXER_CTRL, WMC_BYPR2RMIX); } break; } }
/* Initialize new condition and set to false; can be used to re-initialize a * condition for re-use */ void wmc_init(WinMsgCond *cond, char *pos) { cond->locked = false; cond->pos = pos; wmc_clear(cond); }