Exemple #1
0
uint32_t pdca_init_channel(uint8_t pdca_ch_number,
		const pdca_channel_options_t *opt)
{
	/* get the correct channel pointer */
	volatile avr32_pdca_channel_t *pdca_channel = pdca_get_handler(
			pdca_ch_number);

	pdca_disable_interrupt_transfer_complete(pdca_ch_number); 
	pdca_disable_interrupt_reload_counter_zero(pdca_ch_number);
	
	irqflags_t flags = cpu_irq_save();

	pdca_channel->mar = (uint32_t)opt->addr;
	pdca_channel->tcr = opt->size;
	pdca_channel->psr = opt->pid;
	pdca_channel->marr = (uint32_t)opt->r_addr;
	pdca_channel->tcrr = opt->r_size;
	pdca_channel->mr =
#if (AVR32_PDCA_H_VERSION >= 120)
			opt->etrig << AVR32_PDCA_ETRIG_OFFSET |
#endif
			opt->transfer_size << AVR32_PDCA_SIZE_OFFSET;
	pdca_channel->cr = AVR32_PDCA_ECLR_MASK;
	pdca_channel->isr;
	
	cpu_irq_restore(flags);

	return PDCA_SUCCESS;
}
Exemple #2
0
__interrupt
#endif
static void lin_pdca_int_rx_handler_node1(void)
{
  U8 index = 0;
  U8 l_handle = 0xFF;
  // Check ID Value for the current message
  for(index = 0; index < NUMBER_OF_LIN_FRAMES_NODE1; index ++)
  {
      if(lin_descript_list_node1[index].l_id == usart_lin_get_id_char(usart_lin_node1))
      {
          l_handle = index;
                    break;
      }
  }

  // Check if the ID received is registered into the lin description list
  if (l_handle!=0xFF)
  {
    if (pdca_get_transfer_status(USART_LIN_NODE1_RX_PDCA_CHANNEL)&PDCA_TRANSFER_COMPLETE)
    {
        pdca_disable_interrupt_transfer_complete(USART_LIN_NODE1_RX_PDCA_CHANNEL);
        lin_get_response (1,lin_descript_list_node1[l_handle].l_pt_data);
        // Start of the associated task
        lin_descript_list_node1[l_handle].l_pt_function(lin_descript_list_node1[l_handle].l_pt_data);
        lin_handle_node1 = 0xFF;  // End of communication
    }
  }
}
Exemple #3
0
void aic23b_dac_flush(void)
{
  pdca_disable_interrupt_transfer_complete(AIC23B_SSC_TX_PDCA_CHANNEL);
  pdca_disable_interrupt_reload_counter_zero(AIC23B_SSC_TX_PDCA_CHANNEL);

  while (!(pdca_get_transfer_status(AIC23B_SSC_TX_PDCA_CHANNEL) &
           PDCA_TRANSFER_COMPLETE));
}
Exemple #4
0
/*! \brief Flushes the sample buffer being output to the ABDAC.
 */
