Example #1
0
/* ISR */
static void i2s_isr(void)
{
	uint32_t stat;

	// Determine interrupt source
	stat = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_STAT);

	// Check for errors
	if (stat & (1 << SOC_I2S_STAT_TDATA_UNDERR)) 
	{
		if (i2s_info->cfg[I2S_CHANNEL_TX].cb_err) 
		{
			i2s_info->cfg[I2S_CHANNEL_TX].cb_err_arg=(void *)stat;
			i2s_info->cfg[I2S_CHANNEL_TX].cb_err(i2s_info->cfg[I2S_CHANNEL_TX].cb_err_arg);
		}
		i2s_disable(I2S_CHANNEL_TX);
	}
	if (stat & (1 << SOC_I2S_STAT_RDATA_OVRERR)) 
	{
		if (i2s_info->cfg[I2S_CHANNEL_RX].cb_err) 
		{
			i2s_info->cfg[I2S_CHANNEL_RX].cb_err_arg=(void *)stat;
			i2s_info->cfg[I2S_CHANNEL_RX].cb_err(i2s_info->cfg[I2S_CHANNEL_RX].cb_err_arg);
		}
		i2s_disable(I2S_CHANNEL_RX);
	}

	return;
}
Example #2
0
static void i2s_dma_cb_done(void *num)
{
	uint8_t channel = (uint32_t)num;
 	uint32_t reg;
  
	if(channel == I2S_CHANNEL_TX)
	{
		if((0x00200000 & MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_CTRL))
        	&& !(0x18000000 & MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_CTRL)))
		{	
			for(int i = 0; i < 4; ++i)
				MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_DATA_REG) = 0x0;
		}

		do
		{
			reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].fifo_stat);
		} while(reg & 0x000000FF);
	}
  
	if (i2s_info->cfg[channel].cb_done) 
	{
		i2s_info->cfg[channel].cb_done(i2s_info->cfg[channel].cb_done_arg);
	}
 
	i2s_disable(channel);
 
	return;
}
Example #3
0
/*
 * apl_i2s_send - Send audio samples to I2s controller.
 * @me: I2sOps structure
 * @data: Audio samples
 * @length: Number of samples
 *
 * Send audio samples to I2s controller.
*/
static int apl_i2s_send(I2sOps *me, unsigned int *data, unsigned int length)
{
	int i;
	uint64_t start;
	AplI2s *bus = container_of(me, AplI2s, ops);
	struct AplI2sRegs *i2s_reg = bus->regs;

	if (!bus->initialized) {
		if (apl_i2s_init(bus))
			return -1;
		bus->initialized = 1;
	}

	if (length < LPE_SSP_FIFO_SIZE) {
		printf("%s : Invalid data size\n", __func__);
		return -1;
	}

	gpio_set(bus->sdmode_gpio, 1);

	for (i = 0; i < LPE_SSP_FIFO_SIZE; i++)
		writel(*data++, &i2s_reg->ssdr);

	i2s_enable(bus->regs);
	length -= LPE_SSP_FIFO_SIZE;

	while (length > 0) {
		start = timer_us(0);
		if (read_SSSR(bus->regs) & 0x4) {
			writel(*data++, &i2s_reg->ssdr);
			length--;
		} else {
			if (timer_us(start) > 100000) {
				i2s_disable(bus->regs);
				gpio_set(bus->sdmode_gpio, 0);
				printf("I2S Transfer Timeout\n");
				return -1;
			}
		}
	}

	mdelay(1);
	gpio_set(bus->sdmode_gpio, 0);
	i2s_disable(bus->regs);
	return 0;
}
Example #4
0
void audio_disable(void)
{
	if (audio_drv.enabled) {
		audio_drv.stream_enabled = false;
		i2s_disable();
		audio_drv.enabled = false;
	}
}
Example #5
0
/*
 * apl_i2s_init - Initialize I2s.
 * @bus: i2s config structure
 *
 * Initialize I2s.
 */
