#include #include #include #include #include #include "typedef.h" #include "sys_config.h" #include "rtos_pub.h" #include "i2s_pub.h" #include "i2s.h" #include "drv_i2s.h" #include "general_dma_pub.h" #include "board.h" #if(CFG_USE_I2S == 1) #define I2S_RX_BUFFER_SIZE 2048 #define I2S_TX_BUFFER_SIZE 2048 #define I2S_RX_DMA_CHANNEL GDMA_CHANNEL_1 #define I2S_TX_DMA_CHANNEL GDMA_CHANNEL_3 #define I2S_TX_NODE_COUNT 12 #define I2S_SAMPLE_RATE (44100) #define I2S_BIT_LENGTH (32) #define PAUSE_EN 1 //#define I2S_RX_CALLBACK #if (CFG_SOC_NAME == SOC_BK7252N) #define FIFO_LEVEL_32 FIFO_LEVEL_24 #endif #define I2S_DEFAULT_MODE (I2S_MODE| I2S_LRCK_NO_TURN| I2S_SCK_NO_TURN| I2S_MSB_FIRST| (0< , read complete \n", __FUNCTION__, __LINE__); if (dev->tx_complete != RT_NULL) { dev->tx_complete(dev, node->data_ptr); } } static void i2s_dma_tx_pause_addr_set(UINT32 addr) { GDMA_CFG_ST en_cfg; memset(&en_cfg, 0, sizeof(GDMA_CFG_ST)); en_cfg.channel = I2S_TX_DMA_CHANNEL; en_cfg.param = addr; sddev_control(GDMA_DEV_NAME, CMD_GDMA_SET_SRC_PAUSE_ADDR, &en_cfg); } static void i2s_dma_rx_pause_addr_set(UINT32 addr) { GDMA_CFG_ST en_cfg; memset(&en_cfg, 0, sizeof(GDMA_CFG_ST)); en_cfg.channel = I2S_RX_DMA_CHANNEL; en_cfg.param = addr; sddev_control(GDMA_DEV_NAME, CMD_GDMA_SET_DST_PAUSE_ADDR, &en_cfg); } static void i2s_dma_master_enable(rt_uint32_t enable) { sddev_control(I2S_DEV_NAME, I2S_CMD_DMA_MASTER_ENABLE, (void *)&enable); } static void i2s_enable(rt_uint32_t enable) { if (enable) { sddev_control(I2S_DEV_NAME, I2S_CMD_UNIT_ENABLE, NULL); } else { sddev_control(I2S_DEV_NAME, I2S_CMD_DISABLE_I2S, NULL); } } static void i2s_dma_tx_enable(rt_uint32_t enable) { struct rt_i2s_bus_device *i2s = &g_i2s_bus; GDMA_CFG_ST en_cfg; i2s_trans_dbg("%s:%d tx_enabled=%d,enable=%d\r\n", __FUNCTION__, __LINE__, i2s->tx_enabled, enable); if ((i2s->tx_enabled && enable) || (!i2s->tx_enabled && !enable)) { i2s_trans_dbg("%s:%d already enable tx dma\r\n", __FUNCTION__, __LINE__); return; } en_cfg.channel = I2S_TX_DMA_CHANNEL; if (enable) en_cfg.param = 1; else en_cfg.param = 0; sddev_control(GDMA_DEV_NAME, CMD_GDMA_SET_DMA_ENABLE, &en_cfg); i2s->tx_enabled = enable ? 1 : 0; } static void i2s_dma_rx_enable(rt_uint32_t enable) { struct rt_i2s_bus_device *i2s = &g_i2s_bus; GDMA_CFG_ST en_cfg; i2s_trans_dbg("%s:%d rx_enabled=%d,enable=%d\r\n", __FUNCTION__, __LINE__, i2s->rx_enabled, enable); if ((i2s->rx_enabled && enable) || (!i2s->rx_enabled && !enable)) { i2s_trans_dbg("%s:%d already enable rx dma\r\n", __FUNCTION__, __LINE__); return; } en_cfg.channel = I2S_RX_DMA_CHANNEL; if (enable) en_cfg.param = 1; else en_cfg.param = 0; sddev_control(GDMA_DEV_NAME, CMD_GDMA_SET_DMA_ENABLE, &en_cfg); i2s->rx_enabled = enable ? 1 : 0; } void i2s_dma_tx_half_handler(UINT32 flag) { int result; struct rt_i2s_bus_device *i2s = &g_i2s_bus; rt_kprintf("%s:%d\r\n", __FUNCTION__, __LINE__); //rt_kprintf("%s:%d PCM_CTRL=0x%x,PCM_CN=0x%x,PCM_STAT=0x%x\r\n", __FUNCTION__, __LINE__, REG_READ(PCM_CTRL), REG_READ(PCM_CN), REG_READ(PCM_STAT)); result = rt_data_node_is_empty(i2s->tx_list); if (result) { #ifdef PAUSE_EN i2s_dma_tx_pause_addr_set((UINT32)i2s->tx_fifo + (I2S_TX_BUFFER_SIZE -4)); i2s->tx_paused = 1; //i2s_dma_master_enable(!i2s->tx_paused); i2s->tx_fill_pos = (UINT32)i2s->tx_fifo; i2s->tx_fill_size = I2S_TX_BUFFER_SIZE / 2; #endif memset(i2s->tx_fifo, 0, I2S_TX_BUFFER_SIZE / 2); } else { memset(i2s->tx_fifo, 0, I2S_TX_BUFFER_SIZE / 2); result = rt_data_node_read(i2s->tx_list, i2s->tx_fifo, I2S_TX_BUFFER_SIZE / 2); #ifdef PAUSE_EN if (result < (I2S_TX_BUFFER_SIZE / 2)) { i2s_dma_tx_pause_addr_set((UINT32)i2s->tx_fifo + (I2S_TX_BUFFER_SIZE -4)); i2s->tx_paused = 1; //i2s_dma_master_enable(!i2s->tx_paused); i2s->tx_fill_pos = (UINT32)i2s->tx_fifo + result; i2s->tx_fill_size = I2S_TX_BUFFER_SIZE / 2 - result; } #endif } } void i2s_dma_tx_finish_handler(UINT32 flag) { int result; struct rt_i2s_bus_device *i2s = &g_i2s_bus; rt_kprintf("%s:%d\r\n", __FUNCTION__, __LINE__); //rt_kprintf("%s:%d PCM_CTRL=0x%x,PCM_CN=0x%x,PCM_STAT=0x%x\r\n", __FUNCTION__, __LINE__, REG_READ(PCM_CTRL), REG_READ(PCM_CN), REG_READ(PCM_STAT)); i2s->tx_dma_irq_cnt ++; result = rt_data_node_is_empty(i2s->tx_list); if (result) { #ifdef PAUSE_EN i2s_dma_tx_pause_addr_set((UINT32)i2s->tx_fifo + (I2S_TX_BUFFER_SIZE / 2 -4)); i2s->tx_paused = 1; //i2s_dma_master_enable(!i2s->tx_paused); i2s->tx_fill_pos = (UINT32)i2s->tx_fifo + I2S_TX_BUFFER_SIZE / 2; i2s->tx_fill_size = I2S_TX_BUFFER_SIZE / 2; #endif //rt_kprintf("* "); memset(i2s->tx_fifo + (I2S_TX_BUFFER_SIZE / 2), 0, I2S_TX_BUFFER_SIZE / 2); } else { memset(i2s->tx_fifo + (I2S_TX_BUFFER_SIZE / 2), 0, I2S_TX_BUFFER_SIZE / 2); result = rt_data_node_read(i2s->tx_list, i2s->tx_fifo + (I2S_TX_BUFFER_SIZE / 2), I2S_TX_BUFFER_SIZE / 2); #ifdef PAUSE_EN if (result < (I2S_TX_BUFFER_SIZE / 2)) { i2s_dma_tx_pause_addr_set((UINT32)i2s->tx_fifo + (I2S_TX_BUFFER_SIZE / 2 -4)); i2s->tx_paused = 1; //i2s_dma_master_enable(!i2s->tx_paused); i2s->tx_fill_pos = (UINT32)i2s->tx_fifo + I2S_TX_BUFFER_SIZE / 2 + result; i2s->tx_fill_size = I2S_TX_BUFFER_SIZE / 2 - result; } #endif } } int i2s_dma_tx_init(struct rt_i2s_bus_device *i2s) { GDMACFG_TPYES_ST init_cfg; GDMA_CFG_ST en_cfg; memset(&init_cfg, 0, sizeof(GDMACFG_TPYES_ST)); memset(&en_cfg, 0, sizeof(GDMA_CFG_ST)); init_cfg.dstdat_width = i2s->bits_length; init_cfg.srcdat_width = 32; init_cfg.dstptr_incr = 0; init_cfg.srcptr_incr = 1; init_cfg.src_start_addr = i2s->tx_fifo; init_cfg.dst_start_addr = (void *)PCM_DAT0; init_cfg.channel = I2S_TX_DMA_CHANNEL; init_cfg.prio = 0; init_cfg.u.type4.src_loop_start_addr = i2s->tx_fifo; init_cfg.u.type4.src_loop_end_addr = i2s->tx_fifo + I2S_TX_BUFFER_SIZE; init_cfg.half_fin_handler = i2s_dma_tx_half_handler; init_cfg.fin_handler = i2s_dma_tx_finish_handler; init_cfg.src_module = GDMA_X_SRC_DTCM_RD_REQ; init_cfg.dst_module = GDMA_X_DST_I2S_TX_REQ; sddev_control(GDMA_DEV_NAME, CMD_GDMA_CFG_TYPE4, (void *)&init_cfg); en_cfg.channel = I2S_TX_DMA_CHANNEL; en_cfg.param = I2S_TX_BUFFER_SIZE; // dma translen sddev_control(GDMA_DEV_NAME, CMD_GDMA_SET_TRANS_LENGTH, (void *)&en_cfg); return 0; } #if defined(I2S_RX_CALLBACK) void i2s_dma_rx_half_handler(UINT32 flag) { int result; struct rt_i2s_bus_device *i2s = &g_i2s_bus; rt_kprintf("%s:%d\r\n", __FUNCTION__, __LINE__); //rt_kprintf("%s:%d PCM_CTRL=0x%x,PCM_CN=0x%x,PCM_STAT=0x%x\r\n", __FUNCTION__, __LINE__, REG_READ(PCM_CTRL), REG_READ(PCM_CN), REG_READ(PCM_STAT)); #ifdef PAUSE_EN //i2s_dma_rx_pause_addr_set((UINT32)i2s->rx_fifo + (I2S_RX_BUFFER_SIZE -4)); #endif int index; int *ptr = (int *)i2s->rx_fifo; for (index = 0; index < I2S_RX_BUFFER_SIZE / 8; index++, ptr++) { if (*ptr != 0) { rt_kprintf("rx[%d]=0x%x\r\n", index, *ptr); } } } void i2s_dma_rx_finish_handler(UINT32 flag) { int result; struct rt_i2s_bus_device *i2s = &g_i2s_bus; rt_kprintf("%s:%d\r\n", __FUNCTION__, __LINE__); //rt_kprintf("%s:%d PCM_CTRL=0x%x,PCM_CN=0x%x,PCM_STAT=0x%x\r\n", __FUNCTION__, __LINE__, REG_READ(PCM_CTRL), REG_READ(PCM_CN), REG_READ(PCM_STAT)); #ifdef PAUSE_EN //i2s_dma_rx_pause_addr_set((UINT32)i2s->rx_fifo + (I2S_RX_BUFFER_SIZE / 2 -4)); #endif int index; int *ptr = (int *)i2s->rx_fifo + I2S_RX_BUFFER_SIZE / 8; for (index = I2S_RX_BUFFER_SIZE / 8; index < I2S_RX_BUFFER_SIZE / 4; index++, ptr++) { if (*ptr != 0) { rt_kprintf("rx[%d]=0x%x\r\n", index, *ptr); } } } #endif int i2s_dma_rx_init(struct rt_i2s_bus_device *i2s) { GDMACFG_TPYES_ST init_cfg; GDMA_CFG_ST en_cfg; memset(&init_cfg, 0, sizeof(GDMACFG_TPYES_ST)); memset(&en_cfg, 0, sizeof(GDMA_CFG_ST)); init_cfg.dstdat_width = 32; init_cfg.srcdat_width = i2s->bits_length; init_cfg.dstptr_incr = 1; init_cfg.srcptr_incr = 0; init_cfg.src_start_addr = (void *)PCM_DAT0; init_cfg.dst_start_addr = i2s->rx_fifo; init_cfg.channel = I2S_RX_DMA_CHANNEL; init_cfg.prio = 0; init_cfg.u.type5.dst_loop_start_addr = i2s->rx_fifo; init_cfg.u.type5.dst_loop_end_addr = i2s->rx_fifo + I2S_RX_BUFFER_SIZE; #if defined(I2S_RX_CALLBACK) init_cfg.half_fin_handler = i2s_dma_rx_half_handler; init_cfg.fin_handler = i2s_dma_rx_finish_handler; #endif init_cfg.src_module = GDMA_X_SRC_I2S_RX_REQ; init_cfg.dst_module = GDMA_X_DST_DTCM_WR_REQ; sddev_control(GDMA_DEV_NAME, CMD_GDMA_CFG_TYPE5, (void *)&init_cfg); en_cfg.channel = I2S_RX_DMA_CHANNEL; en_cfg.param = I2S_RX_BUFFER_SIZE; // dma translen sddev_control(GDMA_DEV_NAME, CMD_GDMA_SET_TRANS_LENGTH, (void *)&en_cfg); #if !defined(I2S_RX_CALLBACK) rb_init_dma_write(&i2s->rb_dma_wr, (UINT8*)i2s->rx_fifo, I2S_RX_BUFFER_SIZE, I2S_RX_DMA_CHANNEL); #endif return 0; } static rt_err_t rt_i2s_init(rt_device_t dev) { rt_kprintf("%s:%d\r\n", __FUNCTION__, __LINE__); i2s_init(0); return RT_EOK; } static rt_err_t rt_i2s_open(rt_device_t dev, rt_uint16_t oflag) { struct rt_i2s_bus_device *i2s = (struct rt_i2s_bus_device *)dev; /* open audio , set fifo level set sample rate/datawidth */ if (!oflag) { return -RT_EINVAL; } if (!i2s->open_flag) { i2s->open_flag = oflag; i2s->tx_dma_irq_cnt = 0; #if 1 i2s->tx_paused = 1; i2s->tx_fill_pos = (UINT32)i2s->tx_fifo; i2s->tx_fill_size = I2S_TX_BUFFER_SIZE / 2; #endif i2s->sample_rate = I2S_SAMPLE_RATE; i2s->bits_length = I2S_BIT_LENGTH; //sddev_control(I2S_DEV_NAME, I2S_CMD_DMA_ISR, (void *)i2s_dma_mode_isr); /* rate=8/16/44.4/48 * 1000 bitlength=8/16/24/32 */ i2s_configure(FIFO_LEVEL_32, i2s->sample_rate, i2s->bits_length, I2S_DEFAULT_MODE); if (oflag & RT_DEVICE_OFLAG_RDONLY) { rt_kprintf("%s:%d read with DMA\r\n", __FUNCTION__, __LINE__); i2s_dma_rx_init(i2s); i2s_dma_rx_pause_addr_set(0); } if (oflag & RT_DEVICE_OFLAG_WRONLY) { rt_kprintf("%s:%d write with DMA\r\n", __FUNCTION__, __LINE__); i2s_dma_tx_init(i2s); i2s_dma_tx_pause_addr_set((UINT32)i2s->tx_fifo); } i2s_trans_dbg("[i2s]:open device\r\n"); } return RT_EOK; } static rt_err_t rt_i2s_close(rt_device_t dev) { struct rt_i2s_bus_device *i2s = (struct rt_i2s_bus_device *)dev; if (i2s->open_flag) { // wait_node_free(i2s->tx_list); rt_data_node_empty(i2s->tx_list); i2s_dma_rx_enable(0); i2s_dma_tx_enable(0); //i2s_dma_enable(0); i2s->open_flag = 0; i2s->tx_paused = 0; i2s_enable(0); } i2s_trans_dbg("[i2s]:close device\r\n"); return RT_EOK; } static rt_size_t rt_i2s_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) { struct rt_i2s_bus_device *i2s = (struct rt_i2s_bus_device *)dev; int fill_size; if (!(i2s->open_flag & RT_DEVICE_OFLAG_RDONLY)) { return 0; } #if !defined(I2S_RX_CALLBACK) #if CFG_GENERAL_DMA fill_size = rb_get_fill_size_dma_write(&i2s->rb_dma_wr); if(fill_size > size) fill_size = size; rb_read_dma_write(&i2s->rb_dma_wr, (UINT8 *)buffer + pos, fill_size, 1); #endif #endif return fill_size; } static rt_size_t rt_i2s_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size ) { int ret; struct rt_i2s_bus_device *i2s = (struct rt_i2s_bus_device *)dev; rt_uint32_t result; if (!(i2s->open_flag & RT_DEVICE_OFLAG_WRONLY)) { return 0; } rt_kprintf("%s:%d size=%d\r\n", __FUNCTION__, __LINE__, size); ret = rt_data_node_write(i2s->tx_list, (void *)((UINT8 *)buffer + pos), size); #ifdef PAUSE_EN if (i2s->tx_paused) { result = rt_data_node_read(i2s->tx_list, (void*)i2s->tx_fill_pos, i2s->tx_fill_size); rt_kprintf("%s:%d result=%d,fill_size=%d\r\n", __FUNCTION__, __LINE__, result, i2s->tx_fill_size); if (result == i2s->tx_fill_size) { i2s->tx_paused = 0; //i2s_dma_master_enable(1); i2s_dma_tx_pause_addr_set(0); } else { i2s->tx_fill_pos += result; i2s->tx_fill_size -= result; } } #endif return ret; } static rt_err_t rt_i2s_cotrol(rt_device_t dev, int cmd, void *args) { struct rt_i2s_bus_device *i2s = (struct rt_i2s_bus_device *)dev; switch (cmd) { case RT_DEVICE_CTRL_I2S_DMA_RX_ENABLE: i2s_dma_rx_enable(*(rt_int32_t *)args); break; case RT_DEVICE_CTRL_I2S_DMA_TX_ENABLE: i2s_dma_tx_enable(*(rt_int32_t *)args); break; case RT_DEVICE_CTRL_I2S_DMA_MASTER_ENABLE: i2s_dma_master_enable(*(rt_int32_t *)args); break; case RT_DEVICE_CTRL_I2S_SAMPLE_RATE_SET: if (i2s->sample_rate != *(rt_int32_t *)args) { i2s->sample_rate = *(rt_int32_t *)args; i2s_configure(FIFO_LEVEL_32, i2s->sample_rate, i2s->bits_length, I2S_DEFAULT_MODE); } break; case RT_DEVICE_CTRL_I2S_BIT_LENGTH_SET: if (i2s->bits_length != *(rt_int32_t *)args) { i2s->bits_length = *(rt_int32_t *)args; i2s_configure(FIFO_LEVEL_32, i2s->sample_rate, i2s->bits_length, I2S_DEFAULT_MODE); if (i2s->open_flag & RT_DEVICE_OFLAG_RDONLY) { i2s_dma_rx_init(i2s); i2s_dma_rx_pause_addr_set(0); } if (i2s->open_flag & RT_DEVICE_OFLAG_WRONLY) { i2s_dma_tx_init(i2s); i2s_dma_tx_pause_addr_set((UINT32)i2s->tx_fifo); } } break; } return RT_ERROR; } #ifdef RT_USING_DEVICE_OPS static const struct rt_device_ops i2s_ops = { rt_i2s_init, rt_i2s_open, rt_i2s_close, rt_i2s_read, rt_i2s_write, rt_i2s_cotrol }; #endif /* RT_USING_DEVICE_OPS */ int rt_i2s_hw_init(void) { struct rt_i2s_bus_device *i2s = &g_i2s_bus; struct rt_device *device = &i2s->parent; /* set device type */ device->type = RT_Device_Class_I2SBUS; device->rx_indicate = RT_NULL; device->tx_complete = RT_NULL; device->user_data = RT_NULL; #ifdef RT_USING_DEVICE_OPS device->ops = &i2s_ops; #else device->control = rt_i2s_cotrol; device->init = rt_i2s_init; device->open = rt_i2s_open; device->close = rt_i2s_close; device->read = rt_i2s_read; device->write = rt_i2s_write; #endif /* RT_USING_DEVICE_OPS */ i2s->tx_fifo = (char *)sdram_malloc(I2S_TX_BUFFER_SIZE); if (i2s->tx_fifo == RT_NULL) { rt_kprintf("%s:%d malloc tx_fifo failed\r\n", __FUNCTION__, __LINE__); return -RT_ENOMEM; } memset(i2s->tx_fifo, 0, I2S_TX_BUFFER_SIZE); #if 1 i2s->rx_fifo = (char *)sdram_malloc(I2S_RX_BUFFER_SIZE); if (i2s->rx_fifo == RT_NULL) { rt_kprintf("%s:%d malloc rx_fifo failed\r\n", __FUNCTION__, __LINE__); free(i2s->tx_fifo); return -RT_ENOMEM; } memset(i2s->rx_fifo, 0, I2S_RX_BUFFER_SIZE); #endif rt_data_node_init(&i2s->tx_list, I2S_TX_NODE_COUNT); i2s->tx_list->read_complete = i2s_tx_node_read_complete; i2s->tx_list->user_data = i2s; /* register to device manager */ rt_device_register(device, I2S_DEV_NAME, RT_DEVICE_FLAG_RDWR); rt_kprintf("---i2s register over---\r\n"); return RT_EOK; } INIT_DEVICE_EXPORT(rt_i2s_hw_init); #endif