318 lines
8.3 KiB
C
318 lines
8.3 KiB
C
#include "bsp_wm8904.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "FreeRTOS.h"
|
|
#include "task.h"
|
|
#include "elog.h"
|
|
|
|
static const char *TAG = "bsp_wm8904";
|
|
|
|
#define BSP_WM8904_I2C_ADDR 0x34
|
|
|
|
/*******************************************************************************
|
|
* Definitions
|
|
******************************************************************************/
|
|
|
|
#define WM8904_RESET (0x00)
|
|
#define WM8904_ANALOG_ADC_0 (0x0A)
|
|
#define WM8904_POWER_MGMT_0 (0x0C)
|
|
#define WM8904_POWER_MGMT_2 (0x0E)
|
|
#define WM8904_POWER_MGMT_6 (0x12)
|
|
#define WM8904_CLK_RATES_0 (0x14)
|
|
#define WM8904_CLK_RATES_1 (0x15)
|
|
#define WM8904_CLK_RATES_2 (0x16)
|
|
#define WM8904_AUDIO_IF_0 (0x18)
|
|
#define WM8904_AUDIO_IF_1 (0x19)
|
|
#define WM8904_AUDIO_IF_2 (0x1A)
|
|
#define WM8904_AUDIO_IF_3 (0x1B)
|
|
#define WM8904_DAC_DIG_1 (0x21)
|
|
#define WM8904_ANALOG_LEFT_IN_0 (0x2C)
|
|
#define WM8904_ANALOG_RIGHT_IN_0 (0x2D)
|
|
#define WM8904_ANALOG_LEFT_IN_1 (0x2E)
|
|
#define WM8904_ANALOG_RIGHT_IN_1 (0x2F)
|
|
#define WM8904_ANALOG_OUT1_LEFT (0x39)
|
|
#define WM8904_ANALOG_OUT1_RIGHT (0x3A)
|
|
#define WM8904_ANALOG_OUT2_LEFT (0x3B)
|
|
#define WM8904_ANALOG_OUT2_RIGHT (0x3C)
|
|
#define WM8904_ANALOG_OUT12_ZC (0x3D)
|
|
#define WM8904_DC_SERVO_0 (0x43)
|
|
#define WM8904_DC_SERVO_1 (0x44)
|
|
#define WM8904_ANALOG_HP_0 (0x5A)
|
|
#define WM8904_CHRG_PUMP_0 (0x62)
|
|
#define WM8904_CLS_W_0 (0x68)
|
|
#define WM8904_WRT_SEQUENCER_0 (0x6C)
|
|
#define WM8904_WRT_SEQUENCER_3 (0x6F)
|
|
#define WM8904_WRT_SEQUENCER_4 (0x70)
|
|
|
|
/*******************************************************************************
|
|
* Code
|
|
******************************************************************************/
|
|
|
|
HAL_StatusTypeDef WM8904_WriteRegister(I2C_HandleTypeDef *hi2c, uint8_t reg_addr, uint16_t reg_value)
|
|
{
|
|
HAL_StatusTypeDef status;
|
|
uint8_t reg_bytes[2] = { reg_value >> 8, reg_value & 0xFF };
|
|
|
|
uint8_t retries = 0;
|
|
while (1) {
|
|
status = HAL_I2C_Mem_Write(hi2c, BSP_WM8904_I2C_ADDR, reg_addr, 1, reg_bytes, sizeof(reg_bytes), 100);
|
|
|
|
if (status == HAL_OK) {
|
|
elog_debug(TAG, "write register@0x%02X success, value=0x%04X", reg_addr, reg_value);
|
|
break;
|
|
} else {
|
|
elog_error(TAG, "write register@0x%02X failed", reg_addr);
|
|
I2C_RESET_CR2(hi2c);
|
|
retries ++;
|
|
if (retries > 10) {
|
|
break;
|
|
}
|
|
vTaskDelay(pdMS_TO_TICKS(10));
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
HAL_StatusTypeDef WM8904_ReadRegister(I2C_HandleTypeDef *hi2c, uint8_t reg_addr, uint16_t *reg_value_out)
|
|
{
|
|
HAL_StatusTypeDef status;
|
|
uint8_t reg_bytes[2] = { 0 };
|
|
|
|
uint8_t retries = 0;
|
|
while (1) {
|
|
status = HAL_I2C_Mem_Read(hi2c, BSP_WM8904_I2C_ADDR, reg_addr, 1, reg_bytes, sizeof(reg_bytes), 100);
|
|
*reg_value_out = (reg_bytes[0] << 8) | reg_bytes[1];
|
|
|
|
if (status == HAL_OK) {
|
|
elog_debug(TAG, "read register@0x%02X success, value=0x%04X", reg_addr, *reg_value_out);
|
|
break;
|
|
} else {
|
|
elog_error(TAG, "read register@0x%02X failed", reg_addr);
|
|
I2C_RESET_CR2(hi2c);
|
|
retries ++;
|
|
if (retries > 10) {
|
|
break;
|
|
}
|
|
vTaskDelay(pdMS_TO_TICKS(10));
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
HAL_StatusTypeDef WM8904_ModifyRegister(I2C_HandleTypeDef *hi2c, uint8_t reg, uint16_t mask, uint16_t value)
|
|
{
|
|
uint16_t reg_value;
|
|
HAL_StatusTypeDef ret;
|
|
|
|
ret = WM8904_ReadRegister(hi2c, reg, ®_value);
|
|
if(ret != HAL_OK) {
|
|
return ret;
|
|
}
|
|
|
|
reg_value &= (uint16_t)~mask;
|
|
reg_value |= value;
|
|
|
|
return WM8904_WriteRegister(hi2c, reg, reg_value);
|
|
}
|
|
|
|
HAL_StatusTypeDef WM8904_WaitOnWriteSequencer(I2C_HandleTypeDef *hi2c)
|
|
{
|
|
HAL_StatusTypeDef result;
|
|
uint16_t value;
|
|
|
|
do {
|
|
vTaskDelay(pdMS_TO_TICKS(20));
|
|
result = WM8904_ReadRegister(hi2c, WM8904_WRT_SEQUENCER_4, &value);
|
|
} while ((result == HAL_OK) && (value & 0x0001));
|
|
|
|
return result;
|
|
}
|
|
|
|
HAL_StatusTypeDef WM8904_Init(I2C_HandleTypeDef *hi2c)
|
|
{
|
|
HAL_StatusTypeDef result;
|
|
|
|
elog_info(TAG, "configuring codec");
|
|
|
|
/* reset */
|
|
result = WM8904_WriteRegister(hi2c, WM8904_RESET, 0x0000);
|
|
if (result != HAL_OK) {
|
|
return result;
|
|
}
|
|
|
|
/* MCLK_INV=0, SYSCLK_SRC=0, TOCLK_RATE=1, OPCLK_ENA=0,
|
|
* CLK_SYS_ENA=1, CLK_DSP_ENA=1, TOCLK_ENA=1 */
|
|
result = WM8904_WriteRegister(hi2c, WM8904_CLK_RATES_2, 0x1007);
|
|
if (result != HAL_OK) {
|
|
return result;
|
|
}
|
|
|
|
/* Set Clock ratio and sample rate */
|
|
result = WM8904_WriteRegister(hi2c, WM8904_CLK_RATES_1, 0x0C05); //sysclk/fs=256, sample_rate=44-48khz
|
|
if (result != HAL_OK) {
|
|
return result;
|
|
}
|
|
|
|
/* WSEQ_ENA=1, WSEQ_WRITE_INDEX=0_0000 */
|
|
result = WM8904_WriteRegister(hi2c, WM8904_WRT_SEQUENCER_0, 0x0100);
|
|
if (result != HAL_OK) {
|
|
return result;
|
|
}
|
|
|
|
/* WSEQ_ABORT=0, WSEQ_START=1, WSEQ_START_INDEX=00_0000 */
|
|
result = WM8904_WriteRegister(hi2c, WM8904_WRT_SEQUENCER_3, 0x0100);
|
|
if (result != HAL_OK) {
|
|
return result;
|
|
}
|
|
|
|
result = WM8904_WaitOnWriteSequencer(hi2c);
|
|
if (result != HAL_OK) {
|
|
return result;
|
|
}
|
|
|
|
/* TOCLK_RATE_DIV16=0, TOCLK_RATE_x4=0, SR_MODE=0, MCLK_DIV=0
|
|
* (Required for MMCs: SGY, KRT see erratum CE000546) */
|
|
result = WM8904_WriteRegister(hi2c, WM8904_CLK_RATES_0, 0x845E);
|
|
if (result != HAL_OK) {
|
|
return result;
|
|
}
|
|
|
|
/* HPL_PGA_ENA=1, HPR_PGA_ENA=1 */
|
|
// result = WM8904_WriteRegister(hi2c, WM8904_POWER_MGMT_2, 0x0003);
|
|
// if (result != HAL_OK) {
|
|
// return result;
|
|
// }
|
|
|
|
/* DACL_ENA=1, DACR_ENA=1 */
|
|
// result = WM8904_WriteRegister(hi2c, WM8904_POWER_MGMT_6, 0x000C);
|
|
// if (result != HAL_OK) {
|
|
// return result;
|
|
// }
|
|
|
|
/* BCLK_DIR=1 (output), AIF_WL=00 (16-bits) */
|
|
result = WM8904_WriteRegister(hi2c, WM8904_AUDIO_IF_1, 0x0002 | (1ul << 6)); //16bits, I2S
|
|
if (result != HAL_OK) {
|
|
return result;
|
|
}
|
|
|
|
/* BCLK_DIV=(sysclk/8) */
|
|
result = WM8904_WriteRegister(hi2c, WM8904_AUDIO_IF_2, 0x0008);
|
|
if (result != HAL_OK) {
|
|
return result;
|
|
}
|
|
|
|
/* LRCLK_DIR=1 (output), LRCLK_RATE=(BCLK/32) */
|
|
result = WM8904_WriteRegister(hi2c, WM8904_AUDIO_IF_3, 0x0020 | (1ul << 11));
|
|
if (result != HAL_OK) {
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
|
|
/* FLL_FRACN_EN=1 */
|
|
result = WM8904_WriteRegister(hi2c, 0x74, (1ul << 2));
|
|
if (result != HAL_OK) {
|
|
return result;
|
|
}
|
|
|
|
/* FLL_OUTDIV=000111 (divice by 8), FLL_CTRL_RATE=000 (FVCO/1), FLL_FRATIO=000 (divide by 1) */
|
|
result = WM8904_WriteRegister(hi2c, 0x75, (7ul << 8));
|
|
if (result != HAL_OK) {
|
|
return result;
|
|
}
|
|
|
|
/* FLL_K=0.35 */
|
|
result = WM8904_WriteRegister(hi2c, 0x76, 0x599A);
|
|
if (result != HAL_OK) {
|
|
return result;
|
|
}
|
|
|
|
/* FLL_N=7 */
|
|
result = WM8904_WriteRegister(hi2c, 0x77, 7ul << 5);
|
|
if (result != HAL_OK) {
|
|
return result;
|
|
}
|
|
|
|
/* MCLK_INV=0, SYSCLK_SRC=1, TOCLK_RATE=1, OPCLK_ENA=0,
|
|
* CLK_SYS_ENA=1, CLK_DSP_ENA=1, TOCLK_ENA=1 */
|
|
result = WM8904_WriteRegister(hi2c, WM8904_CLK_RATES_2, 0x1007 | (1ul << 14)); //sysclk connects to fll output
|
|
if (result != HAL_OK) {
|
|
return result;
|
|
}
|
|
|
|
/* FLL_FRACN_EN=1, FLL_ENA=1 */
|
|
result = WM8904_WriteRegister(hi2c, 0x74, (1ul << 2) | (1ul << 0));
|
|
if (result != HAL_OK) {
|
|
return result;
|
|
}
|
|
|
|
vTaskDelay(pdMS_TO_TICKS(100));
|
|
|
|
|
|
|
|
|
|
|
|
/* DAC_MONO=0, DAC_SB_FILT-0, DAC_MUTERATE=0, DAC_UNMUTE RAMP=0,
|
|
* DAC_OSR128=1, DAC_MUTE=0, DEEMPH=0 (none) */
|
|
result = WM8904_WriteRegister(hi2c, WM8904_DAC_DIG_1, 0x0040); //unmute DAC
|
|
if (result != HAL_OK) {
|
|
return result;
|
|
}
|
|
|
|
/* HPL_RMV_SHORT=1, HPL_ENA_OUTP=1, HPL_ENA_DLY=1, HPL_ENA=1,
|
|
* HPR_RMV_SHORT=1, HPR_ENA_OUTP=1, HPR_ENA_DLY=1, HPR_ENA=1 */
|
|
result = WM8904_WriteRegister(hi2c, WM8904_ANALOG_HP_0, 0x00FF);
|
|
if (result != HAL_OK) {
|
|
return result;
|
|
}
|
|
|
|
/* CP_DYN_PWR=1 */
|
|
result = WM8904_WriteRegister(hi2c, WM8904_CLS_W_0, 0x0001);
|
|
if (result != HAL_OK) {
|
|
return result;
|
|
}
|
|
|
|
/* CP_ENA=1 */
|
|
// result = WM8904_WriteRegister(hi2c, WM8904_CHRG_PUMP_0, 0x0001);
|
|
// if (result != HAL_OK) {
|
|
// return result;
|
|
// }
|
|
|
|
result = WM8904_SetVolume(&hi2c1, 30);
|
|
if (result != HAL_OK) {
|
|
return result;
|
|
}
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
HAL_StatusTypeDef WM8904_SetVolume(I2C_HandleTypeDef *hi2c, uint16_t volume)
|
|
{
|
|
HAL_StatusTypeDef result;
|
|
|
|
result = WM8904_WriteRegister(hi2c, WM8904_ANALOG_OUT1_LEFT, volume);
|
|
if (result != HAL_OK) {
|
|
return result;
|
|
}
|
|
|
|
result = WM8904_WriteRegister(hi2c, WM8904_ANALOG_OUT1_RIGHT, volume | 1ul << 7);
|
|
if (result != HAL_OK) {
|
|
return result;
|
|
}
|
|
|
|
result = WM8904_WriteRegister(hi2c, WM8904_ANALOG_OUT2_LEFT, volume);
|
|
if (result != HAL_OK) {
|
|
return result;
|
|
}
|
|
|
|
result = WM8904_WriteRegister(hi2c, WM8904_ANALOG_OUT2_RIGHT, volume | 1ul << 7);
|
|
if (result != HAL_OK) {
|
|
return result;
|
|
}
|
|
|
|
return HAL_OK;
|
|
}
|