void audio_enable(void) { if (!audio_drv.enabled) { audio_drv.enabled = true; i2s_enable(); } }
/* * 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; }
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; }
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; }
//! [setup] static void _configure_i2s(void) { //! [setup_i2s_init] i2s_init(&i2s_instance, CONF_I2S_MODULE); //! [setup_i2s_init] //! [setup_clock_unit_config] struct i2s_clock_unit_config config_clock_unit; //! [setup_clock_unit_config] //! [setup_clock_unit_config_defaults] i2s_clock_unit_get_config_defaults(&config_clock_unit); //! [setup_clock_unit_config_defaults] //! [setup_clock_unit_change_config] config_clock_unit.clock.gclk_src = GCLK_GENERATOR_0; config_clock_unit.clock.mck_src = I2S_MASTER_CLOCK_SOURCE_GCLK; config_clock_unit.clock.mck_out_enable = true; config_clock_unit.clock.mck_out_div = 2; config_clock_unit.clock.sck_src = I2S_SERIAL_CLOCK_SOURCE_MCKDIV; config_clock_unit.clock.sck_div = 4; config_clock_unit.frame.number_slots = 2; config_clock_unit.frame.slot_size = I2S_SLOT_SIZE_32_BIT; config_clock_unit.frame.data_delay = I2S_DATA_DELAY_0; config_clock_unit.frame.frame_sync.source = I2S_FRAME_SYNC_SOURCE_SCKDIV; config_clock_unit.frame.frame_sync.width = I2S_FRAME_SYNC_WIDTH_HALF_FRAME; //! [setup_clock_unit_change_config] //! [setup_clock_unit_change_pins] config_clock_unit.mck_pin.enable = true; config_clock_unit.mck_pin.gpio = CONF_I2S_MCK_PIN; config_clock_unit.mck_pin.mux = CONF_I2S_MCK_MUX; config_clock_unit.sck_pin.enable = true; config_clock_unit.sck_pin.gpio = CONF_I2S_SCK_PIN; config_clock_unit.sck_pin.mux = CONF_I2S_SCK_MUX; config_clock_unit.fs_pin.enable = true; config_clock_unit.fs_pin.gpio = CONF_I2S_FS_PIN; config_clock_unit.fs_pin.mux = CONF_I2S_FS_MUX; //! [setup_clock_unit_change_pins] //! [setup_clock_unit_set_config] i2s_clock_unit_set_config(&i2s_instance, I2S_CLOCK_UNIT_0, &config_clock_unit); //! [setup_clock_unit_set_config] //! [setup_serializer_config] struct i2s_serializer_config config_serializer; //! [setup_serializer_config] //! [setup_serializer_config_defaults] i2s_serializer_get_config_defaults(&config_serializer); //! [setup_serializer_config_defaults] //! [setup_serializer_change_config_tx] config_serializer.clock_unit = I2S_CLOCK_UNIT_0; config_serializer.mode = I2S_SERIALIZER_TRANSMIT; config_serializer.data_size = I2S_DATA_SIZE_16BIT; //! [setup_serializer_change_config_tx] //! [setup_serializer_change_config_pin_tx] config_serializer.data_pin.enable = true; config_serializer.data_pin.gpio = CONF_I2S_SD_PIN; config_serializer.data_pin.mux = CONF_I2S_SD_MUX; //! [setup_serializer_change_config_pin_tx] //! [setup_serializer_set_config_tx] i2s_serializer_set_config(&i2s_instance, I2S_SERIALIZER_0, &config_serializer); //! [setup_serializer_set_config_tx] //! [setup_enable] i2s_enable(&i2s_instance); i2s_clock_unit_enable(&i2s_instance, I2S_CLOCK_UNIT_0); i2s_serializer_enable(&i2s_instance, I2S_SERIALIZER_0); //! [setup_enable] }
/** * \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!"); }