void tpa6130_dac_flush(void)
{
  pdca_disable_interrupt_transfer_complete(TPA6130_ABDAC_PDCA_CHANNEL);
  pdca_disable_interrupt_reload_counter_zero(TPA6130_ABDAC_PDCA_CHANNEL);

  /*TODO Do we really want to wait here? Or do we just don't care when
   * the buffer is empty/flushed */
  //while(!pdca_get_transfer_status(TPA6130_ABDAC_PDCA_CHANNEL) &
  //  PDCA_TRANSFER_COMPLETE);
  pdca_disable       (TPA6130_ABDAC_PDCA_CHANNEL       );
  pdca_load_channel  (TPA6130_ABDAC_PDCA_CHANNEL,0x0, 0);
  pdca_reload_channel(TPA6130_ABDAC_PDCA_CHANNEL,0x0, 0);
  pdca_enable        (TPA6130_ABDAC_PDCA_CHANNEL       );
}
Exemple #5
0
ISR(tpa6130_abdac_tx_pdca_int_handler, TPA6130_ABDAC_PDCA_IRQ_GROUP, TPA6130_ABDAC_PDCA_INT_LEVEL)
{
  if (pdca_get_transfer_status(TPA6130_ABDAC_PDCA_CHANNEL) & PDCA_TRANSFER_COMPLETE)
  {
    pdca_disable_interrupt_transfer_complete(TPA6130_ABDAC_PDCA_CHANNEL);
    if (tpa6130_output_param.callback_opt & AUDIO_DAC_OUT_OF_SAMPLE_CB)
      tpa6130_output_param.callback(AUDIO_DAC_OUT_OF_SAMPLE_CB);
  }

  if (pdca_get_transfer_status(TPA6130_ABDAC_PDCA_CHANNEL) & PDCA_TRANSFER_COUNTER_RELOAD_IS_ZERO)
  {
    pdca_disable_interrupt_reload_counter_zero(TPA6130_ABDAC_PDCA_CHANNEL);
    if (tpa6130_output_param.callback_opt & AUDIO_DAC_RELOAD_CB)
      tpa6130_output_param.callback(AUDIO_DAC_RELOAD_CB);
  }
}
Exemple #6
0
static void pdca_int_handler_i2c0(void)
{
	AVR32_TWIM0.cr = AVR32_TWIM_CR_MDIS_MASK;
	pdca_disable(TWI0_DMA_CH);

	pdca_disable_interrupt_transfer_complete(TWI0_DMA_CH);

	// call callback function to process data, at end of transfer
	// to process data, and maybe add some more data
	schedule[0][current_schedule_slot[0]].transfer_in_progress = 0;

	if (schedule[0][current_schedule_slot[0]].callback) 
	{
		schedule[0][current_schedule_slot[0]].callback;
	}
   print_util_dbg_print( "!");
}
Exemple #7
0
__interrupt
#endif
static void aic23b_ssc_rx_pdca_int_handler(void)
{
  if (pdca_get_transfer_status(AIC23B_SSC_RX_PDCA_CHANNEL) & PDCA_TRANSFER_COMPLETE)
  {
    pdca_disable_interrupt_transfer_complete(AIC23B_SSC_RX_PDCA_CHANNEL);
    if (aic23b_output_params.callback_opt & AUDIO_ADC_OUT_OF_SAMPLE_CB)
      aic23b_output_params.callback(AUDIO_ADC_OUT_OF_SAMPLE_CB);
  }

  if (pdca_get_transfer_status(AIC23B_SSC_RX_PDCA_CHANNEL) & PDCA_TRANSFER_COUNTER_RELOAD_IS_ZERO)
  {
    pdca_disable_interrupt_reload_counter_zero(AIC23B_SSC_RX_PDCA_CHANNEL);
    if (aic23b_output_params.callback_opt & AUDIO_ADC_RELOAD_CB)
      aic23b_output_params.callback(AUDIO_ADC_RELOAD_CB);
  }
}
Exemple #8
0
Fichier : ms3.c Projet : avrxml/asf
__interrupt
#endif
static void ms3_ssc_tx_pdca_int_handler(void)
{
	if (pdca_get_transfer_status(MS3_SSC_TX_PDCA_CHANNEL) & PDCA_TRANSFER_COMPLETE)
	{
		pdca_disable_interrupt_transfer_complete(MS3_SSC_TX_PDCA_CHANNEL);
		if (ms3_output_params.callback_opt & AUDIO_DAC_OUT_OF_SAMPLE_CB)
			ms3_output_params.callback(AUDIO_DAC_OUT_OF_SAMPLE_CB);
	}

	if (pdca_get_transfer_status(MS3_SSC_TX_PDCA_CHANNEL) & PDCA_TRANSFER_COUNTER_RELOAD_IS_ZERO)
	{
		pdca_disable_interrupt_reload_counter_zero(MS3_SSC_TX_PDCA_CHANNEL);
		if (ms3_output_params.callback_opt & AUDIO_DAC_RELOAD_CB)
			ms3_output_params.callback(AUDIO_DAC_RELOAD_CB);
	}
}
__interrupt
#endif
static void pdca_int_handler(void)
{
  // Disable all interrupts.
  Disable_global_interrupt();

  // Disable interrupt channel.
  pdca_disable_interrupt_transfer_complete(AVR32_PDCA_CHANNEL_SPI_RX);

  sd_mmc_spi_read_close_PDCA();//unselects the SD/MMC memory.
  wait();
  // Disable unnecessary channel
  pdca_disable(AVR32_PDCA_CHANNEL_SPI_TX);
  pdca_disable(AVR32_PDCA_CHANNEL_SPI_RX);

  // Enable all interrupts.
  Enable_global_interrupt();

  end_of_transfer = true;
}
Exemple #10
0
static void irq_pdca(void) {
  // Disable all interrupts.
  //  Disable_global_interrupt();
  cpu_irq_disable();
  // Disable interrupt channel.
  pdca_disable_interrupt_transfer_complete(AVR32_PDCA_CHANNEL_SPI_RX);
  //unselects the SD/MMC memory.
  sd_mmc_spi_read_close_PDCA();
  //.... example has a 5000 clock gimpy delay here.
  // using delay_us instead
  delay_ms(10);
  //  delay_ms(2);
  // Disable unnecessary channel
  pdca_disable(AVR32_PDCA_CHANNEL_SPI_TX);
  pdca_disable(AVR32_PDCA_CHANNEL_SPI_RX);
  // Enable all interrupts.
  cpu_irq_enable();
  //  Enable_global_interrupt();
  //  print_dbg("\r\n handled PDCA interrupt. \r\n");
  fsEndTransfer = true;
}
Exemple #11
0
__interrupt
#endif
static void pdca_interrupt_handler(void)
{
  pdca_disable_interrupt_transfer_complete(pdca_channel_usart);

  *((unsigned int *) pbuffer_w) = 1;
  // Point on the next buffer
  pbuffer_w += block_size;
  if (pbuffer_w + block_size >= buffer + BUFFER_SIZE)
    pbuffer_w = buffer;

  // If the next buffer is invalid, make an acquisition of the new data
  if (!*((unsigned int *) pbuffer_w))
  {
    // If the buffer is invalidate, fill it with new data;
    get_new_block = 1;
    fill_activ = 1;
  }
  else
  {
    fill_activ = 0;
  }
}
Exemple #12
0
void aic23b_adc_start(uint32_t sample_rate_hz,
                      uint8_t num_channels,
                      uint8_t bits_per_sample,
                      bool swap_channels,
                      void (*callback)(uint32_t arg),
                      uint32_t callback_opt,
                      uint32_t pba_hz)
{
#if AIC23B_CTRL_INTERFACE == AIC23B_CTRL_INTERFACE_SPI
  static const spi_options_t AIC23B_SPI_OPTIONS =
  {
    .reg          = AIC23B_SPI_NPCS,
    .baudrate     = AIC23B_SPI_MASTER_SPEED,
    .bits         = AIC23B_CTRL_SIZE,
    .spck_delay   = 0,
    .trans_delay  = 0,
    .stay_act     = 0,
    .spi_mode     = 3,
    .modfdis      = 1
  };
  spi_setupChipReg(AIC23B_SPI, &AIC23B_SPI_OPTIONS, pba_hz);
#endif

  aic23b_adc_stop();

  gpio_enable_module(AIC23B_SSC_ADC_GPIO_MAP,
                     sizeof(AIC23B_SSC_ADC_GPIO_MAP) / sizeof(AIC23B_SSC_ADC_GPIO_MAP[0]));

  aic23b_pdc_t pdc;
  pdc.data  = AIC23B_DEFAULT(AIC23B_PDC);
  pdc.off   = 0;
  pdc.clk   = 0;
  pdc.osc   = 0;
  pdc.out   = 0;
  pdc.dac   = 1;
  pdc.adc   = 0;
#if (AIC23B_INPUT==AIC23B_INPUT_LINE)
  pdc.mic   = 1;
  pdc.line  = 0;
#elif (AIC23B_INPUT==AIC23B_INPUT_MIC)
  pdc.mic   = 0;
  pdc.line  = 1;
#else
  #error No Input defined in file 'conf_tlv320aic23b.h'
#endif
  aic23b_set_power_down_state(pdc);

  aic23b_adc_setup(sample_rate_hz,
                   num_channels,
                   bits_per_sample,
                   swap_channels,
                   callback,
                   callback_opt,
                   pba_hz);

  aic23b_aapc_t aapc;
  aapc.data  = AIC23B_DEFAULT(AIC23B_AAPC);
#if (AIC23B_INPUT==AIC23B_INPUT_LINE)
  aapc.ste   = 0;
  aapc.dac   = 0;
  aapc.byp   = 0;
  aapc.insel = 0;
  aapc.micm  = 0;
  aapc.micb  = 0;
#elif (AIC23B_INPUT==AIC23B_INPUT_MIC)
  aapc.ste   = 0;
  aapc.dac   = 0;
  aapc.byp   = 0;
  aapc.insel = 1;
  aapc.micm  = 0;
  aapc.micb  = 0;
#else
  #error No Input defined in file 'conf_tlv320aic23b.h'
#endif
  aic23b_set_analog_audio_path(aapc);

  aic23b_dapc_t dapc;
  dapc.data   = AIC23B_DEFAULT(AIC23B_DAPC);
  dapc.dacm   = 0;
  dapc.deemp  = AIC23B_DAPC_DEEMP_NONE;
  dapc.adchp  = 0;
  aic23b_set_digital_audio_path(dapc);


  aic23b_llicvc_t llivc;
  llivc.data  = AIC23B_DEFAULT(AIC23B_LLICVC);
  llivc.liv   = 20;
  llivc.lim   = 0;
  llivc.lrs   = 1;
  aic23b_write_reg(AIC23B_LLICVC, llivc.data);

  aic23b_rlicvc_t rlivc;
  rlivc.data  = AIC23B_DEFAULT(AIC23B_RLICVC);
  rlivc.riv   = 20;
  rlivc.rim   = 0;
  rlivc.rls   = 1;
  aic23b_write_reg(AIC23B_RLICVC, rlivc.data);

  INTC_register_interrupt(&aic23b_ssc_rx_pdca_int_handler,
                          AIC23B_SSC_RX_PDCA_IRQ,
                          AIC23B_SSC_RX_PDCA_INT_LEVEL);

  aic23b_activate_dig_audio(true);

}

