123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461 |
- /**************************************************************************//**
- * @file i2s.c
- * @brief N9H30 I2S driver source file
- *
- * @note
- * SPDX-License-Identifier: Apache-2.0
- * Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved.
- *****************************************************************************/
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "N9H30.h"
- #include "nu_sys.h"
- #include "nu_i2s.h"
- /** @addtogroup N9H30_Device_Driver N9H30 Device Driver
- @{
- */
- /** @addtogroup N9H30_I2S_Driver I2S Driver
- @{
- */
- /** @addtogroup N9H30_I2S_EXPORTED_CONSTANTS I2S Exported Constants
- @{
- */
- /// @cond HIDDEN_SYMBOLS
- typedef uint32_t (AU_CB_FUNC_T)(uint32_t);
- static AU_CB_FUNC_T *g_fnPlayCallBack;
- static AU_CB_FUNC_T *g_fnRecCallBack;
- static uint8_t i2sOpened = 0;
- /// @endcond /* HIDDEN_SYMBOLS */
- /*@}*/ /* end of group N9H30_I2S_EXPORTED_CONSTANTS */
- /** @addtogroup N9H30_I2S_EXPORTED_FUNCTIONS I2S Exported Functions
- @{
- */
- /// @cond HIDDEN_SYMBOLS
- /**
- * @brief Start to play
- * @param None
- * @return None
- */
- static void i2sStartPlay(void)
- {
- /* start playing */
- //sysprintf("IIS start playing...\n");
- outpw(REG_ACTL_PSR, 0x1);
- outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) | (1 << 5));
- }
- /**
- * @brief Stop to play
- * @param None
- * @return None
- */
- static void i2sStopPlay(void)
- {
- //sysprintf("IIS stop playing\n");
- /* stop playing */
- outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) & ~(1 << 5));
- }
- /**
- * @brief Start to record
- * @param None
- * @return None
- */
- static void i2sStartRecord(void)
- {
- /* start recording */
- //sysprintf("IIS start recording...\n");
- outpw(REG_ACTL_RSR, 0x1);
- outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) | (1 << 6));
- }
- /**
- * @brief Stop to record
- * @param None
- * @return None
- */
- static void i2sStopRecord(void)
- {
- //sysprintf("I2S stop recording\n");
- /* stop recording */
- outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) & ~(1 << 6));
- }
- /**
- * @brief Delay function
- * @param None
- * @return None
- */
- static void Delay(int nCnt)
- {
- int volatile loop;
- for (loop = 0; loop < nCnt * 10; loop++);
- }
- /**
- * @brief Interrupt service routine for i2s
- * @param None
- * @return None
- */
- static void i2sISR(void)
- {
- uint8_t u8SN;
- if (inpw(REG_ACTL_CON) & (1 << 10))
- {
- outpw(REG_ACTL_CON, inpw(REG_ACTL_CON) | (1 << 10)); //Clear TX INT
- if (inpw(REG_ACTL_PSR) & (1 << 4))
- {
- outpw(REG_ACTL_PSR, (1 << 4));
- //sysprintf("\ndebug:DMA_COUNTER_IRQ occur");
- }
- if (inpw(REG_ACTL_PSR) & (1 << 3))
- {
- outpw(REG_ACTL_PSR, (1 << 3));
- //sysprintf("\ndebug:DMA_DATA_ZERO_IRQ occur");
- }
- if (inpw(REG_ACTL_PSR) & 0x1)
- {
- outpw(REG_ACTL_PSR, 0x1);
- u8SN = (inpw(REG_ACTL_PSR) >> 5) & 0x7;
- g_fnPlayCallBack(u8SN);
- }
- }
- if (inpw(REG_ACTL_CON) & (1 << 11))
- {
- outpw(REG_ACTL_CON, inpw(REG_ACTL_CON) | (1 << 11)); //Clear RX INT
- if (inpw(REG_ACTL_RSR) & 0x1)
- {
- outpw(REG_ACTL_RSR, 0x1);
- u8SN = (inpw(REG_ACTL_RSR) >> 5) & 0x7;
- g_fnRecCallBack(u8SN);
- }
- }
- }
- /// @endcond /* HIDDEN_SYMBOLS */
- /**
- * @brief Open i2s interface
- * @return open status
- * @retval I2S_ERR_BUSY error.
- * @retval 0 success.
- */
- int32_t i2sOpen(void)
- {
- if (i2sOpened)
- return I2S_ERR_BUSY;
- /* reset audio interface */
- outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) | (1 << 16));
- Delay(100);
- outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) & ~(1 << 16));
- Delay(100);
- /* reset IIS interface */
- outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) | 0x1);
- Delay(100);
- outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) & ~0x1);
- Delay(100);
- outpw(REG_ACTL_CON, inpw(REG_ACTL_CON) | (1 << 21) | (1 << 20));
- i2sOpened = 1;
- return 0;
- }
- /**
- * @brief Close i2s interface
- * @return None
- */
- void i2sClose(void)
- {
- // reset some variables
- i2sOpened = 0;
- g_fnPlayCallBack = NULL;
- g_fnRecCallBack = NULL;
- // reset i2s interface
- outpw(REG_SYS_AHBIPRST, inpw(REG_SYS_AHBIPRST) | (1 << 8));
- outpw(REG_SYS_AHBIPRST, inpw(REG_SYS_AHBIPRST) & ~(1 << 8));
- }
- /**
- * @brief Initialize i2s interface and setup interrupt
- * @return None
- */
- void i2sInit(void)
- {
- // enable i2s engine clock
- outpw(REG_CLK_HCLKEN, inpw(REG_CLK_HCLKEN) | (1 << 24));
- // enable interrupt and set ISR
- sysSetInterruptType(ACTL_IRQn, HIGH_LEVEL_SENSITIVE);
- sysInstallISR(IRQ_LEVEL_1, ACTL_IRQn, (PVOID)i2sISR);
- sysEnableInterrupt(ACTL_IRQn);
- sysSetLocalInterrupt(ENABLE_IRQ);
- }
- /**
- * @brief IO control for i2s interface
- * @param[in] cmd Command for io control, value could be
- * - \ref I2S_SET_PLAY
- * - \ref I2S_SET_RECORD
- * - \ref I2S_SELECT_BLOCK
- * - \ref I2S_SELECT_BIT
- * - \ref I2S_SET_PLAY_DMA_INT_SEL
- * - \ref I2S_SET_REC_DMA_INT_SEL
- * - \ref I2S_SET_ZEROCROSS
- * - \ref I2S_SET_DMACOUNTER
- * - \ref I2S_SET_CHANNEL
- * - \ref I2S_SET_MODE
- * - \ref I2S_SET_SPLITDATA
- * - \ref I2S_SET_DMA_ADDRESS
- * - \ref I2S_SET_DMA_LENGTH
- * - \ref I2S_GET_DMA_CUR_ADDRESS
- * - \ref I2S_SET_I2S_FORMAT
- * - \ref I2S_SET_I2S_CALLBACKFUN
- * - \ref I2S_SET_PCMSLOT
- * @param[in] arg0 argument 0 for io control
- * @param[in] arg1 argument 1 for io control
- * @retval I2S_ERR_IO Command error.
- * @retval 0 success.
- */
- int32_t i2sIoctl(uint32_t cmd, uint32_t arg0, uint32_t arg1)
- {
- uint32_t *buf;
- AU_CB_FUNC_T *ptr;
- switch (cmd)
- {
- // #define I2S_START_PLAY 0
- // #define I2S_STOP_PLAY 1
- case I2S_SET_PLAY:
- if (arg0 == I2S_START_PLAY)
- i2sStartPlay();
- else
- i2sStopPlay();
- break;
- // #define I2S_START_REC 0
- // #define I2S_STOP_REC 1
- case I2S_SET_RECORD:
- if (arg0 == I2S_START_REC)
- i2sStartRecord();
- else
- i2sStopRecord();
- break;
- // #define I2S_BLOCK_I2S 0
- // #define I2S_BLOCK_PCM 1
- case I2S_SELECT_BLOCK:
- if (arg0 == I2S_BLOCK_I2S)
- outpw(REG_ACTL_CON, (inpw(REG_ACTL_CON) & ~0x3) | 0x1);
- else
- outpw(REG_ACTL_CON, (inpw(REG_ACTL_CON) & ~0x3) | 0x2);
- break;
- // #define I2S_BIT_WIDTH_8 0
- // #define I2S_BIT_WIDTH_16 1
- // #define I2S_BIT_WIDTH_24 2
- case I2S_SELECT_BIT:
- outpw(REG_ACTL_CON, (inpw(REG_ACTL_CON) & ~0x300) | (arg0 << 8));
- break;
- // #define I2S_DMA_INT_END 0
- // #define I2S_DMA_INT_HALF 1
- // #define I2S_DMA_INT_QUARTER 2
- // #define I2S_DMA_INT_EIGTH 3
- case I2S_SET_PLAY_DMA_INT_SEL:
- outpw(REG_ACTL_CON, (inpw(REG_ACTL_CON) & ~0x3000) | (arg0 << 12));
- break;
- case I2S_SET_REC_DMA_INT_SEL:
- outpw(REG_ACTL_CON, (inpw(REG_ACTL_CON) & ~0xc000) | (arg0 << 14));
- break;
- case I2S_SET_ZEROCROSS:
- if (arg0 == I2S_ENABLE)
- outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) | 0x8);
- else
- outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) & ~0x8);
- break;
- case I2S_SET_DMACOUNTER:
- if (arg0 == I2S_ENABLE)
- outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) | 0x10);
- else
- outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) & ~0x10);
- break;
- // #define I2S_CHANNEL_I2S_ONE 2
- // #define I2S_CHANNEL_I2S_TWO 3
- // #define I2S_CHANNEL_PCM_TWO 3
- // #define I2S_CHANNEL_PCM_TWO_SLOT1 0
- // #define I2S_CHANNEL_PCM_TWO_SLOT0 1
- // #define I2S_CHANNEL_PCM_ONE_SLOT0 2
- case I2S_SET_CHANNEL:
- if (arg0 == I2S_PLAY)
- outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) & ~(0x3 << 12) | (arg1 << 12));
- else
- outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) & ~(0x3 << 14) | (arg1 << 14));
- break;
- // #define I2S_MODE_MASTER 0
- // #define I2S_MODE_SLAVE 1
- case I2S_SET_MODE:
- if (arg0 == I2S_MODE_MASTER)
- outpw(REG_ACTL_I2SCON, inpw(REG_ACTL_I2SCON) & ~(0x1 << 20));
- else
- outpw(REG_ACTL_I2SCON, inpw(REG_ACTL_I2SCON) | (0x1 << 20));
- break;
- case I2S_SET_SPLITDATA:
- if (arg0 == I2S_ENABLE)
- outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) | (0x1 << 20));
- else
- outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) & ~(0x1 << 20));
- break;
- case I2S_SET_DMA_ADDRESS:
- if (arg0 == I2S_PLAY)
- outpw(REG_ACTL_PDESB, arg1 | 0x80000000);
- else if (arg0 == I2S_REC)
- outpw(REG_ACTL_RDESB, arg1 | 0x80000000);
- else if (arg0 == PCM_PLAY)
- outpw(REG_ACTL_PDESB2, arg1 | 0x80000000);
- else
- outpw(REG_ACTL_RDESB2, arg1 | 0x80000000);
- break;
- case I2S_SET_DMA_LENGTH:
- if (arg0 == I2S_PLAY)
- outpw(REG_ACTL_PDES_LENGTH, arg1);
- else
- outpw(REG_ACTL_RDES_LENGTH, arg1);
- break;
- case I2S_GET_DMA_CUR_ADDRESS:
- buf = (uint32_t *)arg0;
- if (arg0 == I2S_PLAY)
- *buf = inpw(REG_ACTL_PDESC);
- else
- *buf = inpw(REG_ACTL_RDESC);
- break;
- // #define I2S_FORMAT_I2S 0
- // #define I2S_FORMAT_MSB 1
- case I2S_SET_I2S_FORMAT:
- if (arg0 == I2S_FORMAT_I2S)
- outpw(REG_ACTL_I2SCON, inpw(REG_ACTL_I2SCON) & ~ 0x8);
- else
- outpw(REG_ACTL_I2SCON, inpw(REG_ACTL_I2SCON) | 0x8);
- break;
- case I2S_SET_I2S_CALLBACKFUN:
- ptr = (AU_CB_FUNC_T *)arg1;
- if (arg0 == I2S_PLAY)
- g_fnPlayCallBack = ptr;
- else
- g_fnRecCallBack = ptr;
- break;
- // #define PCM_SLOT1_IN 0
- // #define PCM_SLOT1_OUT 1
- // #define PCM_SLOT2_IN 2
- // #define PCM_SLOT2_OUT 3
- case I2S_SET_PCMSLOT:
- if (arg0 == PCM_SLOT1_IN)
- outpw(REG_ACTL_PCMS1ST, (inpw(REG_ACTL_PCMS1ST) & ~0x3ff) | (arg1 & 0x3ff));
- else if (arg0 == PCM_SLOT1_OUT)
- outpw(REG_ACTL_PCMS1ST, (inpw(REG_ACTL_PCMS1ST) & ~0x3ff0000) | ((arg1 & 0x3ff) << 16));
- else if (arg0 == PCM_SLOT2_IN)
- outpw(REG_ACTL_PCMS2ST, (inpw(REG_ACTL_PCMS2ST) & ~0x3ff) | (arg1 & 0x3ff));
- else
- outpw(REG_ACTL_PCMS2ST, (inpw(REG_ACTL_PCMS2ST) & ~0x3ff0000) | ((arg1 & 0x3ff) << 16));
- break;
- case I2S_SET_PCM_FS_PERIOD:
- outpw(REG_ACTL_PCMCON, (inpw(REG_ACTL_PCMCON) & ~0x03FF0000 | (((arg0 - 1) & 0x3ff) << 16)));
- break;
- default:
- return I2S_ERR_IO;
- }
- return 0;
- }
- /**
- * @brief Configure sampling rate for audio
- * @param[in] u32SourceClockRate source speed to i2s interface
- * @param[in] u32SampleRate sampling rate
- * @param[in] u32DataBit data width
- * @param[in] u32Channel channel number
- * @return None
- */
- void i2sSetSampleRate(uint32_t u32SourceClockRate, uint32_t u32SampleRate, uint32_t u32DataBit, uint32_t u32Channel)
- {
- uint32_t u32BCLKDiv;
- uint32_t u32MCLK, u32MCLKDiv;
- u32MCLK = (u32SampleRate * 256);
- u32MCLKDiv = u32SourceClockRate / u32MCLK;
- outpw(REG_ACTL_I2SCON, (inpw(REG_ACTL_I2SCON) & ~0x000F0000) | (u32MCLKDiv - 1) << 16);
- u32BCLKDiv = u32MCLK / (u32SampleRate * u32DataBit * u32Channel);
- u32BCLKDiv = u32BCLKDiv / 2 - 1;
- outpw(REG_ACTL_I2SCON, (inpw(REG_ACTL_I2SCON) & ~0xF0) | u32BCLKDiv << 5);
- }
- /**
- * @brief Configure MCLK frequency (master mode)
- * @param[in] u32SourceClockRate source clock rate
- * @param[in] u32SampleRate sampling rate
- * @return None
- */
- void i2sSetMCLKFrequency(uint32_t u32SourceClockRate, uint32_t u32SampleRate)
- {
- uint32_t u32MCLK, u32MCLKDiv;
- u32MCLK = (u32SampleRate * 256);
- u32MCLKDiv = u32SourceClockRate / u32MCLK;
- outpw(REG_ACTL_I2SCON, (inpw(REG_ACTL_I2SCON) & ~0x000F0000) | (u32MCLKDiv - 1) << 16);
- }
- /**
- * @brief Configure PCM BCLK frequency (master mode)
- * @param[in] u32SourceClockRate source clock rate
- * @param[in] u32Rate target rate
- * @return None
- */
- void i2sSetPCMBCLKFrequency(uint32_t u32SourceClockRate, uint32_t u32Rate)
- {
- uint32_t u32BCLKDiv;
- u32BCLKDiv = (u32SourceClockRate / (2 * u32Rate)) - 1;
- outpw(REG_ACTL_PCMCON, (inpw(REG_ACTL_PCMCON) & ~0x0000FF00) | (u32BCLKDiv << 8));
- }
- /*@}*/ /* end of group N9H30_I2S_EXPORTED_FUNCTIONS */
- /*@}*/ /* end of group N9H30_I2S_Driver */
- /*@}*/ /* end of group N9H30_Device_Driver */
- /*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/
|