static int apl_i2s_init(AplI2s *bus)
{
	if (enable_DSP_SSP(bus))
		return -1;
	i2s_disable(bus->regs);
	set_ssp_i2s_hw(bus->regs,
		       bus->shim,
		       bus->settings,
		       bus->bits_per_sample);
	return 0;
}
Example #6
0
/* DMA Callbacks */
static void i2s_dma_cb_err(void *num)
{
	uint8_t channel = (uint32_t)num;

	if (i2s_info->cfg[channel].cb_err) 
	{
		i2s_info->cfg[channel].cb_err(i2s_info->cfg[channel].cb_err_arg);
	}
	i2s_disable(channel);

	return;
}
Example #7
0
/* Driver API */
DRIVER_API_RC soc_i2s_init()
{
	int i;
	uint32_t reg;

	// Prep info struct
	for (i = 0; i < I2S_NUM_CHANNELS; i++) 
	{
		i2s_info->en[i] = 0;
		i2s_info->cfgd[i] = 0;
		i2s_info->cfg[i].cb_done = NULL;
		i2s_info->cfg[i].cb_err = NULL;
	}

	// Enable global clock, use local clock gating per channel instead
	set_clock_gate(i2s_info->clk_gate_info, CLK_GATE_ON);

	// Setup ISR (and enable)
	SET_INTERRUPT_HANDLER(i2s_info->int_vector, i2s_interrupt_handler);
	SOC_UNMASK_INTERRUPTS(i2s_info->int_mask);

	// Set up control register
	reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_CTRL);
	reg |= (1 << SOC_I2S_CTRL_TR_CFG_0);
 	reg &= ~(1 << SOC_I2S_CTRL_TSYNC_LOOP_BACK);
	reg &= ~(1 << SOC_I2S_CTRL_RSYNC_LOOP_BACK);
	MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_CTRL) = reg;

	// Set the watermark levels
	MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_TFIFO_CTRL) &= 0xFFFCFFFF;
	MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_TFIFO_CTRL) |= (I2S_TFIFO_THR << SOC_I2S_TFIFO_CTRL_TAFULL_THRS);

	MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_RFIFO_CTRL) &= 0xFFFCFFFF;
	MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_RFIFO_CTRL) |= (I2S_RFIFO_THR << SOC_I2S_RFIFO_CTRL_RAFULL_THRS);

	// Enable global interrupt mask
	reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_CID_CTRL);
	reg |= (1 << SOC_I2S_CID_CTRL_INTREQ_MASK);
	MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_CID_CTRL) = reg;

	// Initially, have all channels disabled
	for (i = 0; i < I2S_NUM_CHANNELS; i++) 
	{
		i2s_disable(i);
	}

	return DRV_RC_OK;
}
Example #8
0
DRIVER_API_RC soc_i2s_stop_stream(void)
{
	uint8_t channel = I2S_CHANNEL_TX;
	uint32_t save;

	if (channel >= I2S_NUM_CHANNELS) 
	{
		return DRV_RC_FAIL;
	} 
	else if (!(i2s_info->en[channel])) 
	{
		return DRV_RC_FAIL;
	}

	save = interrupt_lock();
	i2s_disable(channel);
	interrupt_unlock(save);

	return DRV_RC_OK;
}
Example #9
0
static void i2s_dma_cb_done(void *num)
{
	uint8_t channel = (uint32_t)num;
 	uint32_t reg;
  
	if(channel == I2S_CHANNEL_TX)
	{
		do
		{
			reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].fifo_stat);
		} while(reg & 0x000000FF); 
	}
	
	if (i2s_info->cfg[channel].cb_done) 
	{
		i2s_info->cfg[channel].cb_done(i2s_info->cfg[channel].cb_done_arg);
	}
 
	i2s_disable(channel);
 
	return;
}
Example #10
0
void audio_reset(void)
{
	bool enable_stream;

	tracef("%s(): audio system reset ...", __func__);

	enable_stream = audio_drv.stream_enabled;

	audio_drv.stream_enabled = false;

	codec_hw_reset();
	
	tlv320_reset();

	if (audio_drv.enabled)
		i2s_disable();

	tlv320_init();

	if (audio_drv.enabled)
		i2s_enable();

	audio_drv.stream_enabled = enable_stream;
}
Example #11
0
DRIVER_API_RC soc_i2s_stream(uint32_t *buf, uint32_t len, uint32_t num_bufs)
{
	DRIVER_API_RC ret;
	uint8_t channel = I2S_CHANNEL_TX;
	uint32_t reg;
	uint32_t len_per_buf;
	int i;
	struct soc_dma_xfer_item *dma_list;

	// Check channel no in use and configured
	if (channel >= I2S_NUM_CHANNELS) 
	{
		return DRV_RC_FAIL;
	} 
	else if (i2s_info->en[channel] || !(i2s_info->cfgd[channel])) 
	{
		return DRV_RC_FAIL;
	}

	// Get a DMA channel
	ret = soc_dma_acquire(&(i2s_info->dma_ch[channel]));

	if (ret != DRV_RC_OK) 
	{
		return DRV_RC_FAIL;
	}

	// Enable the channel
	i2s_enable(channel);

	// Determine the length of a single buffer
	if (num_bufs == 0) 
	{
		len_per_buf = len;
	} 
	else 
	{
		len_per_buf = len / num_bufs;
	}

	// Prep some configuration
	i2s_info->dma_cfg[channel].type = SOC_DMA_TYPE_MEM2PER;
	i2s_info->dma_cfg[channel].dest_interface = SOC_DMA_INTERFACE_I2S_TX;
	i2s_info->dma_cfg[channel].dest_step_count = 0;
	i2s_info->dma_cfg[channel].src_step_count = 0;

	i2s_info->dma_cfg[channel].xfer.dest.delta = SOC_DMA_DELTA_NONE;
	i2s_info->dma_cfg[channel].xfer.dest.width = SOC_DMA_WIDTH_32;
	i2s_info->dma_cfg[channel].xfer.dest.addr = (void *)(SOC_I2S_BASE + SOC_I2S_DATA_REG);
	i2s_info->dma_cfg[channel].xfer.src.delta = SOC_DMA_DELTA_INCR;
	i2s_info->dma_cfg[channel].xfer.src.width = SOC_DMA_WIDTH_32;

	if (num_bufs == 0) 
	{
		i2s_info->dma_cfg[channel].cb_done = i2s_dma_cb_done;
		i2s_info->dma_cfg[channel].cb_done_arg = (void *)((uint32_t)channel);
	} 
	else 
	{
		i2s_info->dma_cfg[channel].cb_block = i2s_dma_cb_block;
		i2s_info->dma_cfg[channel].cb_block_arg = (void *)((uint32_t)channel);
	}

	i2s_info->dma_cfg[channel].cb_err = i2s_dma_cb_err;
	i2s_info->dma_cfg[channel].cb_err_arg = (void *)((uint32_t)channel);

	// Setup the linked list
	for (i = 0; i < ((num_bufs == 0) ? 1 : num_bufs); i++) 
	{
		if (i == 0) 
		{
			dma_list = &(i2s_info->dma_cfg[channel].xfer);
		} 
		else 
		{
			ret = soc_dma_alloc_list_item(&dma_list, dma_list);

			if (ret != DRV_RC_OK) 
			{
				goto fail;
			}
		}

		dma_list->src.addr = (void *)(&(buf[i * (len_per_buf / sizeof(uint32_t))]));
		dma_list->size = len_per_buf / sizeof(uint32_t);
	}

	// Create a circular list if we are doing circular buffering
	if (num_bufs != 0) 
	{
		dma_list->next = &(i2s_info->dma_cfg[channel].xfer);
	}

	// Setup and start the DMA engine
	ret = soc_dma_config(&(i2s_info->dma_ch[channel]), &(i2s_info->dma_cfg[channel]));

	if (ret != DRV_RC_OK) 
	{
		goto fail;
	}

	ret = soc_dma_start_transfer(&(i2s_info->dma_ch[channel]));

	if (ret != DRV_RC_OK) 
	{
		goto fail;
	}

	// Enable the channel and let it go!
	reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].ctrl);
	reg |= (1 << (i2s_reg_map[channel].ctrl_en));
	reg |= (1 << (i2s_reg_map[channel].ctrl_sync_rst));
	MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].ctrl) = reg;

	return DRV_RC_OK;