void aic23b_adc_setup(uint32_t sample_rate_hz,
                      uint8_t num_channels,
                      uint8_t bits_per_sample,
                      bool swap_channels,
                      void (*callback)(uint32_t arg),
                      callback_opt,
                      uint32_t pba_hz)
{
  ssc_i2s_init(AIC23B_SSC,
               sample_rate_hz,
               bits_per_sample,
               (bits_per_sample <= 16) ? 16 :
               (bits_per_sample <= 20) ? 20 :
               (bits_per_sample <= 24) ? 24 :
                                         32,
               SSC_I2S_MODE_STEREO_IN,
               pba_hz);

  pdca_channel_options_t aic23b_ssc_pdca_options =
  {
    .addr           = NULL,
    .size           = 0,
    .r_addr         = NULL,
    .r_size         = 0,
    .pid            = AIC23B_SSC_RX_PDCA_PID,
    .transfer_size  = (bits_per_sample <=  8) ? PDCA_TRANSFER_SIZE_BYTE      :
                      (bits_per_sample <= 16) ? PDCA_TRANSFER_SIZE_HALF_WORD :
                                                PDCA_TRANSFER_SIZE_WORD
  };
  pdca_init_channel(AIC23B_SSC_RX_PDCA_CHANNEL, &aic23b_ssc_pdca_options);
  pdca_enable(AIC23B_SSC_RX_PDCA_CHANNEL);

  // Set ADC frequency
  aic23b_configure_freq(AIC23B_MCLK_HZ, sample_rate_hz);

  aic23b_daif_t daif;
  daif.data   = AIC23B_DEFAULT(AIC23B_DAIF);
  daif.ms     = AIC23B_DAIF_MS_SLAVE;
  daif.lrswap = swap_channels;
  daif.lrp    = 0;
  daif.iwl    = (bits_per_sample <= 16) ? AIC23B_DAIF_IWL_16 :
                (bits_per_sample <= 20) ? AIC23B_DAIF_IWL_20 :
                (bits_per_sample <= 24) ? AIC23B_DAIF_IWL_24 :
                                          AIC23B_DAIF_IWL_32;
  daif.fmt    = AIC23B_DAIF_FMT_I2S;
  aic23b_write_reg(AIC23B_DAIF, daif.data);

  aic23b_output_params.num_channels              = num_channels;
  aic23b_output_params.callback                  = callback;
  aic23b_output_params.callback_opt              = callback_opt;
}

