703 lines
22 KiB
C
703 lines
22 KiB
C
/* Copyright 2018 Canaan Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include "i2s.h"
|
|
#include "sysctl.h"
|
|
#include "stdlib.h"
|
|
|
|
volatile struct i2s_t *const i2s[3] =
|
|
{
|
|
(volatile struct i2s_t *)I2S0_BASE_ADDR,
|
|
(volatile struct i2s_t *)I2S1_BASE_ADDR,
|
|
(volatile struct i2s_t *)I2S2_BASE_ADDR
|
|
};
|
|
|
|
void i2s_init(enum i2s_device_num_t device_num, enum i2s_transmit_t rxtx_mode, uint32_t channel_mask)
|
|
{
|
|
sysctl_clock_enable(SYSCTL_CLOCK_I2S0 + device_num);
|
|
sysctl_reset(SYSCTL_RESET_I2S0 + device_num);
|
|
sysctl_clock_set_threshold(SYSCTL_THRESHOLD_I2S0 + device_num, 7);
|
|
/*96k:5,44k:12,24k:23,22k:25 16k:35 sampling*/
|
|
/*sample rate*32bit*2 =75MHz/((N+1)*2) */
|
|
i2s_device_enable(device_num);
|
|
i2s_disable_block(device_num, TRANSMITTER);
|
|
i2s_disable_block(device_num, RECEIVER);
|
|
|
|
if (rxtx_mode == TRANSMITTER)
|
|
{
|
|
for (int i=0; i<4; i++)
|
|
{
|
|
if ((channel_mask & 0x3) == 0x3)
|
|
{
|
|
i2s_set_mask_interrupt(device_num, CHANNEL_0 + i, 1, 1, 1, 1);
|
|
i2s_transimit_enable(device_num, CHANNEL_0 + i);
|
|
}
|
|
else
|
|
{
|
|
i2s_transmit_channel_enable(device_num, CHANNEL_0 + i, 0);
|
|
}
|
|
channel_mask >>= 2;
|
|
}
|
|
i2s_transmit_dma_enable(device_num, 1);
|
|
}
|
|
else
|
|
{
|
|
for (int i=0; i<4; i++)
|
|
{
|
|
if ((channel_mask & 0x3) == 0x3)
|
|
{
|
|
i2s_set_mask_interrupt(device_num, CHANNEL_0 + i, 1, 1, 1, 1);
|
|
i2s_receive_enable(device_num, CHANNEL_0 + i);
|
|
}
|
|
else
|
|
{
|
|
i2s_receive_channel_enable(device_num, CHANNEL_0 + i, 0);
|
|
}
|
|
channel_mask >>= 2;
|
|
}
|
|
i2s_receive_dma_enable(device_num, 1);
|
|
}
|
|
}
|
|
|
|
void i2s_device_enable(enum i2s_device_num_t device_num)
|
|
{
|
|
union ier_u u_ier;
|
|
|
|
u_ier.reg_data = readl(&i2s[device_num]->ier);
|
|
u_ier.ier.ien = 1;
|
|
writel(u_ier.reg_data, &i2s[device_num]->ier);
|
|
}
|
|
|
|
void i2s_dev_enable(enum i2s_device_num_t device_num, uint32_t enable)
|
|
{
|
|
union ier_u u_ier;
|
|
|
|
u_ier.reg_data = readl(&i2s[device_num]->ier);
|
|
u_ier.ier.ien = enable;
|
|
writel(u_ier.reg_data, &i2s[device_num]->ier);
|
|
}
|
|
|
|
void i2s_disable_block(enum i2s_device_num_t device_num, enum i2s_transmit_t rxtx_mode)
|
|
{
|
|
union irer_u u_irer;
|
|
union iter_u u_iter;
|
|
|
|
if (rxtx_mode == RECEIVER)
|
|
{
|
|
u_irer.reg_data = readl(&i2s[device_num]->irer);
|
|
u_irer.irer.rxen = 0;
|
|
writel(u_irer.reg_data, &i2s[device_num]->irer);
|
|
/* Receiver block disable */
|
|
}
|
|
else
|
|
{
|
|
u_iter.reg_data = readl(&i2s[device_num]->iter);
|
|
u_iter.iter.txen = 0;
|
|
writel(u_iter.reg_data, &i2s[device_num]->iter);
|
|
/* Transmitter block disable */
|
|
}
|
|
}
|
|
|
|
void i2s_receive_enable(enum i2s_device_num_t device_num, enum i2s_channel_num_t channel_num)
|
|
{
|
|
union irer_u u_irer;
|
|
|
|
u_irer.reg_data = readl(&i2s[device_num]->irer);
|
|
u_irer.irer.rxen = 1;
|
|
writel(u_irer.reg_data, &i2s[device_num]->irer);
|
|
/* Receiver block enable */
|
|
|
|
i2s_receive_channel_enable(device_num, channel_num, 1);
|
|
/* Receive channel enable */
|
|
}
|
|
|
|
void i2s_transimit_enable(enum i2s_device_num_t device_num, enum i2s_channel_num_t channel_num)
|
|
{
|
|
union iter_u u_iter;
|
|
|
|
u_iter.reg_data = readl(&i2s[device_num]->iter);
|
|
u_iter.iter.txen = 1;
|
|
writel(u_iter.reg_data, &i2s[device_num]->iter);
|
|
/* Transmitter block enable */
|
|
|
|
i2s_transmit_channel_enable(device_num, channel_num, 1);
|
|
/* Transmit channel enable */
|
|
}
|
|
|
|
void i2s_rx_channel_configure(enum i2s_device_num_t device_num,
|
|
enum i2s_channel_num_t channel_num,
|
|
enum word_length_t word_length,
|
|
enum word_select_cycles_t word_select_size,
|
|
enum fifo_threshold_t trigger_level,
|
|
enum i2s_work_mode_t word_mode)
|
|
{
|
|
i2s_receive_channel_enable(device_num, channel_num, 0);
|
|
/* Receive channel disable */
|
|
|
|
writel(0, &i2s[device_num]->channel[channel_num].ter);
|
|
/* disable tx */
|
|
|
|
writel(1, &i2s[device_num]->channel[channel_num].rff);
|
|
/* flash individual fifo */
|
|
|
|
writel(1, &i2s[device_num]->rxffr);
|
|
/* flush tx fifo*/
|
|
|
|
i2s_set_rx_word_length(device_num, word_length, channel_num);
|
|
/* Word length is RESOLUTION_32_BIT */
|
|
|
|
i2s_master_configure(device_num,
|
|
word_select_size, NO_CLOCK_GATING, word_mode);
|
|
/* word select size is 32 bits,no clock gating */
|
|
|
|
i2s_set_rx_threshold(device_num, trigger_level, channel_num);
|
|
/* Interrupt trigger when FIFO level is 8 */
|
|
|
|
readl(&i2s[device_num]->channel[channel_num].ror);
|
|
readl(&i2s[device_num]->channel[channel_num].tor);
|
|
|
|
i2s_receive_channel_enable(device_num, channel_num, 1);
|
|
}
|
|
|
|
void i2s_tx_channel_configure(enum i2s_device_num_t device_num,
|
|
enum i2s_channel_num_t channel_num,
|
|
enum word_length_t word_length,
|
|
enum word_select_cycles_t word_select_size,
|
|
enum fifo_threshold_t trigger_level,
|
|
enum i2s_work_mode_t word_mode)
|
|
{
|
|
writel(0, &i2s[device_num]->channel[channel_num].rer);
|
|
/* disable rx */
|
|
|
|
i2s_transmit_channel_enable(device_num, channel_num, 0);
|
|
/* Transmit channel disable */
|
|
|
|
writel(1, &i2s[device_num]->txffr);
|
|
/* flush tx fifo */
|
|
writel(1, &i2s[device_num]->channel[channel_num].tff);
|
|
/* flush individual fifo */
|
|
|
|
if (word_length == RESOLUTION_16_BIT)
|
|
{
|
|
i2s_transmit_dma_divide(I2S_DEVICE_0, 1);
|
|
}
|
|
i2s_set_tx_word_length(device_num, word_length, channel_num);
|
|
/* Word length is RESOLUTION_16_BIT */
|
|
|
|
i2s_master_configure(device_num, word_select_size, NO_CLOCK_GATING, word_mode);
|
|
/* word select size is 16 bits,gating after 16 bit */
|
|
|
|
i2s_set_tx_threshold(device_num, trigger_level, channel_num);
|
|
/* Interrupt trigger when FIFO level is 8 */
|
|
|
|
i2s_transmit_channel_enable(device_num, channel_num, 1);
|
|
}
|
|
|
|
int i2s_set_rx_word_length(enum i2s_device_num_t device_num,
|
|
enum word_length_t word_length,
|
|
enum i2s_channel_num_t channel_num)
|
|
{
|
|
union rcr_tcr_u u_rcr;
|
|
|
|
if (word_length > RESOLUTION_32_BIT || word_length < IGNORE_WORD_LENGTH)
|
|
return -1;
|
|
if (channel_num < CHANNEL_0 || channel_num > CHANNEL_3)
|
|
return -1;
|
|
|
|
u_rcr.reg_data = readl(&i2s[device_num]->channel[channel_num].rcr);
|
|
u_rcr.rcr_tcr.wlen = word_length;
|
|
writel(u_rcr.reg_data, &i2s[device_num]->channel[channel_num].rcr);
|
|
return 0;
|
|
}
|
|
|
|
int i2s_set_tx_word_length(enum i2s_device_num_t device_num,
|
|
enum word_length_t word_length,
|
|
enum i2s_channel_num_t channel_num)
|
|
{
|
|
union rcr_tcr_u u_tcr;
|
|
|
|
if (word_length > RESOLUTION_32_BIT || word_length < IGNORE_WORD_LENGTH)
|
|
return -1;
|
|
if (channel_num < CHANNEL_0 || channel_num > CHANNEL_3)
|
|
return -1;
|
|
|
|
u_tcr.reg_data = readl(&i2s[device_num]->channel[channel_num].tcr);
|
|
u_tcr.rcr_tcr.wlen = word_length;
|
|
writel(u_tcr.reg_data, &i2s[device_num]->channel[channel_num].tcr);
|
|
return 0;
|
|
}
|
|
|
|
int i2s_master_configure(enum i2s_device_num_t device_num,
|
|
enum word_select_cycles_t word_select_size,
|
|
enum sclk_gating_cycles_t gating_cycles,
|
|
enum i2s_work_mode_t word_mode)
|
|
{
|
|
union ccr_u u_ccr;
|
|
union cer_u u_cer;
|
|
|
|
if (word_select_size < SCLK_CYCLES_16 ||
|
|
word_select_size > SCLK_CYCLES_32)
|
|
return -1;
|
|
if (gating_cycles < NO_CLOCK_GATING ||
|
|
gating_cycles > CLOCK_CYCLES_24)
|
|
return -1;
|
|
|
|
u_ccr.reg_data = readl(&i2s[device_num]->ccr);
|
|
u_ccr.ccr.clk_word_size = word_select_size;
|
|
u_ccr.ccr.clk_gate = gating_cycles;
|
|
u_ccr.ccr.align_mode = word_mode;
|
|
writel(u_ccr.reg_data, &i2s[device_num]->ccr);
|
|
|
|
u_cer.reg_data = readl(&i2s[device_num]->cer);
|
|
u_cer.cer.clken = 1;
|
|
writel(u_cer.reg_data, &i2s[device_num]->cer);
|
|
/* Clock generation enable */
|
|
|
|
return 0;
|
|
}
|
|
|
|
int i2s_set_rx_threshold(enum i2s_device_num_t device_num,
|
|
enum fifo_threshold_t threshold,
|
|
enum i2s_channel_num_t channel_num)
|
|
{
|
|
union rfcr_u u_rfcr;
|
|
|
|
if (threshold < TRIGGER_LEVEL_1 || threshold > TRIGGER_LEVEL_16)
|
|
return -1;
|
|
if (channel_num < CHANNEL_0 || channel_num > CHANNEL_3)
|
|
return -1;
|
|
|
|
u_rfcr.reg_data = readl(&i2s[device_num]->channel[channel_num].rfcr);
|
|
u_rfcr.rfcr.rxchdt = threshold;
|
|
writel(u_rfcr.reg_data, &i2s[device_num]->channel[channel_num].rfcr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int i2s_set_tx_threshold(enum i2s_device_num_t device_num,
|
|
enum fifo_threshold_t threshold,
|
|
enum i2s_channel_num_t channel_num)
|
|
{
|
|
union tfcr_u u_tfcr;
|
|
|
|
if (threshold < TRIGGER_LEVEL_1 || threshold > TRIGGER_LEVEL_16)
|
|
return -1;
|
|
if (channel_num < CHANNEL_0 || channel_num > CHANNEL_3)
|
|
return -1;
|
|
|
|
u_tfcr.reg_data = readl(&i2s[device_num]->channel[channel_num].tfcr);
|
|
u_tfcr.tfcr.txchet = threshold;
|
|
writel(u_tfcr.reg_data, &i2s[device_num]->channel[channel_num].tfcr);
|
|
return 0;
|
|
}
|
|
|
|
int i2s_set_mask_interrupt(enum i2s_device_num_t device_num,
|
|
enum i2s_channel_num_t channel_num,
|
|
uint32_t rx_available_int, uint32_t rx_overrun_int,
|
|
uint32_t tx_empty_int, uint32_t tx_overrun_int)
|
|
{
|
|
union imr_u u_imr;
|
|
|
|
if (channel_num < CHANNEL_0 || channel_num > CHANNEL_3)
|
|
return -1;
|
|
u_imr.reg_data = readl(&i2s[device_num]->channel[channel_num].imr);
|
|
|
|
if (rx_available_int == 1)
|
|
u_imr.imr.rxdam = 1;
|
|
else
|
|
u_imr.imr.rxdam = 0;
|
|
if (rx_overrun_int == 1)
|
|
u_imr.imr.rxfom = 1;
|
|
else
|
|
u_imr.imr.rxfom = 0;
|
|
|
|
if (tx_empty_int == 1)
|
|
u_imr.imr.txfem = 1;
|
|
else
|
|
u_imr.imr.txfem = 0;
|
|
if (tx_overrun_int == 1)
|
|
u_imr.imr.txfom = 1;
|
|
else
|
|
u_imr.imr.txfom = 0;
|
|
writel(u_imr.reg_data, &i2s[device_num]->channel[channel_num].imr);
|
|
return 0;
|
|
}
|
|
|
|
int i2s_receive_channel_enable(enum i2s_device_num_t device_num,
|
|
enum i2s_channel_num_t channel_num, uint32_t enable)
|
|
{
|
|
union rer_u u_rer;
|
|
|
|
if (channel_num < CHANNEL_0 || channel_num > CHANNEL_3)
|
|
return -1;
|
|
u_rer.reg_data = readl(&i2s[device_num]->channel[channel_num].rer);
|
|
u_rer.rer.rxchenx = enable;
|
|
writel(u_rer.reg_data, &i2s[device_num]->channel[channel_num].rer);
|
|
return 0;
|
|
}
|
|
|
|
int i2s_transmit_channel_enable(enum i2s_device_num_t device_num,
|
|
enum i2s_channel_num_t channel_num, uint32_t enable)
|
|
{
|
|
union ter_u u_ter;
|
|
|
|
if (channel_num < CHANNEL_0 || channel_num > CHANNEL_3)
|
|
return -1;
|
|
|
|
u_ter.reg_data = readl(&i2s[device_num]->channel[channel_num].ter);
|
|
u_ter.ter.txchenx = enable;
|
|
writel(u_ter.reg_data, &i2s[device_num]->channel[channel_num].ter);
|
|
return 0;
|
|
}
|
|
|
|
int i2s_transmit_dma_enable(enum i2s_device_num_t device_num, uint32_t enable)
|
|
{
|
|
union ccr_u u_ccr;
|
|
|
|
if (device_num >= I2S_DEVICE_MAX)
|
|
return -1;
|
|
|
|
u_ccr.reg_data = readl(&i2s[device_num]->ccr);
|
|
u_ccr.ccr.dma_tx_en = enable;
|
|
writel(u_ccr.reg_data, &i2s[device_num]->ccr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int i2s_receive_dma_enable(enum i2s_device_num_t device_num, uint32_t enable)
|
|
{
|
|
union ccr_u u_ccr;
|
|
|
|
if (device_num >= I2S_DEVICE_MAX)
|
|
return -1;
|
|
|
|
u_ccr.reg_data = readl(&i2s[device_num]->ccr);
|
|
u_ccr.ccr.dma_rx_en = enable;
|
|
writel(u_ccr.reg_data, &i2s[device_num]->ccr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int i2s_transmit_dma_divide(enum i2s_device_num_t device_num, uint32_t enable)
|
|
{
|
|
union ccr_u u_ccr;
|
|
|
|
if (device_num >= I2S_DEVICE_MAX)
|
|
return -1;
|
|
|
|
u_ccr.reg_data = readl(&i2s[device_num]->ccr);
|
|
u_ccr.ccr.dma_divide_16 = enable;
|
|
writel(u_ccr.reg_data, &i2s[device_num]->ccr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t i2s_receive_data(enum i2s_device_num_t device_num,
|
|
enum i2s_channel_num_t channel_num, uint64_t *buf,
|
|
uint32_t length)
|
|
{
|
|
uint32_t i = 0;
|
|
union isr_u u_isr;
|
|
|
|
readl(&i2s[device_num]->channel[channel_num].ror);
|
|
/*clear over run*/
|
|
|
|
for (i = 0; i < length;)
|
|
{
|
|
u_isr.reg_data = readl(&i2s[device_num]->channel[channel_num].isr);
|
|
if (u_isr.isr.rxda == 1)
|
|
{
|
|
buf[i] = readl(&i2s[device_num]->channel[channel_num].left_rxtx);
|
|
buf[i] <<= 32;
|
|
buf[i++] |= readl(&i2s[device_num]->channel[channel_num].right_rxtx);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int32_t i2s_receive_data_dma(enum i2s_device_num_t device_num, uint32_t *buf,
|
|
uint32_t length, dmac_channel_number channel_num)
|
|
{
|
|
sysctl_dma_select(channel_num, SYSCTL_DMA_SELECT_I2S0_RX_REQ + device_num * 2);
|
|
dmac_set_single_mode(channel_num, (void *)(&i2s[device_num]->rxdma), /*pcm*/buf, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT,
|
|
DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, length);
|
|
dmac_wait_done(channel_num);
|
|
return 0;
|
|
}
|
|
|
|
int32_t i2s_recv_dma(enum i2s_device_num_t device_num, uint32_t *buf,
|
|
uint32_t length, dmac_channel_number channel_num)
|
|
{
|
|
static uint8_t dmac_recv_flag[6] = {0,0,0,0,0,0};
|
|
if(dmac_recv_flag[channel_num])
|
|
dmac_wait_done(channel_num);
|
|
else
|
|
dmac_recv_flag[channel_num] = 1;
|
|
sysctl_dma_select(channel_num, SYSCTL_DMA_SELECT_I2S0_RX_REQ + device_num * 2);
|
|
dmac_set_single_mode(channel_num, (void *)(&i2s[device_num]->rxdma), /*pcm*/buf, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT,
|
|
DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, length);
|
|
return 0;
|
|
}
|
|
|
|
int32_t i2s_special_dma(enum i2s_device_num_t device_src_num, enum i2s_device_num_t device_dest_num,
|
|
uint32_t length, dmac_channel_number channel_num)
|
|
{
|
|
static uint8_t dmac_recv_flag[6] = {0,0,0,0,0,0};
|
|
if(dmac_recv_flag[channel_num])
|
|
dmac_wait_done(channel_num);
|
|
else
|
|
dmac_recv_flag[channel_num] = 1;
|
|
sysctl_dma_select(channel_num, SYSCTL_DMA_SELECT_I2S0_RX_REQ + device_src_num * 2);
|
|
dmac_set_single_mode(channel_num, (void *)(&i2s[device_src_num]->rxdma), (void *)(&i2s[device_dest_num]->txdma), DMAC_ADDR_NOCHANGE, DMAC_ADDR_NOCHANGE,
|
|
DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, length);
|
|
return 0;
|
|
}
|
|
|
|
int i2s_transmit_data(enum i2s_device_num_t device_num,
|
|
enum i2s_channel_num_t channel_num, uint8_t *pcm, uint32_t length, uint8_t single_length)
|
|
{
|
|
union isr_u u_isr;
|
|
uint32_t left_buffer = 0;
|
|
uint32_t right_buffer = 0;
|
|
uint32_t i = 0;
|
|
uint32_t j = 0;
|
|
if (channel_num < CHANNEL_0 || channel_num > CHANNEL_3)
|
|
return -1;
|
|
|
|
length = length / (single_length / 8) / 2; /* sample num */
|
|
readl(&i2s[device_num]->channel[channel_num].tor);
|
|
/* read clear overrun flag */
|
|
|
|
for (j = 0; j < length;)
|
|
{
|
|
u_isr.reg_data = readl(&i2s[device_num]->channel[channel_num].isr);
|
|
if (u_isr.isr.txfe == 1)
|
|
{
|
|
switch(single_length)
|
|
{
|
|
case 16:
|
|
left_buffer = ((uint16_t *)pcm)[i++];
|
|
right_buffer = ((uint16_t *)pcm)[i++];
|
|
break;
|
|
case 24:
|
|
left_buffer = 0;
|
|
left_buffer |= pcm[i++];
|
|
left_buffer |= pcm[i++] << 8;
|
|
left_buffer |= pcm[i++] << 16;
|
|
right_buffer = 0;
|
|
right_buffer |= pcm[i++];
|
|
right_buffer |= pcm[i++] << 8;
|
|
right_buffer |= pcm[i++] << 16;
|
|
break;
|
|
case 32:
|
|
left_buffer = ((uint32_t *)pcm)[i++];
|
|
right_buffer = ((uint32_t *)pcm)[i++];
|
|
break;
|
|
default:
|
|
left_buffer = pcm[i++];
|
|
right_buffer = pcm[i++];
|
|
break;
|
|
}
|
|
writel(left_buffer, &i2s[device_num]->channel[channel_num].left_rxtx);
|
|
writel(right_buffer, &i2s[device_num]->channel[channel_num].right_rxtx);
|
|
j++;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int i2s_trans_data(enum i2s_device_num_t device_num,enum i2s_channel_num_t channel_num,
|
|
uint8_t *pcm, uint32_t length, uint8_t single_length, uint8_t track_num)
|
|
{
|
|
union isr_u u_isr;
|
|
uint32_t left_buffer = 0;
|
|
uint32_t right_buffer = 0;
|
|
uint32_t i = 0;
|
|
uint32_t j = 0;
|
|
if (channel_num < CHANNEL_0 || channel_num > CHANNEL_3)
|
|
return -1;
|
|
readl(&i2s[device_num]->channel[channel_num].tor);
|
|
/* read clear overrun flag */
|
|
|
|
for (j = 0; j < length;)
|
|
{
|
|
u_isr.reg_data = readl(&i2s[device_num]->channel[channel_num].isr);
|
|
if (u_isr.isr.txfe == 1)
|
|
{
|
|
switch(single_length)
|
|
{
|
|
case 16:
|
|
left_buffer = ((uint16_t *)pcm)[i++];
|
|
track_num == 2 ? (right_buffer = ((uint16_t *)pcm)[i++]) : (right_buffer = 0);
|
|
break;
|
|
case 24:
|
|
left_buffer = 0;
|
|
left_buffer |= pcm[i++];
|
|
left_buffer |= pcm[i++] << 8;
|
|
left_buffer |= pcm[i++] << 16;
|
|
right_buffer = 0;
|
|
if(track_num == 2)
|
|
{
|
|
right_buffer |= pcm[i++];
|
|
right_buffer |= pcm[i++] << 8;
|
|
right_buffer |= pcm[i++] << 16;
|
|
}
|
|
break;
|
|
case 32:
|
|
left_buffer = ((uint32_t *)pcm)[i++];
|
|
track_num == 2 ? (right_buffer = ((uint32_t *)pcm)[i++]) : (right_buffer = 0);
|
|
break;
|
|
default:
|
|
left_buffer = pcm[i++];
|
|
track_num == 2 ? (right_buffer = pcm[i++]) : (right_buffer = 0);
|
|
break;
|
|
}
|
|
writel(left_buffer, &i2s[device_num]->channel[channel_num].left_rxtx);
|
|
writel(right_buffer, &i2s[device_num]->channel[channel_num].right_rxtx);
|
|
j ++;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int i2s_transmit_data_dma(enum i2s_device_num_t device_num,
|
|
void *pcm, uint32_t length, uint8_t single_length, dmac_channel_number channel_num)
|
|
{
|
|
length = length / (single_length / 8) / 2;
|
|
sysctl_dma_select(channel_num, SYSCTL_DMA_SELECT_I2S0_TX_REQ + device_num * 2);
|
|
dmac_set_single_mode(channel_num, pcm/*buf*/, (void *)(&i2s[device_num]->txdma), DMAC_ADDR_INCREMENT,
|
|
DMAC_ADDR_NOCHANGE,DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, length);
|
|
dmac_wait_done(channel_num);
|
|
return 0;
|
|
}
|
|
|
|
void i2s_send_data_dma(enum i2s_device_num_t device_num,
|
|
void *pcm, uint32_t length, dmac_channel_number channel_num)
|
|
{
|
|
static uint8_t dmac_init_flag[6] = {0,0,0,0,0,0};
|
|
if(dmac_init_flag[channel_num])
|
|
dmac_wait_done(channel_num);
|
|
else
|
|
dmac_init_flag[channel_num] = 1;
|
|
sysctl_dma_select(channel_num, SYSCTL_DMA_SELECT_I2S0_TX_REQ + device_num * 2);
|
|
dmac_set_single_mode(channel_num, pcm, (void *)(&i2s[device_num]->txdma), DMAC_ADDR_INCREMENT,
|
|
DMAC_ADDR_NOCHANGE, DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, length);
|
|
}
|
|
|
|
void parse_voice(uint32_t *buf, uint8_t *pcm, uint32_t length, uint32_t bits_per_sample,
|
|
uint8_t track_num, uint32_t *send_len)
|
|
{
|
|
uint32_t i,j=0;
|
|
*send_len = length * 2;
|
|
switch(bits_per_sample)
|
|
{
|
|
case 16:
|
|
i2s_transmit_dma_divide(I2S_DEVICE_0, 1);
|
|
for(i = 0; i < length; i++)
|
|
{
|
|
buf[i] = ((uint16_t *)pcm)[i];
|
|
}
|
|
*send_len = length;
|
|
break;
|
|
case 24:
|
|
for(i = 0; i < length; i++)
|
|
{
|
|
buf[2*i] = 0;
|
|
buf[2*i] |= pcm[j++];
|
|
buf[2*i] |= pcm[j++] << 8;
|
|
buf[2*i] |= pcm[j++] << 16;
|
|
buf[2*i+1] = 0;
|
|
if(track_num == 2)
|
|
{
|
|
buf[2*i+1] |= pcm[j++];
|
|
buf[2*i+1] |= pcm[j++] << 8;
|
|
buf[2*i+1] |= pcm[j++] << 16;
|
|
}
|
|
}
|
|
break;
|
|
case 32:
|
|
for(i = 0; i < length; i++)
|
|
{
|
|
buf[2*i] = ((uint32_t *)pcm)[i];
|
|
buf[2*i+1] = 0;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
int i2s_play(enum i2s_device_num_t device_num,dmac_channel_number channel_num,
|
|
uint8_t *buf, size_t length, uint32_t frame, uint32_t bits_per_sample, uint8_t track_num)
|
|
{
|
|
uint32_t sample_cnt = length / ( bits_per_sample / 8 ) / track_num;
|
|
uint32_t frame_cnt = sample_cnt / frame;
|
|
uint32_t frame_remain = sample_cnt % frame;
|
|
uint32_t i;
|
|
uint8_t *trans_buf;
|
|
|
|
if (bits_per_sample == 16 && track_num == 2)
|
|
{
|
|
for (i = 0; i < frame_cnt; i++)
|
|
{
|
|
trans_buf = buf + i * frame * (bits_per_sample / 8) * track_num;
|
|
i2s_send_data_dma(device_num,trans_buf, frame, channel_num);
|
|
}
|
|
if(frame_remain)
|
|
{
|
|
trans_buf = buf + frame_cnt * frame * (bits_per_sample / 8) * track_num;
|
|
i2s_send_data_dma(device_num, trans_buf, frame_remain, channel_num);
|
|
}
|
|
}
|
|
else if (bits_per_sample == 32 && track_num == 2)
|
|
{
|
|
for (i = 0; i < frame_cnt; i++)
|
|
{
|
|
trans_buf = buf + i * frame * (bits_per_sample / 8) * track_num;
|
|
i2s_send_data_dma(device_num,trans_buf, frame * 2, channel_num);
|
|
}
|
|
if(frame_remain)
|
|
{
|
|
trans_buf = buf + frame_cnt * frame * (bits_per_sample / 8) * track_num;
|
|
i2s_send_data_dma(device_num, trans_buf, frame_remain * 2, channel_num);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uint32_t *buff[2];
|
|
buff[0] = malloc(frame * 2 * sizeof(uint32_t) * 2);
|
|
buff[1] = buff[0] + frame * 2;
|
|
uint8_t flag = 0;
|
|
uint32_t send_len = 0;
|
|
for (i = 0; i < frame_cnt; i++)
|
|
{
|
|
trans_buf = buf + i * frame * (bits_per_sample / 8) * track_num;
|
|
parse_voice(buff[flag], trans_buf, frame, bits_per_sample, track_num, &send_len);
|
|
i2s_send_data_dma(device_num,buff[flag], send_len, channel_num);
|
|
flag = !flag;
|
|
}
|
|
if (frame_remain)
|
|
{
|
|
trans_buf = buf + frame_cnt * frame * (bits_per_sample / 8) * track_num;
|
|
parse_voice(buff[flag], trans_buf, frame_remain, bits_per_sample, track_num, &send_len);
|
|
i2s_send_data_dma(device_num, trans_buf, send_len, channel_num);
|
|
}
|
|
free(buff[0]);
|
|
}
|
|
return 0;
|
|
}
|
|
|