fail:
	i2s_disable(channel);
	soc_dma_release(&(i2s_info->dma_ch[channel]));
	return DRV_RC_FAIL;
}
Example #12
0
/**
 * \brief Test audio data transfer and receive.
 *
 * \param test Current test case.
 */
static void run_i2s_test(const struct test_case *test)
{
	uint32_t i;
	struct i2s_config config;
	struct i2s_dev_inst dev_inst;
	Pdc *p_i2sc_pdc;
	Pdc *p_i2sc_pdc2;
	pdc_packet_t pdc_i2sc_packet_tx, pdc_i2sc_packet_rx;
	pdc_packet_t pdc2_i2sc_packet_tx, pdc2_i2sc_packet_rx;

	/* Set the configuration */
	i2s_get_config_defaults(&config);
	config.data_format = I2S_DATE_16BIT;
	config.fs_ratio = I2S_FS_RATE_256;
	config.loopback = true;
	i2s_init(&dev_inst, I2SC0, &config);

	/* Enable the I2SC module. */
	i2s_enable(&dev_inst);

	/* Get pointer to I2SC PDC register base */
	p_i2sc_pdc = i2s_get_pdc_base(&dev_inst);
	p_i2sc_pdc2 = (Pdc *)((uint32_t)p_i2sc_pdc + 0x100U);
	/* Initialize PDC data packet for transfer */
	pdc_i2sc_packet_tx.ul_addr = (uint32_t) output_samples_left;
	pdc_i2sc_packet_tx.ul_size = SOUND_SAMPLES;
	pdc_i2sc_packet_rx.ul_addr = (uint32_t) input_samples_left;
	pdc_i2sc_packet_rx.ul_size = SOUND_SAMPLES;
	pdc2_i2sc_packet_tx.ul_addr = (uint32_t) output_samples_right;
	pdc2_i2sc_packet_tx.ul_size = SOUND_SAMPLES;
	pdc2_i2sc_packet_rx.ul_addr = (uint32_t) input_samples_right;
	pdc2_i2sc_packet_rx.ul_size = SOUND_SAMPLES;
	/* Configure PDC for data transfer */
	pdc_tx_init(p_i2sc_pdc, &pdc_i2sc_packet_tx, NULL);
	pdc_rx_init(p_i2sc_pdc, &pdc_i2sc_packet_rx, NULL);
	pdc_tx_init(p_i2sc_pdc2, &pdc2_i2sc_packet_tx, NULL);
	pdc_rx_init(p_i2sc_pdc2, &pdc2_i2sc_packet_rx, NULL);
	/* Enable PDC transfers */
	pdc_enable_transfer(p_i2sc_pdc, PERIPH_PTCR_TXTEN | PERIPH_PTCR_RXTEN);
	pdc_enable_transfer(p_i2sc_pdc2, PERIPH_PTCR_TXTEN | PERIPH_PTCR_RXTEN);

	/* Enable the functions */
	i2s_enable_transmission(&dev_inst);
	i2s_enable_clocks(&dev_inst);

	/**
	 * Since the transfer and receive timing is not under control, we
	 * need adjust here the enable sequence and add some delay
	 * functions if it's needed.
	 */
	for (i = 0; i < 0x8; i++) {
		input_samples_left[i] = i;
	}

	i2s_enable_reception(&dev_inst);

	/* Wait transfer complete */
	while (!(i2s_get_status(&dev_inst) & I2SC_SR_RXBUFF)) {
	}

	/**
	 * Wait a moment to let the PDC finish. The status bit is cleared
	 * before all transfer finish.
	 */
	delay_us(10);

	/* Disable the PDC module. */
	pdc_disable_transfer(p_i2sc_pdc, PERIPH_PTCR_RXTDIS| PERIPH_PTCR_TXTDIS);
	pdc_disable_transfer(p_i2sc_pdc2, PERIPH_PTCR_RXTDIS| PERIPH_PTCR_TXTDIS);

	/* Disable the I2SC module. */
	i2s_disable(&dev_inst);

	/* Compare the data. */
	for (i = 0; i < SOUND_SAMPLES; i++) {
		if ((input_samples_left[i] != output_samples_left[i]) ||
			(input_samples_right[i] != output_samples_right[i])) {
			flag = false;
		}
	}

	test_assert_true(test, flag == true, "Audio data did not match!");
}