void aic23b_adc_flush(void)
{
  pdca_disable_interrupt_transfer_complete(AIC23B_SSC_RX_PDCA_CHANNEL);

  while (!(pdca_get_transfer_status(AIC23B_SSC_RX_PDCA_CHANNEL) &
           PDCA_TRANSFER_COMPLETE));
}
void aic23b_codec_start(uint32_t sample_rate_hz,
                      uint8_t num_channels,
                      uint8_t bits_per_sample,
                      bool swap_channels,
                      void (*callback)(uint32_t arg),
                      uint32_t callback_opt,
                      uint32_t pba_hz)
{
#if AIC23B_CTRL_INTERFACE == AIC23B_CTRL_INTERFACE_SPI
  static const spi_options_t AIC23B_SPI_OPTIONS =
  {
    .reg          = AIC23B_SPI_NPCS,
    .baudrate     = AIC23B_SPI_MASTER_SPEED,
    .bits         = AIC23B_CTRL_SIZE,
    .spck_delay   = 0,
    .trans_delay  = 0,
    .stay_act     = 0,
    .spi_mode     = 3,
    .modfdis      = 1
  };
  spi_setupChipReg(AIC23B_SPI, &AIC23B_SPI_OPTIONS, pba_hz);
#endif

  aic23b_codec_stop();

  gpio_enable_module(AIC23B_SSC_CODEC_GPIO_MAP,
                     sizeof(AIC23B_SSC_CODEC_GPIO_MAP) / sizeof(AIC23B_SSC_CODEC_GPIO_MAP[0]));

  aic23b_pdc_t pdc;
  pdc.data  = AIC23B_DEFAULT(AIC23B_PDC);
  pdc.off   = 0;
  pdc.clk   = 0;
  pdc.osc   = 0;
  pdc.out   = 0;
  pdc.dac   = 0;
  pdc.adc   = 0;
#if (AIC23B_INPUT==AIC23B_INPUT_LINE)
  pdc.mic   = 1;
  pdc.line  = 0;
#elif (AIC23B_INPUT==AIC23B_INPUT_MIC)
  pdc.mic   = 0;
  pdc.line  = 1;
#else
  #error No Input defined in file 'conf_tlv320aic23b.h'
#endif
  aic23b_set_power_down_state(pdc);

  aic23b_codec_setup(sample_rate_hz,
                   num_channels,
                   bits_per_sample,
                   swap_channels,
                   callback,
                   callback_opt,
                   pba_hz);

  aic23b_aapc_t aapc;
  aapc.data  = AIC23B_DEFAULT(AIC23B_AAPC);
#if (AIC23B_INPUT==AIC23B_INPUT_LINE)
  aapc.ste   = 0;
  aapc.dac   = 1;
  aapc.byp   = 0;
  aapc.insel = 0;
  aapc.micm  = 0;
  aapc.micb  = 1;
#elif (AIC23B_INPUT==AIC23B_INPUT_MIC)
  aapc.ste   = 0;
  aapc.dac   = 1;
  aapc.sta   = 4;
  aapc.byp   = 0;
  aapc.insel = 1;
  aapc.micm  = 0;
  aapc.micb  = 1;
#else
  #error No Input defined in file 'conf_tlv320aic23b.h'
#endif
  aic23b_set_analog_audio_path(aapc);

  aic23b_dapc_t dapc;
  dapc.data   = AIC23B_DEFAULT(AIC23B_DAPC);
  dapc.dacm   = 0;
  dapc.deemp  = AIC23B_DAPC_DEEMP_NONE;
  dapc.adchp  = 0;
  aic23b_set_digital_audio_path(dapc);


  aic23b_llicvc_t llivc;
  llivc.data  = AIC23B_DEFAULT(AIC23B_LLICVC);
  llivc.liv   = 20;
  llivc.lim   = 0;
  llivc.lrs   = 1;
  aic23b_write_reg(AIC23B_LLICVC, llivc.data);

  aic23b_rlicvc_t rlivc;
  rlivc.data  = AIC23B_DEFAULT(AIC23B_RLICVC);
  rlivc.riv   = 20;
  rlivc.rim   = 0;
  rlivc.rls   = 1;
  aic23b_write_reg(AIC23B_RLICVC, rlivc.data);

  INTC_register_interrupt(&aic23b_ssc_rx_pdca_int_handler,
                          AIC23B_SSC_RX_PDCA_IRQ,
                          AIC23B_SSC_RX_PDCA_INT_LEVEL);

  // set an acceptable start volume
  aic23b_set_headphone_volume(AIC23B_LEFT_CHANNEL | AIC23B_RIGHT_CHANNEL,
                              -30,
                              true);

  aic23b_activate_dig_audio(true);

  INTC_register_interrupt(&aic23b_ssc_tx_pdca_int_handler,
                          AIC23B_SSC_TX_PDCA_IRQ,
                          AIC23B_SSC_TX_PDCA_INT_LEVEL);
}

