#include "bsp_aic3204.h"
#include "FreeRTOS.h"
#include "task.h"
#include "elog.h"

static const char *TAG = "bsp_aic3204";

#define BSP_AIC3204_I2C_ADDR 0x30

static HAL_StatusTypeDef bsp_aic3204_write_reg(I2C_HandleTypeDef *hi2c, uint8_t reg_addr, uint8_t reg_value)
{
  HAL_StatusTypeDef status = HAL_I2C_Mem_Write(hi2c, BSP_AIC3204_I2C_ADDR, reg_addr, 1, &reg_value, 1, 100);

  if (status == HAL_OK) {
    // elog_debug(TAG, "write register 0x%02X@0x%02X success", reg_value, reg_addr);
  } else {
    elog_error(TAG, "write register 0x%02X@0x%02X failed", reg_value, reg_addr);
  }

  return status;
}

// static HAL_StatusTypeDef bsp_aic3204_read_reg(I2C_HandleTypeDef *hi2c, uint8_t reg_addr, uint8_t *reg_value_out)
// {
//   HAL_StatusTypeDef status = HAL_I2C_Mem_Read(hi2c, BSP_AIC3204_I2C_ADDR, reg_addr, 1, reg_value_out, 1, 10);

//   if (status == HAL_OK) {
//     elog_debug(TAG, "read register 0x%02X@0x%02X success", *reg_value_out, reg_addr);
//   } else {
//     elog_error(TAG, "read register @0x%02X failed", reg_addr);
//   }

//   return status;
// }

HAL_StatusTypeDef bsp_aic3204_set_fs(I2C_HandleTypeDef *hi2c, uint32_t fs_hz)
{
  uint16_t n_dac;
  uint16_t pll_j, pll_d;
  uint16_t prb_no;

  switch (fs_hz) {
  case 11025:
  case 22050:
  case 44100:
  case 88200:
  case 176400:
    pll_j = 7;
    pll_d = 3500; //PLL输出的时钟频率CODEC_CLKIN=11.2896MHz*8
    n_dac = (8 * 4) / (fs_hz / 11025);
    break;
  case 12000:
  case 24000:
  case 48000:
  case 96000:
  case 192000:
    pll_j = 8;
    pll_d = 0;  //PLL输出的时钟频率CODEC_CLKIN=12.288MHz*8
    n_dac = (8 * 4) / (fs_hz / 12000);
    break;
  case 8000:
  case 16000:
  case 32000:
    pll_j = 8;
    pll_d = 0;  //PLL输出的时钟频率CODEC_CLKIN=12.288MHz*8
    /* PLL输出的时钟频率CODEC_CLKIN=11.2896MHz*8 */
    n_dac = (8 * 6) / (fs_hz / 8000);
    break;
  default:
    elog_error(TAG, "bsp_aic3204_set_fs: unsupported sample rate: %dHz", fs_hz);
    return HAL_ERROR;
  }

  if (fs_hz <= 48000) {
    prb_no = 1;
  } else if (fs_hz <= 96000) {
    prb_no = 9;
  } else {
    prb_no = 19;
  }

  // 设置PLL_J
  bsp_aic3204_write_reg(hi2c, 0x06, pll_j);
  // 设置PLL_D
  bsp_aic3204_write_reg(hi2c, 0x07, pll_d >> 8);
  bsp_aic3204_write_reg(hi2c, 0x08, pll_d & 0xFF);
  // 启动NDAC分频器并设置分频值
  bsp_aic3204_write_reg(hi2c, 0x0b, 0x80 | n_dac);
  // 设置DAC信号处理块(PRB)
  bsp_aic3204_write_reg(hi2c, 0x3C, prb_no);

  elog_info(TAG, "bsp_aic3204_set_fs: sample rate: %dHz, NDAC=%d, PLL J.D=%d.%d", fs_hz, n_dac, pll_j, pll_d);
  return HAL_OK;
}

