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;
    }
}
Example #8
0
/* 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);
}