void aic23b_codec_setup(uint32_t sample_rate_hz,
                      uint8_t num_channels,
                      uint8_t bits_per_sample,
                      bool swap_channels,
                      void (*callback)(uint32_t opt),
                      uint32_t callback_opt,
                      uint32_t pba_hz)
{
  uint32_t master_clock = AIC23B_MCLK_HZ; // default configuration

  // Change the CPU frequency
  //
  //Disable_global_interrupt();

  // Switch to OSC0 during OSC1 transition
  //pm_switch_to_osc0(&AVR32_PM, FOSC0, OSC0_STARTUP);

  // Switch to PLL0 as the master clock
  //pm_switch_to_clock(&AVR32_PM, AVR32_PM_MCCTRL_MCSEL_PLL0);

  if (sample_rate_hz < (8000 + 8021) / 2)
  { // 8000 Hz
  }
  else if (sample_rate_hz < (8021 + 32000) / 2)
  { // 8021 Hz
  }
  else if (sample_rate_hz < (32000 + 44100) / 2)
  { // 32000 Hz
    master_clock = usb_stream_resync_frequency = 8192000;
    cs2200_freq_clk_out(_32_BITS_RATIO(usb_stream_resync_frequency, FOSC0));
    pba_hz = FCPU_HZ = FHSB_HZ = FPBA_HZ = FPBB_HZ = FMCK_HZ(8192000);
  }
  else if (sample_rate_hz < (44100 + 48000) / 2)
  { // 44100 Hz
    master_clock = usb_stream_resync_frequency = 11289600;
    cs2200_freq_clk_out(_32_BITS_RATIO(usb_stream_resync_frequency, FOSC0));
    pba_hz = FCPU_HZ = FHSB_HZ = FPBA_HZ = FPBB_HZ = FMCK_HZ(11289600);
  }
  else if (sample_rate_hz < (48000 + 88200) / 2)
  { // 48000 Hz
    master_clock = usb_stream_resync_frequency = 12288000;
    cs2200_freq_clk_out(_32_BITS_RATIO(usb_stream_resync_frequency, FOSC0));
    pba_hz = FCPU_HZ = FHSB_HZ = FPBA_HZ = FPBB_HZ = FMCK_HZ(12288000);
  }
  else if (sample_rate_hz < (88200 + 96000) / 2)
  { // 88200 Hz
  }
  else
  { // 96000 Hz
  }

  //Enable_global_interrupt();

  ssc_i2s_init(AIC23B_SSC,
               sample_rate_hz,
               bits_per_sample,
               (bits_per_sample <= 16) ? 16 :
               (bits_per_sample <= 20) ? 20 :
               (bits_per_sample <= 24) ? 24 :
                                         32,
               SSC_I2S_MODE_STEREO_OUT_STEREO_IN,
               pba_hz);

  pdca_channel_options_t aic23b_ssc_pdca_options_rx =
  {
    .addr           = NULL,
    .size           = 0,
    .r_addr         = NULL,
    .r_size         = 0,
    .pid            = AIC23B_SSC_RX_PDCA_PID,
    .transfer_size  = (bits_per_sample <=  8) ? PDCA_TRANSFER_SIZE_BYTE      :
                      (bits_per_sample <= 16) ? PDCA_TRANSFER_SIZE_HALF_WORD :
                                                PDCA_TRANSFER_SIZE_WORD

  };
  pdca_init_channel(AIC23B_SSC_RX_PDCA_CHANNEL, &aic23b_ssc_pdca_options_rx);
  pdca_enable(AIC23B_SSC_RX_PDCA_CHANNEL);

  pdca_channel_options_t aic23b_ssc_pdca_options_tx =
  {
    .addr           = NULL,
    .size           = 0,
    .r_addr         = NULL,
    .r_size         = 0,
    .pid            = AIC23B_SSC_TX_PDCA_PID,
    .transfer_size  = (bits_per_sample <=  8) ? PDCA_TRANSFER_SIZE_BYTE      :
                      (bits_per_sample <= 16) ? PDCA_TRANSFER_SIZE_HALF_WORD :
                                                PDCA_TRANSFER_SIZE_WORD
  };
  pdca_init_channel(AIC23B_SSC_TX_PDCA_CHANNEL, &aic23b_ssc_pdca_options_tx);
  pdca_enable(AIC23B_SSC_TX_PDCA_CHANNEL);

  // Set codec frequency
  aic23b_configure_freq(master_clock, sample_rate_hz);

  aic23b_daif_t daif;
  daif.data   = AIC23B_DEFAULT(AIC23B_DAIF);
  daif.ms     = AIC23B_DAIF_MS_SLAVE;
  daif.lrswap = swap_channels;
  daif.lrp    = 0;
  daif.iwl    = (bits_per_sample <= 16) ? AIC23B_DAIF_IWL_16 :
                (bits_per_sample <= 20) ? AIC23B_DAIF_IWL_20 :
                (bits_per_sample <= 24) ? AIC23B_DAIF_IWL_24 :
                                          AIC23B_DAIF_IWL_32;
  daif.fmt    = AIC23B_DAIF_FMT_I2S;
  aic23b_write_reg(AIC23B_DAIF, daif.data);

  aic23b_output_params.num_channels              = num_channels;
  aic23b_output_params.callback                  = callback;
  aic23b_output_params.callback_opt              = callback_opt;
}