HAL_StatusTypeDef bsp_aic3204_init(I2C_HandleTypeDef *hi2c)
{
  // 选择寄存器页0
  // bsp_aic3204_write_reg(hi2c, 0x00, 0x00);
  // 软件复位芯片
  // bsp_aic3204_write_reg(hi2c, 0x01, 0x01);

  // 硬件复位芯片
  HAL_GPIO_WritePin(CODEC_RST_GPIO_Port, CODEC_RST_Pin, GPIO_PIN_RESET);
  vTaskDelay(pdMS_TO_TICKS(10));
  HAL_GPIO_WritePin(CODEC_RST_GPIO_Port, CODEC_RST_Pin, GPIO_PIN_SET);
  vTaskDelay(pdMS_TO_TICKS(10));

  /*
   * 时钟结构
   *       PLL_CLKIN        PLL_CLK                /NDAC            /MDAC                /DOSR
   * MFP5 -----------> PLL ---------> CODEC_CLKIN -------> DAC_CLK -------> DAC_MOD_CLK -------> DAC_FS
   *                                                          |
   *                                                           -------------> BCLK -----------------------> WCLK
   *                                                            /BDIV_CLKIN         /SAMPLE_BITS/CHANNELS
   *
   * 举例如下
   *                         /1              /2                /128
   * MFP5 ----> CODEC_CLKIN ---->  DAC_CLK  ----> DAC_MOD_CLK ------> DAC_FS
   *             12.288MHz        12.288MHz        6.144MHz           48kHz
   *                                  |
   *                                   ---->   BCLK   -------> WCLK
   *                                    /8   1.536MHz  /16/2   48kHz
   *
   * BDIV_CLKIN = MDAC * DOSR / SAMPLE_BITS / CHANNELS
   */

  /*
  uint16_t n_dac = 1;
  uint16_t m_dac = 2;
  uint16_t dac_osr = 128;
  uint16_t bdiv_clkin = m_dac * dac_osr / 16 / 2;

  // 选择寄存器页0
  bsp_aic3204_write_reg(hi2c, 0x00, 0x00);
  // MFP5用于时钟输入
  bsp_aic3204_write_reg(hi2c, 0x34, 0x04);
  // 选择GPIO输入为Codec主时钟源
  bsp_aic3204_write_reg(hi2c, 0x04, 0x02);
  // 启动NDAC分频器并设置分频值为1
  bsp_aic3204_write_reg(hi2c, 0x0b, 0x80 | n_dac);
  // 启动MDAC分频器并设置分频值为2
  bsp_aic3204_write_reg(hi2c, 0x0c, 0x80 | m_dac);
  // 设置DAC的超采样率(OSR)为128
  bsp_aic3204_write_reg(hi2c, 0x0d, (dac_osr >> 8) & 0x03);
  bsp_aic3204_write_reg(hi2c, 0x0e, dac_osr & 0xFF);
  // 总线类型I2S 数据长度16位 BCLK方向为输出 WCLK方向为输出
  bsp_aic3204_write_reg(hi2c, 0x1b, 0x0D);
  // 设置DAC信号处理块(PRB)为PRB_1
  bsp_aic3204_write_reg(hi2c, 0x3c, 0x01);
  // 选择DAC_CLK做为BDIV_CLKIN
  bsp_aic3204_write_reg(hi2c, 0x1D, 0x00);
  // 启用对外WCLK与BCLK时钟输出 CODEC_CLKIN与BCLK的商为每个采样的大小 即声道数与DAC位数的乘积
  bsp_aic3204_write_reg(hi2c, 0x1E, 0x80 | bdiv_clkin);
  */

  // 选择寄存器页0
  bsp_aic3204_write_reg(hi2c, 0x00, 0x00);
  // MFP5用于时钟输入
  bsp_aic3204_write_reg(hi2c, 0x34, 0x04);
  // 选择GPIO输入为PLL时钟源 选择PLL输出为Codec主时钟源
  bsp_aic3204_write_reg(hi2c, 0x04, 0x02 << 2 | 0x03 << 0);
  // 启动PLL并设置PLL_P=1 PLL_R=1
  bsp_aic3204_write_reg(hi2c, 0x05, 0x80 | 1 << 4 | 1 << 0);
  // 设置PLL_J=7
  bsp_aic3204_write_reg(hi2c, 0x06, 0x07);
  // 设置PLL_D=3500
  bsp_aic3204_write_reg(hi2c, 0x07, 3500 >> 8);
  bsp_aic3204_write_reg(hi2c, 0x08, 3500 & 0xFF);
  // 启动NDAC分频器并设置分频值为8
  bsp_aic3204_write_reg(hi2c, 0x0B, 0x80 | 8);
  // 启动MDAC分频器并设置分频值为2
  bsp_aic3204_write_reg(hi2c, 0x0C, 0x80 | 2);
  // 设置DAC的超采样率(OSR)为128
  bsp_aic3204_write_reg(hi2c, 0x0D, 128 >> 8);
  bsp_aic3204_write_reg(hi2c, 0x0E, 128 & 0xFF);
  // 总线类型I2S 数据长度16位 BCLK方向为输出 WCLK方向为输出
  bsp_aic3204_write_reg(hi2c, 0x1B, 0x0D);
  // 选择DAC_CLK做为BDIV_CLKIN
  bsp_aic3204_write_reg(hi2c, 0x1D, 0x00);
  // 启用对外WCLK与BCLK时钟输出 CODEC_CLKIN与BCLK的商为每个采样的大小 即声道数与DAC位数的乘积
  bsp_aic3204_write_reg(hi2c, 0x1E, 0x80 | 8);
  // 设置DAC信号处理块(PRB)为PRB_1
  bsp_aic3204_write_reg(hi2c, 0x3C, 1);

  // 设置左DAC音量
  bsp_aic3204_write_reg(hi2c, 0x41, (uint8_t)-64);
  // 设置右DAC音量
  bsp_aic3204_write_reg(hi2c, 0x42, (uint8_t)-64);

  // 选择寄存器页1
  bsp_aic3204_write_reg(hi2c, 0x00, 0x01);
  // 关闭内部AVDD微供电
  bsp_aic3204_write_reg(hi2c, 0x01, 0x08);
  // 内部LDO上电 DVDD=1.72V AVDD=1.72V
  bsp_aic3204_write_reg(hi2c, 0x02, 0x01);
  // Set the REF charging time to 40ms
  bsp_aic3204_write_reg(hi2c, 0x7b, 0x01);
  // HP soft stepping settings for optimal pop performance at power up
  // Rpop used is 6k with N = 6 and soft step = 20usec. This should work with 47uF coupling capacitor.
  // Can try N=5,6 or 7 time constants as well. Trade-off delay vs “pop” sound.
  bsp_aic3204_write_reg(hi2c, 0x14, 0x25);
  // Set the Input Common Mode to 0.9V and Output Common Mode for Headphone to Input Common Mode
  bsp_aic3204_write_reg(hi2c, 0x0A, 0x00);
  // Route Left DAC to HPL
  bsp_aic3204_write_reg(hi2c, 0x0c, 0x08);
  // Route Right DAC to HPR
  bsp_aic3204_write_reg(hi2c, 0x0d, 0x08);
  // Set the DAC PTM mode to PTM_P3/4
  bsp_aic3204_write_reg(hi2c, 0x03, 0x00);
  bsp_aic3204_write_reg(hi2c, 0x04, 0x00);
  // Set the HPL gain to 0dB
  bsp_aic3204_write_reg(hi2c, 0x10, 0x00);
  // Set the HPR gain to 0dB
  bsp_aic3204_write_reg(hi2c, 0x11, 0x00);

  // 左声道DAC输出到LOL
  bsp_aic3204_write_reg(hi2c, 0x0E, 0x08);
  // 右声道DAC输出到LOR
  bsp_aic3204_write_reg(hi2c, 0x0F, 0x08);
  // 左声道DAC输出到LOL 增益-6dB
  bsp_aic3204_write_reg(hi2c, 0x12, 0x00);
  // 右声道DAC输出到LOR 增益-6dB
  bsp_aic3204_write_reg(hi2c, 0x13, 0x00);

  // 启动HPL HPR LOL LOR驱动器
  bsp_aic3204_write_reg(hi2c, 0x09, 0x3C);
  // Wait for 2.5 sec for soft stepping to take effect
  vTaskDelay(pdMS_TO_TICKS(1000));

  // 选择寄存器页0
  bsp_aic3204_write_reg(hi2c, 0x00, 0x00);
  // Power up the Left and Right DAC Channels with route the Left Audio digital data to Left Channel DAC and Right Audio digital data to Right Channel DAC
  bsp_aic3204_write_reg(hi2c, 0x3f, 0xd6);
  // Unmute the DAC digital volume control
  bsp_aic3204_write_reg(hi2c, 0x40, 0x00);

  elog_info(TAG, "bsp_aic3204_init: codec initialized");
  return HAL_OK;
}
