| /* |
| * Copyright (c) 2016, Freescale Semiconductor, Inc. |
| * Copyright 2016-2017 NXP |
| * |
| * Redistribution and use in source and binary forms, with or without modification, |
| * are permitted provided that the following conditions are met: |
| * |
| * o Redistributions of source code must retain the above copyright notice, this list |
| * of conditions and the following disclaimer. |
| * |
| * o Redistributions in binary form must reproduce the above copyright notice, this |
| * list of conditions and the following disclaimer in the documentation and/or |
| * other materials provided with the distribution. |
| * |
| * o Neither the name of the copyright holder nor the names of its |
| * contributors may be used to endorse or promote products derived from this |
| * software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR |
| * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
| * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "fsl_dmic.h" |
| |
| /******************************************************************************* |
| * Variables |
| ******************************************************************************/ |
| |
| /* Array of DMIC peripheral base address. */ |
| static DMIC_Type *const s_dmicBases[FSL_FEATURE_SOC_DMIC_COUNT] = DMIC_BASE_PTRS; |
| |
| /* Array of DMIC clock name. */ |
| static const clock_ip_name_t s_dmicClock[FSL_FEATURE_SOC_DMIC_COUNT] = DMIC_CLOCKS; |
| |
| /* Array of DMIC IRQ number. */ |
| static const IRQn_Type s_dmicIRQ[FSL_FEATURE_SOC_DMIC_COUNT] = DMIC_IRQS; |
| |
| /*! @brief Callback function array for DMIC(s). */ |
| static dmic_callback_t s_dmicCallback[FSL_FEATURE_SOC_DMIC_COUNT]; |
| |
| /* Array of HWVAD IRQ number. */ |
| static const IRQn_Type s_dmicHwvadIRQ[FSL_FEATURE_SOC_DMIC_COUNT] = DMIC_HWVAD_IRQS; |
| |
| /*! @brief Callback function array for HWVAD(s). */ |
| static dmic_hwvad_callback_t s_dmicHwvadCallback[FSL_FEATURE_SOC_DMIC_COUNT]; |
| |
| /******************************************************************************* |
| * Prototypes |
| ******************************************************************************/ |
| /*! |
| * @brief Get the DMIC instance from peripheral base address. |
| * |
| * @param base DMIC peripheral base address. |
| * @return DMIC instance. |
| */ |
| uint32_t DMIC_GetInstance(DMIC_Type *base) |
| { |
| uint32_t instance; |
| |
| /* Find the instance index from base address mappings. */ |
| for (instance = 0; instance < ARRAY_SIZE(s_dmicBases); instance++) |
| { |
| if (s_dmicBases[instance] == base) |
| { |
| break; |
| } |
| } |
| |
| assert(instance < ARRAY_SIZE(s_dmicBases)); |
| |
| return instance; |
| } |
| |
| void DMIC_Init(DMIC_Type *base) |
| { |
| assert(base); |
| |
| /* Enable the clock to the register interface */ |
| CLOCK_EnableClock(s_dmicClock[DMIC_GetInstance(base)]); |
| |
| /* Reset the peripheral */ |
| RESET_PeripheralReset(kDMIC_RST_SHIFT_RSTn); |
| |
| /* Disable DMA request*/ |
| base->CHANNEL[0].FIFO_CTRL &= ~DMIC_CHANNEL_FIFO_CTRL_DMAEN(1); |
| base->CHANNEL[1].FIFO_CTRL &= ~DMIC_CHANNEL_FIFO_CTRL_DMAEN(1); |
| |
| /* Disable DMIC interrupt. */ |
| base->CHANNEL[0].FIFO_CTRL &= ~DMIC_CHANNEL_FIFO_CTRL_INTEN(1); |
| base->CHANNEL[1].FIFO_CTRL &= ~DMIC_CHANNEL_FIFO_CTRL_INTEN(1); |
| } |
| |
| void DMIC_DeInit(DMIC_Type *base) |
| { |
| assert(base); |
| /* Disable the clock to the register interface */ |
| CLOCK_DisableClock(s_dmicClock[DMIC_GetInstance(base)]); |
| } |
| |
| void DMIC_ConfigIO(DMIC_Type *base, dmic_io_t config) |
| { |
| base->IOCFG = config; |
| } |
| |
| void DMIC_SetOperationMode(DMIC_Type *base, operation_mode_t mode) |
| { |
| if (mode == kDMIC_OperationModeInterrupt) |
| { |
| /* Enable DMIC interrupt. */ |
| base->CHANNEL[0].FIFO_CTRL |= DMIC_CHANNEL_FIFO_CTRL_INTEN(1); |
| base->CHANNEL[1].FIFO_CTRL |= DMIC_CHANNEL_FIFO_CTRL_INTEN(1); |
| } |
| if (mode == kDMIC_OperationModeDma) |
| { |
| /* enable DMA request*/ |
| base->CHANNEL[0].FIFO_CTRL |= DMIC_CHANNEL_FIFO_CTRL_DMAEN(1); |
| base->CHANNEL[1].FIFO_CTRL |= DMIC_CHANNEL_FIFO_CTRL_DMAEN(1); |
| } |
| } |
| |
| void DMIC_ConfigChannel(DMIC_Type *base, |
| dmic_channel_t channel, |
| stereo_side_t side, |
| dmic_channel_config_t *channel_config) |
| { |
| base->CHANNEL[channel].DIVHFCLK = channel_config->divhfclk; |
| base->CHANNEL[channel].OSR = channel_config->osr; |
| base->CHANNEL[channel].GAINSHIFT = channel_config->gainshft; |
| base->CHANNEL[channel].PREAC2FSCOEF = channel_config->preac2coef; |
| base->CHANNEL[channel].PREAC4FSCOEF = channel_config->preac4coef; |
| base->CHANNEL[channel].PHY_CTRL = |
| DMIC_CHANNEL_PHY_CTRL_PHY_FALL(side) | DMIC_CHANNEL_PHY_CTRL_PHY_HALF(channel_config->sample_rate); |
| base->CHANNEL[channel].DC_CTRL = DMIC_CHANNEL_DC_CTRL_DCPOLE(channel_config->dc_cut_level) | |
| DMIC_CHANNEL_DC_CTRL_DCGAIN(channel_config->post_dc_gain_reduce) | |
| DMIC_CHANNEL_DC_CTRL_SATURATEAT16BIT(channel_config->saturate16bit); |
| } |
| |
| void DMIC_CfgChannelDc(DMIC_Type *base, |
| dmic_channel_t channel, |
| dc_removal_t dc_cut_level, |
| uint32_t post_dc_gain_reduce, |
| bool saturate16bit) |
| { |
| base->CHANNEL[channel].DC_CTRL = DMIC_CHANNEL_DC_CTRL_DCPOLE(dc_cut_level) | |
| DMIC_CHANNEL_DC_CTRL_DCGAIN(post_dc_gain_reduce) | |
| DMIC_CHANNEL_DC_CTRL_SATURATEAT16BIT(saturate16bit); |
| } |
| |
| void DMIC_Use2fs(DMIC_Type *base, bool use2fs) |
| { |
| base->USE2FS = (use2fs) ? 0x1 : 0x0; |
| } |
| |
| void DMIC_EnableChannnel(DMIC_Type *base, uint32_t channelmask) |
| { |
| base->CHANEN = channelmask; |
| } |
| |
| void DMIC_FifoChannel(DMIC_Type *base, uint32_t channel, uint32_t trig_level, uint32_t enable, uint32_t resetn) |
| { |
| base->CHANNEL[channel].FIFO_CTRL |= |
| (base->CHANNEL[channel].FIFO_CTRL & (DMIC_CHANNEL_FIFO_CTRL_INTEN_MASK | DMIC_CHANNEL_FIFO_CTRL_DMAEN_MASK)) | |
| DMIC_CHANNEL_FIFO_CTRL_TRIGLVL(trig_level) | DMIC_CHANNEL_FIFO_CTRL_ENABLE(enable) | |
| DMIC_CHANNEL_FIFO_CTRL_RESETN(resetn); |
| } |
| |
| void DMIC_EnableIntCallback(DMIC_Type *base, dmic_callback_t cb) |
| { |
| uint32_t instance; |
| |
| instance = DMIC_GetInstance(base); |
| NVIC_ClearPendingIRQ(s_dmicIRQ[instance]); |
| /* Save callback pointer */ |
| s_dmicCallback[instance] = cb; |
| EnableIRQ(s_dmicIRQ[instance]); |
| } |
| |
| void DMIC_DisableIntCallback(DMIC_Type *base, dmic_callback_t cb) |
| { |
| uint32_t instance; |
| |
| instance = DMIC_GetInstance(base); |
| DisableIRQ(s_dmicIRQ[instance]); |
| s_dmicCallback[instance] = NULL; |
| NVIC_ClearPendingIRQ(s_dmicIRQ[instance]); |
| } |
| |
| void DMIC_HwvadEnableIntCallback(DMIC_Type *base, dmic_hwvad_callback_t vadcb) |
| { |
| uint32_t instance; |
| |
| instance = DMIC_GetInstance(base); |
| NVIC_ClearPendingIRQ(s_dmicHwvadIRQ[instance]); |
| /* Save callback pointer */ |
| s_dmicHwvadCallback[instance] = vadcb; |
| EnableIRQ(s_dmicHwvadIRQ[instance]); |
| } |
| |
| void DMIC_HwvadDisableIntCallback(DMIC_Type *base, dmic_hwvad_callback_t vadcb) |
| { |
| uint32_t instance; |
| |
| instance = DMIC_GetInstance(base); |
| DisableIRQ(s_dmicHwvadIRQ[instance]); |
| s_dmicHwvadCallback[instance] = NULL; |
| NVIC_ClearPendingIRQ(s_dmicHwvadIRQ[instance]); |
| } |
| |
| /* IRQ handler functions overloading weak symbols in the startup */ |
| #if defined(DMIC0) |
| /*DMIC0 IRQ handler */ |
| void DMIC0_DriverIRQHandler(void) |
| { |
| if (s_dmicCallback[0] != NULL) |
| { |
| s_dmicCallback[0](); |
| } |
| } |
| /*DMIC0 HWVAD IRQ handler */ |
| void HWVAD0_IRQHandler(void) |
| { |
| if (s_dmicHwvadCallback[0] != NULL) |
| { |
| s_dmicHwvadCallback[0](); |
| } |
| } |
| #endif |