void aic23b_codec_flush(void)
{
  pdca_disable_interrupt_transfer_complete(AIC23B_SSC_RX_PDCA_CHANNEL);
  while (!(pdca_get_transfer_status(AIC23B_SSC_RX_PDCA_CHANNEL) &
           PDCA_TRANSFER_COMPLETE));
  pdca_disable_interrupt_transfer_complete(AIC23B_SSC_TX_PDCA_CHANNEL);
  while (!(pdca_get_transfer_status(AIC23B_SSC_TX_PDCA_CHANNEL) &
           PDCA_TRANSFER_COMPLETE));
}

void aic23b_codec_stop(void)
{
  aic23b_codec_flush();

  aic23b_reset();

  aic23b_pdc_t pdc;
  pdc.data  = AIC23B_DEFAULT(AIC23B_PDC);
  pdc.off   = 1;
  pdc.clk   = 1;
  pdc.osc   = 1;
  pdc.out   = 1;
  pdc.dac   = 1;
  pdc.adc   = 1;
  pdc.mic   = 1;
  pdc.line  = 1;
  aic23b_set_power_down_state(pdc);

  pdca_disable(AIC23B_SSC_RX_PDCA_CHANNEL);
  pdca_disable(AIC23B_SSC_TX_PDCA_CHANNEL);

  ssc_i2s_reset(AIC23B_SSC);

  gpio_enable_gpio(AIC23B_SSC_CODEC_GPIO_MAP,
                   sizeof(AIC23B_SSC_CODEC_GPIO_MAP) / sizeof(AIC23B_SSC_CODEC_GPIO_MAP[0]));

  aic23b_output_params.num_channels             = 0;
  aic23b_output_params.callback                 = NULL;
  aic23b_output_params.callback_opt             = 0;
}