summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTanek <[email protected]>2018-05-08 16:30:14 +0800
committerGitHub <[email protected]>2018-05-08 16:30:14 +0800
commitd60a6c438e3c5ae061912e2dce5fed2df9891a72 (patch)
tree1569a7420ec71eb3e82e42e255da237a6ad7ca52
parenta00cdcd7506489ad986d2b684b126fce6323349b (diff)
parent8b371e6be0767fc3726d7a1f70236529f7ccbc20 (diff)
Merge pull request #1322 from heyuanjie87/imx1050
Imx1050
-rw-r--r--bsp/imxrt1052-evk/Libraries/drivers/fsl_sai_edma.c8
-rw-r--r--bsp/imxrt1052-evk/SConstruct2
-rw-r--r--bsp/imxrt1052-evk/drivers/SConscript3
-rw-r--r--bsp/imxrt1052-evk/drivers/drv_codec.c394
-rw-r--r--bsp/imxrt1052-evk/drivers/drv_codec.h228
-rw-r--r--bsp/imxrt1052-evk/drivers/fsl_wm8960.c621
-rw-r--r--bsp/imxrt1052-evk/drivers/fsl_wm8960.h426
7 files changed, 1677 insertions, 5 deletions
diff --git a/bsp/imxrt1052-evk/Libraries/drivers/fsl_sai_edma.c b/bsp/imxrt1052-evk/Libraries/drivers/fsl_sai_edma.c
index 6f4dda6998..f895e0de78 100644
--- a/bsp/imxrt1052-evk/Libraries/drivers/fsl_sai_edma.c
+++ b/bsp/imxrt1052-evk/Libraries/drivers/fsl_sai_edma.c
@@ -91,15 +91,15 @@ static void SAI_TxEDMACallback(edma_handle_t *handle, void *userData, bool done,
sai_edma_handle_t *saiHandle = privHandle->handle;
/* If finished a blcok, call the callback function */
- memset(&saiHandle->saiQueue[saiHandle->queueDriver], 0, sizeof(sai_transfer_t));
- saiHandle->queueDriver = (saiHandle->queueDriver + 1) % SAI_XFER_QUEUE_SIZE;
+ saiHandle->saiQueue[saiHandle->queueDriver].dataSize = 0;
if (saiHandle->callback)
{
(saiHandle->callback)(privHandle->base, saiHandle, kStatus_SAI_TxIdle, saiHandle->userData);
}
+ saiHandle->queueDriver = (saiHandle->queueDriver + 1) % SAI_XFER_QUEUE_SIZE;
/* If all data finished, just stop the transfer */
- if (saiHandle->saiQueue[saiHandle->queueDriver].data == NULL)
+ if (saiHandle->saiQueue[saiHandle->queueDriver].dataSize == 0)
{
/* Disable DMA enable bit */
SAI_TxEnableDMA(privHandle->base, kSAI_FIFORequestDMAEnable, false);
@@ -264,7 +264,7 @@ status_t SAI_TransferSendEDMA(I2S_Type *base, sai_edma_handle_t *handle, sai_tra
return kStatus_InvalidArgument;
}
- if (handle->saiQueue[handle->queueUser].data)
+ if (handle->saiQueue[handle->queueUser].dataSize)
{
return kStatus_SAI_QueueFull;
}
diff --git a/bsp/imxrt1052-evk/SConstruct b/bsp/imxrt1052-evk/SConstruct
index 7021727b79..f6e51cbf6a 100644
--- a/bsp/imxrt1052-evk/SConstruct
+++ b/bsp/imxrt1052-evk/SConstruct
@@ -6,7 +6,7 @@ import rtconfig
if os.getenv('RTT_ROOT'):
RTT_ROOT = os.getenv('RTT_ROOT')
else:
- RTT_ROOT = os.path.normpath(os.getcwd() + '/../..')
+ RTT_ROOT = os.path.normpath(os.getcwd() + '/../..')
sys.path = sys.path + [os.path.join(RTT_ROOT, 'tools')]
from building import *
diff --git a/bsp/imxrt1052-evk/drivers/SConscript b/bsp/imxrt1052-evk/drivers/SConscript
index 98f34a1e17..3350d4b3f7 100644
--- a/bsp/imxrt1052-evk/drivers/SConscript
+++ b/bsp/imxrt1052-evk/drivers/SConscript
@@ -62,6 +62,9 @@ if GetDepend('BOARD_RT1050_EVK') or GetDepend('BOARD_RT1050_SeeedStudio'):
src += ['drv_eth.c', 'fsl_phy.c']
CPPDEFINES += ['FSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE']
+if GetDepend('RT_USING_AUDIO'):
+ src += ['drv_codec.c', 'fsl_wm8960.c']
+
group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH, CPPDEFINES=CPPDEFINES)
Return('group')
diff --git a/bsp/imxrt1052-evk/drivers/drv_codec.c b/bsp/imxrt1052-evk/drivers/drv_codec.c
new file mode 100644
index 0000000000..69b731e99f
--- /dev/null
+++ b/bsp/imxrt1052-evk/drivers/drv_codec.c
@@ -0,0 +1,394 @@
+#include <rthw.h>
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#include "board.h"
+#include "drv_codec.h"
+#include "fsl_wm8960.h"
+
+#include <fsl_sai.h>
+#include <fsl_sai_edma.h>
+#include <fsl_lpi2c.h>
+#include <fsl_dmamux.h>
+
+#define DEMO_CODEC_WM8960
+#define DEMO_SAI SAI1
+#define DEMO_SAI_IRQ SAI1_IRQn
+#define SAI_TxIRQHandler SAI1_IRQHandler
+
+/* Select Audio/Video PLL (786.48 MHz) as sai1 clock source */
+#define DEMO_SAI1_CLOCK_SOURCE_SELECT (2U)
+/* Clock pre divider for sai1 clock source */
+#define DEMO_SAI1_CLOCK_SOURCE_PRE_DIVIDER (1U)
+/* Clock divider for sai1 clock source */
+#define DEMO_SAI1_CLOCK_SOURCE_DIVIDER (63U)
+/* Get frequency of sai1 clock */
+#define DEMO_SAI_CLK_FREQ (CLOCK_GetFreq(kCLOCK_AudioPllClk) / (DEMO_SAI1_CLOCK_SOURCE_DIVIDER + 1U) / (DEMO_SAI1_CLOCK_SOURCE_PRE_DIVIDER + 1U))
+
+/* I2C instance and clock */
+#define DEMO_I2C LPI2C1
+
+/* Select USB1 PLL (480 MHz) as master lpi2c clock source */
+#define DEMO_LPI2C_CLOCK_SOURCE_SELECT (0U)
+/* Clock divider for master lpi2c clock source */
+#define DEMO_LPI2C_CLOCK_SOURCE_DIVIDER (5U)
+/* Get frequency of lpi2c clock */
+#define DEMO_I2C_CLK_FREQ ((CLOCK_GetFreq(kCLOCK_Usb1PllClk) / 8) / (DEMO_LPI2C_CLOCK_SOURCE_DIVIDER + 1U))
+
+/* DMA */
+#define DMAMUX0 DMAMUX
+#define EXAMPLE_DMA DMA0
+#define EXAMPLE_CHANNEL (0U)
+#define EXAMPLE_SAI_TX_SOURCE kDmaRequestMuxSai1Tx
+
+struct imxcodec
+{
+ I2S_Type *sai;
+ sai_edma_handle_t txHandle;
+ wm8960_handle_t codecHandle;
+ edma_handle_t dmaHandle;
+ lpi2c_master_handle_t i2cHandle;
+ sai_transfer_format_t format;
+};
+
+static void _InitPins(void)
+{
+ CLOCK_EnableClock(kCLOCK_Iomuxc);
+
+ IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, 1);
+ IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, 1);
+
+ IOMUXC_SetPinConfig( IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, 0xD8B0u);
+ IOMUXC_SetPinConfig( IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, 0xD8B0u);
+
+ IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_09_SAI1_MCLK, 1U);
+ IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_13_SAI1_TX_DATA00, 1U);
+ IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_14_SAI1_TX_BCLK, 1U);
+ IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_15_SAI1_TX_SYNC, 1U);
+
+ IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_09_SAI1_MCLK, 0x10B0u);
+ IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_13_SAI1_TX_DATA00, 0x10B0u);
+ IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_14_SAI1_TX_BCLK, 0x10B0u);
+ IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_15_SAI1_TX_SYNC, 0x10B0u);
+}
+
+static void BOARD_EnableSaiMclkOutput(bool enable)
+{
+ if (enable)
+ {
+ IOMUXC_GPR->GPR1 |= IOMUXC_GPR_GPR1_SAI1_MCLK_DIR_MASK;
+ }
+ else
+ {
+ IOMUXC_GPR->GPR1 &= (~IOMUXC_GPR_GPR1_SAI1_MCLK_DIR_MASK);
+ }
+}
+
+static void saidma_callback(I2S_Type *base, sai_edma_handle_t *handle, status_t status, void *userData)
+{
+ int ind = 0;
+ rt_uint8_t *saddr;
+
+ ind = handle->queueDriver;
+ saddr = (rt_uint8_t*)handle->saiQueue[ind].data;
+ rt_audio_tx_complete(userData, saddr);
+}
+
+/*********************************************************************************************************
+** Audio device
+*********************************************************************************************************/
+
+static rt_err_t icodec_getcaps(struct rt_audio_device *audio,struct rt_audio_caps *caps)
+{
+ rt_err_t result = RT_EOK;
+ struct imxcodec *icodec = (struct imxcodec *)audio->parent.user_data;
+
+ switch (caps->main_type)
+ {
+ case AUDIO_TYPE_QUERY: /* qurey the types of hw_codec device */
+ {
+ switch (caps->sub_type)
+ {
+ case AUDIO_TYPE_QUERY:
+ caps->udata.mask = AUDIO_TYPE_OUTPUT | AUDIO_TYPE_MIXER;
+ break;
+ default:
+ result = -RT_ERROR;
+ break;
+ }
+
+ break;
+ }
+ case AUDIO_TYPE_OUTPUT: /* Provide capabilities of OUTPUT unit */
+ switch (caps->sub_type)
+ {
+ case AUDIO_DSP_PARAM:
+ if (audio->replay == NULL)
+ {
+ result = -RT_ERROR;
+ break;
+ }
+ caps->udata.config.channels = 1;
+ caps->udata.config.samplefmt = 1;
+ caps->udata.config.samplerate = 1;
+ caps->udata.config.samplefmts = 1;
+ break;
+ default:
+ result = -RT_ERROR;
+ break;
+ }
+ break;
+ case AUDIO_TYPE_MIXER: /* report the Mixer Units */
+ switch (caps->sub_type)
+ {
+ case AUDIO_MIXER_QUERY:
+ caps->udata.mask = AUDIO_MIXER_VOLUME | AUDIO_MIXER_DIGITAL | AUDIO_MIXER_LINE;
+ break;
+ case AUDIO_MIXER_VOLUME:
+ caps->udata.value = WM8960_GetVolume(&icodec->codecHandle, kWM8960_ModuleDAC);
+ break;
+ case AUDIO_MIXER_DIGITAL:
+
+ break;
+ case AUDIO_MIXER_LINE:
+
+ break;
+ default:
+ result = -RT_ERROR;
+ break;
+ }
+ break;
+ default:
+ result = -RT_ERROR;
+ break;
+ }
+
+ return result;
+}
+
+static rt_err_t icodec_configure(struct rt_audio_device *audio,struct rt_audio_caps *caps)
+{
+ rt_err_t result = RT_EOK;
+ struct imxcodec *icodec = (struct imxcodec *)audio->parent.user_data;
+
+ switch (caps->main_type)
+ {
+ case AUDIO_TYPE_MIXER:
+ {
+ switch (caps->sub_type)
+ {
+ case AUDIO_MIXER_VOLUME:
+ {
+ WM8960_SetVolume(&icodec->codecHandle, kWM8960_ModuleDAC,
+ caps->udata.value);
+ }
+ break;
+ default:
+ {
+ result = -RT_ERROR;
+ }
+ break;
+ }
+ }
+ break;
+ case AUDIO_TYPE_OUTPUT:
+ {
+ switch (caps->sub_type)
+ {
+ case AUDIO_DSP_PARAM:
+ {
+
+ } break;
+ case AUDIO_DSP_SAMPLERATE:
+ {
+ int rate = caps->udata.value;
+
+ icodec->format.sampleRate_Hz = rate;
+ SAI_TxSetFormat(icodec->sai, &icodec->format, icodec->format.masterClockHz, icodec->format.masterClockHz);
+ }
+ break;
+ default:
+ {
+ result = -RT_ERROR;
+ }
+ break;
+ }
+ }
+ break;
+ default:
+ result = -RT_ERROR;
+ break;
+ }
+
+ return result;
+}
+
+static rt_err_t icodec_init(struct rt_audio_device *audio)
+{
+ sai_config_t config;
+ uint32_t mclkSourceClockHz = 0U;
+ edma_config_t dmaConfig = {0};
+ lpi2c_master_config_t i2cConfig = {0};
+ uint32_t i2cSourceClock;
+ clock_audio_pll_config_t audioPllConfig = {32, 1, 77, 100};
+ struct imxcodec *icodec = audio->parent.user_data;
+ sai_transfer_format_t *format;
+
+ icodec->sai = DEMO_SAI;
+ format = &icodec->format;
+
+ _InitPins();
+ CLOCK_InitAudioPll(&audioPllConfig);
+
+ /*Clock setting for LPI2C*/
+ CLOCK_SetMux(kCLOCK_Lpi2cMux, DEMO_LPI2C_CLOCK_SOURCE_SELECT);
+ CLOCK_SetDiv(kCLOCK_Lpi2cDiv, DEMO_LPI2C_CLOCK_SOURCE_DIVIDER);
+
+ /*Clock setting for SAI1*/
+ CLOCK_SetMux(kCLOCK_Sai1Mux, DEMO_SAI1_CLOCK_SOURCE_SELECT);
+ CLOCK_SetDiv(kCLOCK_Sai1PreDiv, DEMO_SAI1_CLOCK_SOURCE_PRE_DIVIDER);
+ CLOCK_SetDiv(kCLOCK_Sai1Div, DEMO_SAI1_CLOCK_SOURCE_DIVIDER);
+
+ /*Enable MCLK clock*/
+ BOARD_EnableSaiMclkOutput(true);
+
+ /* Create EDMA handle */
+ EDMA_GetDefaultConfig(&dmaConfig);
+ EDMA_Init(EXAMPLE_DMA, &dmaConfig);
+ EDMA_CreateHandle(&icodec->dmaHandle, EXAMPLE_DMA, EXAMPLE_CHANNEL);
+
+ DMAMUX_Init(DMAMUX0);
+ DMAMUX_SetSource(DMAMUX0, EXAMPLE_CHANNEL, EXAMPLE_SAI_TX_SOURCE);
+ DMAMUX_EnableChannel(DMAMUX0, EXAMPLE_CHANNEL);
+
+ /* Init SAI module */
+ SAI_TxGetDefaultConfig(&config);
+ SAI_TxInit(DEMO_SAI, &config);
+
+ /* Configure the audio format */
+ format->bitWidth = kSAI_WordWidth16bits;
+ format->channel = 0U;
+ format->sampleRate_Hz = kSAI_SampleRate48KHz;
+ format->masterClockHz = DEMO_SAI_CLK_FREQ;
+ format->protocol = config.protocol;
+ format->stereo = kSAI_Stereo;
+ format->isFrameSyncCompact = 0;
+ format->watermark = FSL_FEATURE_SAI_FIFO_COUNT / 2U;
+
+ /* Configure Sgtl5000 I2C */
+ icodec->codecHandle.base = DEMO_I2C;
+ icodec->codecHandle.i2cHandle = &icodec->i2cHandle;
+ i2cSourceClock = DEMO_I2C_CLK_FREQ;
+
+ LPI2C_MasterGetDefaultConfig(&i2cConfig);
+ LPI2C_MasterInit(DEMO_I2C, &i2cConfig, i2cSourceClock);
+ LPI2C_MasterTransferCreateHandle(DEMO_I2C, &icodec->i2cHandle, NULL, NULL);
+
+ WM8960_Init(&icodec->codecHandle, NULL);
+ WM8960_ConfigDataFormat(&icodec->codecHandle, format->masterClockHz, format->sampleRate_Hz, format->bitWidth);
+
+ SAI_TransferTxCreateHandleEDMA(icodec->sai, &icodec->txHandle, saidma_callback, audio, &icodec->dmaHandle);
+
+ mclkSourceClockHz = DEMO_SAI_CLK_FREQ;
+ SAI_TransferTxSetFormatEDMA(icodec->sai, &icodec->txHandle, format, mclkSourceClockHz, format->masterClockHz);
+
+ return RT_EOK;
+}
+
+static rt_err_t icodec_shutdown(struct rt_audio_device *audio)
+{
+ return RT_EOK;
+}
+
+rt_err_t icodec_start(struct rt_audio_device *audio,int stream)
+{
+ return RT_EOK;
+}
+
+rt_err_t icodec_stop(struct rt_audio_device *audio,int stream)
+{
+ return RT_EOK;
+}
+
+static rt_err_t icodec_suspend(struct rt_audio_device *audio,int stream)
+{
+ return RT_EOK;
+}
+
+static rt_err_t icodec_resume(struct rt_audio_device *audio,int stream)
+{
+ return RT_EOK;
+}
+
+static rt_err_t icodec_control (struct rt_audio_device *audio, int cmd, void *args)
+{
+ rt_err_t result = RT_EOK;
+
+ switch (cmd)
+ {
+ case AUDIO_CTL_HWRESET:
+
+ break;
+ default:
+ result = -RT_ERROR;
+ break;
+ }
+
+ return result;
+}
+
+static rt_size_t icodec_transmit(struct rt_audio_device *audio, const void *writeBuf, void *readBuf, rt_size_t size)
+{
+ struct imxcodec *icodec = (struct imxcodec *)audio->parent.user_data;
+
+ if(writeBuf != RT_NULL)
+ {
+ sai_transfer_t xfer;
+
+ xfer.data = (uint8_t *)writeBuf;
+ xfer.dataSize = size;
+ if (size%32 == 0)
+ icodec->txHandle.count = 16;
+ else
+ icodec->txHandle.count = 1;
+
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, (void*)writeBuf, size);
+ if (SAI_TransferSendEDMA(icodec->sai, &icodec->txHandle, &xfer) != kStatus_Success)
+ return 0;
+
+ return size;
+ }
+
+ return 0;
+}
+
+static struct imxcodec _g_imxcodec;
+static struct rt_audio_device _g_audio_device;
+const struct rt_audio_ops _g_audio_ops =
+{
+ .getcaps = icodec_getcaps,
+ .configure = icodec_configure,
+
+ .init = icodec_init,
+ .shutdown = icodec_shutdown,
+ .start = icodec_start,
+ .stop = icodec_stop,
+ .suspend = icodec_suspend,
+ .resume = icodec_resume,
+ .control = icodec_control,
+
+ .transmit = icodec_transmit,
+};
+
+int rt_hw_codec_init(void)
+{
+ int result;
+ struct rt_audio_device *audio = &_g_audio_device;
+
+ audio->ops = (struct rt_audio_ops*)&_g_audio_ops;
+ _g_imxcodec.sai = DEMO_SAI;
+ result = rt_audio_register(audio,"sound0", RT_DEVICE_FLAG_WRONLY, &_g_imxcodec);
+
+ return result;
+}
+INIT_DEVICE_EXPORT(rt_hw_codec_init);
diff --git a/bsp/imxrt1052-evk/drivers/drv_codec.h b/bsp/imxrt1052-evk/drivers/drv_codec.h
new file mode 100644
index 0000000000..6ee6c354e9
--- /dev/null
+++ b/bsp/imxrt1052-evk/drivers/drv_codec.h
@@ -0,0 +1,228 @@
+#ifndef __DRV_CODEC_H__
+#define __DRV_CODEC_H__
+
+#define SUNXI_DAC_DPC 0x00
+#define SUNXI_DAC_FIFOC 0x04
+#define SUNXI_DAC_FIFOS 0x08
+#define SUNXI_DAC_TXDATA 0x0c
+#define SUNXI_ADC_FIFOC 0x10
+#define SUNXI_ADC_FIFOS 0x14
+#define SUNXI_ADC_RXDATA 0x18
+#define DAC_MIXER_CTRL 0x20
+#define ADC_MIXER_CTRL 0x24
+#define ADDA_TUNE 0x28
+#define BIAS_DA16_CAL_CTRL0 0x2C
+#define BIAS_DA16_CAL_CTRL1 0x34
+
+#define SUNXI_DAC_CNT 0x40
+#define SUNXI_ADC_CNT 0x44
+#define SUNXI_DAC_DG 0x48
+#define SUNXI_ADC_DG 0x4c
+
+#define AC_PR_CFG 0x400
+
+/*AC_DAC_DPC:0x00*/
+#define EN_DAC 31
+#define MODQU 25
+#define DWA 24
+#define HPF_EN 18
+#define DVOL 12
+/*#define HUB_EN 0 */
+
+/*AC_DAC_FIFOC:0x04*/
+#define DAC_FS 29
+#define FIR_VER 28
+#define SEND_LASAT 26
+#define FIFO_MODE 24
+#define DAC_DRQ_CLR_CNT 21
+#define TX_TRIG_LEVEL 8
+#define ADDA_LOOP_EN 7
+#define DAC_MONO_EN 6
+#define TX_SAMPLE_BITS 5
+#define DAC_DRQ_EN 4
+#define DAC_IRQ_EN 3
+#define FIFO_UNDERRUN_IRQ_EN 2
+#define FIFO_OVERRUN_IRQ_EN 1
+#define FIFO_FLUSH 0
+
+/*AC_ADC_FIFOC:0x10*/
+#define ADFS 29
+#define EN_AD 28
+#define RX_FIFO_MODE 24
+#define ADCDFEN 16
+#define RX_FIFO_TRG_LEVEL 8
+#define ADC_MONO_EN 7
+#define RX_SAMPLE_BITS 6
+#define ADC_DRQ_EN 4
+#define ADC_IRQ_EN 3
+#define ADC_OVERRUN_IRQ_EN 1
+#define ADC_FIFO_FLUSH 0
+
+
+/*DAC_MIXER_CTRL: 0x20*/
+#define DAC_AG_R_EN 31 /* dac right enable bit */
+#define DAC_AG_L_EN 30 /* dac left enable bit */
+#define R_MIXER_EN 29 /* right output mixer */
+#define L_MIXER_EN 28 /* left output mixer */
+#define PH_R_MUTE 27 /* headphone right mute */
+#define PH_L_MUTE 26 /* headphone left mute */
+#define PH_R_PWR_SLT 25
+#define PH_L_PWR_SLT 24
+#define PH_COM_FC 22
+#define PH_COM_PROTEC 21
+#define R_MIXER_MUTE_MIC 20
+#define R_MIXER_MUTE_LINEIN 19
+#define R_MIXER_MUTE_FM 18
+#define R_MIXER_MUTE_R_DAC 17
+#define R_MIXER_MUTE_L_DAC 16
+#define R_MIXER_MUTE 16
+#define HP_POWER_EN 15
+#define L_MIXER_MUTE_MIC 12
+#define L_MIXER_MUTE_LINEIN 11
+#define L_MIXER_MUTE_FM 10
+#define L_MIXER_MUTE_R_DAC 9
+#define L_MIXER_MUTE_L_DAC 8
+#define L_MIXER_MUTE 8
+#define L_HP_TO_R_HP_MUTE 7
+#define R_HP_TO_L_HP_MUTE 6
+#define HP_VOL 0
+
+/*ADC_MIXER_CTRL: 0x24*/
+#define ADC_EN 31 /* adc enable bit */
+/* mic in boost stage to L or R output mixer gain control */
+#define MIC_GAIN_CTL 24
+#define LINEIN_VOL 21 /* right output mixer */
+#define ADC_IN_GAIN_CTL 16 /* adc input gain control */
+#define COS_SLOP_TM 14 /* COS slop time control for Anti-pop */
+#define ADC_MIX_MUTE_MIC 13
+#define ADC_MIX_MUTE_FML 12
+#define ADC_MIX_MUTE_FMR 11
+#define ADC_MIX_MUTE_LINEIN 10
+#define ADC_MIX_MUTE_L 9
+#define ADC_MIX_MUTE_R 8
+#define ADC_MIX_MUTE 8 /* ADC mixer mute control */
+#define PA_SPEED_SLT 7 /* PA speed select->0: normal 1: fast */
+#define FM_TO_MIX_GAIN 4 /* FMin to mixer gain control */
+#define MIC_BST_AMP_EN 3 /* MIC boost AMP enable */
+#define MIC_BOST_GAIN 0 /* MIC boast AMP gain control */
+
+/*AC_ADC_TXDATA:0x20*/
+#define TX_DATA 0
+
+/*AC_DAC_CNT:0x40*/
+#define TX_CNT 0
+
+/*AC_ADC_CNT:0x44*/
+#define RX_CNT 0
+
+/*AC_DAC_DG:0x48*/
+/*
+* DAC Modulator Debug
+* 0:DAC Modulator Normal Mode
+* 1:DAC Modulator Debug Mode
+*/
+#define DAC_MODU_SELECT 11
+/*
+* DAC Pattern Select
+* 00:Normal(Audio sample from TX fifo)
+* 01: -6 dB sin wave
+* 10: -60 dB sin wave
+* 11: silent wave
+*/
+#define DAC_PATTERN_SELECT 9
+/*
+* CODEC Clock Source Select
+* 0:codec clock from PLL
+* 1:codec clock from OSC(for debug)
+*/
+#define CODEC_CLK_SELECT 8
+/*
+* DAC output channel swap enable
+* 0:disable
+* 1:enable
+*/
+#define DA_SWP 6
+
+/*AC_ADC_DG:0x4c*/
+#define AD_SWP 24
+
+/*AC_PR_CFG:0x400*/
+#define AC_PR_RST 28
+#define AC_PR_RW 24
+#define AC_PR_ADDR 16
+#define ADDA_PR_WDAT 8
+#define ADDA_PR_RDAT 0
+
+
+
+/* 时钟配置相关寄存器 */
+#define R6_REG_CCU_BASE 0x01c20000
+#define R6_REG_PLL_AUDIO_CTRL (R6_REG_CCU_BASE + 0x008)
+#define R6_REG_BUS_CLK_GATING_0 (R6_REG_CCU_BASE + 0x060)
+#define R6_REG_BUS_CLK_GATING_1 (R6_REG_CCU_BASE + 0x064)
+#define R6_REG_BUS_CLK_GATING_2 (R6_REG_CCU_BASE + 0x068)
+#define R6_REG_AUDIO_CODEC_CLK (R6_REG_CCU_BASE + 0x140)
+#define R6_REG_BUS_SOFT_RST_0 (R6_REG_CCU_BASE + 0x02C0)
+#define R6_REG_BUS_SOFT_RST_1 (R6_REG_CCU_BASE + 0x02C4)
+#define R6_REG_BUS_SOFT_RST_2 (R6_REG_CCU_BASE + 0x02D0)
+
+/* GPIO配置相关寄存器 */
+#define R6_REG_PIO_BASE 0x01c20800
+#define R6_REG_PD_CFG0 (R6_REG_PIO_BASE + (3 * 0x24 + 0X00))
+#define R6_REG_PD_CFG1 (R6_REG_PIO_BASE + (3 * 0x24 + 0X04))
+#define R6_REG_PD_CFG2 (R6_REG_PIO_BASE + (3 * 0x24 + 0X08))
+#define R6_REG_PD_CFG3 (R6_REG_PIO_BASE + (3 * 0x24 + 0X0c))
+#define R6_REG_PD_DATA (R6_REG_PIO_BASE + (3 * 0x24 + 0X10))
+#define R6_REG_PD_DRV0 (R6_REG_PIO_BASE + (3 * 0x24 + 0X14))
+#define R6_REG_PD_DRV1 (R6_REG_PIO_BASE + (3 * 0x24 + 0X18))
+#define R6_REG_PD_PUL0 (R6_REG_PIO_BASE + (3 * 0x24 + 0X1c))
+#define R6_REG_PD_PUL1 (R6_REG_PIO_BASE + (3 * 0x24 + 0X20))
+
+
+/* AUDIO配置相关寄存器 */
+#define R6_REG_AC_BASE 0x01c23c00
+#define R6_REG_AC_DAC_DPC (R6_REG_AC_BASE + 0x00)
+#define R6_REG_AC_DAC_FIFOC (R6_REG_AC_BASE + 0x04)
+#define R6_REG_AC_DAC_FIFOS (R6_REG_AC_BASE + 0x08)
+#define R6_REG_AC_DAC_TXDADA (R6_REG_AC_BASE + 0x0c)
+#define R6_REG_AC_ADC_FIFOC (R6_REG_AC_BASE + 0x10)
+#define R6_REG_AC_ADC_FIFOS (R6_REG_AC_BASE + 0x14)
+#define R6_REG_AC_ADC_RXDADA (R6_REG_AC_BASE + 0x18)
+#define R6_REG_DAC_MIXER_CTRL (R6_REG_AC_BASE + 0x20)
+#define R6_REG_ADC_MIXER_CTRL (R6_REG_AC_BASE + 0x24)
+#define R6_REG_AC_DAC_CNT (R6_REG_AC_BASE + 0x40)
+
+/* DMA配置相关寄存器 */
+#define R6_REG_NDMA_0_BASE (0x01c02000 + 0x100 + 0 * 0x20)
+
+#define R6_REG_DMA_INT_CTRL (0x01c02000 + 0x00)
+#define R6_REG_DMA_INT_STA (0x01c02000 + 0x04)
+#define R6_REG_DMA_PTY_CFG (0x01c02000 + 0x08)
+#define REG_NDMA_CFG (0x0)
+#define REG_NDMA_SRC_ADR (0x4)
+#define REG_NDMA_DES_ADR (0x8)
+#define REG_NDMA_BYTE_CNT (0xc)
+// #define REG_NDMA_PAR (0x300 + 0x1c)
+
+
+#define NDMA_CFG_SRC_DRQ_IR_RX (0x00 << 0)
+#define NDMA_CFG_SRC_DRQ_NONE (0x01 << 0)
+#define NDMA_CFG_SRC_DRQ_SDRAM (0x11 << 0)
+
+#define NDMA_CFG_DST_LINEAR (0x00 << 21)
+
+#define NDMA_CFG_DST_DRQ_IR_RX (0x00 << 16)
+#define NDMA_CFG_DST_DRQ_NONE (0x01 << 16)
+#define NDMA_CFG_DST_DRQ_SRAM (0x10 << 16)
+#define NDMA_CFG_DST_DRQ_SDRAM (0x11 << 16)
+
+#define NDMA_CFG_SRC_DRQ_SRAM (0x10 << 0)
+#define NDMA_CFG_SRC_LINEAR (0x00 << 5)
+#define NDMA_CFG_SRC_BST4_WIDTH32 ((0x1 << 7) | (0x2 << 8))
+#define NDMA_CFG_DST_DRQ_CODEC (0x0c << 16)
+#define NDMA_CFG_DST_IO (0x1 << 21)
+#define NDMA_CFG_DST_BST4_WIDTH32 ((0x1 << 23) | (0x2 << 24))
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+#endif
diff --git a/bsp/imxrt1052-evk/drivers/fsl_wm8960.c b/bsp/imxrt1052-evk/drivers/fsl_wm8960.c
new file mode 100644
index 0000000000..11c21742ec
--- /dev/null
+++ b/bsp/imxrt1052-evk/drivers/fsl_wm8960.c
@@ -0,0 +1,621 @@
+/*
+ * 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_wm8960.h"
+#include "fsl_common.h"
+
+/*******************************************************************************
+ * Definitations
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*
+ * wm8960 register cache
+ * We can't read the WM8960 register space when we are
+ * using 2 wire for device control, so we cache them instead.
+ */
+static const uint16_t wm8960_reg[WM8960_CACHEREGNUM] = {
+ 0x0097, 0x0097, 0x0000, 0x0000, 0x0000, 0x0008, 0x0000, 0x000a, 0x01c0, 0x0000, 0x00ff, 0x00ff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x007b, 0x0100, 0x0032, 0x0000, 0x00c3, 0x00c3, 0x01c0, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0100, 0x0050, 0x0050, 0x0050, 0x0050, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0040, 0x0000, 0x0000, 0x0050, 0x0050, 0x0000, 0x0002, 0x0037, 0x004d, 0x0080, 0x0008, 0x0031, 0x0026, 0x00e9,
+};
+
+static uint16_t reg_cache[WM8960_CACHEREGNUM];
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+void WM8960_Init(wm8960_handle_t *handle, wm8960_config_t *config)
+{
+ uint32_t i = 4000000;
+
+ memcpy(reg_cache, wm8960_reg, sizeof(wm8960_reg));
+
+ /* Set WM8960 I2C address */
+ handle->xfer.slaveAddress = WM8960_I2C_ADDR;
+
+ /* NULL pointer means default setting. */
+ if (config == NULL)
+ {
+ /*
+ * Reset all registers
+ */
+ WM8960_WriteReg(handle, WM8960_RESET, 0x00);
+
+ WM8960_WriteReg(handle, WM8960_IFACE2, 0x40);
+ /*
+ * VMID=50K, Enable VREF, AINL, AINR, ADCL and ADCR
+ * I2S_IN (bit 0), I2S_OUT (bit 1), DAP (bit 4), DAC (bit 5), ADC (bit 6) are powered on
+ */
+ WM8960_WriteReg(handle, WM8960_POWER1, 0xCA);
+
+ /*
+ * Enable DACL, DACR, LOUT1, ROUT1, PLL down
+ */
+ WM8960_WriteReg(handle, WM8960_POWER2, 0x1E0);
+
+ /*
+ * Enable left and right channel input PGA, left and right output mixer
+ */
+ WM8960_WriteReg(handle, WM8960_POWER3, 0xC);
+
+ /* Configure SYS_FS clock to 44.1kHz, MCLK_FREQ to 256*Fs, SYSCLK derived from MCLK input */
+ WM8960_WriteReg(handle, WM8960_CLOCK1, 0x00);
+
+ /*
+ * Audio data length = 32bit, Left justified data format
+ */
+ WM8960_WriteReg(handle, WM8960_IFACE1, 0x0D);
+
+ /*
+ * LMICBOOST = 0dB, Connect left and right PGA to left and right Input Boost Mixer
+ */
+ WM8960_WriteReg(handle, WM8960_LINPATH, 0x18);
+ WM8960_WriteReg(handle, WM8960_RINPATH, 0x18);
+
+ /*
+ * Left and right input boost, LIN3BOOST and RIN3BOOST = 0dB
+ */
+ WM8960_WriteReg(handle, WM8960_INBMIX1, 0x70);
+ WM8960_WriteReg(handle, WM8960_INBMIX2, 0x70);
+
+ /*
+ * Left DAC and LINPUT3 to left output mixer, LINPUT3 left output mixer volume = 0dB
+ */
+ WM8960_WriteReg(handle, WM8960_LOUTMIX, 0x100);
+
+ /*
+ * Right DAC and RINPUT3 to right output mixer, RINPUT3 right output mixer volume = 0dB
+ */
+ WM8960_WriteReg(handle, WM8960_ROUTMIX, 0x100);
+
+ WM8960_WriteReg(handle, WM8960_BYPASS1, 0x0);
+
+ WM8960_WriteReg(handle, WM8960_BYPASS2, 0x0);
+
+ WM8960_WriteReg(handle, WM8960_MONOMIX1, 0x00);
+ WM8960_WriteReg(handle, WM8960_MONOMIX2, 0x00);
+ }
+ else
+ {
+ WM8960_SetDataRoute(handle, config->route);
+ WM8960_SetProtocol(handle, config->bus);
+ WM8960_SetMasterSlave(handle, config->master_slave);
+ }
+ WM8960_WriteReg(handle, WM8960_ADDCTL1, 0x0C4);
+ WM8960_WriteReg(handle, WM8960_ADDCTL4, 0x40);
+
+ /*
+ * ADC volume, 0dB
+ */
+ WM8960_WriteReg(handle, WM8960_LADC, 0x1F3);
+ WM8960_WriteReg(handle, WM8960_RADC, 0x1F3);
+
+ /*
+ * Digital DAC volume, 0dB
+ */
+ WM8960_WriteReg(handle, WM8960_LDAC, 0x1E0);
+ WM8960_WriteReg(handle, WM8960_RDAC, 0x1E0);
+
+ /*
+ * Headphone volume, LOUT1 and ROUT1, 0dB
+ */
+ WM8960_WriteReg(handle, WM8960_LOUT1, 0x16F);
+ WM8960_WriteReg(handle, WM8960_ROUT1, 0x16F);
+
+ /* Delay for some while */
+ while (i)
+ {
+ __ASM("nop");
+ i--;
+ }
+
+ /* Unmute DAC. */
+ WM8960_WriteReg(handle, WM8960_DACCTL1, 0x0000);
+}
+
+void WM8960_Deinit(wm8960_handle_t *handle)
+{
+ WM8960_SetModule(handle, kWM8960_ModuleADC, false);
+ WM8960_SetModule(handle, kWM8960_ModuleDAC, false);
+ WM8960_SetModule(handle, kWM8960_ModuleVREF, false);
+ WM8960_SetModule(handle, kWM8960_ModuleLineIn, false);
+ WM8960_SetModule(handle, kWM8960_ModuleLineOut, false);
+ WM8960_SetModule(handle, kWM8960_ModuleSpeaker, false);
+}
+
+void WM8960_SetMasterSlave(wm8960_handle_t *handle, bool master)
+{
+ if (master == 1)
+ {
+ WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_MS_MASK, WM8960_IFACE1_MS(WM8960_IFACE1_MASTER));
+ }
+ else
+ {
+ WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_MS_MASK, WM8960_IFACE1_MS(WM8960_IFACE1_SLAVE));
+ }
+}
+
+status_t WM8960_SetModule(wm8960_handle_t *handle, wm8960_module_t module, bool isEnabled)
+{
+ status_t ret = kStatus_Success;
+ switch (module)
+ {
+ case kWM8960_ModuleADC:
+ WM8960_ModifyReg(handle, WM8960_POWER1, WM8960_POWER1_ADCL_MASK,
+ ((uint16_t)isEnabled << WM8960_POWER1_ADCL_SHIFT));
+ WM8960_ModifyReg(handle, WM8960_POWER1, WM8960_POWER1_ADCR_MASK,
+ ((uint16_t)isEnabled << WM8960_POWER1_ADCR_SHIFT));
+ break;
+ case kWM8960_ModuleDAC:
+ WM8960_ModifyReg(handle, WM8960_POWER2, WM8960_POWER2_DACL_MASK,
+ ((uint16_t)isEnabled << WM8960_POWER2_DACL_SHIFT));
+ WM8960_ModifyReg(handle, WM8960_POWER2, WM8960_POWER2_DACR_MASK,
+ ((uint16_t)isEnabled << WM8960_POWER2_DACR_SHIFT));
+ break;
+ case kWM8960_ModuleVREF:
+ WM8960_ModifyReg(handle, WM8960_POWER1, WM8960_POWER1_VREF_MASK,
+ ((uint16_t)isEnabled << WM8960_POWER1_VREF_SHIFT));
+ break;
+ case kWM8960_ModuleLineIn:
+ WM8960_ModifyReg(handle, WM8960_POWER1, WM8960_POWER1_AINL_MASK,
+ ((uint16_t)isEnabled << WM8960_POWER1_AINL_SHIFT));
+ WM8960_ModifyReg(handle, WM8960_POWER1, WM8960_POWER1_AINR_MASK,
+ ((uint16_t)isEnabled << WM8960_POWER1_AINR_SHIFT));
+ break;
+ case kWM8960_ModuleLineOut:
+ WM8960_ModifyReg(handle, WM8960_POWER2, WM8960_POWER2_LOUT1_MASK,
+ ((uint16_t)isEnabled << WM8960_POWER2_LOUT1_SHIFT));
+ WM8960_ModifyReg(handle, WM8960_POWER2, WM8960_POWER2_ROUT1_MASK,
+ ((uint16_t)isEnabled << WM8960_POWER2_ROUT1_SHIFT));
+ break;
+ case kWM8960_ModuleSpeaker:
+ WM8960_ModifyReg(handle, WM8960_POWER2, WM8960_POWER2_SPKL_MASK,
+ ((uint16_t)isEnabled << WM8960_POWER2_SPKL_SHIFT));
+ WM8960_ModifyReg(handle, WM8960_POWER2, WM8960_POWER2_SPKR_MASK,
+ ((uint16_t)isEnabled << WM8960_POWER2_SPKR_SHIFT));
+ WM8960_WriteReg(handle, WM8960_CLASSD1, 0xF7);
+ break;
+ default:
+ ret = kStatus_InvalidArgument;
+ break;
+ }
+ return ret;
+}
+
+status_t WM8960_SetDataRoute(wm8960_handle_t *handle, wm8960_route_t route)
+{
+ status_t ret = kStatus_Success;
+ switch (route)
+ {
+ case kWM8960_RouteBypass:
+ /* Bypass means from line-in to HP*/
+ /*
+ * Left LINPUT3 to left output mixer, LINPUT3 left output mixer volume = 0dB
+ */
+ WM8960_WriteReg(handle, WM8960_LOUTMIX, 0x80);
+
+ /*
+ * Right RINPUT3 to right output mixer, RINPUT3 right output mixer volume = 0dB
+ */
+ WM8960_WriteReg(handle, WM8960_ROUTMIX, 0x80);
+ break;
+ case kWM8960_RoutePlayback:
+ /* Data route I2S_IN-> DAC-> HP */
+ /*
+ * Left DAC to left output mixer, LINPUT3 left output mixer volume = 0dB
+ */
+ WM8960_WriteReg(handle, WM8960_LOUTMIX, 0x100);
+
+ /*
+ * Right DAC to right output mixer, RINPUT3 right output mixer volume = 0dB
+ */
+ WM8960_WriteReg(handle, WM8960_ROUTMIX, 0x100);
+ break;
+ case kWM8960_RoutePlaybackandRecord:
+ /* I2S IN->DAC->HP LINE_IN->ADC->I2S_OUT */
+ /*
+ * Left and right input boost, LIN3BOOST and RIN3BOOST = 0dB
+ */
+ WM8960_WriteReg(handle, WM8960_INBMIX1, 0x50);
+ WM8960_WriteReg(handle, WM8960_INBMIX2, 0x50);
+ /*
+ * Left DAC to left output mixer, LINPUT3 left output mixer volume = 0dB
+ */
+ WM8960_WriteReg(handle, WM8960_LOUTMIX, 0x100);
+
+ /*
+ * Right DAC to right output mixer, RINPUT3 right output mixer volume = 0dB
+ */
+ WM8960_WriteReg(handle, WM8960_ROUTMIX, 0x100);
+ break;
+ case kWM8960_RoutePlaybackwithDAP:
+ /* I2S_IN->DAP->DAC->HP */
+ break;
+ case kWM8960_RoutePlaybackwithDAPandRecord:
+ /* I2S_IN->DAP->DAC->HP, LINE_IN->ADC->I2S_OUT */
+ break;
+ case kWM8960_RouteRecord:
+ /* LINE_IN->ADC->I2S_OUT */
+ /*
+ * Left and right input boost, LIN3BOOST and RIN3BOOST = 0dB
+ */
+ WM8960_WriteReg(handle, WM8960_INBMIX1, 0x50);
+ WM8960_WriteReg(handle, WM8960_INBMIX2, 0x50);
+ break;
+ default:
+ ret = kStatus_InvalidArgument;
+ break;
+ }
+ return ret;
+}
+
+status_t WM8960_SetProtocol(wm8960_handle_t *handle, wm8960_protocol_t protocol)
+{
+ status_t ret = kStatus_Success;
+ switch (protocol)
+ {
+ case kWM8960_BusI2S:
+ WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_FORMAT_MASK,
+ WM8960_IFACE1_FORMAT(WM8960_IFACE1_FORMAT_I2S));
+ break;
+ case kWM8960_BusLeftJustified:
+ WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_FORMAT_MASK,
+ WM8960_IFACE1_FORMAT(WM8960_IFACE1_FORMAT_LJ));
+ break;
+ case kWM8960_BusRightJustified:
+ WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_FORMAT_MASK,
+ WM8960_IFACE1_FORMAT(WM8960_IFACE1_FORMAT_RJ));
+ break;
+ case kWM8960_BusPCMA:
+ WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_FORMAT_MASK,
+ WM8960_IFACE1_FORMAT(WM8960_IFACE1_FORMAT_DSP));
+ WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_LRP_MASK, WM8960_IFACE1_LRP(WM8960_IFACE1_DSP_MODEA));
+ break;
+ case kWM8960_BusPCMB:
+ WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_FORMAT_MASK,
+ WM8960_IFACE1_FORMAT(WM8960_IFACE1_FORMAT_DSP));
+ WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_LRP_MASK, WM8960_IFACE1_LRP(WM8960_IFACE1_DSP_MODEB));
+ break;
+ default:
+ ret = kStatus_InvalidArgument;
+ break;
+ }
+ WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_WL_MASK, WM8960_IFACE1_WL(WM8960_IFACE1_WL_32BITS));
+ return ret;
+}
+
+status_t WM8960_SetVolume(wm8960_handle_t *handle, wm8960_module_t module, uint32_t volume)
+{
+ uint16_t vol = 0;
+ status_t ret = kStatus_Success;
+ switch (module)
+ {
+ case kWM8960_ModuleADC:
+ vol = 0x100 | volume;
+ ret = WM8960_WriteReg(handle, WM8960_LADC, vol);
+ ret = WM8960_WriteReg(handle, WM8960_RADC, vol);
+ break;
+ case kWM8960_ModuleDAC:
+ vol = 0x100 | volume;
+ ret = WM8960_WriteReg(handle, WM8960_LDAC, vol);
+ ret = WM8960_WriteReg(handle, WM8960_RDAC, vol);
+ break;
+ case kWM8960_ModuleHP:
+ vol = 0x100 | volume;
+ ret = WM8960_WriteReg(handle, WM8960_LOUT1, vol);
+ ret = WM8960_WriteReg(handle, WM8960_ROUT1, vol);
+ break;
+ case kWM8960_ModuleLineIn:
+ vol = 0x100 | volume;
+ ret = WM8960_WriteReg(handle, WM8960_LINVOL, vol);
+ ret = WM8960_WriteReg(handle, WM8960_RINVOL, vol);
+ break;
+ case kWM8960_ModuleSpeaker:
+ vol = 0x100 | volume;
+ ret = WM8960_WriteReg(handle, WM8960_LOUT2, vol);
+ ret = WM8960_WriteReg(handle, WM8960_ROUT2, vol);
+ break;
+ default:
+ ret = kStatus_InvalidArgument;
+ break;
+ }
+ return ret;
+}
+
+uint32_t WM8960_GetVolume(wm8960_handle_t *handle, wm8960_module_t module)
+{
+ uint16_t vol = 0;
+ switch (module)
+ {
+ case kWM8960_ModuleADC:
+ WM8960_ReadReg(WM8960_LADC, &vol);
+ vol &= 0xFF;
+ break;
+ case kWM8960_ModuleDAC:
+ WM8960_ReadReg(WM8960_LDAC, &vol);
+ vol &= 0xFF;
+ break;
+ case kWM8960_ModuleHP:
+ WM8960_ReadReg(WM8960_LOUT1, &vol);
+ vol &= 0x7F;
+ break;
+ case kWM8960_ModuleLineOut:
+ WM8960_ReadReg(WM8960_LINVOL, &vol);
+ vol &= 0x3F;
+ break;
+ default:
+ vol = 0;
+ break;
+ }
+ return vol;
+}
+
+status_t WM8960_SetMute(wm8960_handle_t *handle, wm8960_module_t module, bool isEnabled)
+{
+ status_t ret = kStatus_Success;
+ switch (module)
+ {
+ case kWM8960_ModuleADC:
+ /*
+ * Digital Mute
+ */
+ if (isEnabled)
+ {
+ ret = WM8960_WriteReg(handle, WM8960_LADC, 0x100);
+ ret = WM8960_WriteReg(handle, WM8960_RADC, 0x100);
+ }
+ else
+ {
+ ret = WM8960_WriteReg(handle, WM8960_LADC, 0x1C3);
+ ret = WM8960_WriteReg(handle, WM8960_RADC, 0x1C3);
+ }
+ break;
+ case kWM8960_ModuleDAC:
+ /*
+ * Digital mute
+ */
+ if (isEnabled)
+ {
+ ret = WM8960_WriteReg(handle, WM8960_LDAC, 0x100);
+ ret = WM8960_WriteReg(handle, WM8960_RDAC, 0x100);
+ }
+ else
+ {
+ ret = WM8960_WriteReg(handle, WM8960_LDAC, 0x1FF);
+ ret = WM8960_WriteReg(handle, WM8960_RDAC, 0x1FF);
+ }
+ break;
+ case kWM8960_ModuleHP:
+ /*
+ * Analog mute
+ */
+ if (isEnabled)
+ {
+ ret = WM8960_WriteReg(handle, WM8960_LOUT1, 0x100);
+ ret = WM8960_WriteReg(handle, WM8960_ROUT1, 0x100);
+ }
+ else
+ {
+ ret = WM8960_WriteReg(handle, WM8960_LOUT1, 0x179);
+ ret = WM8960_WriteReg(handle, WM8960_ROUT1, 0x179);
+ }
+ break;
+ case kWM8960_ModuleLineOut:
+ break;
+ default:
+ ret = kStatus_InvalidArgument;
+ break;
+ }
+ return ret;
+}
+
+status_t WM8960_ConfigDataFormat(wm8960_handle_t *handle, uint32_t mclk, uint32_t sample_rate, uint8_t bits)
+{
+ status_t retval = kStatus_Success;
+
+ switch (sample_rate)
+ {
+ case 8000:
+ retval = WM8960_WriteReg(handle, WM8960_CLOCK1, 0x1B0);
+ break;
+ case 11025:
+ retval = WM8960_WriteReg(handle, WM8960_CLOCK1, 0xD8);
+ break;
+ case 12000:
+ retval = WM8960_WriteReg(handle, WM8960_CLOCK1, 0x120);
+ break;
+ case 16000:
+ retval = WM8960_WriteReg(handle, WM8960_CLOCK1, 0xD8);
+ break;
+ case 22050:
+ retval = WM8960_WriteReg(handle, WM8960_CLOCK1, 0xD8);
+ break;
+ case 24000:
+ retval = WM8960_WriteReg(handle, WM8960_CLOCK1, 0x90);
+ break;
+ case 32000:
+ retval = WM8960_WriteReg(handle, WM8960_CLOCK1, 0x48);
+ break;
+ case 44100:
+ retval = WM8960_WriteReg(handle, WM8960_CLOCK1, 0xD8);
+ break;
+ case 48000:
+ retval = WM8960_WriteReg(handle, WM8960_CLOCK1, 0x00);
+ break;
+ default:
+ retval = kStatus_InvalidArgument;
+ break;
+ }
+
+ /*
+ * Slave mode (MS = 0), LRP = 0, 32bit WL, left justified (FORMAT[1:0]=0b01)
+ */
+ switch (bits)
+ {
+ case 16:
+ retval = WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_WL_MASK,
+ WM8960_IFACE1_WL(WM8960_IFACE1_WL_16BITS));
+ break;
+ case 20:
+ retval = WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_WL_MASK,
+ WM8960_IFACE1_WL(WM8960_IFACE1_WL_20BITS));
+ break;
+ case 24:
+ retval = WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_WL_MASK,
+ WM8960_IFACE1_WL(WM8960_IFACE1_WL_24BITS));
+ break;
+ case 32:
+ retval = WM8960_ModifyReg(handle, WM8960_IFACE1, WM8960_IFACE1_WL_MASK,
+ WM8960_IFACE1_WL(WM8960_IFACE1_WL_32BITS));
+ break;
+ default:
+ retval = kStatus_InvalidArgument;
+ break;
+ }
+
+ return retval;
+}
+
+status_t WM8960_SetJackDetect(wm8960_handle_t *handle, bool isEnabled)
+{
+ uint8_t retval = 0;
+ uint16_t val = 0;
+
+ WM8960_ReadReg(WM8960_ADDCTL2, &val);
+
+ if (isEnabled)
+ {
+ val |= 0x40U;
+ }
+ else
+ {
+ val &= 0xCF;
+ }
+
+ retval = WM8960_WriteReg(handle, WM8960_ADDCTL2, val);
+
+ return retval;
+}
+
+status_t WM8960_WriteReg(wm8960_handle_t *handle, uint8_t reg, uint16_t val)
+{
+ uint8_t cmd, buff;
+ uint8_t retval = 0;
+
+ /* The register address */
+ cmd = (reg << 1) | ((val >> 8U) & 0x0001U);
+ /* Data */
+ buff = val & 0xFF;
+
+ /* Copy data to cache */
+ reg_cache[reg] = val;
+
+#if defined(FSL_FEATURE_SOC_LPI2C_COUNT) && (FSL_FEATURE_SOC_LPI2C_COUNT)
+ uint8_t data[2];
+ data[0] = cmd;
+ data[1] = buff;
+ retval = LPI2C_MasterStart(handle->base, WM8960_I2C_ADDR, kLPI2C_Write);
+ retval = LPI2C_MasterSend(handle->base, data, 2);
+ retval = LPI2C_MasterStop(handle->base);
+#else
+ /* Config the I2C xfer */
+ handle->xfer.direction = kI2C_Write;
+ handle->xfer.subaddress = cmd;
+ handle->xfer.subaddressSize = 1U;
+ handle->xfer.data = &buff;
+ handle->xfer.dataSize = 1U;
+
+ retval = I2C_MasterTransferBlocking(handle->base, &handle->xfer);
+#endif
+
+ if (retval != kStatus_Success)
+ {
+ return kStatus_Fail;
+ }
+ return kStatus_Success;
+}
+
+status_t WM8960_ReadReg(uint8_t reg, uint16_t *val)
+{
+ if (reg >= WM8960_CACHEREGNUM)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ *val = reg_cache[reg];
+
+ return kStatus_Success;
+}
+
+status_t WM8960_ModifyReg(wm8960_handle_t *handle, uint8_t reg, uint16_t mask, uint16_t val)
+{
+ uint8_t retval = 0;
+ uint16_t reg_val = 0;
+ retval = WM8960_ReadReg(reg, &reg_val);
+ if (retval != kStatus_Success)
+ {
+ return kStatus_Fail;
+ }
+ reg_val &= (uint16_t)~mask;
+ reg_val |= val;
+ retval = WM8960_WriteReg(handle, reg, reg_val);
+ if (retval != kStatus_Success)
+ {
+ return kStatus_Fail;
+ }
+ return kStatus_Success;
+}
diff --git a/bsp/imxrt1052-evk/drivers/fsl_wm8960.h b/bsp/imxrt1052-evk/drivers/fsl_wm8960.h
new file mode 100644
index 0000000000..848e0332f9
--- /dev/null
+++ b/bsp/imxrt1052-evk/drivers/fsl_wm8960.h
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+#ifndef _FSL_WM8960_H_
+#define _FSL_WM8960_H_
+
+#include "fsl_common.h"
+#if defined(FSL_FEATURE_SOC_LPI2C_COUNT) && (FSL_FEATURE_SOC_LPI2C_COUNT)
+#include "fsl_lpi2c.h"
+#else
+#include "fsl_i2c.h"
+#endif
+
+/*!
+ * @addtogroup wm8960
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @brief Define the register address of WM8960. */
+#define WM8960_LINVOL 0x0
+#define WM8960_RINVOL 0x1
+#define WM8960_LOUT1 0x2
+#define WM8960_ROUT1 0x3
+#define WM8960_CLOCK1 0x4
+#define WM8960_DACCTL1 0x5
+#define WM8960_DACCTL2 0x6
+#define WM8960_IFACE1 0x7
+#define WM8960_CLOCK2 0x8
+#define WM8960_IFACE2 0x9
+#define WM8960_LDAC 0xa
+#define WM8960_RDAC 0xb
+
+#define WM8960_RESET 0xf
+#define WM8960_3D 0x10
+#define WM8960_ALC1 0x11
+#define WM8960_ALC2 0x12
+#define WM8960_ALC3 0x13
+#define WM8960_NOISEG 0x14
+#define WM8960_LADC 0x15
+#define WM8960_RADC 0x16
+#define WM8960_ADDCTL1 0x17
+#define WM8960_ADDCTL2 0x18
+#define WM8960_POWER1 0x19
+#define WM8960_POWER2 0x1a
+#define WM8960_ADDCTL3 0x1b
+#define WM8960_APOP1 0x1c
+#define WM8960_APOP2 0x1d
+
+#define WM8960_LINPATH 0x20
+#define WM8960_RINPATH 0x21
+#define WM8960_LOUTMIX 0x22
+
+#define WM8960_ROUTMIX 0x25
+#define WM8960_MONOMIX1 0x26
+#define WM8960_MONOMIX2 0x27
+#define WM8960_LOUT2 0x28
+#define WM8960_ROUT2 0x29
+#define WM8960_MONO 0x2a
+#define WM8960_INBMIX1 0x2b
+#define WM8960_INBMIX2 0x2c
+#define WM8960_BYPASS1 0x2d
+#define WM8960_BYPASS2 0x2e
+#define WM8960_POWER3 0x2f
+#define WM8960_ADDCTL4 0x30
+#define WM8960_CLASSD1 0x31
+
+#define WM8960_CLASSD3 0x33
+#define WM8960_PLL1 0x34
+#define WM8960_PLL2 0x35
+#define WM8960_PLL3 0x36
+#define WM8960_PLL4 0x37
+
+/*! @brief Cache register number */
+#define WM8960_CACHEREGNUM 56
+
+/*! @brief WM8960_IFACE1 FORMAT bits */
+#define WM8960_IFACE1_FORMAT_MASK 0x03
+#define WM8960_IFACE1_FORMAT_SHIFT 0x00
+#define WM8960_IFACE1_FORMAT_RJ 0x00
+#define WM8960_IFACE1_FORMAT_LJ 0x01
+#define WM8960_IFACE1_FORMAT_I2S 0x02
+#define WM8960_IFACE1_FORMAT_DSP 0x03
+#define WM8960_IFACE1_FORMAT(x) ((x << WM8960_IFACE1_FORMAT_SHIFT) & WM8960_IFACE1_FORMAT_MASK)
+
+/*! @brief WM8960_IFACE1 WL bits */
+#define WM8960_IFACE1_WL_MASK 0x0C
+#define WM8960_IFACE1_WL_SHIFT 0x02
+#define WM8960_IFACE1_WL_16BITS 0x00
+#define WM8960_IFACE1_WL_20BITS 0x01
+#define WM8960_IFACE1_WL_24BITS 0x02
+#define WM8960_IFACE1_WL_32BITS 0x03
+#define WM8960_IFACE1_WL(x) ((x << WM8960_IFACE1_WL_SHIFT) & WM8960_IFACE1_WL_MASK)
+
+/*! @brief WM8960_IFACE1 LRP bit */
+#define WM8960_IFACE1_LRP_MASK 0x10
+#define WM8960_IFACE1_LRP_SHIFT 0x04
+#define WM8960_IFACE1_LRCLK_NORMAL_POL 0x00
+#define WM8960_IFACE1_LRCLK_INVERT_POL 0x01
+#define WM8960_IFACE1_DSP_MODEA 0x00
+#define WM8960_IFACE1_DSP_MODEB 0x01
+#define WM8960_IFACE1_LRP(x) ((x << WM8960_IFACE1_LRP_SHIFT) & WM8960_IFACE1_LRP_MASK)
+
+/*! @brief WM8960_IFACE1 DLRSWAP bit */
+#define WM8960_IFACE1_DLRSWAP_MASK 0x20
+#define WM8960_IFACE1_DLRSWAP_SHIFT 0x05
+#define WM8960_IFACE1_DACCH_NORMAL 0x00
+#define WM8960_IFACE1_DACCH_SWAP 0x01
+#define WM8960_IFACE1_DLRSWAP(x) ((x << WM8960_IFACE1_DLRSWAP_SHIFT) & WM8960_IFACE1_DLRSWAP_MASK)
+
+/*! @brief WM8960_IFACE1 MS bit */
+#define WM8960_IFACE1_MS_MASK 0x40
+#define WM8960_IFACE1_MS_SHIFT 0x06
+#define WM8960_IFACE1_SLAVE 0x00
+#define WM8960_IFACE1_MASTER 0x01
+#define WM8960_IFACE1_MS(x) ((x << WM8960_IFACE1_MS_SHIFT) & WM8960_IFACE1_MS_MASK)
+
+/*! @brief WM8960_IFACE1 BCLKINV bit */
+#define WM8960_IFACE1_BCLKINV_MASK 0x80
+#define WM8960_IFACE1_BCLKINV_SHIFT 0x07
+#define WM8960_IFACE1_BCLK_NONINVERT 0x00
+#define WM8960_IFACE1_BCLK_INVERT 0x01
+#define WM8960_IFACE1_BCLKINV(x) ((x << WM8960_IFACE1_BCLKINV_SHIFT) & WM8960_IFACE1_BCLKINV_MASK)
+
+/*! @brief WM8960_IFACE1 ALRSWAP bit */
+#define WM8960_IFACE1_ALRSWAP_MASK 0x100
+#define WM8960_IFACE1_ALRSWAP_SHIFT 0x08
+#define WM8960_IFACE1_ADCCH_NORMAL 0x00
+#define WM8960_IFACE1_ADCCH_SWAP 0x01
+#define WM8960_IFACE1_ALRSWAP(x) ((x << WM8960_IFACE1_ALRSWAP_SHIFT) & WM8960_IFACE1_ALRSWAP_MASK)
+
+/*! @brief WM8960_POWER1 */
+#define WM8960_POWER1_VREF_MASK 0x40
+#define WM8960_POWER1_VREF_SHIFT 0x06
+
+#define WM8960_POWER1_AINL_MASK 0x20
+#define WM8960_POWER1_AINL_SHIFT 0x05
+
+#define WM8960_POWER1_AINR_MASK 0x10
+#define WM8960_POWER1_AINR_SHIFT 0x04
+
+#define WM8960_POWER1_ADCL_MASK 0x08
+#define WM8960_POWER1_ADCL_SHIFT 0x03
+
+#define WM8960_POWER1_ADCR_MASK 0x04
+#define WM8960_POWER1_ADCR_SHIFT 0x02
+
+/*! @brief WM8960_POWER2 */
+#define WM8960_POWER2_DACL_MASK 0x100
+#define WM8960_POWER2_DACL_SHIFT 0x08
+
+#define WM8960_POWER2_DACR_MASK 0x80
+#define WM8960_POWER2_DACR_SHIFT 0x07
+
+#define WM8960_POWER2_LOUT1_MASK 0x40
+#define WM8960_POWER2_LOUT1_SHIFT 0x06
+
+#define WM8960_POWER2_ROUT1_MASK 0x20
+#define WM8960_POWER2_ROUT1_SHIFT 0x05
+
+#define WM8960_POWER2_SPKL_MASK 0x10
+#define WM8960_POWER2_SPKL_SHIFT 0x04
+
+#define WM8960_POWER2_SPKR_MASK 0x08
+#define WM8960_POWER2_SPKR_SHIFT 0x03
+
+/*! @brief WM8960 I2C address. */
+#define WM8960_I2C_ADDR 0x1A
+
+/*! @brief Modules in WM8960 board. */
+typedef enum _WM8960_module
+{
+ kWM8960_ModuleADC = 0x0, /*!< ADC module in WM8960 */
+ kWM8960_ModuleDAC = 0x1, /*!< DAC module in WM8960 */
+ kWM8960_ModuleVREF = 0x2, /*!< VREF module */
+ kWM8960_ModuleHP = 0x03, /*!< Headphone module */
+ kWM8960_ModuleLineIn = 0x6, /*!< Line-in module */
+ kWM8960_ModuleLineOut = 0x7, /*!< Line out module */
+ kWM8960_ModuleSpeaker = 0x8 /*!< Speaker module */
+} wm8960_module_t;
+
+/*!
+* @brief WM8960 data route.
+* Only provide some typical data route, not all route listed.
+* Note: Users cannot combine any routes, once a new route is set, the previous one would be replaced.
+*/
+typedef enum _wm8960_route
+{
+ kWM8960_RouteBypass = 0x0, /*!< LINEIN->Headphone. */
+ kWM8960_RoutePlayback = 0x1, /*!< I2SIN->DAC->Headphone. */
+ kWM8960_RoutePlaybackandRecord = 0x2, /*!< I2SIN->DAC->Headphone, LINEIN->ADC->I2SOUT. */
+ kWM8960_RoutePlaybackwithDAP = 0x3, /*!< I2SIN->DAP->DAC->Headphone. */
+ kWM8960_RoutePlaybackwithDAPandRecord = 0x4, /*!< I2SIN->DAP->DAC->HP, LINEIN->ADC->I2SOUT. */
+ kWM8960_RouteRecord = 0x5 /*!< LINEIN->ADC->I2SOUT. */
+} wm8960_route_t;
+
+/*!
+* @brief The audio data transfer protocol choice.
+* WM8960 only supports I2S format and PCM format.
+*/
+typedef enum _wm8960_protocol
+{
+ kWM8960_BusI2S = 0x0, /*!< I2S type */
+ kWM8960_BusLeftJustified = 0x1, /*!< Left justified mode */
+ kWM8960_BusRightJustified = 0x2, /*!< Right justified mode */
+ kWM8960_BusPCMA = 0x3, /*!< PCM A mode */
+ kWM8960_BusPCMB = 0x4 /*!< PCM B mode */
+} wm8960_protocol_t;
+
+/*! @brief WM8960 configure definition. */
+typedef struct wm8960_handle
+{
+#if defined(FSL_FEATURE_SOC_LPI2C_COUNT) && (FSL_FEATURE_SOC_LPI2C_COUNT)
+ LPI2C_Type *base;
+ lpi2c_master_transfer_t xfer;
+ lpi2c_master_handle_t *i2cHandle;
+#else
+ /* I2C relevant definition. */
+ I2C_Type *base; /*!< I2C instance. */
+ i2c_master_transfer_t xfer; /*!< I2C device setting */
+ i2c_master_handle_t *i2cHandle; /*!< I2C internal state space. */
+#endif
+} wm8960_handle_t;
+
+/*! @brief Initialize structure of WM8960 */
+typedef struct wm8960_config
+{
+ wm8960_route_t route; /*!< Audio data route.*/
+ wm8960_protocol_t bus; /*!< Audio transfer protocol */
+ bool master_slave; /*!< Master or slave. */
+} wm8960_config_t;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @brief WM8960 initialize function.
+ *
+ * The second parameter is NULL to WM8960 in this version. If users want
+ * to change the settings, they have to use wm8960_write_reg() or wm8960_modify_reg()
+ * to set the register value of WM8960.
+ * Note: If the codec_config is NULL, it would initialize WM8960 using default settings.
+ * The default setting:
+ * codec_config->route = kWM8960_RoutePlaybackandRecord
+ * codec_config->bus = kWM8960_BusI2S
+ * codec_config->master = slave
+ *
+ * @param handle WM8960 handle structure.
+ * @param codec_config WM8960 configuration structure.
+ */
+void WM8960_Init(wm8960_handle_t *handle, wm8960_config_t *config);
+
+/*!
+ * @brief Deinit the WM8960 codec.
+ *
+ * This function close all modules in WM8960 to save power.
+ *
+ * @param handle WM8960 handle structure pointer.
+ */
+void WM8960_Deinit(wm8960_handle_t *handle);
+
+/*!
+ * @brief Set audio data route in WM8960.
+ *
+ * This function would set the data route according to route. The route cannot be combined,
+ * as all route would enable different modules.
+ * Note: If a new route is set, the previous route would not work.
+ *
+ * @param handle WM8960 handle structure.
+ * @param route Audio data route in WM8960.
+ */
+status_t WM8960_SetDataRoute(wm8960_handle_t *handle, wm8960_route_t route);
+
+/*!
+ * @brief Set the audio transfer protocol.
+ *
+ * WM8960 only supports I2S, left justified, right justified, PCM A, PCM B format.
+ *
+ * @param handle WM8960 handle structure.
+ * @param bus Audio data transfer protocol.
+ */
+status_t WM8960_SetProtocol(wm8960_handle_t *handle, wm8960_protocol_t protocol);
+
+/*!
+ * @brief Set WM8960 as master or slave.
+ *
+ * @param handle WM8960 handle structure.
+ * @param master 1 represent master, 0 represent slave.
+ */
+void WM8960_SetMasterSlave(wm8960_handle_t *handle, bool master);
+
+/*!
+ * @brief Set the volume of different modules in WM8960.
+ *
+ * This function would set the volume of WM8960 modules. Uses need to appoint the module.
+ * The function assume that left channel and right channel has the same volume.
+ *
+ * @param handle WM8960 handle structure.
+ * @param module Module to set volume, it can be ADC, DAC, Headphone and so on.
+ * @param volume Volume value need to be set.
+ */
+status_t WM8960_SetVolume(wm8960_handle_t *handle, wm8960_module_t module, uint32_t volume);
+
+/*!
+ * @brief Get the volume of different modules in WM8960.
+ *
+ * This function gets the volume of WM8960 modules. Uses need to appoint the module.
+ * The function assume that left channel and right channel has the same volume.
+ *
+ * @param handle WM8960 handle structure.
+ * @param module Module to set volume, it can be ADC, DAC, Headphone and so on.
+ * @return Volume value of the module.
+ */
+uint32_t WM8960_GetVolume(wm8960_handle_t *handle, wm8960_module_t module);
+
+/*!
+ * @brief Mute modules in WM8960.
+ *
+ * @param handle WM8960 handle structure.
+ * @param module Modules need to be mute.
+ * @param isEnabled Mute or unmute, 1 represent mute.
+ */
+status_t WM8960_SetMute(wm8960_handle_t *handle, wm8960_module_t module, bool isEnabled);
+
+/*!
+ * @brief Enable/disable expected devices.
+ *
+ * @param handle WM8960 handle structure.
+ * @param module Module expected to enable.
+ * @param isEnabled Enable or disable moudles.
+ */
+status_t WM8960_SetModule(wm8960_handle_t *handle, wm8960_module_t module, bool isEnabled);
+
+/*!
+ * @brief Configure the data format of audio data.
+ *
+ * This function would configure the registers about the sample rate, bit depths.
+ *
+ * @param handle WM8960 handle structure pointer.
+ * @param mclk Master clock frequency of I2S.
+ * @param sample_rate Sample rate of audio file running in WM8960. WM8960 now
+ * supports 8k, 11.025k, 12k, 16k, 22.05k, 24k, 32k, 44.1k, 48k and 96k sample rate.
+ * @param bits Bit depth of audio file (WM8960 only supports 16bit, 20bit, 24bit
+ * and 32 bit in HW).
+ */
+status_t WM8960_ConfigDataFormat(wm8960_handle_t *handle, uint32_t mclk, uint32_t sample_rate, uint8_t bits);
+
+/*!
+ * @brief Enable/disable jack detect feature.
+ *
+ * @param handle WM8960 handle structure.
+ * @param isEnabled Enable or disable moudles.
+ */
+status_t WM8960_SetJackDetect(wm8960_handle_t *handle, bool isEnabled);
+
+/*!
+ * @brief Write register to WM8960 using I2C.
+ *
+ * @param handle WM8960 handle structure.
+ * @param reg The register address in WM8960.
+ * @param val Value needs to write into the register.
+ */
+status_t WM8960_WriteReg(wm8960_handle_t *handle, uint8_t reg, uint16_t val);
+
+/*!
+ * @brief Read register from WM8960 using I2C.
+ * @param handle WM8960 handle structure.
+ * @param reg The register address in WM8960.
+ * @param val Value written to.
+ */
+status_t WM8960_ReadReg(uint8_t reg, uint16_t *val);
+
+/*!
+ * @brief Modify some bits in the register using I2C.
+ * @param handle WM8960 handle structure.
+ * @param reg The register address in WM8960.
+ * @param mask The mask code for the bits want to write. The bit you want to write should be 0.
+ * @param val Value needs to write into the register.
+ */
+status_t WM8960_ModifyReg(wm8960_handle_t *handle, uint8_t reg, uint16_t mask, uint16_t val);
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @} */
+
+#endif /* _FSL_WM8960_H_ */
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/