| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564 |
- /*******************************************************************************
- * File Name : i2s.c
- * Author : ZJH
- * Date First Issued : 6/24/2024
- * Description : i2s drive.
- ********************************************************************************
- * History:
- * 6/24/2024: V0.1
- *******************************************************************************/
- #include "chip.h"
- #include "soc-dai.h"
- #include "audio/audio.h"
- typedef struct ark_i2s_private_data {
- uint32_t adc_fmt;
- uint32_t dac_fmt;
- struct codec_register_inf *adc_inf;
- struct codec_register_inf *dac_inf;
- } ark_i2s_pd;
- struct ark_i2s_drv i2s_drv_tab[I2S_NUMS] = {
- #if ((AUDIO_REPLAY_I2S == I2S_ID0) || (AUDIO_RECORD_I2S == I2S_ID0))
- {
- .base = REGS_I2S_BASE,
- .nco_base = SYS_I2S_NCO_CFG + REGS_SYSCTL_BASE,
- .id = I2S_ID0,
- .clkid = CLK_I2S,
- .irqn = I2S_IRQn,
- .dma_tx_req_id = I2S_TX,
- .dma_rx_req_id = I2S_RX,
- .softreset_id = softreset_i2s,
- .dma_tx_chn = I2S_DMA_TXCH,
- .dma_rx_chn = I2S_DMA_RXCH,
- .type = IIS_BUS,
- .sup_func = I2S_SUP_MASTER|I2S_SUP_SLAVER|I2S_SUP_FULL_DUPLEX,
- .is_master = 1,
- .chn_sum = 2,
- .encoder_name = AUDIO_CODEC_ADC_NAME,
- .decoder_name = AUDIO_CODEC_DAC_NAME,
- },
- #endif
- #if ((AUDIO_REPLAY_I2S == I2S_ID1) || (AUDIO_RECORD_I2S == I2S_ID1))
- {
- .base = REGS_I2S1_BASE,
- .nco_base = SYS_I2S_NCO_CFG1 + REGS_SYSCTL_BASE,
- .id = I2S_ID1,
- .clkid = CLK_I2S1,
- .irqn = I2S1_IRQn,
- .dma_tx_req_id = I2S1_TX,
- .dma_rx_req_id = I2S1_RX,
- .softreset_id = softreset_i2s1,
- .dma_tx_chn = I2S1_DMA_TXCH,
- .dma_rx_chn = I2S1_DMA_RXCH,
- .type = IIS_BUS,
- .sup_func = I2S_SUP_MASTER|I2S_SUP_SLAVER|I2S_SUP_FULL_DUPLEX,
- .is_master = 1,
- .chn_sum = 2,
- .encoder_name = AUDIO_CODEC_ADC_NAME,
- .decoder_name = AUDIO_CODEC_DAC_NAME,
- },
- #endif
- };
- static void ark_i2s_start_play(struct ark_i2s_drv *i2s)
- {
- u32 val = readl(i2s->base + I2S_SACR1);
- val &= ~SACR1_DRPL;
- writel(val, i2s->base + I2S_SACR1);
- }
- static void ark_i2s_stop_play(struct ark_i2s_drv *i2s)
- {
- u32 val = readl(i2s->base + I2S_SACR1);
- val |= SACR1_DRPL;
- writel(val, i2s->base + I2S_SACR1);
- }
- static void ark_i2s_start_record(struct ark_i2s_drv *i2s)
- {
- u32 val = readl(i2s->base + I2S_SACR1);
- val &= ~SACR1_DREC;
- writel(val, i2s->base + I2S_SACR1);
- }
- static void ark_i2s_stop_record(struct ark_i2s_drv *i2s)
- {
- u32 val = readl(i2s->base + I2S_SACR1);
- val |= SACR1_DREC;
- writel(val, i2s->base + I2S_SACR1);
- }
- static void i2s_interrupt_handler(void *param)
- {
- struct ark_i2s_drv *i2s = (struct ark_i2s_drv *)param;
- unsigned int status;
- //unsigned int val;
- if(!i2s)
- return;
- status = readl(i2s->base + I2S_SASR0);
- #if 1
- writel(0xFF, i2s->base + I2S_SAICR);
- if (status & SASR0_TUR) {
- //printf("i2s txfifo underrun.\n");
- }
- #else
- val = readl(i2s->base + I2S_SAICR);
- if(status & SASR0_TFS)
- val |= SAICR_TFS;
- if(status & SASR0_TUR)
- val |= SAICR_TUR;
- if(status & SASR0_RFS)
- val |= SAICR_RFS;
- if(status & SASR0_ROR)
- val |= SAICR_ROR;
- writel(val, i2s->base + I2S_SAICR);
- #endif
- writel(0x0, i2s->base + I2S_SAICR);
- }
- static int codec_init(struct ark_i2s_drv *i2s, int dir)
- {
- ark_i2s_pd *pdata = NULL;
- int ret = -1;
- if(!i2s->extdata) {
- pdata = (ark_i2s_pd *)pvPortMalloc(sizeof(struct ark_i2s_private_data));
- memset(pdata, 0, sizeof(ark_i2s_pd));
- i2s->extdata = (void *)pdata;
- } else {
- printf("[ERR] %s() codec_init have been called, exit.\n", __func__);
- return -1;
- }
- if(pdata) {
- if (i2s->type == IIS_BUS) {
- #ifdef AUDIO_RECORD
- if (dir & I2S_DIR_INPUT && (i2s->id == AUDIO_RECORD_I2S)) {
- pdata->adc_inf = get_codec_register_inf(i2s->encoder_name);
- if (pdata->adc_inf) {
- if (pdata->adc_inf->ops && pdata->adc_inf->ops->init) {
- pdata->adc_inf->ops->init(pdata->adc_inf->codec_prvdata, !i2s->is_master);
- }
- } else {
- printf("[ERR] %s() get adc info fail!\n", __func__);
- }
- }
- #endif
- #ifdef AUDIO_REPLAY
- if (dir & I2S_DIR_OUTPUT && (i2s->id == AUDIO_REPLAY_I2S)) {
- pdata->dac_inf = get_codec_register_inf(i2s->decoder_name);
- if (pdata->dac_inf) {
- if (pdata->dac_inf->ops && pdata->dac_inf->ops->init) {
- pdata->dac_inf->ops->init(pdata->dac_inf->codec_prvdata, !i2s->is_master);
- }
- } else {
- printf("[ERR] %s() get dac info fail!\n", __func__);
- }
- }
- #endif
- }
- }
- return ret;
- }
- static int i2s_soft_reset(struct ark_i2s_drv *i2s)
- {
- u32 val;
- val = readl(i2s->base + I2S_SACR0);
- val |= SACR0_RST;
- writel(val, i2s->base + I2S_SACR0);
- return 0;
- }
- static int ark_i2s_set_rfirst(struct ark_i2s_drv *i2s, int enable)
- {
- if (!i2s->cfg) {
- printf("[ERR] %s(), invalid cfg.\n", __func__);
- return -ENXIO;
- }
- i2s->cfg->rfirst = enable;
- return 0;
- }
- int ark_i2s_set_samplerate(struct ark_i2s_drv *i2s, int rates)
- {
- uint32_t step = 256 * 2, modulo;
- uint32_t val, freq;
- if (!i2s->cfg) {
- printf("[ERR] %s(), invalid cfg.\n", __func__);
- return -ENXIO;
- }
- i2s->cfg->rates = rates;
- if (!i2s->nco_base) {
- printf("[ERR] %s(), invalid nco_base.\n", __func__);
- return 0;
- }
- /* mclk = rate * 256, mclk = freq * step / (2 * modulo) */
- freq = ulClkGetRate(i2s->clkid);
- modulo = freq / rates;
- val = (step << 16) | modulo;
- writel(val, i2s->nco_base);
- return 0;
- }
- int ark_i2s_set_channels(struct ark_i2s_drv *i2s, int channels)
- {
- if (!i2s->cfg) {
- printf("[ERR] %s(), invalid cfg.\n", __func__);
- return -ENXIO;
- }
- i2s->cfg->channels = channels;
- return 0;
- }
- int ark_i2s_set_samplebits(struct ark_i2s_drv *i2s, int bits)
- {
- if (!i2s->cfg) {
- printf("[ERR] %s(), invalid cfg.\n", __func__);
- return -ENXIO;
- }
- if (bits > 16)
- i2s->cfg->bits = 32;
- else
- i2s->cfg->bits = 16;
- return 0;
- }
- int ark_i2s_set_volume(struct ark_i2s_drv *i2s, int dir, int lvol, int rvol)
- {
- ark_i2s_pd *pdata = i2s->extdata;
- struct snd_pcm_substream substream;
- u32 val;
- if (!i2s->cfg) {
- printf("[ERR] %s(), invalid cfg.\n", __func__);
- return -ENXIO;
- }
- if(lvol > I2S_VOL_MAX)
- lvol = I2S_VOL_MAX;
- if(rvol > I2S_VOL_MAX)
- rvol = I2S_VOL_MAX;
- if(lvol < I2S_VOL_MIN)
- lvol = I2S_VOL_MIN;
- if(rvol < I2S_VOL_MIN)
- rvol = I2S_VOL_MIN;
- if (!pdata) {
- printf("[ERR] %s(), invalid pdata.\n", __func__);
- return -ENXIO;
- }
- if (dir & I2S_DIR_OUTPUT) {
- substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
- if (pdata->dac_inf && pdata->dac_inf->ops && pdata->dac_inf->ops->set_vol) {
- pdata->dac_inf->ops->set_vol(pdata->dac_inf->codec_prvdata, &substream, lvol, rvol);
- } else {
- printf("[ERR] %s(), dac not support volume setting.\n", __func__);
- return -ENXIO;
- }
- i2s->cfg->out_lvol = lvol;
- i2s->cfg->out_rvol = rvol;
- }
- if (dir & I2S_DIR_INPUT) {
- substream.stream = SNDRV_PCM_STREAM_CAPTURE;
- if (pdata->adc_inf && pdata->adc_inf->ops && pdata->adc_inf->ops->set_vol) {
- pdata->adc_inf->ops->set_vol(pdata->adc_inf->codec_prvdata, &substream, lvol, rvol);
- } else {
- printf("[ERR] %s(), adc not support volume setting.\n", __func__);
- return -ENXIO;
- }
- i2s->cfg->in_lvol = lvol;
- i2s->cfg->in_rvol = rvol;
- }
- return 0;
- }
- int ark_i2s_set_mute(struct ark_i2s_drv *i2s, int dir, int mute)
- {
- int in_lvol, in_rvol;
- int out_lvol, out_rvol;
- if (!i2s->cfg) {
- printf("[ERR] %s(), invalid cfg.\n", __func__);
- return -ENXIO;
- }
- if (mute) {
- in_lvol = i2s->cfg->in_lvol;
- in_rvol = i2s->cfg->in_rvol;
- out_lvol = i2s->cfg->out_lvol;
- out_rvol = i2s->cfg->out_rvol;
- ark_i2s_set_volume(i2s, dir, 0, 0);
- i2s->cfg->in_lvol = in_lvol;
- i2s->cfg->in_rvol = in_rvol;
- i2s->cfg->out_lvol = out_lvol;
- i2s->cfg->out_rvol = out_rvol;
- } else {
- if (dir & I2S_DIR_OUTPUT)
- ark_i2s_set_volume(i2s, I2S_DIR_OUTPUT, i2s->cfg->out_lvol, i2s->cfg->out_rvol);
- if (dir & I2S_DIR_INPUT)
- ark_i2s_set_volume(i2s, I2S_DIR_INPUT, i2s->cfg->in_lvol, i2s->cfg->in_rvol);
- }
- return 0;
- }
- int ark_i2s_startup(struct ark_i2s_drv *i2s, int dir)
- {
- unsigned int val;
- struct snd_pcm_substream substream;
- unsigned int codec_fmt = 0;
- ark_i2s_pd *pdata = NULL;
- if (!i2s->cfg) {
- printf("[ERR] %s(), invalid cfg.\n", __func__);
- return -ENXIO;
- }
- if (!(i2s->cfg->dir & (I2S_DIR_OUTPUT | I2S_DIR_INPUT))) {
- printf("[ERR] %s(), invalid dir.\n", __func__);
- return -EPERM;
- }
- pdata = i2s->extdata;
- if ((i2s->cfg->status & (I2S_STA_OUTPUTTING | I2S_STA_INPUTTING)) == 0){
- /* reset */
- /* stop replay and record */
- ark_i2s_stop_play(i2s);
- ark_i2s_stop_record(i2s);
- val = SACR0_CHANLOCK | SACR0_RFTH(0x10) | SACR0_TFTH(0xF) | SACR0_ENB;
- codec_fmt |= SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF;
- if (!(i2s->cfg->rfirst))
- val |= SACR0_TFIFOFIRSTBIT | SACR0_RFIFIFIRSTBIT;
- if (i2s->cfg->channels == 1)
- val |= SACR0_SCBIT;
- if (i2s->cfg->bits > 16)
- val |= SACR0_BITS; //32 Bits.
- if (i2s->is_master) {
- val |= SACR0_BCKD | SACR0_SYNCD;
- codec_fmt |= SND_SOC_DAIFMT_CBS_CFS;
- } else {
- codec_fmt |= SND_SOC_DAIFMT_CBS_CFM;
- }
- if (i2s->dma_txch)
- val |= SACR0_TDMAEN;
- if (i2s->dma_rxch)
- val |= SACR0_RDMAEN;
- writel(val, i2s->base + I2S_SACR0);
- /* interrupt clear */
- writel(0xFFFFFFFF, i2s->base + I2S_SAICR);
- writel(0, i2s->base + I2S_SAICR);
- /* interrupt enable */
- val = readl(i2s->base + I2S_SAIMR);
- val |= (SAIMR_TFS | SAIMR_TUR | SAIMR_ROR | SAIMR_RFS);
- writel(val, i2s->base + I2S_SAIMR);
- if (pdata) {
- pdata->adc_fmt = codec_fmt;
- pdata->dac_fmt = codec_fmt;
- }
- }
- if ((dir & I2S_DIR_OUTPUT) && (i2s->cfg->dir & I2S_DIR_OUTPUT)) {
- substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
- if (pdata && pdata->dac_inf && pdata->dac_inf->ops) {
- if (pdata->dac_inf->ops->set_fmt) {
- pdata->dac_inf->ops->set_fmt(pdata->dac_inf->codec_prvdata, pdata->dac_fmt);
- }
- if (pdata->dac_inf->ops->hw_params) {
- struct snd_soc_hw_params params;
- params.rates = i2s->cfg->rates;
- params.channels = i2s->cfg->channels;
- params.bits = i2s->cfg->bits;
- pdata->dac_inf->ops->hw_params(pdata->dac_inf->codec_prvdata, &substream, ¶ms);
- }
- if (pdata->dac_inf->ops->startup) {
- pdata->dac_inf->ops->startup(pdata->dac_inf->codec_prvdata, &substream, 1);
- }
- if(pdata->dac_inf->ops->set_mute){
- pdata->dac_inf->ops->set_mute(pdata->dac_inf->codec_prvdata, &substream, 0);
- }
- }
- ark_i2s_start_play(i2s);
- i2s->cfg->status |= I2S_STA_OUTPUTTING;
- }
- if((dir & I2S_DIR_INPUT) && (i2s->cfg->dir & I2S_DIR_INPUT)){
- substream.stream = SNDRV_PCM_STREAM_CAPTURE;
- if (pdata && pdata->adc_inf && pdata->adc_inf->ops) {
- if (pdata->adc_inf->ops->set_fmt) {
- pdata->adc_inf->ops->set_fmt(pdata->adc_inf->codec_prvdata, pdata->dac_fmt);
- }
- if (pdata->adc_inf->ops->hw_params) {
- struct snd_soc_hw_params params;
- params.rates = i2s->cfg->rates;
- params.channels = i2s->cfg->channels;
- params.bits = i2s->cfg->bits;
- pdata->adc_inf->ops->hw_params(pdata->adc_inf->codec_prvdata, &substream, ¶ms);
- }
- if (pdata->adc_inf->ops->startup) {
- pdata->adc_inf->ops->startup(pdata->adc_inf->codec_prvdata, &substream, 1);
- }
- if (pdata->adc_inf->ops->set_mute) {
- pdata->adc_inf->ops->set_mute(pdata->adc_inf->codec_prvdata, &substream, 0);
- }
- }
- ark_i2s_start_record(i2s);
- i2s->cfg->status |= I2S_STA_INPUTTING;
- }
- return 0;
- }
- int ark_i2s_stop(struct ark_i2s_drv *i2s, int dir)
- {
- ark_i2s_pd *pdata = i2s->extdata;
- struct snd_pcm_substream substream;
- u32 val;
- if (!i2s->cfg) {
- printf("[ERR] %s(), invalid cfg.\n", __func__);
- return -ENXIO;
- }
- if (dir & I2S_DIR_OUTPUT) {
- if ((i2s->cfg->status & I2S_STA_OUTPUTTING) == I2S_STA_OUTPUTTING){
- ark_i2s_stop_play(i2s);
- /* interrupt disable */
- val = readl(i2s->base + I2S_SAIMR);
- val &= ~(SAIMR_TFS | SAIMR_TUR);
- writel(val, i2s->base + I2S_SAIMR);
- }
- i2s->cfg->status &= ~I2S_STA_OUTPUTTING;
- substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
- if (pdata && pdata->dac_inf && pdata->dac_inf->ops && pdata->dac_inf->ops->startup) {
- pdata->dac_inf->ops->startup(pdata->dac_inf->codec_prvdata, &substream, 0);
- }
- }
- if (dir & I2S_DIR_INPUT) {
- if ((i2s->cfg->status & I2S_STA_INPUTTING) == I2S_STA_INPUTTING){
- ark_i2s_stop_record(i2s);
- /* interrupt disable */
- val = readl(i2s->base + I2S_SAIMR);
- val &= ~(SAIMR_ROR | SAIMR_RFS);
- writel(val, i2s->base + I2S_SAIMR);
- }
- i2s->cfg->status &= ~I2S_STA_INPUTTING;
- substream.stream = SNDRV_PCM_STREAM_CAPTURE;
- if (pdata && pdata->adc_inf && pdata->adc_inf->ops && pdata->adc_inf->ops->startup) {
- pdata->adc_inf->ops->startup(pdata->adc_inf->codec_prvdata, &substream, 0);
- }
- }
- if (!(i2s->cfg->status & (I2S_STA_OUTPUTTING | I2S_STA_INPUTTING))) {
- writel(readl(i2s->base + I2S_SACR0) & (~SACR0_ENB), i2s->base + I2S_SACR0);
- }
- return 0;
- }
- int ark_i2s_init(struct ark_i2s_drv *i2s, int dir)
- {
- if ((dir & I2S_DIR_FULL_DUPLEX) == 0) {
- printf("[ERR] %s(), invalid dir.\n", __func__);
- return -EINVAL;
- }
- if ((dir & I2S_DIR_FULL_DUPLEX) == I2S_DIR_FULL_DUPLEX) {
- if (!(i2s->sup_func & I2S_SUP_FULL_DUPLEX)) {
- printf("[ERR] %s(), invalid sup_func.\n", __func__);
- return -EPERM;
- }
- }
- if (i2s->is_master) {
- if (!(i2s->sup_func & I2S_SUP_MASTER)) {
- printf("[ERR] %s(), sup_func not support master.\n", __func__);
- return -EPERM;
- }
- } else {
- if (!(i2s->sup_func & I2S_SUP_SLAVER)) {
- printf("[ERR] %s(), sup_func not support slaver.\n", __func__);
- return -EPERM;
- }
- }
- i2s->dma_txch = NULL;
- i2s->dma_rxch = NULL;
- if (dir & I2S_DIR_OUTPUT) {
- if (i2s->sup_func & (I2S_SUP_OUTPUT | I2S_SUP_FULL_DUPLEX)) {
- i2s->dma_txch = dma_request_channel(i2s->dma_tx_chn);
- if (!i2s->dma_txch) {
- printf("[ERR] %s() i2s replay dma_request_channel fail.\n", __func__);
- return -ENODEV;
- }
- } else {
- printf("[ERR] %s() The i2s controller does not support output!\n", __func__);
- return -EINVAL;
- }
- }
- if (dir & I2S_DIR_INPUT) {
- if (i2s->sup_func & (I2S_SUP_INPUT | I2S_SUP_FULL_DUPLEX)) {
- i2s->dma_rxch = dma_request_channel(i2s->dma_rx_chn);
- if (!i2s->dma_rxch) {
- printf("[ERR] %s() i2s record dma_request_channel fail.\n", __func__);
- return -ENODEV;
- }
- } else {
- printf("[ERR] %s() The i2s controller does not support input!\n", __func__);
- return -EINVAL;
- }
- }
- i2s->cfg = (struct ark_i2s_cfg *)pvPortMalloc(sizeof(struct ark_i2s_cfg));
- if (!i2s->cfg) {
- printf("[ERR] %s(), malloc fail.\n", __func__);
- return -ENOMEM;
- }
- memset(i2s->cfg, 0, sizeof(struct ark_i2s_cfg));
- i2s->cfg->dir = dir;
- sys_soft_reset(i2s->softreset_id);
- i2s_soft_reset(i2s);
- vClkEnable(i2s->clkid);
- // request_irq(i2s->irqn, 0, IRQ_TYPE_LEVEL_HIGH, i2s_interrupt_handler, i2s);
- codec_init(i2s, dir);
- ark_i2s_set_rfirst(i2s, 1);
- return 0;
- }
|