123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605 |
- /*
- * Copyright (c) 2006-2021, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2015-11-19 Urey the first version
- */
- #include <rthw.h>
- #include <rtthread.h>
- #include <rtdevice.h>
- #include <drivers/audio.h>
- #include "dma.h"
- #ifdef RT_USING_FINSH
- #include <finsh.h>
- #endif
- #include "board.h"
- #include "drv_clock.h"
- #include "drv_dma.h"
- #include "drv_gpio.h"
- #include "drv_aic.h"
- #include "drv_aic_i2s.h"
- #define AIC_DEBUG 0
- #if AIC_DEBUG
- #define AIC_DBG(...) rt_kprintf("[AIC]"),rt_kprintf(__VA_ARGS__)
- #else
- #define AIC_DBG(...)
- #endif
- static struct jz_aic _g_jz_aic;
- int aic_set_rate(struct jz_aic *aic, uint32_t freq)
- {
- int ret;
- // clk_disable(aic->clk);
- if (aic->clk_rate != freq)
- {
- ret = clk_set_rate(aic->clk, freq);
- if (!ret)
- aic->clk_rate = clk_get_rate(aic->clk);
- }
- // clk_enable(aic->clk);
- AIC_DBG("aic clock = %d\n",clk_get_rate(aic->clk));
- return aic->clk_rate;
- }
- static void aic_irq_handler(int vector, void *param)
- {
- struct jz_aic *aic = (struct jz_aic *)param;
- aic->mask = __aic_get_irq_enmask(aic);
- if (aic->mask && (aic->mask & __aic_get_irq_flag(aic)))
- {
- /*Disable all aic interrupt*/
- __aic_set_irq_enmask(aic, 0);
- if ((aic->mask & 0x8) && __aic_test_ror(aic))
- {
- aic->ror++;
- AIC_DBG("recieve fifo [overrun] interrupt time [%d]\n",
- aic->ror);
- }
- if ((aic->mask & 0x4) && __aic_test_tur(aic))
- {
- aic->tur++;
- AIC_DBG("transmit fifo [underrun] interrupt time [%d]\n",
- aic->tur);
- }
- if ((aic->mask & 0x2) && __aic_test_rfs(aic))
- {
- AIC_DBG("[recieve] fifo at or above threshold interrupt time\n");
- }
- if ((aic->mask & 0x1) && __aic_test_tfs(aic))
- {
- AIC_DBG("[transmit] fifo at or blow threshold interrupt time\n");
- }
- /*sleep, avoid frequently interrupt*/
- __aic_clear_all_irq_flag(aic);
- __aic_set_irq_enmask(aic, aic->mask);
- }
- }
- struct jz_aic* _aic_init(void)
- {
- struct jz_aic *aic = &_g_jz_aic;
- struct rt_device *device;
- aic->base = AIC_BASE;
- aic->clk_gate = clk_get("aic");
- aic->clk = clk_get("cgu_i2s");
- if((aic->clk_gate == RT_NULL) || (aic->clk == RT_NULL))
- {
- AIC_DBG("aic or i2s clk error\n");
- goto aic_init_error;
- }
- /* set system clock */
- clk_set_rate(aic->clk, 24000000);
- aic->clk_rate = 24000000;
- clk_enable(aic->clk_gate);
- clk_enable(aic->clk);
- aic->irqno = IRQ_AIC0;
- aic->irqflags = 0;
- rt_hw_interrupt_install(IRQ_AIC0,aic_irq_handler,aic,"irq_aic");
- rt_hw_interrupt_umask(IRQ_AIC0);
- return aic;
- aic_init_error:
- clk_put(aic->clk);
- clk_put(aic->clk_gate);
- return RT_NULL;
- }
- #define I2S_DEBUG 0
- #if I2S_DEBUG
- #define I2S_DBG(...) rt_kprintf("[I2S]"),rt_kprintf(__VA_ARGS__)
- #else
- #define I2S_DBG(...)
- #endif
- #define I2S_TFIFO_DEPTH 64
- #define I2S_RFIFO_DEPTH 32
- #define I2S_OSS_FMT 16
- #define I2S_ISS_FMT 16
- #define I2S_PALY_CHANEL 2
- struct jz_i2s _g_jz_i2s =
- {
- .aic = 0,
- .i2s_init = 0,
- .i2s_mode = 0,
- .tx_dr_base = ((AIC_BASE + AICDR) & 0x1FFFFFFF),
- .channels = 2,
- .fmt_width = 16,
- .tx_dmac = RT_NULL,
- .rx_dmac = RT_NULL,
- };
- #define I2S_DMA_TX_CHAN 2
- #define I2S_DMA_RX_CHAN 3
- static void aic_i2s_trans_complete(struct rt_dma_channel *dmac, struct dma_message *msg);
- static void dump_registers(struct jz_aic *aic)
- {
- rt_kprintf("AIC_FR 0x%08x : 0x%08x\n", (aic->base+AICFR), jz_aic_read_reg(aic, AICFR));
- rt_kprintf("AIC_CR 0x%08x : 0x%08x\n", (aic->base+AICCR), jz_aic_read_reg(aic, AICCR));
- rt_kprintf("AIC_I2SCR 0x%08x : 0x%08x\n", (aic->base+I2SCR), jz_aic_read_reg(aic, I2SCR));
- rt_kprintf("AIC_SR 0x%08x : 0x%08x\n", (aic->base+AICSR), jz_aic_read_reg(aic, AICSR));
- rt_kprintf("AIC_I2SSR 0x%08x : 0x%08x\n", (aic->base+I2SSR), jz_aic_read_reg(aic, I2SSR));
- rt_kprintf("AIC_I2SDIV 0x%08x : 0x%08x\n", (aic->base+I2SDIV), jz_aic_read_reg(aic, I2SDIV));
- rt_kprintf("AIC_DR 0x%08x : 0x%08x\n", (aic->base+AICDR), jz_aic_read_reg(aic, AICDR));
- rt_kprintf("AIC_I2SCDR\t 0x%08x\n",*(volatile unsigned int*)0xb0000060);
- rt_kprintf("AIC_I2SCDR1\t 0x%08x\n",*(volatile unsigned int*)0xb0000070);
- rt_kprintf("AICSR\t 0x%08x\n",*(volatile unsigned int*)0xb0020014);
- return;
- }
- int dump_aic_i2s(void)
- {
- dump_registers(_g_jz_i2s.aic);
- return 0;
- }
- MSH_CMD_EXPORT(dump_aic_i2s,dump i2s registers...);
- #if 0
- int i2scdr_extclk(void)
- {
- rt_uint32_t regValue;
- regValue = readl(0xb0000060);
- regValue &= ~(0x01 << 30);
- writel(regValue,0xb0000060);
- rt_kprintf("AIC_I2SCDR\t 0x%08x\n",*(volatile unsigned int*)0xb0000060);
- }
- MSH_CMD_EXPORT(i2scdr_extclk,set i2s cdr ext clk...);
- int i2scdr_pllclk(void)
- {
- rt_uint32_t regValue;
- regValue = readl(0xb0000060);
- regValue |= (0x01 << 30);
- writel(regValue,0xb0000060);
- rt_kprintf("AIC_I2SCDR\t 0x%08x\n",*(volatile unsigned int*)0xb0000060);
- }
- MSH_CMD_EXPORT(i2scdr_pllclk,set i2s cdr pll clk...);
- #endif
- static void aic_i2s_start_substream(struct jz_i2s *i2s,int stream)
- {
- struct jz_aic *aic = i2s->aic;
- if(stream == AUDIO_STREAM_REPLAY)
- {
- int i = 4;
- I2S_DBG("codec fifo level0 %x\n", jz_aic_read_reg(aic, AICSR));
- for (i= 0; i < I2S_TFIFO_DEPTH ; i++)
- {
- __aic_write_txfifo(aic, 0x0);
- __aic_write_txfifo(aic, 0x0);
- }
- __aic_clear_tur(aic);
- I2S_DBG("codec fifo level1 %x\n", jz_aic_read_reg(aic, AICSR));
- __i2s_enable_replay(aic);
- while (!__aic_test_tur(aic)) ;
- __i2s_enable_transmit_dma(aic);
- __aic_clear_tur(aic);
- #if I2S_DEBUG
- __aic_en_tur_int(aic);
- #endif
- }
- else
- {
- __aic_flush_rxfifo(aic);
- rt_thread_delay(1);
- __i2s_enable_record(aic);
- __i2s_enable_receive_dma(aic);
- #if I2S_DEBUG
- __aic_en_ror_int(aic);
- #endif
- }
- I2S_DBG("strtup sub stream ok!\n");
- }
- static void aic_i2s_stop_substream(struct jz_i2s *i2s,int stream)
- {
- struct jz_aic *aic = i2s->aic;
- if(stream == AUDIO_STREAM_REPLAY)
- {
- #if I2S_DEBUG
- __aic_dis_tur_int(aic);
- #endif
- if (__i2s_transmit_dma_is_enable(aic))
- {
- //wait all dma queue is complete
- while(i2s->tx_dmac->get_index != i2s->tx_dmac->put_index)
- rt_thread_delay(1);
- __i2s_disable_transmit_dma(aic);
- __aic_clear_tur(aic);
- /*hrtime mode: stop will be happen in any where, make sure there is
- * no data transfer on ahb bus before stop dma
- */
- while(!__aic_test_tur(aic));
- }
- __i2s_disable_replay(aic);
- __aic_clear_tur(aic);
- }
- else
- {
- // if (jz_i2s_debug) __aic_dis_ror_int(aic);
- if (__i2s_receive_dma_is_enable(aic))
- {
- __i2s_disable_receive_dma(aic);
- __aic_clear_ror(aic);
- while(!__aic_test_ror(aic));
- }
- __i2s_disable_record(aic);
- __aic_clear_ror(aic);
- }
- }
- int aic_i2s_set_clkdiv(struct jz_i2s *i2s,int div_id, int div)
- {
- struct jz_aic *aic = i2s->aic;
- I2S_DBG("enter %s div_id %d div %d\n", __func__, div_id , div);
- /*BIT CLK fix 64FS*/
- /*SYS_CLK is 256, 384, 512, 768*/
- if (div != 256 && div != 384 && div != 512 && div != 768)
- return -RT_EIO;
- __i2s_set_dv(aic, (div/64) - 1);
- __i2s_set_idv(aic, (div/64) - 1);
- return RT_EOK;
- }
- /*
- * stream = CODEC_STREAM_PLAYBACK or CODEC_STREAM_CAPTURE
- */
- int aic_i2s_startup(struct jz_i2s *i2s,int stream)
- {
- struct jz_aic *aic = i2s->aic;
- if(!i2s->i2s_mode)
- {
- I2S_DBG("start set AIC register....\n");
- __aic_disable(aic);
- __aic_select_i2s(aic);
- __i2s_select_i2s_fmt(aic);
- #ifndef CODEC_AS_MASTER
- __i2s_bclk_output(aic);
- __i2s_sync_output(aic);
- #else
- __i2s_bclk_input(aic);
- __i2s_sync_input(aic);
- #endif
- aic_i2s_set_sysclk(i2s,CODEC_DEF_RATE);
- __i2s_play_lastsample(aic);
- __i2s_set_transmit_trigger(aic, I2S_TFIFO_DEPTH/4);
- __i2s_set_receive_trigger(aic, (I2S_RFIFO_DEPTH/4 - 1));
- __aic_enable(aic);
- }
- /* Set playback or record mode */
- if(stream == AUDIO_STREAM_REPLAY)
- {
- __i2s_send_rfirst(aic);
- __i2s_disable_transmit_dma(aic);
- __i2s_disable_replay(aic);
- __aic_clear_tur(aic);
- i2s->i2s_mode |= I2S_WRITE;
- }
- else
- {
- __i2s_disable_receive_dma(aic);
- __i2s_disable_record(aic);
- __aic_clear_ror(aic);
- i2s->i2s_mode |= I2S_READ;
- }
- return 0;
- }
- int aic_i2s_trigger(struct jz_i2s* i2s,int cmd,int stream)
- {
- switch (cmd)
- {
- case I2S_TRIGGER_START:
- case I2S_TRIGGER_RESUME:
- case I2S_TRIGGER_PAUSE_RELEASE:
- aic_i2s_start_substream(i2s,stream);
- break;
- case I2S_TRIGGER_STOP:
- case I2S_TRIGGER_SUSPEND:
- case I2S_TRIGGER_PAUSE_PUSH:
- default:
- aic_i2s_stop_substream(i2s,stream);
- break;
- }
- return 0;
- }
- int aic_i2s_hw_params(struct jz_i2s* i2s,int stream)
- {
- struct jz_aic *aic = i2s->aic;
- struct dma_config config;
- int trigger;
- int bus_width;
- I2S_DBG("upgrade hw params...\n");
- if(stream == AUDIO_STREAM_REPLAY)
- {
- /* channel */
- __i2s_channel(aic, i2s->channels);
- /* format */
- if(i2s->fmt_width == 8)
- bus_width = RT_DMA_BUSWIDTH_1_BYTE;
- else if(i2s->fmt_width == 16)
- bus_width = RT_DMA_BUSWIDTH_2_BYTES;
- else
- bus_width = RT_DMA_BUSWIDTH_4_BYTES;
- i2s->tx_dmac = rt_dma_get_channel(I2S_DMA_TX_CHAN);
- RT_ASSERT(i2s->tx_dmac != RT_NULL);
- if(i2s->tx_dmac != RT_NULL)
- {
- config.direction = RT_DMA_MEM_TO_DEV;
- config.src_addr_width = bus_width;
- config.src_maxburst = (64 * 1024);
- config.dst_addr_width = bus_width;
- config.dst_maxburst = (I2S_TFIFO_DEPTH * bus_width)/2;
- rt_dma_configture(i2s->tx_dmac,&config);
- i2s->tx_dmac->start = RT_NULL;
- i2s->tx_dmac->complete = aic_i2s_trans_complete;
- }
- __i2s_set_oss(aic, i2s->fmt_width);
- __i2s_set_transmit_trigger(aic, (I2S_TFIFO_DEPTH / 4));
- I2S_DBG("TX_DMAC config ok!\n");
- }
- else
- {
- /* format */
- if(i2s->fmt_width == 8)
- bus_width = RT_DMA_BUSWIDTH_1_BYTE;
- else if(i2s->fmt_width == 16)
- bus_width = RT_DMA_BUSWIDTH_2_BYTES;
- else
- bus_width = RT_DMA_BUSWIDTH_4_BYTES;
- i2s->rx_dmac = rt_dma_get_channel(I2S_DMA_RX_CHAN);
- if(i2s->rx_dmac != RT_NULL)
- {
- config.direction = RT_DMA_DEV_TO_MEM;
- config.src_addr_width = bus_width;
- config.src_maxburst = (I2S_RFIFO_DEPTH * bus_width)/2;
- config.dst_addr_width = bus_width;
- config.dst_maxburst = (64 * 1024);
- rt_dma_configture(i2s->rx_dmac,&config);
- i2s->rx_dmac->start = RT_NULL;
- i2s->rx_dmac->complete = aic_i2s_trans_complete;
- I2S_DBG("RX DMA config ok \n");
- }
- __i2s_set_iss(aic, i2s->fmt_width);
- __i2s_set_receive_trigger(aic, (I2S_RFIFO_DEPTH/4 - 1));
- }
- return 0;
- }
- void aic_i2s_shutdown(struct jz_i2s *i2s,int stream)
- {
- struct jz_aic *aic = i2s->aic;
- aic_i2s_stop_substream(i2s,stream);
- if(stream == AUDIO_STREAM_REPLAY)
- i2s->i2s_mode &= ~I2S_WRITE;
- else
- i2s->i2s_mode &= ~I2S_READ;
- if(!i2s->i2s_mode)
- __aic_disable(aic);
- }
- int aic_i2s_set_sysclk(struct jz_i2s *i2s,uint32_t freq)
- {
- struct jz_aic *aic = i2s->aic;
- #ifdef RT_USING_ICODEC
- __aic_select_internal_codec(aic);
- #else
- __aic_select_external_codec(aic);
- #endif
- __i2s_stop_bitclk(aic);
- aic_set_rate(aic, freq);
- __i2s_start_bitclk(aic);
- #ifdef CFG_AIC_SOC_CLKOUT
- /* Master clk output */
- __i2s_select_sysclk_output(aic);
- __i2s_enable_sysclk_output(aic);
- #else
- /* Master clk input */
- __i2s_select_sysclk_input(aic);
- __i2s_disable_sysclk_output(aic);
- #endif
- return 0;
- }
- static void aic_i2s_trans_complete(struct rt_dma_channel *dmac, struct dma_message *msg)
- {
- I2S_DBG("TAG,%d,%s\n",__LINE__,__func__);
- if(msg->complete_cb)
- {
- if(msg->t_mode == JZDMA_REQ_I2S0_TX)
- msg->complete_cb(msg->complete_arg,msg->src_addr);
- else
- msg->complete_cb(msg->complete_arg,msg->dst_addr);
- }
- }
- rt_size_t aic_i2s_send(struct jz_i2s *i2s, const void* buffer, rt_size_t size,void (*tx_callback)(void *,void *), void *tx_arg)
- {
- struct dma_message message;
- I2S_DBG("TAG,%d,%s\n",__LINE__,__func__);
- message.src_addr = (uint8_t *) (buffer);
- message.src_option = RT_DMA_ADDR_INC;
- message.dst_addr = (uint8_t *) (AIC_BASE + AICDR);
- message.dst_option = RT_DMA_ADDR_FIX;
- message.t_size = size;
- message.t_mode = JZDMA_REQ_I2S0_TX;
- message.complete_cb = (void *)tx_callback;
- message.complete_arg= tx_arg;
- I2S_DBG("i2s trans length = %d\n",size);
- if (rt_dma_trans_message(i2s->tx_dmac, &message) == RT_EOK)
- return size;
- return 0;
- }
- rt_size_t aic_i2s_recv(struct jz_i2s *i2s, void* buffer, rt_size_t size,void (*rx_callback)(void *,void *), void *rx_arg)
- {
- struct dma_message message;
- message.src_addr = (uint8_t *) (AIC_BASE + AICDR);
- message.src_option = RT_DMA_ADDR_FIX;
- message.dst_addr = (uint8_t *) (buffer);
- message.dst_option = RT_DMA_ADDR_INC;
- message.t_size = size;
- message.t_mode = JZDMA_REQ_I2S0_RX;
- message.complete_cb = (void *)rx_callback;
- message.complete_arg= rx_arg;
- if(rt_dma_trans_message(i2s->rx_dmac,&message) == RT_EOK)
- return size;
- return 0;
- }
- struct jz_i2s *rt_hw_aic_i2s_init(void)
- {
- struct jz_aic *aic;
- struct jz_i2s *i2s = &_g_jz_i2s;
- #ifndef RT_USING_ICODEC
- #ifdef CFG_AIC_SOC_CLKOUT
- gpio_set_func(GPIO_PORT_B, GPIO_Pin_0, GPIO_FUNC_1); // I2S_MCLK
- #endif
- gpio_set_func(GPIO_PORT_B, GPIO_Pin_1, GPIO_FUNC_1); // I2S_BCLK
- gpio_set_func(GPIO_PORT_B, GPIO_Pin_2, GPIO_FUNC_1); // I2S_LRCLK
- gpio_set_func(GPIO_PORT_B, GPIO_Pin_3, GPIO_FUNC_1); // I2S_DI
- gpio_set_func(GPIO_PORT_B, GPIO_Pin_4, GPIO_FUNC_1); // I2S_DO
- #endif
- I2S_DBG("TAG,%d,%s\n",__LINE__,__func__);
- aic = _aic_init();
- if(aic == RT_NULL)
- return RT_NULL;
- i2s->aic = aic;
- i2s->i2s_mode = 0;
- I2S_DBG("TAG,%d,%s\n",__LINE__,__func__);
- /* now ,we just support I2S playback */
- aic_i2s_startup(i2s,AUDIO_STREAM_REPLAY);
- aic_i2s_hw_params(i2s,AUDIO_STREAM_REPLAY);
- return i2s;
- }
|