4399 lines
136 KiB
C
4399 lines
136 KiB
C
/***************************************************************************
|
|
*
|
|
* Copyright 2015-2019 BES.
|
|
* All rights reserved. All unpublished rights reserved.
|
|
*
|
|
* No part of this work may be used or reproduced in any form or by any
|
|
* means, or stored in a database or retrieval system, without prior written
|
|
* permission of BES.
|
|
*
|
|
* Use of this work is governed by a license granted by BES.
|
|
* This work contains confidential and proprietary information of
|
|
* BES. which is protected by copyright, trade secret,
|
|
* trademark and other intellectual property rights.
|
|
*
|
|
****************************************************************************/
|
|
#include "plat_addr_map.h"
|
|
#include CHIP_SPECIFIC_HDR(reg_codec)
|
|
#include "analog.h"
|
|
#include "cmsis.h"
|
|
#include "hal_aud.h"
|
|
#include "hal_cmu.h"
|
|
#include "hal_codec.h"
|
|
#include "hal_psc.h"
|
|
#include "hal_timer.h"
|
|
#include "hal_trace.h"
|
|
#include "string.h"
|
|
#include "tgt_hardware.h"
|
|
#ifdef RTOS
|
|
#include "cmsis_os.h"
|
|
#endif
|
|
#include "hal_chipid.h"
|
|
|
|
#define NO_DAC_RESET
|
|
|
|
#define SDM_MUTE_NOISE_SUPPRESSION
|
|
|
|
#ifndef CODEC_OUTPUT_DEV
|
|
#define CODEC_OUTPUT_DEV CFG_HW_AUD_OUTPUT_PATH_SPEAKER_DEV
|
|
#endif
|
|
#if ((CODEC_OUTPUT_DEV & CFG_HW_AUD_OUTPUT_PATH_SPEAKER_DEV) == 0)
|
|
#ifndef AUDIO_OUTPUT_SWAP
|
|
#define AUDIO_OUTPUT_SWAP
|
|
#endif
|
|
#endif
|
|
|
|
#if (defined(__TWS__) || defined(IBRT)) && defined(ANC_APP)
|
|
//#define CODEC_TIMER
|
|
#endif
|
|
|
|
#ifdef CODEC_DSD
|
|
#ifdef ANC_APP
|
|
#error "ANC_APP conflicts with CODEC_DSD"
|
|
#endif
|
|
#ifdef AUDIO_ANC_FB_MC
|
|
#error "AUDIO_ANC_FB_MC conflicts with CODEC_DSD"
|
|
#endif
|
|
#ifdef __AUDIO_RESAMPLE__
|
|
#error "__AUDIO_RESAMPLE__ conflicts with CODEC_DSD"
|
|
#endif
|
|
#endif
|
|
|
|
#define RS_CLOCK_FACTOR 200
|
|
|
|
// Trigger DMA request when TX-FIFO *empty* count > threshold
|
|
#define HAL_CODEC_TX_FIFO_TRIGGER_LEVEL (3)
|
|
// Trigger DMA request when RX-FIFO count >= threshold
|
|
#define HAL_CODEC_RX_FIFO_TRIGGER_LEVEL (4)
|
|
|
|
#define MAX_DIG_DBVAL (50)
|
|
#define ZERODB_DIG_DBVAL (0)
|
|
#define MIN_DIG_DBVAL (-99)
|
|
|
|
#define MAX_SIDETONE_DBVAL (30)
|
|
#define MIN_SIDETONE_DBVAL (-30)
|
|
#define SIDETONE_DBVAL_STEP (-2)
|
|
|
|
#define MAX_SIDETONE_REGVAL (0)
|
|
#define MIN_SIDETONE_REGVAL (30)
|
|
#define MUTE_SIDETONE_REGVAL (31)
|
|
|
|
#ifndef MC_DELAY_COMMON
|
|
#define MC_DELAY_COMMON 28
|
|
#endif
|
|
|
|
#ifndef CODEC_DIGMIC_PHASE
|
|
#define CODEC_DIGMIC_PHASE 7
|
|
#endif
|
|
|
|
#define ADC_IIR_CH_NUM 2
|
|
|
|
#define MAX_DIG_MIC_CH_NUM 5
|
|
|
|
#define NORMAL_ADC_CH_NUM 5
|
|
// Echo cancel ADC channel number
|
|
#define EC_ADC_CH_NUM 2
|
|
#define MAX_ADC_CH_NUM (NORMAL_ADC_CH_NUM + EC_ADC_CH_NUM)
|
|
|
|
#define MAX_DAC_CH_NUM 2
|
|
|
|
#ifdef CODEC_DSD
|
|
#define NORMAL_MIC_MAP \
|
|
(AUD_CHANNEL_MAP_NORMAL_ALL & \
|
|
~(AUD_CHANNEL_MAP_CH5 | AUD_CHANNEL_MAP_CH6 | AUD_CHANNEL_MAP_CH7 | \
|
|
AUD_CHANNEL_MAP_DIGMIC_CH5 | AUD_CHANNEL_MAP_DIGMIC_CH6 | \
|
|
AUD_CHANNEL_MAP_DIGMIC_CH7 | AUD_CHANNEL_MAP_DIGMIC_CH2 | \
|
|
AUD_CHANNEL_MAP_DIGMIC_CH3))
|
|
#else
|
|
#define NORMAL_MIC_MAP \
|
|
(AUD_CHANNEL_MAP_NORMAL_ALL & \
|
|
~(AUD_CHANNEL_MAP_CH5 | AUD_CHANNEL_MAP_CH6 | AUD_CHANNEL_MAP_CH7 | \
|
|
AUD_CHANNEL_MAP_DIGMIC_CH5 | AUD_CHANNEL_MAP_DIGMIC_CH6 | \
|
|
AUD_CHANNEL_MAP_DIGMIC_CH7))
|
|
#endif
|
|
#define NORMAL_ADC_MAP \
|
|
(AUD_CHANNEL_MAP_CH0 | AUD_CHANNEL_MAP_CH1 | AUD_CHANNEL_MAP_CH2 | \
|
|
AUD_CHANNEL_MAP_CH3 | AUD_CHANNEL_MAP_CH4)
|
|
|
|
#define EC_MIC_MAP (AUD_CHANNEL_MAP_ECMIC_CH0 | AUD_CHANNEL_MAP_ECMIC_CH1)
|
|
#define EC_ADC_MAP (AUD_CHANNEL_MAP_CH5 | AUD_CHANNEL_MAP_CH6)
|
|
|
|
#define VALID_MIC_MAP (NORMAL_MIC_MAP | EC_MIC_MAP)
|
|
#define VALID_ADC_MAP (NORMAL_ADC_MAP | EC_ADC_MAP)
|
|
|
|
#define VALID_SPK_MAP (AUD_CHANNEL_MAP_CH0 | AUD_CHANNEL_MAP_CH1)
|
|
#define VALID_DAC_MAP VALID_SPK_MAP
|
|
|
|
#if (CFG_HW_AUD_OUTPUT_PATH_SPEAKER_DEV & ~VALID_SPK_MAP)
|
|
#error "Invalid CFG_HW_AUD_OUTPUT_PATH_SPEAKER_DEV"
|
|
#endif
|
|
#if (CODEC_OUTPUT_DEV & ~VALID_SPK_MAP)
|
|
#error "Invalid CODEC_OUTPUT_DEV"
|
|
#endif
|
|
|
|
#define RSTN_ADC_FREE_RUNNING_CLK CODEC_SOFT_RSTN_ADC(1 << NORMAL_ADC_CH_NUM)
|
|
|
|
#if defined(SPEECH_SIDETONE) && \
|
|
(defined(CFG_HW_AUD_SIDETONE_MIC_DEV) && (CFG_HW_AUD_SIDETONE_MIC_DEV)) && \
|
|
defined(CFG_HW_AUD_SIDETONE_GAIN_DBVAL)
|
|
#define SIDETONE_ENABLE
|
|
#if (CFG_HW_AUD_SIDETONE_GAIN_DBVAL > MAX_SIDETONE_DBVAL) || \
|
|
(CFG_HW_AUD_SIDETONE_GAIN_DBVAL < MIN_SIDETONE_DBVAL) || \
|
|
defined(CFG_HW_AUD_SIDETONE_IIR_INDEX) || \
|
|
defined(CFG_HW_AUD_SIDETONE_GAIN_RAMP)
|
|
#define SIDETONE_DEDICATED_ADC_CHAN
|
|
#define SIDETONE_RESERVED_ADC_CHAN
|
|
#endif
|
|
#endif
|
|
|
|
enum CODEC_ADC_EN_REQ_T {
|
|
CODEC_ADC_EN_REQ_STREAM,
|
|
CODEC_ADC_EN_REQ_MC,
|
|
CODEC_ADC_EN_REQ_DSD,
|
|
|
|
CODEC_ADC_EN_REQ_QTY,
|
|
};
|
|
|
|
enum CODEC_IRQ_TYPE_T {
|
|
CODEC_IRQ_TYPE_BT_TRIGGER,
|
|
CODEC_IRQ_TYPE_VAD,
|
|
CODEC_IRQ_TYPE_ANC_FB_CHECK,
|
|
|
|
CODEC_IRQ_TYPE_QTY,
|
|
};
|
|
|
|
struct CODEC_DAC_DRE_CFG_T {
|
|
uint8_t dre_delay;
|
|
uint8_t thd_db_offset;
|
|
uint8_t step_mode;
|
|
uint32_t dre_win;
|
|
uint16_t amp_high;
|
|
};
|
|
|
|
struct CODEC_DAC_SAMPLE_RATE_T {
|
|
enum AUD_SAMPRATE_T sample_rate;
|
|
uint32_t codec_freq;
|
|
uint8_t codec_div;
|
|
uint8_t cmu_div;
|
|
uint8_t dac_up;
|
|
uint8_t bypass_cnt;
|
|
uint8_t mc_delay;
|
|
};
|
|
|
|
static const struct CODEC_DAC_SAMPLE_RATE_T codec_dac_sample_rate[] = {
|
|
#ifdef __AUDIO_RESAMPLE__
|
|
{AUD_SAMPRATE_8463, CODEC_FREQ_CRYSTAL, 1, 1, 6, 0, MC_DELAY_COMMON + 160},
|
|
{AUD_SAMPRATE_16927, CODEC_FREQ_CRYSTAL, 1, 1, 3, 0, MC_DELAY_COMMON + 85},
|
|
{AUD_SAMPRATE_50781, CODEC_FREQ_CRYSTAL, 1, 1, 1, 0, MC_DELAY_COMMON + 29},
|
|
#endif
|
|
{AUD_SAMPRATE_7350, CODEC_FREQ_44_1K_SERIES, CODEC_PLL_DIV, CODEC_CMU_DIV,
|
|
6, 0, MC_DELAY_COMMON + 174},
|
|
{AUD_SAMPRATE_8000, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, CODEC_CMU_DIV, 6,
|
|
0, MC_DELAY_COMMON + 168}, // T
|
|
{AUD_SAMPRATE_14700, CODEC_FREQ_44_1K_SERIES, CODEC_PLL_DIV, CODEC_CMU_DIV,
|
|
3, 0, MC_DELAY_COMMON + 71},
|
|
{AUD_SAMPRATE_16000, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, CODEC_CMU_DIV, 3,
|
|
0, MC_DELAY_COMMON + 88}, // T
|
|
{AUD_SAMPRATE_22050, CODEC_FREQ_44_1K_SERIES, CODEC_PLL_DIV, CODEC_CMU_DIV,
|
|
2, 0, MC_DELAY_COMMON + 60},
|
|
{AUD_SAMPRATE_24000, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, CODEC_CMU_DIV, 2,
|
|
0, MC_DELAY_COMMON + 58},
|
|
{AUD_SAMPRATE_44100, CODEC_FREQ_44_1K_SERIES, CODEC_PLL_DIV, CODEC_CMU_DIV,
|
|
1, 0, MC_DELAY_COMMON + 31}, // T
|
|
{AUD_SAMPRATE_48000, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, CODEC_CMU_DIV, 1,
|
|
0, MC_DELAY_COMMON + 30}, // T
|
|
{AUD_SAMPRATE_88200, CODEC_FREQ_44_1K_SERIES, CODEC_PLL_DIV, CODEC_CMU_DIV,
|
|
1, 1, MC_DELAY_COMMON + 12},
|
|
{AUD_SAMPRATE_96000, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, CODEC_CMU_DIV, 1,
|
|
1, MC_DELAY_COMMON + 12}, // T
|
|
{AUD_SAMPRATE_176400, CODEC_FREQ_44_1K_SERIES, CODEC_PLL_DIV, CODEC_CMU_DIV,
|
|
1, 2, MC_DELAY_COMMON + 5},
|
|
{AUD_SAMPRATE_192000, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, CODEC_CMU_DIV,
|
|
1, 2, MC_DELAY_COMMON + 5},
|
|
{AUD_SAMPRATE_352800, CODEC_FREQ_44_1K_SERIES, CODEC_PLL_DIV, CODEC_CMU_DIV,
|
|
1, 3, MC_DELAY_COMMON + 2},
|
|
{AUD_SAMPRATE_384000, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, CODEC_CMU_DIV,
|
|
1, 3, MC_DELAY_COMMON + 2},
|
|
};
|
|
|
|
struct CODEC_ADC_SAMPLE_RATE_T {
|
|
enum AUD_SAMPRATE_T sample_rate;
|
|
uint32_t codec_freq;
|
|
uint8_t codec_div;
|
|
uint8_t cmu_div;
|
|
uint8_t adc_down;
|
|
uint8_t bypass_cnt;
|
|
};
|
|
|
|
static const struct CODEC_ADC_SAMPLE_RATE_T codec_adc_sample_rate[] = {
|
|
#ifdef __AUDIO_RESAMPLE__
|
|
{AUD_SAMPRATE_8463, CODEC_FREQ_CRYSTAL, 1, 1, 6, 0},
|
|
{AUD_SAMPRATE_16927, CODEC_FREQ_CRYSTAL, 1, 1, 3, 0},
|
|
{AUD_SAMPRATE_50781, CODEC_FREQ_CRYSTAL, 1, 1, 1, 0},
|
|
#endif
|
|
{AUD_SAMPRATE_7350, CODEC_FREQ_44_1K_SERIES, CODEC_PLL_DIV, CODEC_CMU_DIV,
|
|
6, 0},
|
|
{AUD_SAMPRATE_8000, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, CODEC_CMU_DIV, 6,
|
|
0},
|
|
{AUD_SAMPRATE_14700, CODEC_FREQ_44_1K_SERIES, CODEC_PLL_DIV, CODEC_CMU_DIV,
|
|
3, 0},
|
|
{AUD_SAMPRATE_16000, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, CODEC_CMU_DIV, 3,
|
|
0},
|
|
{AUD_SAMPRATE_44100, CODEC_FREQ_44_1K_SERIES, CODEC_PLL_DIV, CODEC_CMU_DIV,
|
|
1, 0},
|
|
{AUD_SAMPRATE_48000, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, CODEC_CMU_DIV, 1,
|
|
0},
|
|
{AUD_SAMPRATE_88200, CODEC_FREQ_44_1K_SERIES, CODEC_PLL_DIV, CODEC_CMU_DIV,
|
|
1, 1},
|
|
{AUD_SAMPRATE_96000, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, CODEC_CMU_DIV, 1,
|
|
1},
|
|
{AUD_SAMPRATE_176400, CODEC_FREQ_44_1K_SERIES, CODEC_PLL_DIV, CODEC_CMU_DIV,
|
|
1, 2},
|
|
{AUD_SAMPRATE_192000, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, CODEC_CMU_DIV,
|
|
1, 2},
|
|
{AUD_SAMPRATE_352800, CODEC_FREQ_44_1K_SERIES, CODEC_PLL_DIV, CODEC_CMU_DIV,
|
|
1, 3},
|
|
{AUD_SAMPRATE_384000, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, CODEC_CMU_DIV,
|
|
1, 3},
|
|
};
|
|
|
|
const CODEC_ADC_VOL_T WEAK codec_adc_vol[TGT_ADC_VOL_LEVEL_QTY] = {
|
|
-99, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28,
|
|
};
|
|
|
|
static struct CODEC_T *const codec = (struct CODEC_T *)CODEC_BASE;
|
|
|
|
#define CODEC_FIR_CH0_BASE (CODEC_BASE + 0x9000)
|
|
#define CODEC_FIR_CH1_BASE (CODEC_BASE + 0xB000)
|
|
#define CODEC_FIR_CH2_BASE (CODEC_BASE + 0xD000)
|
|
#define CODEC_FIR_CH3_BASE (CODEC_BASE + 0xF000)
|
|
|
|
#define CODEC_FIR_HISTORY_CH0_BASE (CODEC_FIR_CH0_BASE - 0x1000)
|
|
#define CODEC_FIR_HISTORY_CH1_BASE (CODEC_FIR_CH1_BASE - 0x1000)
|
|
#define CODEC_FIR_HISTORY_CH2_BASE (CODEC_FIR_CH2_BASE - 0x1000)
|
|
#define CODEC_FIR_HISTORY_CH3_BASE (CODEC_FIR_CH3_BASE - 0x1000)
|
|
|
|
#ifdef CODEC_MIN_PHASE
|
|
static volatile int32_t *const codec_fir_ch0 = (int32_t *)CODEC_FIR_CH0_BASE;
|
|
static volatile int32_t *const codec_fir_ch1 = (int32_t *)CODEC_FIR_CH1_BASE;
|
|
static volatile int32_t *const codec_fir_ch2 = (int32_t *)CODEC_FIR_CH2_BASE;
|
|
static volatile int32_t *const codec_fir_ch3 = (int32_t *)CODEC_FIR_CH3_BASE;
|
|
static volatile int32_t *const codec_fir_history0 =
|
|
(int32_t *)CODEC_FIR_HISTORY_CH0_BASE;
|
|
static volatile int32_t *const codec_fir_history1 =
|
|
(int32_t *)CODEC_FIR_HISTORY_CH1_BASE;
|
|
static volatile int32_t *const codec_fir_history2 =
|
|
(int32_t *)CODEC_FIR_HISTORY_CH2_BASE;
|
|
static volatile int32_t *const codec_fir_history3 =
|
|
(int32_t *)CODEC_FIR_HISTORY_CH3_BASE;
|
|
|
|
#define MAX_FIR_ORDERS (512)
|
|
|
|
#define FIR_LOW_FREQ
|
|
|
|
#ifdef FIR_LOW_FREQ
|
|
#define FIR_DAC_ORDERS (220)
|
|
#define FIR_ADC_ORDERS (220)
|
|
#else
|
|
#define FIR_DAC_ORDERS (512)
|
|
#define FIR_ADC_ORDERS (512)
|
|
#endif
|
|
|
|
STATIC_ASSERT(FIR_DAC_ORDERS <= MAX_FIR_ORDERS, "FIR_DAC_ORDERS too large");
|
|
STATIC_ASSERT(FIR_ADC_ORDERS <= MAX_FIR_ORDERS, "FIR_ADC_ORDERS too large");
|
|
|
|
const static int32_t POSSIBLY_UNUSED fir_coef_linear[FIR_DAC_ORDERS] = {
|
|
524287,
|
|
};
|
|
|
|
const static int32_t POSSIBLY_UNUSED fir_coef_minimun[FIR_DAC_ORDERS] = {
|
|
#ifdef FIR_LOW_FREQ
|
|
171, 1077, 4203, 12582, 31473, 68652, 133899, 237244,
|
|
385800, 579602, 807418, 1044189, 1251727, 1383990, 1396843, 1260694,
|
|
972640, 563948, 99101, -335381, -650923, -780973, -701927, -443652,
|
|
-84578, 268808, 512951, 579186, 455906, 192655, -116310, -364122,
|
|
-468309, -399443, -190845, 74646, 296174, 392908, 334154, 149860,
|
|
-82526, -269615, -339392, -269328, -94001, 110604, 259377, 293401,
|
|
203556, 32780, -143605, -250723, -245944, -136029, 27365, 171442,
|
|
234497, 192404, 67901, -80955, -187545, -206431, -132784, -3152,
|
|
122291, 187500, 165597, 69954, -53253, -147114, -170196, -114838,
|
|
-9444, 95806, 152719, 137136, 59154, -42785, -120684, -139533,
|
|
-93024, -5397, 80987, 126029, 110487, 44131, -39952, -101741,
|
|
-113290, -71331, 2185, 71419, 104055, 86354, 28846, -39643,
|
|
-86369, -90279, -51459, 9830, 63615, 84824, 64943, 15296,
|
|
-39213, -72539, -69912, -34308, 15781, 55890, 67480, 46479,
|
|
4496, -37461, -59466, -52097, -20389, 19303, 47689, 51882,
|
|
31200, -3160, -34103, -47104, -36994, -9893, 20334, 39133,
|
|
38235, 19235, -7752, -29414, -35781, -24769, -2693, 19264,
|
|
30682, 26817, 10499, -9713, -23968, -25906, -15440, 1619,
|
|
16733, 22882, 17788, 4668, -9693, -18412, -17788, -8810,
|
|
3652, 13454, 16181, 11101, 1226, -8416, -13305, -11533,
|
|
-4481, 4101, 10062, 10834, 6508, -446, -6545, -9016,
|
|
-7036, -1934, 3627, 7021, 6880, 3613, -961, -4595,
|
|
-5701, -4025, -619, 2769, 4591, 4179, 1965, -839,
|
|
-2887, -3327, -2140, -46, 1903, 2850, 2488, 1144,
|
|
-458, -1565, -1740, -1020, 170, 1245, 1754, 1547,
|
|
815, -53, -656, -761, -376, 288, 927, 1290,
|
|
1257, 878, 307, -256, -663, -840, -809, -642,
|
|
-427, -237, -103, -33,
|
|
#else
|
|
358, 2134, 7870, 22383, 53324, 110934, 206479, 349044,
|
|
541000, 773159, 1021370, 1246556, 1399740, 1432299, 1309745, 1025462,
|
|
609633, 129002, -324731, -656532, -794417, -712592, -443054, -70120,
|
|
292346, 535048, 587990, 443750, 160328, -158614, -400055, -481834,
|
|
-382027, -146176, 130807, 341515, 407598, 309695, 93804, -148511,
|
|
-318068, -348626, -233320, -26063, 182493, 304084, 290262, 152119,
|
|
-45991, -215703, -283797, -223953, -67174, 113414, 236243, 248077,
|
|
147280, -16729, -167204, -235765, -193530, -63427, 91650, 198950,
|
|
209932, 122330, -19887, -148250, -202614, -159367, -41765, 92191,
|
|
178176, 176391, 90055, -37106, -142792, -176569, -123965, -12686,
|
|
101744, 163572, 143971, 54527, -59287, -141093, -151499, -87091,
|
|
18628, 112527, 148481, 110037, 17958, -80830, -137074, -123736,
|
|
-49016, 48438, 119432, 129027, 73750, -17278, -97589, -127045,
|
|
-91900, -11220, 73360, 119064, 103602, 36056, -48313, -106407,
|
|
-109292, -56617, 23738, 90354, 109596, 72600, -665, -72105,
|
|
-105274, -83967, -20135, 52732, 97141, 90877, 38119, -33174,
|
|
-86035, -93649, -52950, 14213, 72765, 92702, 64465, 3511,
|
|
-58099, -88538, -72655, -19509, 42731, 81690, 77624, 33421,
|
|
-27283, -72714, -79582, -45018, 12285, 62151, 78801, 54174,
|
|
1818, -50528, -75615, -60867, -14676, 38325, 70381, 65146,
|
|
26015, -25988, -63481, -67140, -35653, 13901, 55293, 67020,
|
|
43473, -2402, -46194, -65008, -49433, -8237, 36534, 61346,
|
|
53542, 17793, -26648, -56304, -55870, -26107, 16829, 50150,
|
|
56518, 33065, -7346, -43163, -55631, -38609, -1582, 35606,
|
|
53375, 42719, 9762, -27735, -49938, -45423, -17053, 19783,
|
|
45514, 46773, 23343, -11967, -40312, -46863, -28563, 4471,
|
|
34530, 45798, 32673, 2539, -28370, -43713, -35673, -8936,
|
|
22017, 40746, 37582, 14610, -15648, -37053, -38453, -19489,
|
|
9418, 32783, 38351, 23519, -3470, -28096, -37370, -26681,
|
|
-2079, 23137, 35604, 28971, 7128, -18054, -33170, -30413,
|
|
-11603, 12974, 30179, 31045, 15443, -8023, -26756, -30924,
|
|
-18617, 3302, 23015, 30118, 21105, 1094, -19077, -28707,
|
|
-22913, -5093, 15046, 26776, 24054, 8635, -11031, -24419,
|
|
-24565, -11680, 7118, 21726, 24486, 14198, -3394, -18792,
|
|
-23876, -16181, -76, 15704, 22793, 17629, 3230, -12551,
|
|
-21309, -18559, -6028, 9408, 19490, 18994, 8433, -6352,
|
|
-17414, -18974, -10431, 3440, 15149, 18537, 12008, -731,
|
|
-12769, -17737, -13172, -1735, 10336, 16622, 13932, 3920,
|
|
-7916, -15252, -14311, -5805, 5559, 13680, 14335, 7371,
|
|
-3319, -11967, -14040, -8615, 1232, 10161, 13463, 9538,
|
|
664, -8320, -12648, -10154, -2348, 6485, 11634, 10474,
|
|
3797, -4703, -10470, -10527, -5006, 3007, 9196, 10334,
|
|
5966, -1433, -7856, -9930, -6686, 1, 6486, 9343,
|
|
7168, 1266, -5126, -8610, -7432, -2359, 3803, 7762,
|
|
7491, 3267, -2551, -6835, -7369, -3991, 1387, 5858,
|
|
7087, 4531, -335, -4863, -6673, -4898, -597, 3875,
|
|
6149, 5100, 1395, -2920, -5545, -5154, -2058, 2015,
|
|
4882, 5073, 2582, -1181, -4187, -4878, -2974, 427,
|
|
3479, 4586, 3237, 234, -2781, -4219, -3383, -799,
|
|
2107, 3793, 3420, 1262, -1476, -3331, -3363, -1628,
|
|
894, 2845, 3224, 1895, -375, -2357, -3021, -2074,
|
|
-79, 1875, 2764, 2167, 459, -1416, -2470, -2186,
|
|
-771, 987, 2151, 2139, 1009, -599, -1823, -2040,
|
|
-1182, 254, 1492, 1894, 1290, 40, -1172, -1717,
|
|
-1342, -286, 869, 1516, 1343, 480, -592, -1303,
|
|
-1303, -626, 342, 1084, 1226, 725, -127, -870,
|
|
-1124, -784, -55, 664, 1001, 803, 200, -475,
|
|
-869, -794, -313, 303, 729, 756, 392, -154,
|
|
-592, -701, -443, 28, 458, 630, 468, 74,
|
|
-337, -553, -473, -155, 226, 471, 462, 215,
|
|
-130, -394, -443, -263, 45, 319, 420, 302,
|
|
31, -253, -404, -349, -115, 181, 394, 418,
|
|
237, -74, -375, -536, -472, -196, 214, 626,
|
|
935, 1062, 1013, 824, 581, 341, 166, 55,
|
|
#endif
|
|
};
|
|
|
|
static uint8_t min_phase_cfg;
|
|
#endif
|
|
|
|
static bool codec_init = false;
|
|
static bool codec_opened = false;
|
|
|
|
static int8_t digdac_gain[MAX_DAC_CH_NUM];
|
|
static int8_t digadc_gain[NORMAL_ADC_CH_NUM];
|
|
|
|
static bool codec_mute[AUD_STREAM_NUM];
|
|
|
|
#ifdef AUDIO_OUTPUT_SWAP
|
|
static bool output_swap = true;
|
|
#endif
|
|
|
|
#ifdef ANC_APP
|
|
static float anc_boost_gain_attn;
|
|
static int8_t anc_adc_gain_offset[NORMAL_ADC_CH_NUM];
|
|
static enum AUD_CHANNEL_MAP_T anc_adc_gain_offset_map;
|
|
#endif
|
|
#if defined(NOISE_GATING) && defined(NOISE_REDUCTION)
|
|
static bool codec_nr_enabled;
|
|
static int8_t digdac_gain_offset_nr;
|
|
#endif
|
|
#ifdef AUDIO_OUTPUT_DC_CALIB
|
|
static int32_t dac_dc_l;
|
|
static int32_t dac_dc_r;
|
|
static float dac_dc_gain_attn;
|
|
#endif
|
|
#ifdef __AUDIO_RESAMPLE__
|
|
static uint8_t rs_clk_map;
|
|
STATIC_ASSERT(sizeof(rs_clk_map) * 8 >= AUD_STREAM_NUM,
|
|
"rs_clk_map size too small");
|
|
|
|
static uint32_t resample_clk_freq;
|
|
static uint8_t resample_rate_idx[AUD_STREAM_NUM];
|
|
#endif
|
|
#ifdef CODEC_TIMER
|
|
static uint32_t cur_codec_freq;
|
|
#endif
|
|
// EC
|
|
static uint8_t codec_rate_idx[AUD_STREAM_NUM];
|
|
|
|
// static HAL_CODEC_DAC_RESET_CALLBACK dac_reset_callback;
|
|
|
|
static uint8_t codec_irq_map;
|
|
STATIC_ASSERT(sizeof(codec_irq_map) * 8 >= CODEC_IRQ_TYPE_QTY,
|
|
"codec_irq_map size too small");
|
|
static HAL_CODEC_IRQ_CALLBACK codec_irq_callback[CODEC_IRQ_TYPE_QTY];
|
|
|
|
static enum AUD_CHANNEL_MAP_T codec_dac_ch_map;
|
|
static enum AUD_CHANNEL_MAP_T codec_adc_ch_map;
|
|
static enum AUD_CHANNEL_MAP_T anc_adc_ch_map;
|
|
static enum AUD_CHANNEL_MAP_T codec_mic_ch_map;
|
|
static enum AUD_CHANNEL_MAP_T anc_mic_ch_map;
|
|
#ifdef SIDETONE_DEDICATED_ADC_CHAN
|
|
static enum AUD_CHANNEL_MAP_T sidetone_adc_ch_map;
|
|
static int8_t sidetone_adc_gain;
|
|
static int8_t sidetone_gain_offset;
|
|
#ifdef CFG_HW_AUD_SIDETONE_GAIN_RAMP
|
|
static float sidetone_ded_chan_coef;
|
|
#endif
|
|
#endif
|
|
|
|
static uint8_t dac_delay_ms;
|
|
|
|
#ifdef ANC_PROD_TEST
|
|
#define OPT_TYPE
|
|
#else
|
|
#define OPT_TYPE const
|
|
#endif
|
|
|
|
static OPT_TYPE uint8_t codec_digmic_phase = CODEC_DIGMIC_PHASE;
|
|
|
|
#if defined(AUDIO_ANC_FB_MC) && defined(__AUDIO_RESAMPLE__)
|
|
#error "Music cancel cannot work with audio resample"
|
|
#endif
|
|
#ifdef AUDIO_ANC_FB_MC
|
|
static bool mc_enabled;
|
|
static bool mc_dual_chan;
|
|
static bool mc_16bit;
|
|
#endif
|
|
|
|
#ifdef CODEC_DSD
|
|
static bool dsd_enabled;
|
|
static uint8_t dsd_rate_idx;
|
|
#endif
|
|
|
|
#if defined(AUDIO_ANC_FB_MC) || defined(CODEC_DSD)
|
|
static uint8_t adc_en_map;
|
|
STATIC_ASSERT(sizeof(adc_en_map) * 8 >= CODEC_ADC_EN_REQ_QTY,
|
|
"adc_en_map size too small");
|
|
#endif
|
|
|
|
#ifdef PERF_TEST_POWER_KEY
|
|
static enum HAL_CODEC_PERF_TEST_POWER_T cur_perft_power;
|
|
#endif
|
|
|
|
#ifdef AUDIO_OUTPUT_SW_GAIN
|
|
static int8_t swdac_gain;
|
|
static HAL_CODEC_SW_OUTPUT_COEF_CALLBACK sw_output_coef_callback;
|
|
#endif
|
|
|
|
static HAL_CODEC_BT_TRIGGER_CALLBACK bt_trigger_callback = NULL;
|
|
|
|
#ifdef VOICE_DETECTOR_EN
|
|
#define CODEC_VAD_BUF_ADDR 0x40304000
|
|
#define CODEC_VAD_BUF_SIZE 0x4000
|
|
static enum AUD_VAD_TYPE_T vad_type;
|
|
static AUD_VAD_CALLBACK vad_handler;
|
|
static bool vad_enabled;
|
|
static uint32_t vad_data_cnt;
|
|
static uint32_t vad_addr_cnt;
|
|
#endif
|
|
|
|
#if defined(DAC_CLASSG_ENABLE)
|
|
static struct dac_classg_cfg _dac_classg_cfg = {
|
|
.thd2 = 0xC0,
|
|
.thd1 = 0x10,
|
|
.thd0 = 0x10,
|
|
.lr = 1,
|
|
.step_4_3n = 0,
|
|
.quick_down = 1,
|
|
.wind_width = 0x400,
|
|
};
|
|
#endif
|
|
|
|
#ifdef DAC_DRE_ENABLE
|
|
static const struct CODEC_DAC_DRE_CFG_T dac_dre_cfg = {
|
|
.dre_delay = 8,
|
|
.thd_db_offset = 0xF, // 5,
|
|
.step_mode = 0,
|
|
.dre_win = 0x6000,
|
|
.amp_high = 2, // 0x10,
|
|
};
|
|
#endif
|
|
|
|
static void hal_codec_set_dig_adc_gain(enum AUD_CHANNEL_MAP_T map,
|
|
int32_t gain);
|
|
static void hal_codec_set_dig_dac_gain(enum AUD_CHANNEL_MAP_T map,
|
|
int32_t gain);
|
|
static void hal_codec_restore_dig_dac_gain(void);
|
|
static void hal_codec_set_dac_gain_value(enum AUD_CHANNEL_MAP_T map,
|
|
uint32_t val);
|
|
static int hal_codec_set_adc_down(enum AUD_CHANNEL_MAP_T map, uint32_t val);
|
|
static int hal_codec_set_adc_hbf_bypass_cnt(enum AUD_CHANNEL_MAP_T map,
|
|
uint32_t cnt);
|
|
static uint32_t hal_codec_get_adc_chan(enum AUD_CHANNEL_MAP_T mic_map);
|
|
#ifdef AUDIO_OUTPUT_SW_GAIN
|
|
static void hal_codec_set_sw_gain(int32_t gain);
|
|
#endif
|
|
#ifdef __AUDIO_RESAMPLE__
|
|
static float get_playback_resample_phase(void);
|
|
static float get_capture_resample_phase(void);
|
|
static uint32_t resample_phase_float_to_value(float phase);
|
|
static float resample_phase_value_to_float(uint32_t value);
|
|
#endif
|
|
|
|
static void hal_codec_reg_update_delay(void) { hal_sys_timer_delay_us(2); }
|
|
|
|
#if defined(DAC_CLASSG_ENABLE)
|
|
void hal_codec_classg_config(const struct dac_classg_cfg *cfg) {
|
|
_dac_classg_cfg = *cfg;
|
|
}
|
|
|
|
static void hal_codec_classg_enable(bool en) {
|
|
struct dac_classg_cfg *config;
|
|
|
|
if (en) {
|
|
config = &_dac_classg_cfg;
|
|
|
|
codec->REG_0B4 =
|
|
SET_BITFIELD(codec->REG_0B4, CODEC_CODEC_CLASSG_THD2, config->thd2);
|
|
codec->REG_0B4 =
|
|
SET_BITFIELD(codec->REG_0B4, CODEC_CODEC_CLASSG_THD1, config->thd1);
|
|
codec->REG_0B4 =
|
|
SET_BITFIELD(codec->REG_0B4, CODEC_CODEC_CLASSG_THD0, config->thd0);
|
|
|
|
// Make class-g set the lowest gain after several samples.
|
|
// Class-g gain will have impact on dc.
|
|
codec->REG_0B0 = SET_BITFIELD(codec->REG_0B0, CODEC_CODEC_CLASSG_WINDOW, 6);
|
|
|
|
if (config->lr)
|
|
codec->REG_0B0 |= CODEC_CODEC_CLASSG_LR;
|
|
else
|
|
codec->REG_0B0 &= ~CODEC_CODEC_CLASSG_LR;
|
|
|
|
if (config->step_4_3n)
|
|
codec->REG_0B0 |= CODEC_CODEC_CLASSG_STEP_3_4N;
|
|
else
|
|
codec->REG_0B0 &= ~CODEC_CODEC_CLASSG_STEP_3_4N;
|
|
|
|
if (config->quick_down)
|
|
codec->REG_0B0 |= CODEC_CODEC_CLASSG_QUICK_DOWN;
|
|
else
|
|
codec->REG_0B0 &= ~CODEC_CODEC_CLASSG_QUICK_DOWN;
|
|
|
|
codec->REG_0B0 |= CODEC_CODEC_CLASSG_EN;
|
|
|
|
// Restore class-g window after the gain has been updated
|
|
hal_codec_reg_update_delay();
|
|
codec->REG_0B0 = SET_BITFIELD(codec->REG_0B0, CODEC_CODEC_CLASSG_WINDOW,
|
|
config->wind_width);
|
|
} else {
|
|
codec->REG_0B0 &= ~CODEC_CODEC_CLASSG_QUICK_DOWN;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(AUDIO_OUTPUT_DC_CALIB) || defined(SDM_MUTE_NOISE_SUPPRESSION)
|
|
static void hal_codec_dac_dc_offset_enable(int32_t dc_l, int32_t dc_r) {
|
|
codec->REG_0E0 &= CODEC_CODEC_DAC_DC_UPDATE_CH0;
|
|
hal_codec_reg_update_delay();
|
|
codec->REG_0E8 = SET_BITFIELD(codec->REG_0E8, CODEC_CODEC_DAC_DC_CH1, dc_r);
|
|
codec->REG_0E0 = SET_BITFIELD(codec->REG_0E0, CODEC_CODEC_DAC_DC_CH0, dc_l) |
|
|
CODEC_CODEC_DAC_DC_UPDATE_CH0;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CODEC_MIN_PHASE
|
|
static void hal_codec_min_phase_init(void) {
|
|
int i;
|
|
|
|
// SYS clock should be 52M or above
|
|
|
|
// DAC
|
|
codec->REG_108 &= ~(CODEC_STREAM0_FIR1_CH0);
|
|
codec->REG_108 = SET_BITFIELD(codec->REG_108, CODEC_FIR_MODE_CH0, 0);
|
|
codec->REG_108 =
|
|
SET_BITFIELD(codec->REG_108, CODEC_FIR_ORDER_CH0, FIR_DAC_ORDERS);
|
|
|
|
codec->REG_10C = SET_BITFIELD(codec->REG_10C, CODEC_FIR_BURST_LENGTH_CH0, 4);
|
|
codec->REG_10C = SET_BITFIELD(codec->REG_10C, CODEC_FIR_GAIN_SEL_CH0, 4);
|
|
|
|
codec->REG_110 &= ~(CODEC_STREAM0_FIR1_CH1);
|
|
codec->REG_110 = SET_BITFIELD(codec->REG_110, CODEC_FIR_MODE_CH1, 0);
|
|
codec->REG_110 =
|
|
SET_BITFIELD(codec->REG_110, CODEC_FIR_ORDER_CH1, FIR_DAC_ORDERS);
|
|
|
|
codec->REG_114 = SET_BITFIELD(codec->REG_114, CODEC_FIR_BURST_LENGTH_CH1, 4);
|
|
codec->REG_114 = SET_BITFIELD(codec->REG_114, CODEC_FIR_GAIN_SEL_CH1, 4);
|
|
|
|
// ADC
|
|
codec->REG_118 &= ~(CODEC_STREAM0_FIR1_CH2);
|
|
codec->REG_118 = SET_BITFIELD(codec->REG_118, CODEC_FIR_MODE_CH2, 0);
|
|
codec->REG_118 =
|
|
SET_BITFIELD(codec->REG_118, CODEC_FIR_ORDER_CH2, FIR_ADC_ORDERS);
|
|
|
|
// codec->REG_11C = SET_BITFIELD(codec->REG_11C,CODEC_FIR_BURST_LENGTH_CH2,4);
|
|
codec->REG_11C = SET_BITFIELD(codec->REG_11C, CODEC_FIR_GAIN_SEL_CH2, 6);
|
|
|
|
codec->REG_120 &= ~(CODEC_STREAM0_FIR1_CH3);
|
|
codec->REG_120 = SET_BITFIELD(codec->REG_120, CODEC_FIR_MODE_CH3, 0);
|
|
codec->REG_120 =
|
|
SET_BITFIELD(codec->REG_120, CODEC_FIR_ORDER_CH3, FIR_ADC_ORDERS);
|
|
|
|
// codec->REG_124 = SET_BITFIELD(codec->REG_124,CODEC_FIR_BURST_LENGTH_CH3,4);
|
|
codec->REG_124 = SET_BITFIELD(codec->REG_124, CODEC_FIR_GAIN_SEL_CH3, 6);
|
|
|
|
// DAC
|
|
codec->REG_100 |= (CODEC_FIR_UPSAMPLE_CH0 | CODEC_FIR_UPSAMPLE_CH1);
|
|
|
|
for (i = 0; i < FIR_DAC_ORDERS; i++) {
|
|
codec_fir_ch0[i] = fir_coef_minimun[i];
|
|
codec_fir_ch1[i] = fir_coef_minimun[i];
|
|
}
|
|
|
|
// ADC
|
|
codec->REG_100 &= ~(CODEC_FIR_UPSAMPLE_CH2 | CODEC_FIR_UPSAMPLE_CH3);
|
|
|
|
for (i = 0; i < FIR_DAC_ORDERS; i++) {
|
|
codec_fir_ch2[i] = fir_coef_minimun[i];
|
|
codec_fir_ch3[i] = fir_coef_minimun[i];
|
|
}
|
|
|
|
// Init history buffer
|
|
for (i = 0; i < MAX_FIR_ORDERS; i++) {
|
|
codec_fir_history0[i] = 0;
|
|
codec_fir_history1[i] = 0;
|
|
codec_fir_history2[i] = 0;
|
|
codec_fir_history3[i] = 0;
|
|
}
|
|
}
|
|
|
|
static void hal_codec_min_phase_term(void) {
|
|
// Release SYS clock request
|
|
}
|
|
#endif
|
|
|
|
int hal_codec_open(enum HAL_CODEC_ID_T id) {
|
|
int i;
|
|
bool first_open;
|
|
|
|
#ifdef CODEC_POWER_DOWN
|
|
first_open = true;
|
|
#else
|
|
first_open = !codec_init;
|
|
#endif
|
|
|
|
analog_aud_pll_open(ANA_AUD_PLL_USER_CODEC);
|
|
|
|
if (!codec_init) {
|
|
for (i = 0; i < CFG_HW_AUD_INPUT_PATH_NUM; i++) {
|
|
if (cfg_audio_input_path_cfg[i].cfg & AUD_CHANNEL_MAP_ALL &
|
|
~VALID_MIC_MAP) {
|
|
ASSERT(false, "Invalid input path cfg: i=%d io_path=%d cfg=0x%X", i,
|
|
cfg_audio_input_path_cfg[i].io_path,
|
|
cfg_audio_input_path_cfg[i].cfg);
|
|
}
|
|
}
|
|
#ifdef ANC_APP
|
|
anc_boost_gain_attn = 1.0f;
|
|
#endif
|
|
codec_init = true;
|
|
}
|
|
if (first_open) {
|
|
// Codec will be powered down first
|
|
hal_psc_codec_enable();
|
|
}
|
|
hal_cmu_codec_clock_enable();
|
|
hal_cmu_codec_reset_clear();
|
|
|
|
codec_opened = true;
|
|
|
|
codec->REG_060 |= CODEC_EN_CLK_ADC_MASK | CODEC_EN_CLK_ADC_ANA_MASK |
|
|
CODEC_POL_ADC_ANA_MASK | CODEC_POL_DAC_OUT;
|
|
codec->REG_064 |= CODEC_SOFT_RSTN_32K | CODEC_SOFT_RSTN_IIR |
|
|
CODEC_SOFT_RSTN_RS | CODEC_SOFT_RSTN_DAC |
|
|
CODEC_SOFT_RSTN_ADC_MASK | CODEC_SOFT_RSTN_ADC_ANA_MASK;
|
|
codec->REG_000 = 0;
|
|
codec->REG_04C &= ~CODEC_MC_ENABLE;
|
|
codec->REG_004 = ~0UL;
|
|
hal_codec_reg_update_delay();
|
|
codec->REG_004 = 0;
|
|
codec->REG_000 |= CODEC_CODEC_IF_EN;
|
|
|
|
codec->REG_054 |= CODEC_FAULT_MUTE_DAC_ENABLE;
|
|
|
|
#ifdef AUDIO_OUTPUT_SWAP
|
|
if (output_swap) {
|
|
codec->REG_0A0 |= CODEC_CODEC_DAC_OUT_SWAP;
|
|
} else {
|
|
codec->REG_0A0 &= ~CODEC_CODEC_DAC_OUT_SWAP;
|
|
}
|
|
#endif
|
|
|
|
if (first_open) {
|
|
#ifdef AUDIO_ANC_FB_MC
|
|
codec->REG_04C = CODEC_DMA_CTRL_MC;
|
|
codec->REG_230 |= CODEC_MC_EN_SEL | CODEC_MC_RATE_SRC_SEL;
|
|
#endif
|
|
|
|
// ANC zero-crossing
|
|
codec->REG_0D4 |= CODEC_CODEC_ANC_MUTE_GAIN_PASS0_FF_CH0 |
|
|
CODEC_CODEC_ANC_MUTE_GAIN_PASS0_FF_CH1;
|
|
codec->REG_0D8 |= CODEC_CODEC_ANC_MUTE_GAIN_PASS0_FB_CH0 |
|
|
CODEC_CODEC_ANC_MUTE_GAIN_PASS0_FB_CH1;
|
|
|
|
// Enable ADC zero-crossing gain adjustment
|
|
for (i = 0; i < NORMAL_ADC_CH_NUM; i++) {
|
|
*(&codec->REG_084 + i) |= CODEC_CODEC_ADC_GAIN_SEL_CH0;
|
|
}
|
|
|
|
// DRE ini gain and offset
|
|
uint8_t max_gain, ini_gain, dre_offset;
|
|
max_gain = analog_aud_get_max_dre_gain();
|
|
if (max_gain < 0xF) {
|
|
ini_gain = 0xF - max_gain;
|
|
} else {
|
|
ini_gain = 0;
|
|
}
|
|
if (max_gain > 0xF) {
|
|
dre_offset = max_gain - 0xF;
|
|
} else {
|
|
dre_offset = 0;
|
|
}
|
|
codec->REG_0C0 = CODEC_CODEC_DRE_INI_ANA_GAIN_CH0(ini_gain) |
|
|
CODEC_CODEC_DRE_GAIN_OFFSET_CH0(dre_offset);
|
|
codec->REG_0C8 = CODEC_CODEC_DRE_INI_ANA_GAIN_CH1(ini_gain) |
|
|
CODEC_CODEC_DRE_GAIN_OFFSET_CH1(dre_offset);
|
|
codec->REG_0E0 = CODEC_CODEC_DAC_ANA_GAIN_UPDATE_DELAY_CH0(0);
|
|
codec->REG_0E8 = CODEC_CODEC_DAC_ANA_GAIN_UPDATE_DELAY_CH1(0);
|
|
|
|
#ifdef ANC_PROD_TEST
|
|
#ifdef AUDIO_ANC_FB_MC
|
|
// Enable ADC + music cancel.
|
|
codec->REG_130 |= CODEC_CODEC_FB_CHECK_KEEP_CH0;
|
|
codec->REG_134 |= CODEC_CODEC_FB_CHECK_KEEP_CH1;
|
|
#elif defined(AUDIO_ANC_FB_MC_HW)
|
|
// Enable ADC + music cancel.
|
|
codec->REG_130 |= CODEC_CODEC_FB_CHECK_KEEP_CH0;
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(FIXED_CODEC_ADC_VOL) && defined(SINGLE_CODEC_ADC_VOL)
|
|
const CODEC_ADC_VOL_T *adc_gain_db;
|
|
|
|
adc_gain_db = hal_codec_get_adc_volume(CODEC_SADC_VOL);
|
|
if (adc_gain_db) {
|
|
hal_codec_set_dig_adc_gain(NORMAL_ADC_MAP, *adc_gain_db);
|
|
#ifdef SIDETONE_DEDICATED_ADC_CHAN
|
|
sidetone_adc_gain = *adc_gain_db;
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#ifdef AUDIO_OUTPUT_DC_CALIB
|
|
hal_codec_dac_dc_offset_enable(dac_dc_l, dac_dc_r);
|
|
#elif defined(SDM_MUTE_NOISE_SUPPRESSION)
|
|
hal_codec_dac_dc_offset_enable(1, 1);
|
|
#endif
|
|
|
|
#ifdef AUDIO_OUTPUT_SW_GAIN
|
|
const struct CODEC_DAC_VOL_T *vol_tab_ptr;
|
|
|
|
// Init gain settings
|
|
vol_tab_ptr = hal_codec_get_dac_volume(0);
|
|
if (vol_tab_ptr) {
|
|
analog_aud_set_dac_gain(vol_tab_ptr->tx_pa_gain);
|
|
hal_codec_set_dig_dac_gain(VALID_DAC_MAP, ZERODB_DIG_DBVAL);
|
|
}
|
|
#else
|
|
// Enable DAC zero-crossing gain adjustment
|
|
codec->REG_09C |= CODEC_CODEC_DAC_GAIN_SEL_CH0;
|
|
codec->REG_0A0 |= CODEC_CODEC_DAC_GAIN_SEL_CH1;
|
|
#endif
|
|
|
|
#ifdef AUDIO_OUTPUT_DC_CALIB_ANA
|
|
// Reset SDM
|
|
hal_codec_set_dac_gain_value(VALID_DAC_MAP, 0);
|
|
codec->REG_098 |= CODEC_CODEC_DAC_SDM_CLOSE;
|
|
#endif
|
|
|
|
#ifdef SDM_MUTE_NOISE_SUPPRESSION
|
|
codec->REG_098 =
|
|
SET_BITFIELD(codec->REG_098, CODEC_CODEC_DAC_DITHER_GAIN, 0x10);
|
|
#endif
|
|
|
|
#ifdef __AUDIO_RESAMPLE__
|
|
codec->REG_0E4 &=
|
|
~(CODEC_CODEC_RESAMPLE_DAC_ENABLE | CODEC_CODEC_RESAMPLE_ADC_ENABLE |
|
|
CODEC_CODEC_RESAMPLE_DAC_PHASE_UPDATE |
|
|
CODEC_CODEC_RESAMPLE_ADC_PHASE_UPDATE);
|
|
#endif
|
|
|
|
#ifdef CODEC_DSD
|
|
for (i = 0; i < ARRAY_SIZE(codec_adc_sample_rate); i++) {
|
|
if (codec_adc_sample_rate[i].sample_rate == AUD_SAMPRATE_44100) {
|
|
break;
|
|
}
|
|
}
|
|
hal_codec_set_adc_down((AUD_CHANNEL_MAP_CH2 | AUD_CHANNEL_MAP_CH3),
|
|
codec_adc_sample_rate[i].adc_down);
|
|
hal_codec_set_adc_hbf_bypass_cnt(
|
|
(AUD_CHANNEL_MAP_CH2 | AUD_CHANNEL_MAP_CH3),
|
|
codec_adc_sample_rate[i].bypass_cnt);
|
|
#endif
|
|
|
|
// Mute DAC when cpu fault occurs
|
|
hal_cmu_codec_set_fault_mask(0x3F);
|
|
|
|
#ifdef CODEC_TIMER
|
|
// Disable sync stamp auto clear to avoid impacting codec timer capture
|
|
codec->REG_054 &= ~CODEC_STAMP_CLR_USED;
|
|
#else
|
|
// Enable sync stamp auto clear
|
|
codec->REG_054 |= CODEC_STAMP_CLR_USED;
|
|
#endif
|
|
}
|
|
|
|
#ifdef CODEC_MIN_PHASE
|
|
if (min_phase_cfg) {
|
|
hal_codec_min_phase_init();
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
int hal_codec_close(enum HAL_CODEC_ID_T id) {
|
|
#ifdef CODEC_MIN_PHASE
|
|
if (min_phase_cfg) {
|
|
hal_codec_min_phase_term();
|
|
}
|
|
#endif
|
|
|
|
codec->REG_054 &= ~CODEC_FAULT_MUTE_DAC_ENABLE;
|
|
|
|
codec->REG_000 &= ~CODEC_CODEC_IF_EN;
|
|
codec->REG_064 &= ~(CODEC_SOFT_RSTN_32K | CODEC_SOFT_RSTN_IIR |
|
|
CODEC_SOFT_RSTN_RS | CODEC_SOFT_RSTN_DAC |
|
|
CODEC_SOFT_RSTN_ADC_MASK | CODEC_SOFT_RSTN_ADC_ANA_MASK);
|
|
codec->REG_060 &= ~(CODEC_EN_CLK_ADC_MASK | CODEC_EN_CLK_ADC_ANA_MASK);
|
|
|
|
codec_opened = false;
|
|
|
|
#ifdef CODEC_POWER_DOWN
|
|
hal_cmu_codec_reset_set();
|
|
hal_cmu_codec_clock_disable();
|
|
hal_psc_codec_disable();
|
|
#else
|
|
// NEVER reset or power down CODEC registers, for the CODEC driver expects
|
|
// that last configurations still exist in the next stream setup
|
|
hal_cmu_codec_clock_disable();
|
|
#endif
|
|
|
|
analog_aud_pll_close(ANA_AUD_PLL_USER_CODEC);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void hal_codec_crash_mute(void) {
|
|
if (codec_opened) {
|
|
codec->REG_000 &= ~CODEC_CODEC_IF_EN;
|
|
}
|
|
}
|
|
|
|
#ifdef DAC_DRE_ENABLE
|
|
static void hal_codec_dac_dre_enable(void) {
|
|
codec->REG_0C0 =
|
|
(codec->REG_0C0 & ~(CODEC_CODEC_DRE_THD_DB_OFFSET_SIGN_CH0 |
|
|
CODEC_CODEC_DRE_DELAY_CH0_MASK |
|
|
CODEC_CODEC_DRE_INI_ANA_GAIN_CH0_MASK |
|
|
CODEC_CODEC_DRE_THD_DB_OFFSET_CH0_MASK |
|
|
CODEC_CODEC_DRE_STEP_MODE_CH0_MASK)) |
|
|
CODEC_CODEC_DRE_DELAY_CH0(dac_dre_cfg.dre_delay) |
|
|
CODEC_CODEC_DRE_INI_ANA_GAIN_CH0(0xF) |
|
|
CODEC_CODEC_DRE_THD_DB_OFFSET_CH0(dac_dre_cfg.thd_db_offset) |
|
|
CODEC_CODEC_DRE_THD_DB_OFFSET_CH0(dac_dre_cfg.step_mode) |
|
|
CODEC_CODEC_DRE_ENABLE_CH0;
|
|
codec->REG_0C4 = (codec->REG_0C4 & ~(CODEC_CODEC_DRE_WINDOW_CH0_MASK |
|
|
CODEC_CODEC_DRE_AMP_HIGH_CH0_MASK)) |
|
|
CODEC_CODEC_DRE_WINDOW_CH0(dac_dre_cfg.dre_win) |
|
|
CODEC_CODEC_DRE_AMP_HIGH_CH0(dac_dre_cfg.amp_high);
|
|
|
|
codec->REG_0C8 =
|
|
(codec->REG_0C8 & ~(CODEC_CODEC_DRE_THD_DB_OFFSET_SIGN_CH1 |
|
|
CODEC_CODEC_DRE_DELAY_CH1_MASK |
|
|
CODEC_CODEC_DRE_INI_ANA_GAIN_CH1_MASK |
|
|
CODEC_CODEC_DRE_THD_DB_OFFSET_CH1_MASK |
|
|
CODEC_CODEC_DRE_STEP_MODE_CH1_MASK)) |
|
|
CODEC_CODEC_DRE_DELAY_CH1(dac_dre_cfg.dre_delay) |
|
|
CODEC_CODEC_DRE_INI_ANA_GAIN_CH1(0xF) |
|
|
CODEC_CODEC_DRE_THD_DB_OFFSET_CH1(dac_dre_cfg.thd_db_offset) |
|
|
CODEC_CODEC_DRE_THD_DB_OFFSET_CH1(dac_dre_cfg.step_mode) |
|
|
CODEC_CODEC_DRE_ENABLE_CH1;
|
|
codec->REG_0CC = (codec->REG_0CC & ~(CODEC_CODEC_DRE_WINDOW_CH1_MASK |
|
|
CODEC_CODEC_DRE_AMP_HIGH_CH1_MASK)) |
|
|
CODEC_CODEC_DRE_WINDOW_CH1(dac_dre_cfg.dre_win) |
|
|
CODEC_CODEC_DRE_AMP_HIGH_CH1(dac_dre_cfg.amp_high);
|
|
}
|
|
|
|
static void hal_codec_dac_dre_disable(void) {
|
|
codec->REG_0C0 &= ~CODEC_CODEC_DRE_ENABLE_CH0;
|
|
codec->REG_0C8 &= ~CODEC_CODEC_DRE_ENABLE_CH1;
|
|
}
|
|
#endif
|
|
|
|
#ifdef PERF_TEST_POWER_KEY
|
|
static void hal_codec_update_perf_test_power(void) {
|
|
int32_t nominal_vol;
|
|
uint32_t ini_ana_gain;
|
|
int32_t dac_vol;
|
|
|
|
if (!codec_opened) {
|
|
return;
|
|
}
|
|
|
|
dac_vol = 0;
|
|
if (cur_perft_power == HAL_CODEC_PERF_TEST_30MW) {
|
|
nominal_vol = 0;
|
|
ini_ana_gain = 0;
|
|
} else if (cur_perft_power == HAL_CODEC_PERF_TEST_10MW) {
|
|
nominal_vol = -5;
|
|
ini_ana_gain = 6;
|
|
} else if (cur_perft_power == HAL_CODEC_PERF_TEST_5MW) {
|
|
nominal_vol = -8;
|
|
ini_ana_gain = 0xA;
|
|
} else if (cur_perft_power == HAL_CODEC_PERF_TEST_M60DB) {
|
|
nominal_vol = -60;
|
|
ini_ana_gain = 0xF; // about -11 dB
|
|
dac_vol = -49;
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
if (codec->REG_0C0 & CODEC_CODEC_DRE_ENABLE_CH0) {
|
|
dac_vol = nominal_vol;
|
|
} else {
|
|
codec->REG_0C0 = SET_BITFIELD(
|
|
codec->REG_0C0, CODEC_CODEC_DRE_INI_ANA_GAIN_CH0, ini_ana_gain);
|
|
codec->REG_0C8 = SET_BITFIELD(
|
|
codec->REG_0C8, CODEC_CODEC_DRE_INI_ANA_GAIN_CH1, ini_ana_gain);
|
|
}
|
|
|
|
#ifdef AUDIO_OUTPUT_SW_GAIN
|
|
hal_codec_set_sw_gain(dac_vol);
|
|
#else
|
|
hal_codec_set_dig_dac_gain(VALID_DAC_MAP, dac_vol);
|
|
#endif
|
|
|
|
#if defined(NOISE_GATING) && defined(NOISE_REDUCTION)
|
|
if (codec_nr_enabled) {
|
|
codec_nr_enabled = false;
|
|
hal_codec_set_noise_reduction(true);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void hal_codec_dac_gain_m60db_check(enum HAL_CODEC_PERF_TEST_POWER_T type) {
|
|
cur_perft_power = type;
|
|
|
|
if (!codec_opened || (codec->REG_098 & CODEC_CODEC_DAC_EN) == 0) {
|
|
return;
|
|
}
|
|
|
|
hal_codec_update_perf_test_power();
|
|
}
|
|
#endif
|
|
|
|
#if defined(NOISE_GATING) && defined(NOISE_REDUCTION)
|
|
void hal_codec_set_noise_reduction(bool enable) {
|
|
uint32_t ini_ana_gain;
|
|
|
|
if (codec_nr_enabled == enable) {
|
|
// Avoid corrupting digdac_gain_offset_nr or using an invalid one
|
|
return;
|
|
}
|
|
|
|
codec_nr_enabled = enable;
|
|
|
|
if (!codec_opened) {
|
|
return;
|
|
}
|
|
|
|
// ini_ana_gain=0 --> 0dB
|
|
// ini_ana_gain=0xF --> -11dB
|
|
if (enable) {
|
|
ini_ana_gain =
|
|
GET_BITFIELD(codec->REG_0C0, CODEC_CODEC_DRE_INI_ANA_GAIN_CH0);
|
|
digdac_gain_offset_nr = ((0xF - ini_ana_gain) * 11 + 0xF / 2) / 0xF;
|
|
ini_ana_gain = 0xF;
|
|
} else {
|
|
ini_ana_gain = 0xF - (digdac_gain_offset_nr * 0xF + 11 / 2) / 11;
|
|
digdac_gain_offset_nr = 0;
|
|
}
|
|
|
|
codec->REG_0C0 = SET_BITFIELD(codec->REG_0C0,
|
|
CODEC_CODEC_DRE_INI_ANA_GAIN_CH0, ini_ana_gain);
|
|
codec->REG_0C8 = SET_BITFIELD(codec->REG_0C8,
|
|
CODEC_CODEC_DRE_INI_ANA_GAIN_CH1, ini_ana_gain);
|
|
|
|
#ifdef AUDIO_OUTPUT_SW_GAIN
|
|
hal_codec_set_sw_gain(swdac_gain);
|
|
#else
|
|
hal_codec_restore_dig_dac_gain();
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
void hal_codec_stop_playback_stream(enum HAL_CODEC_ID_T id) {
|
|
#if (defined(AUDIO_OUTPUT_DC_CALIB_ANA) || defined(AUDIO_OUTPUT_DC_CALIB)) && \
|
|
(!(defined(__TWS__) || defined(IBRT)) || defined(ANC_APP))
|
|
// Disable PA
|
|
analog_aud_codec_speaker_enable(false);
|
|
#endif
|
|
|
|
codec->REG_098 &=
|
|
~(CODEC_CODEC_DAC_EN | CODEC_CODEC_DAC_EN_CH0 | CODEC_CODEC_DAC_EN_CH1);
|
|
|
|
#ifdef CODEC_TIMER
|
|
// Reset codec timer
|
|
codec->REG_054 &= ~CODEC_EVENT_FOR_CAPTURE;
|
|
#endif
|
|
|
|
#ifdef DAC_DRE_ENABLE
|
|
hal_codec_dac_dre_disable();
|
|
#endif
|
|
|
|
#if defined(DAC_CLASSG_ENABLE)
|
|
hal_codec_classg_enable(false);
|
|
#endif
|
|
|
|
#ifndef NO_DAC_RESET
|
|
// Reset DAC
|
|
// Avoid DAC outputing noise after it is disabled
|
|
codec->REG_064 &= ~CODEC_SOFT_RSTN_DAC;
|
|
codec->REG_064 |= CODEC_SOFT_RSTN_DAC;
|
|
#endif
|
|
codec->REG_060 &= ~CODEC_EN_CLK_DAC;
|
|
}
|
|
|
|
void hal_codec_start_playback_stream(enum HAL_CODEC_ID_T id) {
|
|
codec->REG_060 |= CODEC_EN_CLK_DAC;
|
|
#ifndef NO_DAC_RESET
|
|
// Reset DAC
|
|
codec->REG_064 &= ~CODEC_SOFT_RSTN_DAC;
|
|
codec->REG_064 |= CODEC_SOFT_RSTN_DAC;
|
|
#endif
|
|
|
|
#ifdef DAC_DRE_ENABLE
|
|
if (
|
|
//(codec->REG_044 & CODEC_MODE_16BIT_DAC) == 0 &&
|
|
#ifdef ANC_APP
|
|
anc_adc_ch_map == 0 &&
|
|
#endif
|
|
1) {
|
|
hal_codec_dac_dre_enable();
|
|
}
|
|
#endif
|
|
|
|
#ifdef PERF_TEST_POWER_KEY
|
|
hal_codec_update_perf_test_power();
|
|
#endif
|
|
|
|
#if defined(DAC_CLASSG_ENABLE)
|
|
hal_codec_classg_enable(true);
|
|
#endif
|
|
|
|
#ifdef CODEC_TIMER
|
|
// Enable codec timer and record time by bt event instead of gpio event
|
|
codec->REG_054 =
|
|
(codec->REG_054 & ~CODEC_EVENT_SEL) | CODEC_EVENT_FOR_CAPTURE;
|
|
#endif
|
|
|
|
if (codec_dac_ch_map & AUD_CHANNEL_MAP_CH0) {
|
|
codec->REG_098 |= CODEC_CODEC_DAC_EN_CH0;
|
|
} else {
|
|
codec->REG_098 &= ~CODEC_CODEC_DAC_EN_CH0;
|
|
}
|
|
if (codec_dac_ch_map & AUD_CHANNEL_MAP_CH1) {
|
|
codec->REG_098 |= CODEC_CODEC_DAC_EN_CH1;
|
|
} else {
|
|
codec->REG_098 &= ~CODEC_CODEC_DAC_EN_CH1;
|
|
}
|
|
|
|
#if (defined(AUDIO_OUTPUT_DC_CALIB_ANA) || defined(AUDIO_OUTPUT_DC_CALIB)) && \
|
|
(!(defined(__TWS__) || defined(IBRT)) || defined(ANC_APP))
|
|
#if 0
|
|
uint32_t cfg_en;
|
|
uint32_t anc_ff_gain, anc_fb_gain;
|
|
|
|
cfg_en = codec->REG_000 & CODEC_DAC_ENABLE;
|
|
anc_ff_gain = codec->REG_0D4;
|
|
anc_fb_gain = codec->REG_0D8;
|
|
|
|
if (cfg_en) {
|
|
codec->REG_000 &= ~cfg_en;
|
|
}
|
|
if (anc_ff_gain) {
|
|
codec->REG_0D4 = CODEC_CODEC_ANC_MUTE_GAIN_PASS0_FF_CH0 | CODEC_CODEC_ANC_MUTE_GAIN_PASS0_FF_CH1;
|
|
anc_ff_gain |= CODEC_CODEC_ANC_MUTE_GAIN_PASS0_FF_CH0 | CODEC_CODEC_ANC_MUTE_GAIN_PASS0_FF_CH1;
|
|
}
|
|
if (anc_fb_gain) {
|
|
codec->REG_0D8 = CODEC_CODEC_ANC_MUTE_GAIN_PASS0_FB_CH0 | CODEC_CODEC_ANC_MUTE_GAIN_PASS0_FB_CH1;
|
|
anc_fb_gain = CODEC_CODEC_ANC_MUTE_GAIN_PASS0_FB_CH0 | CODEC_CODEC_ANC_MUTE_GAIN_PASS0_FB_CH1;
|
|
}
|
|
osDelay(1);
|
|
#endif
|
|
#endif
|
|
|
|
codec->REG_098 |= CODEC_CODEC_DAC_EN;
|
|
|
|
#if (defined(AUDIO_OUTPUT_DC_CALIB_ANA) || defined(AUDIO_OUTPUT_DC_CALIB)) && \
|
|
(!(defined(__TWS__) || defined(IBRT)) || defined(ANC_APP))
|
|
#ifdef AUDIO_OUTPUT_DC_CALIB
|
|
// At least delay 4ms for 8K-sample-rate mute data to arrive at DAC PA
|
|
osDelay(5);
|
|
#endif
|
|
|
|
#if 0
|
|
if (cfg_en) {
|
|
codec->REG_000 |= cfg_en;
|
|
}
|
|
if (anc_ff_gain) {
|
|
codec->REG_0D4 = anc_ff_gain;
|
|
}
|
|
if (anc_fb_gain) {
|
|
codec->REG_0D8 = anc_fb_gain;
|
|
}
|
|
#endif
|
|
|
|
// Enable PA
|
|
analog_aud_codec_speaker_enable(true);
|
|
|
|
#ifdef AUDIO_ANC_FB_MC
|
|
if (mc_enabled) {
|
|
uint32_t lock;
|
|
lock = int_lock();
|
|
// MC FIFO and DAC FIFO must be started at the same time
|
|
codec->REG_04C |= CODEC_MC_ENABLE;
|
|
codec->REG_000 |= CODEC_DAC_ENABLE;
|
|
int_unlock(lock);
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
#ifdef AF_ADC_I2S_SYNC
|
|
static bool _hal_codec_capture_enable_delay = false;
|
|
|
|
void hal_codec_capture_enable_delay(void) {
|
|
_hal_codec_capture_enable_delay = true;
|
|
}
|
|
|
|
void hal_codec_capture_enable(void) { codec->REG_080 |= CODEC_CODEC_ADC_EN; }
|
|
#endif
|
|
|
|
int hal_codec_start_stream(enum HAL_CODEC_ID_T id, enum AUD_STREAM_T stream) {
|
|
if (stream == AUD_STREAM_PLAYBACK) {
|
|
// Reset and start DAC
|
|
hal_codec_start_playback_stream(id);
|
|
} else {
|
|
#if defined(AUDIO_ANC_FB_MC) || defined(CODEC_DSD)
|
|
adc_en_map |= (1 << CODEC_ADC_EN_REQ_STREAM);
|
|
if (adc_en_map == (1 << CODEC_ADC_EN_REQ_STREAM))
|
|
#endif
|
|
{
|
|
// Reset ADC ANA
|
|
codec->REG_064 &= ~CODEC_SOFT_RSTN_ADC_ANA_MASK;
|
|
codec->REG_064 |= CODEC_SOFT_RSTN_ADC_ANA_MASK;
|
|
|
|
#ifdef AF_ADC_I2S_SYNC
|
|
if (_hal_codec_capture_enable_delay) {
|
|
_hal_codec_capture_enable_delay = false;
|
|
} else {
|
|
hal_codec_capture_enable();
|
|
}
|
|
#else
|
|
codec->REG_080 |= CODEC_CODEC_ADC_EN;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int hal_codec_stop_stream(enum HAL_CODEC_ID_T id, enum AUD_STREAM_T stream) {
|
|
if (stream == AUD_STREAM_PLAYBACK) {
|
|
// Stop and reset DAC
|
|
hal_codec_stop_playback_stream(id);
|
|
} else {
|
|
#if defined(AUDIO_ANC_FB_MC) || defined(CODEC_DSD)
|
|
adc_en_map &= ~(1 << CODEC_ADC_EN_REQ_STREAM);
|
|
if (adc_en_map == 0)
|
|
#endif
|
|
{
|
|
codec->REG_080 &= ~CODEC_CODEC_ADC_EN;
|
|
#ifdef AF_ADC_I2S_SYNC
|
|
_hal_codec_capture_enable_delay = false;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CODEC_DSD
|
|
void hal_codec_dsd_enable(void) { dsd_enabled = true; }
|
|
|
|
void hal_codec_dsd_disable(void) { dsd_enabled = false; }
|
|
|
|
static void hal_codec_dsd_cfg_start(void) {
|
|
#if !(defined(FIXED_CODEC_ADC_VOL) && defined(SINGLE_CODEC_ADC_VOL))
|
|
uint32_t vol;
|
|
const CODEC_ADC_VOL_T *adc_gain_db;
|
|
|
|
vol = hal_codec_get_mic_chan_volume_level(AUD_CHANNEL_MAP_DIGMIC_CH2);
|
|
adc_gain_db = hal_codec_get_adc_volume(vol);
|
|
if (adc_gain_db) {
|
|
hal_codec_set_dig_adc_gain((AUD_CHANNEL_MAP_CH2 | AUD_CHANNEL_MAP_CH3),
|
|
*adc_gain_db);
|
|
}
|
|
#endif
|
|
|
|
codec->REG_004 |= CODEC_DSD_RX_FIFO_FLUSH | CODEC_DSD_TX_FIFO_FLUSH;
|
|
hal_codec_reg_update_delay();
|
|
codec->REG_004 &= ~(CODEC_DSD_RX_FIFO_FLUSH | CODEC_DSD_TX_FIFO_FLUSH);
|
|
|
|
codec->REG_0B8 = CODEC_CODEC_DSD_ENABLE_L | CODEC_CODEC_DSD_ENABLE_R |
|
|
CODEC_CODEC_DSD_SAMPLE_RATE(dsd_rate_idx);
|
|
codec->REG_048 = CODEC_DSD_IF_EN | CODEC_DSD_ENABLE | CODEC_DSD_DUAL_CHANNEL |
|
|
CODEC_MODE_24BIT_DSD |
|
|
/* CODEC_DMA_CTRL_RX_DSD | */ CODEC_DMA_CTRL_TX_DSD |
|
|
CODEC_DSD_IN_16BIT;
|
|
|
|
codec->REG_080 = (codec->REG_080 & ~(CODEC_CODEC_LOOP_SEL_L_MASK |
|
|
CODEC_CODEC_LOOP_SEL_R_MASK)) |
|
|
CODEC_CODEC_ADC_LOOP | CODEC_CODEC_LOOP_SEL_L(2) |
|
|
CODEC_CODEC_LOOP_SEL_R(3);
|
|
|
|
codec->REG_0A8 = SET_BITFIELD(codec->REG_0A8, CODEC_CODEC_PDM_MUX_CH2, 2);
|
|
codec->REG_0A4 |= CODEC_CODEC_PDM_ADC_SEL_CH2;
|
|
codec->REG_0A8 = SET_BITFIELD(codec->REG_0A8, CODEC_CODEC_PDM_MUX_CH3, 3);
|
|
codec->REG_0A4 |= CODEC_CODEC_PDM_ADC_SEL_CH3;
|
|
|
|
codec->REG_064 &=
|
|
~(CODEC_SOFT_RSTN_ADC(1 << 2) | CODEC_SOFT_RSTN_ADC(1 << 3));
|
|
codec->REG_064 |= CODEC_SOFT_RSTN_ADC(1 << 2) | CODEC_SOFT_RSTN_ADC(1 << 3);
|
|
codec->REG_080 |= CODEC_CODEC_ADC_EN_CH2 | CODEC_CODEC_ADC_EN_CH3;
|
|
|
|
if (adc_en_map == 0) {
|
|
// Reset ADC free running clock and ADC ANA
|
|
codec->REG_064 &=
|
|
~(RSTN_ADC_FREE_RUNNING_CLK | CODEC_SOFT_RSTN_ADC_ANA_MASK);
|
|
codec->REG_064 |=
|
|
(RSTN_ADC_FREE_RUNNING_CLK | CODEC_SOFT_RSTN_ADC_ANA_MASK);
|
|
codec->REG_080 |= CODEC_CODEC_ADC_EN;
|
|
}
|
|
adc_en_map |= (1 << CODEC_ADC_EN_REQ_DSD);
|
|
}
|
|
|
|
static void hal_codec_dsd_cfg_stop(void) {
|
|
adc_en_map &= ~(1 << CODEC_ADC_EN_REQ_DSD);
|
|
if (adc_en_map == 0) {
|
|
codec->REG_080 &= ~CODEC_CODEC_ADC_EN;
|
|
}
|
|
|
|
codec->REG_080 &= ~(CODEC_CODEC_ADC_EN_CH2 | CODEC_CODEC_ADC_EN_CH3);
|
|
codec->REG_0A4 &=
|
|
~(CODEC_CODEC_PDM_ADC_SEL_CH2 | CODEC_CODEC_PDM_ADC_SEL_CH3);
|
|
codec->REG_048 = 0;
|
|
codec->REG_0B8 = 0;
|
|
|
|
codec->REG_080 &= ~CODEC_CODEC_ADC_LOOP;
|
|
}
|
|
#endif
|
|
|
|
#ifdef __AUDIO_RESAMPLE__
|
|
void hal_codec_resample_clock_enable(enum AUD_STREAM_T stream) {
|
|
uint32_t clk;
|
|
bool set = false;
|
|
|
|
// 192K-24BIT requires 52M clock, and 384K-24BIT requires 104M clock
|
|
if (stream == AUD_STREAM_PLAYBACK) {
|
|
clk = codec_dac_sample_rate[resample_rate_idx[AUD_STREAM_PLAYBACK]]
|
|
.sample_rate *
|
|
RS_CLOCK_FACTOR;
|
|
} else {
|
|
clk = codec_adc_sample_rate[resample_rate_idx[AUD_STREAM_CAPTURE]]
|
|
.sample_rate *
|
|
RS_CLOCK_FACTOR;
|
|
}
|
|
|
|
if (rs_clk_map == 0) {
|
|
set = true;
|
|
} else {
|
|
if (resample_clk_freq < clk) {
|
|
set = true;
|
|
}
|
|
}
|
|
|
|
if (set) {
|
|
resample_clk_freq = clk;
|
|
hal_cmu_codec_rs_enable(clk);
|
|
}
|
|
|
|
rs_clk_map |= (1 << stream);
|
|
}
|
|
|
|
void hal_codec_resample_clock_disable(enum AUD_STREAM_T stream) {
|
|
if (rs_clk_map == 0) {
|
|
return;
|
|
}
|
|
rs_clk_map &= ~(1 << stream);
|
|
if (rs_clk_map == 0) {
|
|
hal_cmu_codec_rs_disable();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static void hal_codec_enable_dig_mic(enum AUD_CHANNEL_MAP_T mic_map) {
|
|
uint32_t phase = 0;
|
|
uint32_t line_map = 0;
|
|
|
|
phase = codec->REG_0A8;
|
|
for (int i = 0; i < MAX_DIG_MIC_CH_NUM; i++) {
|
|
if (mic_map & (AUD_CHANNEL_MAP_DIGMIC_CH0 << i)) {
|
|
line_map |= (1 << (i / 2));
|
|
}
|
|
phase = (phase & ~(CODEC_CODEC_PDM_CAP_PHASE_CH0_MASK << (i * 2))) |
|
|
(CODEC_CODEC_PDM_CAP_PHASE_CH0(codec_digmic_phase) << (i * 2));
|
|
}
|
|
codec->REG_0A8 = phase;
|
|
codec->REG_0A4 |= CODEC_CODEC_PDM_ENABLE;
|
|
hal_iomux_set_dig_mic(line_map);
|
|
}
|
|
|
|
static void hal_codec_disable_dig_mic(void) {
|
|
codec->REG_0A4 &= ~CODEC_CODEC_PDM_ENABLE;
|
|
}
|
|
|
|
static void hal_codec_set_ec_down_sel(bool dac_rate_valid) {
|
|
uint8_t dac_factor;
|
|
uint8_t adc_factor;
|
|
uint8_t d, a;
|
|
uint8_t val;
|
|
uint8_t sel = 0;
|
|
bool err = false;
|
|
|
|
if (dac_rate_valid) {
|
|
d = codec_rate_idx[AUD_STREAM_PLAYBACK];
|
|
if (codec_dac_sample_rate[d].sample_rate < AUD_SAMPRATE_44100) {
|
|
dac_factor = (6 / codec_dac_sample_rate[d].dac_up) *
|
|
(codec_dac_sample_rate[d].bypass_cnt + 1);
|
|
} else {
|
|
// SINC to 48K/44.1K
|
|
dac_factor = (6 / 1) * (0 + 1);
|
|
}
|
|
a = codec_rate_idx[AUD_STREAM_CAPTURE];
|
|
adc_factor = (6 / codec_adc_sample_rate[a].adc_down) *
|
|
(codec_adc_sample_rate[a].bypass_cnt + 1);
|
|
|
|
val = dac_factor / adc_factor;
|
|
if (val * adc_factor == dac_factor) {
|
|
if (val == 3) {
|
|
sel = 0;
|
|
} else if (val == 6) {
|
|
sel = 1;
|
|
} else if (val == 1) {
|
|
sel = 2;
|
|
} else if (val == 2) {
|
|
sel = 3;
|
|
} else {
|
|
err = true;
|
|
}
|
|
} else {
|
|
err = true;
|
|
}
|
|
|
|
ASSERT(!err, "%s: Invalid EC sample rate: play=%u cap=%u", __FUNCTION__,
|
|
codec_dac_sample_rate[d].sample_rate,
|
|
codec_adc_sample_rate[a].sample_rate);
|
|
} else {
|
|
sel = 0;
|
|
}
|
|
|
|
uint32_t ec_mask, ec_val;
|
|
|
|
ec_mask = 0;
|
|
ec_val = 0;
|
|
if (codec_adc_ch_map & AUD_CHANNEL_MAP_CH5) {
|
|
ec_mask |= CODEC_CODEC_DOWN_SEL_MC_CH0_MASK;
|
|
ec_val |= CODEC_CODEC_DOWN_SEL_MC_CH0(sel);
|
|
}
|
|
if (codec_adc_ch_map & AUD_CHANNEL_MAP_CH6) {
|
|
ec_mask |= CODEC_CODEC_DOWN_SEL_MC_CH1_MASK;
|
|
ec_val |= CODEC_CODEC_DOWN_SEL_MC_CH1(sel);
|
|
}
|
|
codec->REG_228 = (codec->REG_228 & ~ec_mask) | ec_val;
|
|
}
|
|
|
|
static void hal_codec_ec_enable(void) {
|
|
uint32_t ec_val;
|
|
bool dac_rate_valid;
|
|
uint8_t a;
|
|
|
|
dac_rate_valid = !!(codec->REG_000 & CODEC_DAC_ENABLE);
|
|
|
|
hal_codec_set_ec_down_sel(dac_rate_valid);
|
|
|
|
// If no normal ADC chan, ADC0 must be enabled
|
|
if ((codec_adc_ch_map & ~EC_ADC_MAP) == 0) {
|
|
a = codec_rate_idx[AUD_STREAM_CAPTURE];
|
|
hal_codec_set_adc_down(AUD_CHANNEL_MAP_CH0,
|
|
codec_adc_sample_rate[a].adc_down);
|
|
hal_codec_set_adc_hbf_bypass_cnt(AUD_CHANNEL_MAP_CH0,
|
|
codec_adc_sample_rate[a].bypass_cnt);
|
|
codec->REG_080 |= CODEC_CODEC_ADC_EN_CH0;
|
|
}
|
|
|
|
ec_val = 0;
|
|
if (codec_adc_ch_map & AUD_CHANNEL_MAP_CH5) {
|
|
ec_val |= CODEC_CODEC_MC_ENABLE_CH0;
|
|
}
|
|
if (codec_adc_ch_map & AUD_CHANNEL_MAP_CH6) {
|
|
ec_val |= CODEC_CODEC_MC_ENABLE_CH1;
|
|
}
|
|
if (codec->REG_0E4 & CODEC_CODEC_RESAMPLE_ADC_PHASE_UPDATE) {
|
|
ec_val |= CODEC_CODEC_RESAMPLE_MC_ENABLE;
|
|
if ((codec_adc_ch_map & EC_ADC_MAP) == EC_ADC_MAP) {
|
|
ec_val |= CODEC_CODEC_RESAMPLE_MC_DUAL_CH;
|
|
}
|
|
}
|
|
codec->REG_228 |= ec_val;
|
|
}
|
|
|
|
static void hal_codec_ec_disable(void) {
|
|
codec->REG_228 &=
|
|
~(CODEC_CODEC_MC_ENABLE_CH0 | CODEC_CODEC_MC_ENABLE_CH1 |
|
|
CODEC_CODEC_RESAMPLE_MC_ENABLE | CODEC_CODEC_RESAMPLE_MC_DUAL_CH);
|
|
if ((codec_adc_ch_map & ~EC_ADC_MAP) == 0 &&
|
|
(anc_adc_ch_map & AUD_CHANNEL_MAP_CH0) == 0) {
|
|
codec->REG_080 &= ~CODEC_CODEC_ADC_EN_CH0;
|
|
}
|
|
}
|
|
|
|
int hal_codec_start_interface(enum HAL_CODEC_ID_T id, enum AUD_STREAM_T stream,
|
|
int dma) {
|
|
uint32_t fifo_flush = 0;
|
|
|
|
if (stream == AUD_STREAM_PLAYBACK) {
|
|
#ifdef CODEC_DSD
|
|
if (dsd_enabled) {
|
|
hal_codec_dsd_cfg_start();
|
|
}
|
|
#endif
|
|
#ifdef CODEC_MIN_PHASE
|
|
if (min_phase_cfg & (1 << AUD_STREAM_PLAYBACK)) {
|
|
if (codec_dac_ch_map & AUD_CHANNEL_MAP_CH0) {
|
|
codec->REG_100 |= CODEC_FIR_STREAM_ENABLE_CH0;
|
|
codec->REG_098 |= CODEC_CODEC_DAC_L_FIR_UPSAMPLE;
|
|
}
|
|
if (codec_dac_ch_map & AUD_CHANNEL_MAP_CH1) {
|
|
codec->REG_100 |= CODEC_FIR_STREAM_ENABLE_CH1;
|
|
codec->REG_098 |= CODEC_CODEC_DAC_R_FIR_UPSAMPLE;
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef __AUDIO_RESAMPLE__
|
|
if (codec->REG_0E4 & CODEC_CODEC_RESAMPLE_DAC_PHASE_UPDATE) {
|
|
hal_codec_resample_clock_enable(stream);
|
|
#if (defined(__TWS__) || defined(IBRT)) && defined(ANC_APP)
|
|
enum HAL_CODEC_SYNC_TYPE_T sync_type;
|
|
|
|
sync_type =
|
|
GET_BITFIELD(codec->REG_0E4, CODEC_CODEC_RESAMPLE_DAC_TRIGGER_SEL);
|
|
if (sync_type != HAL_CODEC_SYNC_TYPE_NONE) {
|
|
codec->REG_0E4 =
|
|
SET_BITFIELD(codec->REG_0E4, CODEC_CODEC_RESAMPLE_DAC_TRIGGER_SEL,
|
|
HAL_CODEC_SYNC_TYPE_NONE);
|
|
codec->REG_0E4 &= ~CODEC_CODEC_RESAMPLE_DAC_PHASE_UPDATE;
|
|
hal_codec_reg_update_delay();
|
|
codec->REG_0F4 = resample_phase_float_to_value(1.0f);
|
|
hal_codec_reg_update_delay();
|
|
codec->REG_0E4 |= CODEC_CODEC_RESAMPLE_DAC_PHASE_UPDATE;
|
|
hal_codec_reg_update_delay();
|
|
codec->REG_0E4 &= ~CODEC_CODEC_RESAMPLE_DAC_PHASE_UPDATE;
|
|
codec->REG_0E4 = SET_BITFIELD(
|
|
codec->REG_0E4, CODEC_CODEC_RESAMPLE_DAC_TRIGGER_SEL, sync_type);
|
|
hal_codec_reg_update_delay();
|
|
codec->REG_0F4 =
|
|
resample_phase_float_to_value(get_playback_resample_phase());
|
|
codec->REG_0E4 |= CODEC_CODEC_RESAMPLE_DAC_PHASE_UPDATE;
|
|
}
|
|
#endif
|
|
codec->REG_0E4 |= CODEC_CODEC_RESAMPLE_DAC_ENABLE;
|
|
}
|
|
#endif
|
|
if ((codec->REG_000 & CODEC_ADC_ENABLE) &&
|
|
(codec_adc_ch_map & EC_ADC_MAP)) {
|
|
hal_codec_set_ec_down_sel(true);
|
|
}
|
|
#ifdef AUDIO_ANC_FB_MC
|
|
fifo_flush |= CODEC_MC_FIFO_FLUSH;
|
|
#endif
|
|
fifo_flush |= CODEC_TX_FIFO_FLUSH;
|
|
codec->REG_004 |= fifo_flush;
|
|
hal_codec_reg_update_delay();
|
|
codec->REG_004 &= ~fifo_flush;
|
|
if (dma) {
|
|
codec->REG_008 = SET_BITFIELD(codec->REG_008, CODEC_CODEC_TX_THRESHOLD,
|
|
HAL_CODEC_TX_FIFO_TRIGGER_LEVEL);
|
|
codec->REG_000 |= CODEC_DMACTRL_TX;
|
|
// Delay a little time for DMA to fill the TX FIFO before sending
|
|
for (volatile int i = 0; i < 50; i++)
|
|
;
|
|
}
|
|
#ifdef AUDIO_ANC_FB_MC
|
|
if (mc_dual_chan) {
|
|
codec->REG_04C |= CODEC_DUAL_CHANNEL_MC;
|
|
} else {
|
|
codec->REG_04C &= ~CODEC_DUAL_CHANNEL_MC;
|
|
}
|
|
if (mc_16bit) {
|
|
codec->REG_04C |= CODEC_MODE_16BIT_MC;
|
|
} else {
|
|
codec->REG_04C &= ~CODEC_MODE_16BIT_MC;
|
|
}
|
|
if (adc_en_map == 0) {
|
|
// Reset ADC free running clock and ADC ANA
|
|
codec->REG_064 &=
|
|
~(RSTN_ADC_FREE_RUNNING_CLK | CODEC_SOFT_RSTN_ADC_ANA_MASK);
|
|
codec->REG_064 |=
|
|
(RSTN_ADC_FREE_RUNNING_CLK | CODEC_SOFT_RSTN_ADC_ANA_MASK);
|
|
codec->REG_080 |= CODEC_CODEC_ADC_EN;
|
|
}
|
|
adc_en_map |= (1 << CODEC_ADC_EN_REQ_MC);
|
|
// If codec function has been enabled, start FIFOs directly;
|
|
// otherwise, start FIFOs after PA is enabled
|
|
if (codec->REG_098 & CODEC_CODEC_DAC_EN) {
|
|
uint32_t lock;
|
|
lock = int_lock();
|
|
// MC FIFO and DAC FIFO must be started at the same time
|
|
codec->REG_04C |= CODEC_MC_ENABLE;
|
|
codec->REG_000 |= CODEC_DAC_ENABLE;
|
|
int_unlock(lock);
|
|
}
|
|
mc_enabled = true;
|
|
#else
|
|
codec->REG_000 |= CODEC_DAC_ENABLE;
|
|
#endif
|
|
} else {
|
|
#ifdef VOICE_DETECTOR_EN
|
|
if ((codec_adc_ch_map & AUD_CHANNEL_MAP_CH4) &&
|
|
(vad_type == AUD_VAD_TYPE_MIX || vad_type == AUD_VAD_TYPE_DIG)) {
|
|
// Stop vad buffering
|
|
hal_codec_vad_stop();
|
|
}
|
|
#endif
|
|
#ifdef CODEC_MIN_PHASE
|
|
if (min_phase_cfg & (1 << AUD_STREAM_CAPTURE)) {
|
|
if (codec_adc_ch_map & AUD_CHANNEL_MAP_CH2) {
|
|
codec->REG_100 |= CODEC_FIR_STREAM_ENABLE_CH2;
|
|
codec->REG_0D0 |= CODEC_CODEC_ADC_FIR_DS_EN_CH2;
|
|
}
|
|
if (codec_adc_ch_map & AUD_CHANNEL_MAP_CH3) {
|
|
codec->REG_100 |= CODEC_FIR_STREAM_ENABLE_CH3;
|
|
codec->REG_0D0 |= CODEC_CODEC_ADC_FIR_DS_EN_CH3;
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef __AUDIO_RESAMPLE__
|
|
if (codec->REG_0E4 & CODEC_CODEC_RESAMPLE_ADC_PHASE_UPDATE) {
|
|
hal_codec_resample_clock_enable(stream);
|
|
#if (defined(__TWS__) || defined(IBRT)) && defined(ANC_APP)
|
|
enum HAL_CODEC_SYNC_TYPE_T sync_type;
|
|
|
|
sync_type =
|
|
GET_BITFIELD(codec->REG_0E4, CODEC_CODEC_RESAMPLE_ADC_TRIGGER_SEL);
|
|
if (sync_type != HAL_CODEC_SYNC_TYPE_NONE) {
|
|
codec->REG_0E4 =
|
|
SET_BITFIELD(codec->REG_0E4, CODEC_CODEC_RESAMPLE_ADC_TRIGGER_SEL,
|
|
HAL_CODEC_SYNC_TYPE_NONE);
|
|
codec->REG_0E4 &= ~CODEC_CODEC_RESAMPLE_ADC_PHASE_UPDATE;
|
|
hal_codec_reg_update_delay();
|
|
codec->REG_0F8 = resample_phase_float_to_value(1.0f);
|
|
hal_codec_reg_update_delay();
|
|
codec->REG_0E4 |= CODEC_CODEC_RESAMPLE_ADC_PHASE_UPDATE;
|
|
hal_codec_reg_update_delay();
|
|
codec->REG_0E4 &= ~CODEC_CODEC_RESAMPLE_ADC_PHASE_UPDATE;
|
|
codec->REG_0E4 = SET_BITFIELD(
|
|
codec->REG_0E4, CODEC_CODEC_RESAMPLE_ADC_TRIGGER_SEL, sync_type);
|
|
hal_codec_reg_update_delay();
|
|
codec->REG_0F8 =
|
|
resample_phase_float_to_value(get_capture_resample_phase());
|
|
codec->REG_0E4 |= CODEC_CODEC_RESAMPLE_ADC_PHASE_UPDATE;
|
|
}
|
|
#endif
|
|
codec->REG_0E4 |= CODEC_CODEC_RESAMPLE_ADC_ENABLE;
|
|
}
|
|
#endif
|
|
if (codec_mic_ch_map & AUD_CHANNEL_MAP_DIGMIC_ALL) {
|
|
hal_codec_enable_dig_mic(codec_mic_ch_map);
|
|
}
|
|
if (codec_adc_ch_map & EC_ADC_MAP) {
|
|
hal_codec_ec_enable();
|
|
}
|
|
for (int i = 0; i < MAX_ADC_CH_NUM; i++) {
|
|
if (codec_adc_ch_map & (AUD_CHANNEL_MAP_CH0 << i)) {
|
|
if (i < NORMAL_ADC_CH_NUM &&
|
|
(codec->REG_080 & (CODEC_CODEC_ADC_EN_CH0 << i)) == 0) {
|
|
// Reset ADC channel
|
|
codec->REG_064 &= ~CODEC_SOFT_RSTN_ADC(1 << i);
|
|
codec->REG_064 |= CODEC_SOFT_RSTN_ADC(1 << i);
|
|
codec->REG_080 |= (CODEC_CODEC_ADC_EN_CH0 << i);
|
|
}
|
|
codec->REG_000 |= (CODEC_ADC_ENABLE_CH0 << i);
|
|
}
|
|
}
|
|
fifo_flush = CODEC_RX_FIFO_FLUSH_CH0 | CODEC_RX_FIFO_FLUSH_CH1 |
|
|
CODEC_RX_FIFO_FLUSH_CH2 | CODEC_RX_FIFO_FLUSH_CH3 |
|
|
CODEC_RX_FIFO_FLUSH_CH4 | CODEC_RX_FIFO_FLUSH_CH5 |
|
|
CODEC_RX_FIFO_FLUSH_CH6;
|
|
codec->REG_004 |= fifo_flush;
|
|
hal_codec_reg_update_delay();
|
|
codec->REG_004 &= ~fifo_flush;
|
|
if (dma) {
|
|
codec->REG_008 = SET_BITFIELD(codec->REG_008, CODEC_CODEC_RX_THRESHOLD,
|
|
HAL_CODEC_RX_FIFO_TRIGGER_LEVEL);
|
|
codec->REG_000 |= CODEC_DMACTRL_RX;
|
|
}
|
|
codec->REG_000 |= CODEC_ADC_ENABLE;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int hal_codec_stop_interface(enum HAL_CODEC_ID_T id, enum AUD_STREAM_T stream) {
|
|
uint32_t fifo_flush = 0;
|
|
|
|
if (stream == AUD_STREAM_PLAYBACK) {
|
|
codec->REG_000 &= ~CODEC_DAC_ENABLE;
|
|
codec->REG_000 &= ~CODEC_DMACTRL_TX;
|
|
#ifdef __AUDIO_RESAMPLE__
|
|
codec->REG_0E4 &= ~CODEC_CODEC_RESAMPLE_DAC_ENABLE;
|
|
hal_codec_resample_clock_disable(stream);
|
|
#endif
|
|
#ifdef CODEC_MIN_PHASE
|
|
if (min_phase_cfg & (1 << AUD_STREAM_PLAYBACK)) {
|
|
if (codec_dac_ch_map & AUD_CHANNEL_MAP_CH0) {
|
|
codec->REG_100 &= ~CODEC_FIR_STREAM_ENABLE_CH0;
|
|
codec->REG_098 &= ~CODEC_CODEC_DAC_L_FIR_UPSAMPLE;
|
|
}
|
|
if (codec_dac_ch_map & AUD_CHANNEL_MAP_CH1) {
|
|
codec->REG_100 &= ~CODEC_FIR_STREAM_ENABLE_CH1;
|
|
codec->REG_098 &= ~CODEC_CODEC_DAC_R_FIR_UPSAMPLE;
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef CODEC_DSD
|
|
hal_codec_dsd_cfg_stop();
|
|
dsd_enabled = false;
|
|
#endif
|
|
#ifdef AUDIO_ANC_FB_MC
|
|
mc_enabled = false;
|
|
codec->REG_04C &= ~CODEC_MC_ENABLE;
|
|
adc_en_map &= ~(1 << CODEC_ADC_EN_REQ_MC);
|
|
if (adc_en_map == 0) {
|
|
codec->REG_080 &= ~CODEC_CODEC_ADC_EN;
|
|
}
|
|
fifo_flush |= CODEC_MC_FIFO_FLUSH;
|
|
#endif
|
|
fifo_flush |= CODEC_TX_FIFO_FLUSH;
|
|
codec->REG_004 |= fifo_flush;
|
|
hal_codec_reg_update_delay();
|
|
codec->REG_004 &= ~fifo_flush;
|
|
// Cancel dac sync request
|
|
hal_codec_sync_dac_disable();
|
|
hal_codec_sync_dac_resample_rate_disable();
|
|
hal_codec_sync_dac_gain_disable();
|
|
#ifdef NO_DAC_RESET
|
|
// Clean up DAC intermediate states
|
|
osDelay(dac_delay_ms);
|
|
#endif
|
|
} else {
|
|
codec->REG_000 &=
|
|
~(CODEC_ADC_ENABLE | CODEC_ADC_ENABLE_CH0 | CODEC_ADC_ENABLE_CH1 |
|
|
CODEC_ADC_ENABLE_CH2 | CODEC_ADC_ENABLE_CH3 | CODEC_ADC_ENABLE_CH4 |
|
|
CODEC_ADC_ENABLE_CH5 | CODEC_ADC_ENABLE_CH6);
|
|
codec->REG_000 &= ~CODEC_DMACTRL_RX;
|
|
for (int i = 0; i < MAX_ADC_CH_NUM; i++) {
|
|
if (i < NORMAL_ADC_CH_NUM &&
|
|
(codec_adc_ch_map & (AUD_CHANNEL_MAP_CH0 << i)) &&
|
|
(anc_adc_ch_map & (AUD_CHANNEL_MAP_CH0 << i)) == 0) {
|
|
codec->REG_080 &= ~(CODEC_CODEC_ADC_EN_CH0 << i);
|
|
}
|
|
}
|
|
if (codec_adc_ch_map & EC_ADC_MAP) {
|
|
hal_codec_ec_disable();
|
|
}
|
|
if ((codec_mic_ch_map & AUD_CHANNEL_MAP_DIGMIC_ALL) &&
|
|
(anc_mic_ch_map & AUD_CHANNEL_MAP_DIGMIC_ALL) == 0) {
|
|
hal_codec_disable_dig_mic();
|
|
}
|
|
#ifdef __AUDIO_RESAMPLE__
|
|
codec->REG_0E4 &= ~CODEC_CODEC_RESAMPLE_ADC_ENABLE;
|
|
hal_codec_resample_clock_disable(stream);
|
|
#endif
|
|
#ifdef CODEC_MIN_PHASE
|
|
if (min_phase_cfg & (1 << AUD_STREAM_CAPTURE)) {
|
|
if (codec_adc_ch_map & AUD_CHANNEL_MAP_CH2) {
|
|
codec->REG_100 &= ~CODEC_FIR_STREAM_ENABLE_CH2;
|
|
codec->REG_0D0 &= ~CODEC_CODEC_ADC_FIR_DS_EN_CH2;
|
|
}
|
|
if (codec_adc_ch_map & AUD_CHANNEL_MAP_CH3) {
|
|
codec->REG_100 &= ~CODEC_FIR_STREAM_ENABLE_CH3;
|
|
codec->REG_0D0 &= ~CODEC_CODEC_ADC_FIR_DS_EN_CH3;
|
|
}
|
|
}
|
|
#endif
|
|
fifo_flush = CODEC_RX_FIFO_FLUSH_CH0 | CODEC_RX_FIFO_FLUSH_CH1 |
|
|
CODEC_RX_FIFO_FLUSH_CH2 | CODEC_RX_FIFO_FLUSH_CH3 |
|
|
CODEC_RX_FIFO_FLUSH_CH4 | CODEC_RX_FIFO_FLUSH_CH5 |
|
|
CODEC_RX_FIFO_FLUSH_CH6;
|
|
codec->REG_004 |= fifo_flush;
|
|
hal_codec_reg_update_delay();
|
|
codec->REG_004 &= ~fifo_flush;
|
|
// Cancel adc sync request
|
|
hal_codec_sync_adc_disable();
|
|
hal_codec_sync_adc_resample_rate_disable();
|
|
hal_codec_sync_adc_gain_disable();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void hal_codec_set_dac_gain_value(enum AUD_CHANNEL_MAP_T map,
|
|
uint32_t val) {
|
|
codec->REG_09C &= ~CODEC_CODEC_DAC_GAIN_UPDATE;
|
|
hal_codec_reg_update_delay();
|
|
if (map & AUD_CHANNEL_MAP_CH0) {
|
|
codec->REG_09C =
|
|
SET_BITFIELD(codec->REG_09C, CODEC_CODEC_DAC_GAIN_CH0, val);
|
|
}
|
|
if (map & AUD_CHANNEL_MAP_CH1) {
|
|
codec->REG_0A0 =
|
|
SET_BITFIELD(codec->REG_0A0, CODEC_CODEC_DAC_GAIN_CH1, val);
|
|
}
|
|
codec->REG_09C |= CODEC_CODEC_DAC_GAIN_UPDATE;
|
|
}
|
|
|
|
void hal_codec_get_dac_gain(float *left_gain, float *right_gain) {
|
|
struct DAC_GAIN_T {
|
|
int32_t v : 20;
|
|
};
|
|
|
|
struct DAC_GAIN_T left;
|
|
struct DAC_GAIN_T right;
|
|
|
|
left.v = GET_BITFIELD(codec->REG_09C, CODEC_CODEC_DAC_GAIN_CH0);
|
|
right.v = GET_BITFIELD(codec->REG_0A0, CODEC_CODEC_DAC_GAIN_CH1);
|
|
|
|
*left_gain = left.v;
|
|
*right_gain = right.v;
|
|
|
|
// Gain format: 6.14
|
|
*left_gain /= (1 << 14);
|
|
*right_gain /= (1 << 14);
|
|
}
|
|
|
|
void hal_codec_dac_mute(bool mute) {
|
|
codec_mute[AUD_STREAM_PLAYBACK] = mute;
|
|
|
|
#ifdef AUDIO_OUTPUT_SW_GAIN
|
|
hal_codec_set_sw_gain(swdac_gain);
|
|
#else
|
|
if (mute) {
|
|
hal_codec_set_dac_gain_value(VALID_DAC_MAP, 0);
|
|
} else {
|
|
hal_codec_restore_dig_dac_gain();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static float db_to_amplitude_ratio(int32_t db) {
|
|
float coef;
|
|
|
|
if (db == ZERODB_DIG_DBVAL) {
|
|
coef = 1;
|
|
} else if (db <= MIN_DIG_DBVAL) {
|
|
coef = 0;
|
|
} else {
|
|
if (db > MAX_DIG_DBVAL) {
|
|
db = MAX_DIG_DBVAL;
|
|
}
|
|
coef = db_to_float(db);
|
|
}
|
|
|
|
return coef;
|
|
}
|
|
|
|
static float digdac_gain_to_float(int32_t gain) {
|
|
float coef;
|
|
|
|
#if defined(NOISE_GATING) && defined(NOISE_REDUCTION)
|
|
gain += digdac_gain_offset_nr;
|
|
#endif
|
|
|
|
coef = db_to_amplitude_ratio(gain);
|
|
|
|
#ifdef AUDIO_OUTPUT_DC_CALIB
|
|
coef *= dac_dc_gain_attn;
|
|
#endif
|
|
|
|
#ifdef ANC_APP
|
|
coef *= anc_boost_gain_attn;
|
|
#endif
|
|
|
|
#if 0
|
|
static const float thd_attn = 0.982878873; // -0.15dB
|
|
|
|
// Ensure that THD is good at max gain
|
|
if (coef > thd_attn) {
|
|
coef = thd_attn;
|
|
}
|
|
#endif
|
|
|
|
return coef;
|
|
}
|
|
|
|
static void hal_codec_set_dig_dac_gain(enum AUD_CHANNEL_MAP_T map,
|
|
int32_t gain) {
|
|
uint32_t val;
|
|
float coef;
|
|
bool mute;
|
|
|
|
if (map & AUD_CHANNEL_MAP_CH0) {
|
|
digdac_gain[0] = gain;
|
|
}
|
|
if (map & AUD_CHANNEL_MAP_CH1) {
|
|
digdac_gain[1] = gain;
|
|
}
|
|
|
|
#ifdef AUDIO_OUTPUT_SW_GAIN
|
|
mute = false;
|
|
#else
|
|
mute = codec_mute[AUD_STREAM_PLAYBACK];
|
|
#endif
|
|
|
|
#ifdef AUDIO_OUTPUT_DC_CALIB_ANA
|
|
if (codec->REG_098 & CODEC_CODEC_DAC_SDM_CLOSE) {
|
|
mute = true;
|
|
}
|
|
#endif
|
|
|
|
if (mute) {
|
|
val = 0;
|
|
} else {
|
|
coef = digdac_gain_to_float(gain);
|
|
|
|
// Gain format: 6.14
|
|
int32_t s_val = (int32_t)(coef * (1 << 14));
|
|
val = __SSAT(s_val, 20);
|
|
}
|
|
|
|
hal_codec_set_dac_gain_value(map, val);
|
|
}
|
|
|
|
static void hal_codec_restore_dig_dac_gain(void) {
|
|
if (digdac_gain[0] == digdac_gain[1]) {
|
|
hal_codec_set_dig_dac_gain(VALID_DAC_MAP, digdac_gain[0]);
|
|
} else {
|
|
hal_codec_set_dig_dac_gain(AUD_CHANNEL_MAP_CH0, digdac_gain[0]);
|
|
hal_codec_set_dig_dac_gain(AUD_CHANNEL_MAP_CH1, digdac_gain[1]);
|
|
}
|
|
}
|
|
|
|
#ifdef AUDIO_OUTPUT_SW_GAIN
|
|
static void hal_codec_set_sw_gain(int32_t gain) {
|
|
float coef;
|
|
bool mute;
|
|
|
|
swdac_gain = gain;
|
|
|
|
mute = codec_mute[AUD_STREAM_PLAYBACK];
|
|
|
|
if (mute) {
|
|
coef = 0;
|
|
} else {
|
|
coef = digdac_gain_to_float(gain);
|
|
}
|
|
|
|
if (sw_output_coef_callback) {
|
|
sw_output_coef_callback(coef);
|
|
}
|
|
}
|
|
|
|
void hal_codec_set_sw_output_coef_callback(
|
|
HAL_CODEC_SW_OUTPUT_COEF_CALLBACK callback) {
|
|
sw_output_coef_callback = callback;
|
|
}
|
|
#endif
|
|
|
|
static void hal_codec_set_adc_gain_value(enum AUD_CHANNEL_MAP_T map,
|
|
uint32_t val) {
|
|
uint32_t gain_update = 0;
|
|
|
|
for (int i = 0; i < NORMAL_ADC_CH_NUM; i++) {
|
|
if (map & (AUD_CHANNEL_MAP_CH0 << i)) {
|
|
*(&codec->REG_084 + i) =
|
|
SET_BITFIELD(*(&codec->REG_084 + i), CODEC_CODEC_ADC_GAIN_CH0, val);
|
|
gain_update |= (CODEC_CODEC_ADC_GAIN_UPDATE_CH0 << i);
|
|
}
|
|
}
|
|
codec->REG_09C &= ~gain_update;
|
|
hal_codec_reg_update_delay();
|
|
codec->REG_09C |= gain_update;
|
|
}
|
|
|
|
static void hal_codec_set_dig_adc_gain(enum AUD_CHANNEL_MAP_T map,
|
|
int32_t gain) {
|
|
uint32_t val;
|
|
float coef;
|
|
bool mute;
|
|
int i;
|
|
int32_t s_val;
|
|
|
|
for (i = 0; i < NORMAL_ADC_CH_NUM; i++) {
|
|
if (map & (1 << i)) {
|
|
digadc_gain[i] = gain;
|
|
}
|
|
}
|
|
|
|
mute = codec_mute[AUD_STREAM_CAPTURE];
|
|
|
|
if (mute) {
|
|
val = 0;
|
|
} else {
|
|
#ifdef ANC_APP
|
|
enum AUD_CHANNEL_MAP_T adj_map;
|
|
int32_t anc_gain;
|
|
|
|
adj_map = map & anc_adc_gain_offset_map;
|
|
while (adj_map) {
|
|
i = get_msb_pos(adj_map);
|
|
adj_map &= ~(1 << i);
|
|
anc_gain = gain + anc_adc_gain_offset[i];
|
|
coef = db_to_amplitude_ratio(anc_gain);
|
|
coef /= anc_boost_gain_attn;
|
|
// Gain format: 8.12
|
|
s_val = (int32_t)(coef * (1 << 12));
|
|
val = __SSAT(s_val, 20);
|
|
hal_codec_set_adc_gain_value((1 << i), val);
|
|
}
|
|
|
|
map &= ~anc_adc_gain_offset_map;
|
|
#endif
|
|
|
|
if (map) {
|
|
coef = db_to_amplitude_ratio(gain);
|
|
#ifdef ANC_APP
|
|
coef /= anc_boost_gain_attn;
|
|
#endif
|
|
// Gain format: 8.12
|
|
s_val = (int32_t)(coef * (1 << 12));
|
|
val = __SSAT(s_val, 20);
|
|
} else {
|
|
val = 0;
|
|
}
|
|
}
|
|
|
|
hal_codec_set_adc_gain_value(map, val);
|
|
}
|
|
|
|
static void hal_codec_restore_dig_adc_gain(void) {
|
|
int i;
|
|
|
|
for (i = 0; i < NORMAL_ADC_CH_NUM; i++) {
|
|
hal_codec_set_dig_adc_gain((1 << i), digadc_gain[i]);
|
|
}
|
|
}
|
|
|
|
static void POSSIBLY_UNUSED hal_codec_get_adc_gain(enum AUD_CHANNEL_MAP_T map,
|
|
float *gain) {
|
|
struct ADC_GAIN_T {
|
|
int32_t v : 20;
|
|
};
|
|
|
|
struct ADC_GAIN_T adc_val;
|
|
|
|
for (int i = 0; i < NORMAL_ADC_CH_NUM; i++) {
|
|
if (map & (AUD_CHANNEL_MAP_CH0 << i)) {
|
|
adc_val.v =
|
|
GET_BITFIELD(*(&codec->REG_084 + i), CODEC_CODEC_ADC_GAIN_CH0);
|
|
|
|
*gain = adc_val.v;
|
|
// Gain format: 8.12
|
|
*gain /= (1 << 12);
|
|
return;
|
|
}
|
|
}
|
|
|
|
*gain = 0;
|
|
}
|
|
|
|
void hal_codec_adc_mute(bool mute) {
|
|
codec_mute[AUD_STREAM_CAPTURE] = mute;
|
|
|
|
if (mute) {
|
|
hal_codec_set_adc_gain_value(NORMAL_ADC_MAP, 0);
|
|
} else {
|
|
hal_codec_restore_dig_adc_gain();
|
|
}
|
|
}
|
|
|
|
int hal_codec_set_chan_vol(enum AUD_STREAM_T stream,
|
|
enum AUD_CHANNEL_MAP_T ch_map, uint8_t vol) {
|
|
if (stream == AUD_STREAM_PLAYBACK) {
|
|
#ifdef AUDIO_OUTPUT_SW_GAIN
|
|
ASSERT(false, "%s: Cannot set play chan vol with AUDIO_OUTPUT_SW_GAIN",
|
|
__func__);
|
|
#else
|
|
#ifdef SINGLE_CODEC_DAC_VOL
|
|
ASSERT(false, "%s: Cannot set play chan vol with SINGLE_CODEC_DAC_VOL",
|
|
__func__);
|
|
#else
|
|
const struct CODEC_DAC_VOL_T *vol_tab_ptr;
|
|
|
|
vol_tab_ptr = hal_codec_get_dac_volume(vol);
|
|
if (vol_tab_ptr) {
|
|
if (ch_map & AUD_CHANNEL_MAP_CH0) {
|
|
hal_codec_set_dig_dac_gain(AUD_CHANNEL_MAP_CH0,
|
|
vol_tab_ptr->sdac_volume);
|
|
}
|
|
if (ch_map & AUD_CHANNEL_MAP_CH1) {
|
|
hal_codec_set_dig_dac_gain(AUD_CHANNEL_MAP_CH1,
|
|
vol_tab_ptr->sdac_volume);
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
} else {
|
|
#ifdef SINGLE_CODEC_ADC_VOL
|
|
ASSERT(false, "%s: Cannot set cap chan vol with SINGLE_CODEC_ADC_VOL",
|
|
__func__);
|
|
#else
|
|
uint8_t mic_ch, adc_ch;
|
|
enum AUD_CHANNEL_MAP_T map;
|
|
const CODEC_ADC_VOL_T *adc_gain_db;
|
|
|
|
adc_gain_db = hal_codec_get_adc_volume(vol);
|
|
if (adc_gain_db) {
|
|
map = ch_map & ~EC_MIC_MAP;
|
|
while (map) {
|
|
mic_ch = get_lsb_pos(map);
|
|
map &= ~(1 << mic_ch);
|
|
adc_ch = hal_codec_get_adc_chan(1 << mic_ch);
|
|
ASSERT(adc_ch < NORMAL_ADC_CH_NUM, "%s: Bad cap ch_map=0x%X (ch=%u)",
|
|
__func__, ch_map, mic_ch);
|
|
hal_codec_set_dig_adc_gain((1 << adc_ch), *adc_gain_db);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int hal_codec_set_dac_hbf_bypass_cnt(uint32_t cnt) {
|
|
uint32_t bypass = 0;
|
|
uint32_t bypass_mask = CODEC_CODEC_DAC_HBF1_BYPASS |
|
|
CODEC_CODEC_DAC_HBF2_BYPASS |
|
|
CODEC_CODEC_DAC_HBF3_BYPASS;
|
|
|
|
if (cnt == 0) {
|
|
} else if (cnt == 1) {
|
|
bypass = CODEC_CODEC_DAC_HBF3_BYPASS;
|
|
} else if (cnt == 2) {
|
|
bypass = CODEC_CODEC_DAC_HBF2_BYPASS | CODEC_CODEC_DAC_HBF3_BYPASS;
|
|
} else if (cnt == 3) {
|
|
bypass = CODEC_CODEC_DAC_HBF1_BYPASS | CODEC_CODEC_DAC_HBF2_BYPASS |
|
|
CODEC_CODEC_DAC_HBF3_BYPASS;
|
|
} else {
|
|
ASSERT(false, "%s: Invalid dac bypass cnt: %u", __FUNCTION__, cnt);
|
|
}
|
|
|
|
// OSR is fixed to 512
|
|
// codec->REG_098 = SET_BITFIELD(codec->REG_098, CODEC_CODEC_DAC_OSR_SEL, 2);
|
|
|
|
codec->REG_098 = (codec->REG_098 & ~bypass_mask) | bypass;
|
|
return 0;
|
|
}
|
|
|
|
static int hal_codec_set_dac_up(uint32_t val) {
|
|
uint32_t sel = 0;
|
|
|
|
if (val == 2) {
|
|
sel = 0;
|
|
} else if (val == 3) {
|
|
sel = 1;
|
|
} else if (val == 4) {
|
|
sel = 2;
|
|
} else if (val == 6) {
|
|
sel = 3;
|
|
} else if (val == 1) {
|
|
sel = 4;
|
|
} else {
|
|
ASSERT(false, "%s: Invalid dac up: %u", __FUNCTION__, val);
|
|
}
|
|
codec->REG_098 = SET_BITFIELD(codec->REG_098, CODEC_CODEC_DAC_UP_SEL, sel);
|
|
return 0;
|
|
}
|
|
|
|
static uint32_t POSSIBLY_UNUSED hal_codec_get_dac_up(void) {
|
|
uint32_t sel;
|
|
|
|
sel = GET_BITFIELD(codec->REG_098, CODEC_CODEC_DAC_UP_SEL);
|
|
if (sel == 0) {
|
|
return 2;
|
|
} else if (sel == 1) {
|
|
return 3;
|
|
} else if (sel == 2) {
|
|
return 4;
|
|
} else if (sel == 3) {
|
|
return 6;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
static int hal_codec_set_adc_down(enum AUD_CHANNEL_MAP_T map, uint32_t val) {
|
|
uint32_t sel = 0;
|
|
|
|
if (val == 3) {
|
|
sel = 0;
|
|
} else if (val == 6) {
|
|
sel = 1;
|
|
} else if (val == 1) {
|
|
sel = 2;
|
|
} else {
|
|
ASSERT(false, "%s: Invalid adc down: %u", __FUNCTION__, val);
|
|
}
|
|
for (int i = 0; i < NORMAL_ADC_CH_NUM; i++) {
|
|
if (map & (AUD_CHANNEL_MAP_CH0 << i)) {
|
|
*(&codec->REG_084 + i) = SET_BITFIELD(*(&codec->REG_084 + i),
|
|
CODEC_CODEC_ADC_DOWN_SEL_CH0, sel);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int hal_codec_set_adc_hbf_bypass_cnt(enum AUD_CHANNEL_MAP_T map,
|
|
uint32_t cnt) {
|
|
uint32_t bypass = 0;
|
|
uint32_t bypass_mask = CODEC_CODEC_ADC_HBF1_BYPASS_CH0 |
|
|
CODEC_CODEC_ADC_HBF2_BYPASS_CH0 |
|
|
CODEC_CODEC_ADC_HBF3_BYPASS_CH0;
|
|
|
|
if (cnt == 0) {
|
|
} else if (cnt == 1) {
|
|
bypass = CODEC_CODEC_ADC_HBF3_BYPASS_CH0;
|
|
} else if (cnt == 2) {
|
|
bypass = CODEC_CODEC_ADC_HBF2_BYPASS_CH0 | CODEC_CODEC_ADC_HBF3_BYPASS_CH0;
|
|
} else if (cnt == 3) {
|
|
bypass = CODEC_CODEC_ADC_HBF1_BYPASS_CH0 | CODEC_CODEC_ADC_HBF2_BYPASS_CH0 |
|
|
CODEC_CODEC_ADC_HBF3_BYPASS_CH0;
|
|
} else {
|
|
ASSERT(false, "%s: Invalid bypass cnt: %u", __FUNCTION__, cnt);
|
|
}
|
|
for (int i = 0; i < NORMAL_ADC_CH_NUM; i++) {
|
|
if (map & (AUD_CHANNEL_MAP_CH0 << i)) {
|
|
*(&codec->REG_084 + i) = (*(&codec->REG_084 + i) & ~bypass_mask) | bypass;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#ifdef __AUDIO_RESAMPLE__
|
|
static float get_playback_resample_phase(void) {
|
|
return (float)codec_dac_sample_rate[resample_rate_idx[AUD_STREAM_PLAYBACK]]
|
|
.codec_freq /
|
|
hal_cmu_get_crystal_freq();
|
|
}
|
|
|
|
static float get_capture_resample_phase(void) {
|
|
return (float)hal_cmu_get_crystal_freq() /
|
|
codec_adc_sample_rate[resample_rate_idx[AUD_STREAM_CAPTURE]]
|
|
.codec_freq;
|
|
}
|
|
|
|
static uint32_t resample_phase_float_to_value(float phase) {
|
|
if (phase >= 4.0) {
|
|
return (uint32_t)-1;
|
|
} else {
|
|
// Phase format: 2.30
|
|
return (uint32_t)(phase * (1 << 30));
|
|
}
|
|
}
|
|
|
|
static float POSSIBLY_UNUSED resample_phase_value_to_float(uint32_t value) {
|
|
// Phase format: 2.30
|
|
return (float)value / (1 << 30);
|
|
}
|
|
#endif
|
|
|
|
#ifdef SIDETONE_ENABLE
|
|
static void hal_codec_set_sidetone_adc_chan(enum AUD_CHANNEL_MAP_T chan_map) {
|
|
if (chan_map == AUD_CHANNEL_MAP_CH0) {
|
|
codec->REG_080 &= ~CODEC_CODEC_SIDE_TONE_MIC_SEL;
|
|
codec->REG_078 &= ~CODEC_CODEC_SIDE_TONE_CH_SEL;
|
|
} else if (chan_map == AUD_CHANNEL_MAP_CH2) {
|
|
codec->REG_080 &= ~CODEC_CODEC_SIDE_TONE_MIC_SEL;
|
|
codec->REG_078 |= CODEC_CODEC_SIDE_TONE_CH_SEL;
|
|
} else if (chan_map == AUD_CHANNEL_MAP_CH4) {
|
|
codec->REG_080 |= CODEC_CODEC_SIDE_TONE_MIC_SEL;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
int hal_codec_setup_stream(enum HAL_CODEC_ID_T id, enum AUD_STREAM_T stream,
|
|
const struct HAL_CODEC_CONFIG_T *cfg) {
|
|
int i;
|
|
int rate_idx;
|
|
uint32_t ana_dig_div;
|
|
enum AUD_SAMPRATE_T sample_rate;
|
|
|
|
if (stream == AUD_STREAM_PLAYBACK) {
|
|
if ((HAL_CODEC_CONFIG_CHANNEL_MAP | HAL_CODEC_CONFIG_CHANNEL_NUM) &
|
|
cfg->set_flag) {
|
|
if (cfg->channel_num == AUD_CHANNEL_NUM_2) {
|
|
if (cfg->channel_map != (AUD_CHANNEL_MAP_CH0 | AUD_CHANNEL_MAP_CH1)) {
|
|
TRACE(2, "\n!!! WARNING:%s: Bad play stereo ch map: 0x%X\n", __func__,
|
|
cfg->channel_map);
|
|
}
|
|
codec->REG_044 |= CODEC_DUAL_CHANNEL_DAC;
|
|
} else {
|
|
ASSERT(cfg->channel_num == AUD_CHANNEL_NUM_1, "%s: Bad play ch num: %u",
|
|
__func__, cfg->channel_num);
|
|
// Allow to DMA one channel but output 2 channels
|
|
ASSERT((cfg->channel_map &
|
|
~(AUD_CHANNEL_MAP_CH0 | AUD_CHANNEL_MAP_CH1)) == 0,
|
|
"%s: Bad play mono ch map: 0x%X", __func__, cfg->channel_map);
|
|
codec->REG_044 &= ~CODEC_DUAL_CHANNEL_DAC;
|
|
}
|
|
codec_dac_ch_map = AUD_CHANNEL_MAP_CH0 | AUD_CHANNEL_MAP_CH1;
|
|
}
|
|
|
|
if (HAL_CODEC_CONFIG_BITS & cfg->set_flag) {
|
|
if (cfg->bits == AUD_BITS_16) {
|
|
codec->REG_044 =
|
|
(codec->REG_044 & ~CODEC_MODE_32BIT_DAC) | CODEC_MODE_16BIT_DAC;
|
|
codec->REG_04C =
|
|
(codec->REG_04C & ~CODEC_MODE_32BIT_MC) | CODEC_MODE_16BIT_MC;
|
|
} else if (cfg->bits == AUD_BITS_24) {
|
|
codec->REG_044 &= ~(CODEC_MODE_16BIT_DAC | CODEC_MODE_32BIT_DAC);
|
|
codec->REG_04C &= ~(CODEC_MODE_16BIT_MC | CODEC_MODE_32BIT_MC);
|
|
} else if (cfg->bits == AUD_BITS_32) {
|
|
codec->REG_044 =
|
|
(codec->REG_044 & ~CODEC_MODE_16BIT_DAC) | CODEC_MODE_32BIT_DAC;
|
|
codec->REG_04C =
|
|
(codec->REG_04C & ~CODEC_MODE_16BIT_MC) | CODEC_MODE_32BIT_MC;
|
|
} else {
|
|
ASSERT(false, "%s: Bad play bits: %u", __func__, cfg->bits);
|
|
}
|
|
}
|
|
|
|
if (HAL_CODEC_CONFIG_SAMPLE_RATE & cfg->set_flag) {
|
|
sample_rate = cfg->sample_rate;
|
|
#ifdef CODEC_DSD
|
|
if (dsd_enabled) {
|
|
if (sample_rate == AUD_SAMPRATE_176400) {
|
|
dsd_rate_idx = 0;
|
|
} else if (sample_rate == AUD_SAMPRATE_352800) {
|
|
dsd_rate_idx = 1;
|
|
} else if (sample_rate == AUD_SAMPRATE_705600) {
|
|
dsd_rate_idx = 2;
|
|
} else {
|
|
ASSERT(false, "%s: Bad DSD sample rate: %u", __func__, sample_rate);
|
|
}
|
|
sample_rate = AUD_SAMPRATE_44100;
|
|
}
|
|
#endif
|
|
|
|
for (i = 0; i < ARRAY_SIZE(codec_dac_sample_rate); i++) {
|
|
if (codec_dac_sample_rate[i].sample_rate == sample_rate) {
|
|
break;
|
|
}
|
|
}
|
|
ASSERT(i < ARRAY_SIZE(codec_dac_sample_rate),
|
|
"%s: Invalid playback sample rate: %u", __func__, sample_rate);
|
|
rate_idx = i;
|
|
ana_dig_div = codec_dac_sample_rate[rate_idx].codec_div /
|
|
codec_dac_sample_rate[rate_idx].cmu_div;
|
|
ASSERT(ana_dig_div * codec_dac_sample_rate[rate_idx].cmu_div ==
|
|
codec_dac_sample_rate[rate_idx].codec_div,
|
|
"%s: Invalid playback div for rate %u: codec_div=%u cmu_div=%u",
|
|
__func__, sample_rate, codec_dac_sample_rate[rate_idx].codec_div,
|
|
codec_dac_sample_rate[rate_idx].cmu_div);
|
|
|
|
TRACE(2, "[%s] playback sample_rate=%d", __func__, sample_rate);
|
|
|
|
#ifdef CODEC_TIMER
|
|
cur_codec_freq = codec_dac_sample_rate[rate_idx].codec_freq;
|
|
#endif
|
|
|
|
codec_rate_idx[AUD_STREAM_PLAYBACK] = rate_idx;
|
|
|
|
#ifdef __AUDIO_RESAMPLE__
|
|
uint32_t mask, val;
|
|
|
|
if (hal_cmu_get_audio_resample_status() &&
|
|
codec_dac_sample_rate[rate_idx].codec_freq != CODEC_FREQ_CRYSTAL) {
|
|
#ifdef CODEC_TIMER
|
|
cur_codec_freq = CODEC_FREQ_CRYSTAL;
|
|
#endif
|
|
if ((codec->REG_0E4 & CODEC_CODEC_RESAMPLE_DAC_PHASE_UPDATE) == 0 ||
|
|
resample_rate_idx[AUD_STREAM_PLAYBACK] != rate_idx) {
|
|
resample_rate_idx[AUD_STREAM_PLAYBACK] = rate_idx;
|
|
codec->REG_0E4 &= ~CODEC_CODEC_RESAMPLE_DAC_PHASE_UPDATE;
|
|
hal_codec_reg_update_delay();
|
|
codec->REG_0F4 =
|
|
resample_phase_float_to_value(get_playback_resample_phase());
|
|
hal_codec_reg_update_delay();
|
|
codec->REG_0E4 |= CODEC_CODEC_RESAMPLE_DAC_PHASE_UPDATE;
|
|
}
|
|
|
|
mask = CODEC_CODEC_RESAMPLE_DAC_L_ENABLE |
|
|
CODEC_CODEC_RESAMPLE_DAC_R_ENABLE;
|
|
val = 0;
|
|
if (codec_dac_ch_map & AUD_CHANNEL_MAP_CH0) {
|
|
val |= CODEC_CODEC_RESAMPLE_DAC_L_ENABLE;
|
|
}
|
|
if (codec_dac_ch_map & AUD_CHANNEL_MAP_CH1) {
|
|
val |= CODEC_CODEC_RESAMPLE_DAC_R_ENABLE;
|
|
}
|
|
} else {
|
|
mask = CODEC_CODEC_RESAMPLE_DAC_L_ENABLE |
|
|
CODEC_CODEC_RESAMPLE_DAC_R_ENABLE |
|
|
CODEC_CODEC_RESAMPLE_DAC_PHASE_UPDATE;
|
|
val = 0;
|
|
}
|
|
codec->REG_0E4 = (codec->REG_0E4 & ~mask) | val;
|
|
#endif
|
|
|
|
// 8K -> 4ms, 16K -> 2ms, ...
|
|
dac_delay_ms =
|
|
4 / ((sample_rate + AUD_SAMPRATE_8000 / 2) / AUD_SAMPRATE_8000);
|
|
if (dac_delay_ms < 2) {
|
|
dac_delay_ms = 2;
|
|
}
|
|
|
|
#ifdef __AUDIO_RESAMPLE__
|
|
if (!hal_cmu_get_audio_resample_status())
|
|
#endif
|
|
{
|
|
#ifdef __AUDIO_RESAMPLE__
|
|
ASSERT(codec_dac_sample_rate[rate_idx].codec_freq != CODEC_FREQ_CRYSTAL,
|
|
"%s: playback sample rate %u is for resample only", __func__,
|
|
sample_rate);
|
|
#endif
|
|
analog_aud_freq_pll_config(codec_dac_sample_rate[rate_idx].codec_freq,
|
|
codec_dac_sample_rate[rate_idx].codec_div);
|
|
hal_cmu_codec_dac_set_div(codec_dac_sample_rate[rate_idx].cmu_div *
|
|
CODEC_FREQ_EXTRA_DIV);
|
|
}
|
|
hal_codec_set_dac_up(codec_dac_sample_rate[rate_idx].dac_up);
|
|
hal_codec_set_dac_hbf_bypass_cnt(
|
|
codec_dac_sample_rate[rate_idx].bypass_cnt);
|
|
#ifdef AUDIO_ANC_FB_MC
|
|
codec->REG_04C = SET_BITFIELD(codec->REG_04C, CODEC_MC_DELAY,
|
|
codec_dac_sample_rate[rate_idx].mc_delay);
|
|
#endif
|
|
}
|
|
|
|
if (HAL_CODEC_CONFIG_VOL & cfg->set_flag) {
|
|
const struct CODEC_DAC_VOL_T *vol_tab_ptr;
|
|
|
|
vol_tab_ptr = hal_codec_get_dac_volume(cfg->vol);
|
|
if (vol_tab_ptr) {
|
|
#ifdef AUDIO_OUTPUT_SW_GAIN
|
|
hal_codec_set_sw_gain(vol_tab_ptr->sdac_volume);
|
|
#else
|
|
analog_aud_set_dac_gain(vol_tab_ptr->tx_pa_gain);
|
|
hal_codec_set_dig_dac_gain(VALID_DAC_MAP, vol_tab_ptr->sdac_volume);
|
|
#endif
|
|
#ifdef PERF_TEST_POWER_KEY
|
|
// Update performance test power after applying new dac volume
|
|
hal_codec_update_perf_test_power();
|
|
#endif
|
|
}
|
|
}
|
|
} else {
|
|
enum AUD_CHANNEL_MAP_T mic_map;
|
|
enum AUD_CHANNEL_MAP_T reserv_map;
|
|
uint8_t cnt;
|
|
uint8_t ch_idx;
|
|
uint32_t cfg_set_mask;
|
|
uint32_t cfg_clr_mask;
|
|
#ifdef VOICE_DETECTOR_EN
|
|
uint32_t adc_channel_en = 0;
|
|
#endif
|
|
|
|
mic_map = 0;
|
|
if ((HAL_CODEC_CONFIG_CHANNEL_MAP | HAL_CODEC_CONFIG_CHANNEL_NUM) &
|
|
cfg->set_flag) {
|
|
codec_adc_ch_map = 0;
|
|
codec_mic_ch_map = 0;
|
|
mic_map = cfg->channel_map;
|
|
}
|
|
|
|
if (mic_map) {
|
|
codec_mic_ch_map = mic_map;
|
|
reserv_map = 0;
|
|
|
|
#ifdef ANC_APP
|
|
#if defined(ANC_FF_MIC_CH_L) || defined(ANC_FF_MIC_CH_R)
|
|
#ifdef ANC_PROD_TEST
|
|
if ((ANC_FF_MIC_CH_L & ~NORMAL_MIC_MAP) ||
|
|
(ANC_FF_MIC_CH_L & (ANC_FF_MIC_CH_L - 1))) {
|
|
ASSERT(false, "Invalid ANC_FF_MIC_CH_L: 0x%04X", ANC_FF_MIC_CH_L);
|
|
}
|
|
if ((ANC_FF_MIC_CH_R & ~NORMAL_MIC_MAP) ||
|
|
(ANC_FF_MIC_CH_R & (ANC_FF_MIC_CH_R - 1))) {
|
|
ASSERT(false, "Invalid ANC_FF_MIC_CH_R: 0x%04X", ANC_FF_MIC_CH_R);
|
|
}
|
|
if (ANC_FF_MIC_CH_L & ANC_FF_MIC_CH_R) {
|
|
ASSERT(
|
|
false,
|
|
"Conflicted ANC_FF_MIC_CH_L (0x%04X) and ANC_FF_MIC_CH_R (0x%04X)",
|
|
ANC_FF_MIC_CH_L, ANC_FF_MIC_CH_R);
|
|
}
|
|
#if defined(ANC_FB_MIC_CH_L) || defined(ANC_FB_MIC_CH_R)
|
|
if ((ANC_FF_MIC_CH_L & ANC_FB_MIC_CH_L) ||
|
|
(ANC_FF_MIC_CH_L & ANC_FB_MIC_CH_R) ||
|
|
(ANC_FF_MIC_CH_R & ANC_FB_MIC_CH_L) ||
|
|
(ANC_FF_MIC_CH_R & ANC_FB_MIC_CH_R)) {
|
|
ASSERT(false,
|
|
"Conflicted FF MIC (0x%04X/0x%04X) and FB MIC (0x%04X/0x%04X)",
|
|
ANC_FF_MIC_CH_L, ANC_FF_MIC_CH_R, ANC_FB_MIC_CH_L,
|
|
ANC_FB_MIC_CH_R);
|
|
}
|
|
#endif
|
|
#ifdef VOICE_DETECTOR_EN
|
|
if (ANC_FF_MIC_CH_L & AUD_CHANNEL_MAP_CH4) {
|
|
ASSERT(false, "Conflicted ANC_FF_MIC_CH_L and VAD MIC");
|
|
}
|
|
if (ANC_FF_MIC_CH_R & AUD_CHANNEL_MAP_CH4) {
|
|
ASSERT(false, "Conflicted ANC_FF_MIC_CH_R and VAD MIC");
|
|
}
|
|
#endif
|
|
#else // !ANC_PROD_TEST
|
|
#if (ANC_FF_MIC_CH_L & ~NORMAL_MIC_MAP) || \
|
|
(ANC_FF_MIC_CH_L & (ANC_FF_MIC_CH_L - 1))
|
|
#error "Invalid ANC_FF_MIC_CH_L"
|
|
#endif
|
|
#if (ANC_FF_MIC_CH_R & ~NORMAL_MIC_MAP) || \
|
|
(ANC_FF_MIC_CH_R & (ANC_FF_MIC_CH_R - 1))
|
|
#error "Invalid ANC_FF_MIC_CH_R"
|
|
#endif
|
|
#if (ANC_FF_MIC_CH_L & ANC_FF_MIC_CH_R)
|
|
#error "Conflicted ANC_FF_MIC_CH_L and ANC_FF_MIC_CH_R"
|
|
#endif
|
|
#if defined(ANC_FB_MIC_CH_L) || defined(ANC_FB_MIC_CH_R)
|
|
#if (ANC_FF_MIC_CH_L & ANC_FB_MIC_CH_L) || \
|
|
(ANC_FF_MIC_CH_L & ANC_FB_MIC_CH_R) || \
|
|
(ANC_FF_MIC_CH_R & ANC_FB_MIC_CH_L) || (ANC_FF_MIC_CH_R & ANC_FB_MIC_CH_R)
|
|
#error \
|
|
"Conflicted ANC_FF_MIC_CH_L and ANC_FF_MIC_CH_R, ANC_FB_MIC_CH_L, ANC_FB_MIC_CH_R"
|
|
#endif
|
|
#endif
|
|
#ifdef VOICE_DETECTOR_EN
|
|
#if (ANC_FF_MIC_CH_L & AUD_CHANNEL_MAP_CH4)
|
|
#error "Conflicted ANC_FF_MIC_CH_L and VAD MIC"
|
|
#endif
|
|
#if (ANC_FF_MIC_CH_R & AUD_CHANNEL_MAP_CH4)
|
|
#error "Conflicted ANC_FF_MIC_CH_R and VAD MIC"
|
|
#endif
|
|
#endif
|
|
#endif // !ANC_PROD_TEST
|
|
if (mic_map & ANC_FF_MIC_CH_L) {
|
|
codec_adc_ch_map |= AUD_CHANNEL_MAP_CH0;
|
|
mic_map &= ~ANC_FF_MIC_CH_L;
|
|
ch_idx = get_msb_pos(ANC_FF_MIC_CH_L);
|
|
if (ANC_FF_MIC_CH_L & AUD_CHANNEL_MAP_DIGMIC_ALL) {
|
|
ch_idx = hal_codec_get_digmic_hw_index(ch_idx);
|
|
codec->REG_0A8 =
|
|
SET_BITFIELD(codec->REG_0A8, CODEC_CODEC_PDM_MUX_CH0, ch_idx);
|
|
codec->REG_0A4 |= CODEC_CODEC_PDM_ADC_SEL_CH0;
|
|
} else {
|
|
codec->REG_084 =
|
|
SET_BITFIELD(codec->REG_084, CODEC_CODEC_ADC_IN_SEL_CH0, ch_idx);
|
|
codec->REG_0A4 &= ~CODEC_CODEC_PDM_ADC_SEL_CH0;
|
|
}
|
|
} else if (ANC_FF_MIC_CH_L & AUD_CHANNEL_MAP_ALL) {
|
|
reserv_map |= AUD_CHANNEL_MAP_CH0;
|
|
}
|
|
if (mic_map & ANC_FF_MIC_CH_R) {
|
|
codec_adc_ch_map |= AUD_CHANNEL_MAP_CH1;
|
|
mic_map &= ~ANC_FF_MIC_CH_R;
|
|
ch_idx = get_msb_pos(ANC_FF_MIC_CH_R);
|
|
if (ANC_FF_MIC_CH_R & AUD_CHANNEL_MAP_DIGMIC_ALL) {
|
|
ch_idx = hal_codec_get_digmic_hw_index(ch_idx);
|
|
codec->REG_0A8 =
|
|
SET_BITFIELD(codec->REG_0A8, CODEC_CODEC_PDM_MUX_CH1, ch_idx);
|
|
codec->REG_0A4 |= CODEC_CODEC_PDM_ADC_SEL_CH1;
|
|
} else {
|
|
codec->REG_088 =
|
|
SET_BITFIELD(codec->REG_088, CODEC_CODEC_ADC_IN_SEL_CH1, ch_idx);
|
|
codec->REG_0A4 &= ~CODEC_CODEC_PDM_ADC_SEL_CH1;
|
|
}
|
|
} else if (ANC_FF_MIC_CH_R & AUD_CHANNEL_MAP_ALL) {
|
|
reserv_map |= AUD_CHANNEL_MAP_CH1;
|
|
}
|
|
#if defined(SIDETONE_ENABLE) && !defined(SIDETONE_DEDICATED_ADC_CHAN)
|
|
if (CFG_HW_AUD_SIDETONE_MIC_DEV == ANC_FF_MIC_CH_L) {
|
|
hal_codec_set_sidetone_adc_chan(AUD_CHANNEL_MAP_CH0);
|
|
}
|
|
#ifdef ANC_PROD_TEST
|
|
if (CFG_HW_AUD_SIDETONE_MIC_DEV == ANC_FF_MIC_CH_R) {
|
|
ASSERT(false, "SIDETONE MIC cannot be ANC_FF_MIC_CH_R: 0x%X",
|
|
ANC_FF_MIC_CH_R);
|
|
}
|
|
#elif (CFG_HW_AUD_SIDETONE_MIC_DEV == ANC_FF_MIC_CH_R)
|
|
#error "SIDETONE MIC cannot be ANC_FF_MIC_CH_R"
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(ANC_FB_MIC_CH_L) || defined(ANC_FB_MIC_CH_R)
|
|
#ifdef ANC_PROD_TEST
|
|
if ((ANC_FB_MIC_CH_L & ~NORMAL_MIC_MAP) ||
|
|
(ANC_FB_MIC_CH_L & (ANC_FB_MIC_CH_L - 1))) {
|
|
ASSERT(false, "Invalid ANC_FB_MIC_CH_L: 0x%04X", ANC_FB_MIC_CH_L);
|
|
}
|
|
if ((ANC_FB_MIC_CH_R & ~NORMAL_MIC_MAP) ||
|
|
(ANC_FB_MIC_CH_R & (ANC_FB_MIC_CH_R - 1))) {
|
|
ASSERT(false, "Invalid ANC_FB_MIC_CH_R: 0x%04X", ANC_FB_MIC_CH_R);
|
|
}
|
|
if (ANC_FB_MIC_CH_L & ANC_FB_MIC_CH_R) {
|
|
ASSERT(
|
|
false,
|
|
"Conflicted ANC_FB_MIC_CH_L (0x%04X) and ANC_FB_MIC_CH_R (0x%04X)",
|
|
ANC_FB_MIC_CH_L, ANC_FB_MIC_CH_R);
|
|
}
|
|
#ifdef VOICE_DETECTOR_EN
|
|
if (ANC_FB_MIC_CH_L & AUD_CHANNEL_MAP_CH4) {
|
|
ASSERT(false, "Conflicted ANC_FB_MIC_CH_L and VAD MIC");
|
|
}
|
|
if (ANC_FB_MIC_CH_R & AUD_CHANNEL_MAP_CH4) {
|
|
ASSERT(false, "Conflicted ANC_FB_MIC_CH_R and VAD MIC");
|
|
}
|
|
#endif
|
|
#else // !ANC_PROD_TEST
|
|
#if (ANC_FB_MIC_CH_L & ~NORMAL_MIC_MAP) || \
|
|
(ANC_FB_MIC_CH_L & (ANC_FB_MIC_CH_L - 1))
|
|
#error "Invalid ANC_FB_MIC_CH_L"
|
|
#endif
|
|
#if (ANC_FB_MIC_CH_R & ~NORMAL_MIC_MAP) || \
|
|
(ANC_FB_MIC_CH_R & (ANC_FB_MIC_CH_R - 1))
|
|
#error "Invalid ANC_FB_MIC_CH_R"
|
|
#endif
|
|
#if (ANC_FB_MIC_CH_L & ANC_FB_MIC_CH_R)
|
|
#error "Conflicted ANC_FB_MIC_CH_L and ANC_FB_MIC_CH_R"
|
|
#endif
|
|
#ifdef VOICE_DETECTOR_EN
|
|
#if (ANC_FB_MIC_CH_L & AUD_CHANNEL_MAP_CH4)
|
|
#error "Conflicted ANC_FB_MIC_CH_L and VAD MIC"
|
|
#endif
|
|
#if (ANC_FB_MIC_CH_R & AUD_CHANNEL_MAP_CH4)
|
|
#error "Conflicted ANC_FB_MIC_CH_R and VAD MIC"
|
|
#endif
|
|
#endif
|
|
#endif // !ANC_PROD_TEST
|
|
if (mic_map & ANC_FB_MIC_CH_L) {
|
|
codec_adc_ch_map |= AUD_CHANNEL_MAP_CH2;
|
|
mic_map &= ~ANC_FB_MIC_CH_L;
|
|
ch_idx = get_msb_pos(ANC_FB_MIC_CH_L);
|
|
if (ANC_FB_MIC_CH_L & AUD_CHANNEL_MAP_DIGMIC_ALL) {
|
|
ch_idx = hal_codec_get_digmic_hw_index(ch_idx);
|
|
codec->REG_0A8 =
|
|
SET_BITFIELD(codec->REG_0A8, CODEC_CODEC_PDM_MUX_CH2, ch_idx);
|
|
codec->REG_0A4 |= CODEC_CODEC_PDM_ADC_SEL_CH2;
|
|
} else {
|
|
codec->REG_08C =
|
|
SET_BITFIELD(codec->REG_08C, CODEC_CODEC_ADC_IN_SEL_CH2, ch_idx);
|
|
codec->REG_0A4 &= ~CODEC_CODEC_PDM_ADC_SEL_CH2;
|
|
}
|
|
} else if (ANC_FB_MIC_CH_L & AUD_CHANNEL_MAP_ALL) {
|
|
reserv_map |= AUD_CHANNEL_MAP_CH2;
|
|
}
|
|
if (mic_map & ANC_FB_MIC_CH_R) {
|
|
codec_adc_ch_map |= AUD_CHANNEL_MAP_CH3;
|
|
mic_map &= ~ANC_FB_MIC_CH_R;
|
|
ch_idx = get_msb_pos(ANC_FB_MIC_CH_R);
|
|
if (ANC_FB_MIC_CH_R & AUD_CHANNEL_MAP_DIGMIC_ALL) {
|
|
ch_idx = hal_codec_get_digmic_hw_index(ch_idx);
|
|
codec->REG_0A8 =
|
|
SET_BITFIELD(codec->REG_0A8, CODEC_CODEC_PDM_MUX_CH3, ch_idx);
|
|
codec->REG_0A4 |= CODEC_CODEC_PDM_ADC_SEL_CH3;
|
|
} else {
|
|
codec->REG_090 =
|
|
SET_BITFIELD(codec->REG_090, CODEC_CODEC_ADC_IN_SEL_CH3, ch_idx);
|
|
codec->REG_0A4 &= ~CODEC_CODEC_PDM_ADC_SEL_CH3;
|
|
}
|
|
} else if (ANC_FB_MIC_CH_R & AUD_CHANNEL_MAP_ALL) {
|
|
reserv_map |= AUD_CHANNEL_MAP_CH3;
|
|
}
|
|
#if defined(SIDETONE_ENABLE) && !defined(SIDETONE_DEDICATED_ADC_CHAN)
|
|
if (CFG_HW_AUD_SIDETONE_MIC_DEV == ANC_FB_MIC_CH_L) {
|
|
hal_codec_set_sidetone_adc_chan(AUD_CHANNEL_MAP_CH2);
|
|
}
|
|
#ifdef ANC_PROD_TEST
|
|
if (CFG_HW_AUD_SIDETONE_MIC_DEV == ANC_FB_MIC_CH_R) {
|
|
ASSERT(false, "SIDETONE MIC cannot be ANC_FB_MIC_CH_R: 0x%X",
|
|
ANC_FB_MIC_CH_R);
|
|
}
|
|
#elif (CFG_HW_AUD_SIDETONE_MIC_DEV == ANC_FB_MIC_CH_R)
|
|
#error "SIDETONE MIC cannot be ANC_FB_MIC_CH_R"
|
|
#endif
|
|
#endif
|
|
#endif
|
|
#endif // ANC_APP
|
|
|
|
#ifdef CODEC_DSD
|
|
reserv_map |= AUD_CHANNEL_MAP_CH2 | AUD_CHANNEL_MAP_CH3;
|
|
#endif
|
|
|
|
if (mic_map & AUD_CHANNEL_MAP_CH4) {
|
|
codec_adc_ch_map |= AUD_CHANNEL_MAP_CH4;
|
|
mic_map &= ~AUD_CHANNEL_MAP_CH4;
|
|
codec->REG_094 =
|
|
SET_BITFIELD(codec->REG_094, CODEC_CODEC_ADC_IN_SEL_CH4, 4);
|
|
codec->REG_0A4 &= ~CODEC_CODEC_PDM_ADC_SEL_CH4;
|
|
#if defined(SIDETONE_ENABLE) && !defined(SIDETONE_DEDICATED_ADC_CHAN)
|
|
if (CFG_HW_AUD_SIDETONE_MIC_DEV == AUD_CHANNEL_MAP_CH4) {
|
|
hal_codec_set_sidetone_adc_chan(AUD_CHANNEL_MAP_CH4);
|
|
}
|
|
#endif
|
|
}
|
|
if (mic_map & AUD_CHANNEL_MAP_ECMIC_CH0) {
|
|
codec_adc_ch_map |= AUD_CHANNEL_MAP_CH5;
|
|
mic_map &= ~AUD_CHANNEL_MAP_ECMIC_CH0;
|
|
codec->REG_228 &= ~CODEC_CODEC_MC_SEL_CH0;
|
|
}
|
|
if (mic_map & AUD_CHANNEL_MAP_ECMIC_CH1) {
|
|
codec_adc_ch_map |= AUD_CHANNEL_MAP_CH6;
|
|
mic_map &= ~AUD_CHANNEL_MAP_ECMIC_CH1;
|
|
codec->REG_228 |= CODEC_CODEC_MC_SEL_CH1;
|
|
}
|
|
|
|
reserv_map |= codec_adc_ch_map;
|
|
|
|
#ifdef CODEC_MIN_PHASE
|
|
if (min_phase_cfg & (1 << AUD_STREAM_CAPTURE)) {
|
|
if (mic_map && (reserv_map & AUD_CHANNEL_MAP_CH2) == 0) {
|
|
codec_adc_ch_map |= AUD_CHANNEL_MAP_CH2;
|
|
reserv_map |= codec_adc_ch_map;
|
|
ch_idx = get_lsb_pos(mic_map);
|
|
mic_map &= ~(1 << ch_idx);
|
|
if ((1 << ch_idx) & AUD_CHANNEL_MAP_DIGMIC_ALL) {
|
|
ch_idx = hal_codec_get_digmic_hw_index(ch_idx);
|
|
codec->REG_0A8 =
|
|
SET_BITFIELD(codec->REG_0A8, CODEC_CODEC_PDM_MUX_CH2, ch_idx);
|
|
codec->REG_0A4 |= CODEC_CODEC_PDM_ADC_SEL_CH2;
|
|
} else {
|
|
codec->REG_08C = SET_BITFIELD(codec->REG_08C,
|
|
CODEC_CODEC_ADC_IN_SEL_CH2, ch_idx);
|
|
codec->REG_0A4 &= ~CODEC_CODEC_PDM_ADC_SEL_CH2;
|
|
}
|
|
}
|
|
if (mic_map && (reserv_map & AUD_CHANNEL_MAP_CH3) == 0) {
|
|
codec_adc_ch_map |= AUD_CHANNEL_MAP_CH3;
|
|
reserv_map |= codec_adc_ch_map;
|
|
ch_idx = get_lsb_pos(mic_map);
|
|
mic_map &= ~(1 << ch_idx);
|
|
if ((1 << ch_idx) & AUD_CHANNEL_MAP_DIGMIC_ALL) {
|
|
ch_idx = hal_codec_get_digmic_hw_index(ch_idx);
|
|
codec->REG_0A8 =
|
|
SET_BITFIELD(codec->REG_0A8, CODEC_CODEC_PDM_MUX_CH3, ch_idx);
|
|
codec->REG_0A4 |= CODEC_CODEC_PDM_ADC_SEL_CH3;
|
|
} else {
|
|
codec->REG_090 = SET_BITFIELD(codec->REG_090,
|
|
CODEC_CODEC_ADC_IN_SEL_CH3, ch_idx);
|
|
codec->REG_0A4 &= ~CODEC_CODEC_PDM_ADC_SEL_CH3;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef SIDETONE_ENABLE
|
|
#if defined(SIDETONE_DEDICATED_ADC_CHAN) || defined(SIDETONE_RESERVED_ADC_CHAN)
|
|
if (mic_map & CFG_HW_AUD_SIDETONE_MIC_DEV) {
|
|
enum AUD_CHANNEL_MAP_T st_map = 0;
|
|
|
|
// Alloc sidetone adc chan
|
|
if ((reserv_map & AUD_CHANNEL_MAP_CH0) == 0) {
|
|
st_map = AUD_CHANNEL_MAP_CH0;
|
|
} else if ((reserv_map & AUD_CHANNEL_MAP_CH2) == 0) {
|
|
st_map = AUD_CHANNEL_MAP_CH2;
|
|
} else if ((reserv_map & AUD_CHANNEL_MAP_CH4) == 0) {
|
|
st_map = AUD_CHANNEL_MAP_CH4;
|
|
} else {
|
|
ASSERT(false,
|
|
"%s: Cannot alloc dedicated sidetone adc: reserv_map=0x%X",
|
|
__func__, reserv_map);
|
|
}
|
|
// Associate mic and sidetone adc
|
|
hal_codec_set_sidetone_adc_chan(st_map);
|
|
ch_idx = get_lsb_pos(CFG_HW_AUD_SIDETONE_MIC_DEV);
|
|
i = get_lsb_pos(st_map);
|
|
if ((1 << ch_idx) & AUD_CHANNEL_MAP_DIGMIC_ALL) {
|
|
ch_idx = hal_codec_get_digmic_hw_index(ch_idx);
|
|
codec->REG_0A8 =
|
|
(codec->REG_0A8 & ~(CODEC_CODEC_PDM_MUX_CH0_MASK << (3 * i))) |
|
|
(CODEC_CODEC_PDM_MUX_CH0(ch_idx) << (3 * i));
|
|
codec->REG_0A4 |= CODEC_CODEC_PDM_ADC_SEL_CH0 << i;
|
|
} else {
|
|
*(&codec->REG_084 + i) = SET_BITFIELD(
|
|
*(&codec->REG_084 + i), CODEC_CODEC_ADC_IN_SEL_CH0, ch_idx);
|
|
codec->REG_0A4 &= ~(CODEC_CODEC_PDM_ADC_SEL_CH0 << i);
|
|
}
|
|
#ifdef SIDETONE_DEDICATED_ADC_CHAN
|
|
sidetone_adc_ch_map = st_map;
|
|
#else
|
|
mic_map &= ~(1 << ch_idx);
|
|
codec_adc_ch_map |= st_map;
|
|
#endif
|
|
// Mark sidetone adc as used
|
|
reserv_map |= st_map;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
i = 0;
|
|
while (mic_map && i < NORMAL_ADC_CH_NUM) {
|
|
ASSERT(i < MAX_ANA_MIC_CH_NUM || (mic_map & AUD_CHANNEL_MAP_DIGMIC_ALL),
|
|
"%s: Not enough ana cap chan: mic_map=0x%X adc_map=0x%X "
|
|
"reserv_map=0x%X",
|
|
__func__, mic_map, codec_adc_ch_map, reserv_map);
|
|
ch_idx = get_lsb_pos(mic_map);
|
|
mic_map &= ~(1 << ch_idx);
|
|
while ((reserv_map & (AUD_CHANNEL_MAP_CH0 << i)) &&
|
|
i < NORMAL_ADC_CH_NUM) {
|
|
i++;
|
|
}
|
|
#if defined(SIDETONE_ENABLE) && !(defined(SIDETONE_DEDICATED_ADC_CHAN) || \
|
|
defined(SIDETONE_RESERVED_ADC_CHAN))
|
|
if (CFG_HW_AUD_SIDETONE_MIC_DEV == (1 << ch_idx)) {
|
|
if ((reserv_map & AUD_CHANNEL_MAP_CH0) == 0) {
|
|
i = 0;
|
|
} else if ((reserv_map & AUD_CHANNEL_MAP_CH2) == 0) {
|
|
i = 2;
|
|
} else if ((reserv_map & AUD_CHANNEL_MAP_CH4) == 0) {
|
|
i = 4;
|
|
} else {
|
|
ASSERT(false,
|
|
"%s: No sidetone adc: reserv_map=0x%X. Try "
|
|
"SIDETONE_RESERVED_ADC_CHAN",
|
|
__func__, reserv_map);
|
|
}
|
|
hal_codec_set_sidetone_adc_chan((1 << i));
|
|
}
|
|
#endif
|
|
if (i < NORMAL_ADC_CH_NUM) {
|
|
codec_adc_ch_map |= (AUD_CHANNEL_MAP_CH0 << i);
|
|
reserv_map |= codec_adc_ch_map;
|
|
if ((1 << ch_idx) & AUD_CHANNEL_MAP_DIGMIC_ALL) {
|
|
ch_idx = hal_codec_get_digmic_hw_index(ch_idx);
|
|
codec->REG_0A8 =
|
|
(codec->REG_0A8 & ~(CODEC_CODEC_PDM_MUX_CH0_MASK << (3 * i))) |
|
|
(CODEC_CODEC_PDM_MUX_CH0(ch_idx) << (3 * i));
|
|
codec->REG_0A4 |= CODEC_CODEC_PDM_ADC_SEL_CH0 << i;
|
|
} else {
|
|
*(&codec->REG_084 + i) = SET_BITFIELD(
|
|
*(&codec->REG_084 + i), CODEC_CODEC_ADC_IN_SEL_CH0, ch_idx);
|
|
codec->REG_0A4 &= ~(CODEC_CODEC_PDM_ADC_SEL_CH0 << i);
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
#if defined(SIDETONE_ENABLE) && !(defined(SIDETONE_DEDICATED_ADC_CHAN) || \
|
|
defined(SIDETONE_RESERVED_ADC_CHAN))
|
|
if (mic_map) {
|
|
if (reserv_map + 1 < (1 << NORMAL_ADC_CH_NUM)) {
|
|
ASSERT(false,
|
|
"%s: No adc due to sidetone mic_map=0x%X reserv_map=0x%X. Try "
|
|
"SIDETONE_RESERVED_ADC_CHAN",
|
|
__func__, mic_map, reserv_map);
|
|
}
|
|
}
|
|
#endif
|
|
ASSERT(mic_map == 0, "%s: Bad cap chan map: 0x%X reserv_map=0x%X",
|
|
__func__, mic_map, reserv_map);
|
|
}
|
|
|
|
if (HAL_CODEC_CONFIG_BITS & cfg->set_flag) {
|
|
cfg_set_mask = 0;
|
|
cfg_clr_mask = CODEC_MODE_16BIT_ADC_CH0 | CODEC_MODE_16BIT_ADC_CH1 |
|
|
CODEC_MODE_16BIT_ADC_CH2 | CODEC_MODE_16BIT_ADC_CH3 |
|
|
CODEC_MODE_16BIT_ADC_CH4 | CODEC_MODE_16BIT_ADC_CH5 |
|
|
CODEC_MODE_16BIT_ADC_CH6 | CODEC_MODE_24BIT_ADC |
|
|
CODEC_MODE_32BIT_ADC;
|
|
if (cfg->bits == AUD_BITS_16) {
|
|
cfg_set_mask |= CODEC_MODE_16BIT_ADC_CH0 | CODEC_MODE_16BIT_ADC_CH1 |
|
|
CODEC_MODE_16BIT_ADC_CH2 | CODEC_MODE_16BIT_ADC_CH3 |
|
|
CODEC_MODE_16BIT_ADC_CH4 | CODEC_MODE_16BIT_ADC_CH5 |
|
|
CODEC_MODE_16BIT_ADC_CH6;
|
|
} else if (cfg->bits == AUD_BITS_24) {
|
|
cfg_set_mask |= CODEC_MODE_24BIT_ADC;
|
|
} else if (cfg->bits == AUD_BITS_32) {
|
|
cfg_set_mask |= CODEC_MODE_32BIT_ADC;
|
|
} else {
|
|
ASSERT(false, "%s: Bad cap bits: %d", __func__, cfg->bits);
|
|
}
|
|
#ifdef VOICE_DETECTOR_EN
|
|
for (int i = 0; i < MAX_ADC_CH_NUM; i++) {
|
|
adc_channel_en |= (CODEC_ADC_ENABLE_CH0 << i);
|
|
}
|
|
|
|
if (((codec->REG_000 & adc_channel_en) != 0) &&
|
|
((codec->REG_040 & cfg_set_mask) == 0)) {
|
|
ASSERT(false, "%s: Cap bits conflict: %d", __func__, cfg->bits);
|
|
} else
|
|
#endif
|
|
codec->REG_040 = (codec->REG_040 & ~cfg_clr_mask) | cfg_set_mask;
|
|
}
|
|
|
|
cnt = 0;
|
|
for (i = 0; i < MAX_ADC_CH_NUM; i++) {
|
|
if (codec_adc_ch_map & (AUD_CHANNEL_MAP_CH0 << i)) {
|
|
cnt++;
|
|
}
|
|
}
|
|
ASSERT(cnt == cfg->channel_num,
|
|
"%s: Invalid capture stream chan cfg: map=0x%X num=%u", __func__,
|
|
codec_adc_ch_map, cfg->channel_num);
|
|
|
|
if (HAL_CODEC_CONFIG_SAMPLE_RATE & cfg->set_flag) {
|
|
sample_rate = cfg->sample_rate;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(codec_adc_sample_rate); i++) {
|
|
if (codec_adc_sample_rate[i].sample_rate == sample_rate) {
|
|
break;
|
|
}
|
|
}
|
|
ASSERT(i < ARRAY_SIZE(codec_adc_sample_rate),
|
|
"%s: Invalid capture sample rate: %d", __func__, sample_rate);
|
|
rate_idx = i;
|
|
ana_dig_div = codec_adc_sample_rate[rate_idx].codec_div /
|
|
codec_adc_sample_rate[rate_idx].cmu_div;
|
|
ASSERT(ana_dig_div * codec_adc_sample_rate[rate_idx].cmu_div ==
|
|
codec_adc_sample_rate[rate_idx].codec_div,
|
|
"%s: Invalid catpure div for rate %u: codec_div=%u cmu_div=%u",
|
|
__func__, sample_rate, codec_adc_sample_rate[rate_idx].codec_div,
|
|
codec_adc_sample_rate[rate_idx].cmu_div);
|
|
|
|
TRACE(2, "[%s] capture sample_rate=%d", __func__, sample_rate);
|
|
|
|
#ifdef CODEC_TIMER
|
|
cur_codec_freq = codec_adc_sample_rate[rate_idx].codec_freq;
|
|
#endif
|
|
|
|
codec_rate_idx[AUD_STREAM_CAPTURE] = rate_idx;
|
|
|
|
if (codec_adc_ch_map & EC_ADC_MAP) {
|
|
// If EC enabled, init resample-adc-ch0 to adc0
|
|
codec->REG_0E4 =
|
|
SET_BITFIELD(codec->REG_0E4, CODEC_CODEC_RESAMPLE_ADC_CH0_SEL, 0);
|
|
}
|
|
|
|
uint32_t normal_chan_num;
|
|
|
|
normal_chan_num = cfg->channel_num;
|
|
if (codec_adc_ch_map & AUD_CHANNEL_MAP_CH5) {
|
|
normal_chan_num--;
|
|
}
|
|
if (codec_adc_ch_map & AUD_CHANNEL_MAP_CH6) {
|
|
normal_chan_num--;
|
|
}
|
|
|
|
#ifdef __AUDIO_RESAMPLE__
|
|
uint32_t mask, val;
|
|
|
|
if (hal_cmu_get_audio_resample_status() &&
|
|
codec_adc_sample_rate[rate_idx].codec_freq != CODEC_FREQ_CRYSTAL) {
|
|
ASSERT(normal_chan_num <= AUD_CHANNEL_NUM_2,
|
|
"%s: Invalid capture resample chan num: %d/%d map=0x%X",
|
|
__func__, normal_chan_num, cfg->channel_num, cfg->channel_map);
|
|
#ifdef CODEC_TIMER
|
|
cur_codec_freq = CODEC_FREQ_CRYSTAL;
|
|
#endif
|
|
if ((codec->REG_0E4 & CODEC_CODEC_RESAMPLE_ADC_PHASE_UPDATE) == 0 ||
|
|
resample_rate_idx[AUD_STREAM_CAPTURE] != rate_idx) {
|
|
resample_rate_idx[AUD_STREAM_CAPTURE] = rate_idx;
|
|
codec->REG_0E4 &= ~CODEC_CODEC_RESAMPLE_ADC_PHASE_UPDATE;
|
|
hal_codec_reg_update_delay();
|
|
codec->REG_0F8 =
|
|
resample_phase_float_to_value(get_capture_resample_phase());
|
|
hal_codec_reg_update_delay();
|
|
codec->REG_0E4 |= CODEC_CODEC_RESAMPLE_ADC_PHASE_UPDATE;
|
|
}
|
|
|
|
mask = CODEC_CODEC_RESAMPLE_ADC_DUAL_CH |
|
|
CODEC_CODEC_RESAMPLE_ADC_CH0_SEL_MASK |
|
|
CODEC_CODEC_RESAMPLE_ADC_CH1_SEL_MASK;
|
|
val = 0;
|
|
cnt = 0;
|
|
for (i = 0; i < NORMAL_ADC_CH_NUM; i++) {
|
|
if (codec_adc_ch_map & (AUD_CHANNEL_MAP_CH0 << i)) {
|
|
if (cnt == 0) {
|
|
val |= CODEC_CODEC_RESAMPLE_ADC_CH0_SEL(i);
|
|
} else {
|
|
val |= CODEC_CODEC_RESAMPLE_ADC_CH1_SEL(i);
|
|
}
|
|
cnt++;
|
|
}
|
|
}
|
|
if (normal_chan_num == AUD_CHANNEL_NUM_2) {
|
|
val |= CODEC_CODEC_RESAMPLE_ADC_DUAL_CH;
|
|
}
|
|
} else {
|
|
mask = CODEC_CODEC_RESAMPLE_ADC_DUAL_CH |
|
|
CODEC_CODEC_RESAMPLE_ADC_CH0_SEL_MASK |
|
|
CODEC_CODEC_RESAMPLE_ADC_CH1_SEL_MASK |
|
|
CODEC_CODEC_RESAMPLE_ADC_PHASE_UPDATE;
|
|
val = 0;
|
|
}
|
|
codec->REG_0E4 = (codec->REG_0E4 & ~mask) | val;
|
|
#endif
|
|
|
|
// Echo cancel channels will check the enable signal of resample ADC CH0,
|
|
// even when resample is disabled
|
|
if (codec_adc_ch_map & EC_ADC_MAP) {
|
|
if (normal_chan_num &&
|
|
(codec->REG_0E4 & CODEC_CODEC_RESAMPLE_ADC_PHASE_UPDATE) == 0) {
|
|
for (i = 0; i < NORMAL_ADC_CH_NUM; i++) {
|
|
if (codec_adc_ch_map & (AUD_CHANNEL_MAP_CH0 << i)) {
|
|
codec->REG_0E4 = SET_BITFIELD(
|
|
codec->REG_0E4, CODEC_CODEC_RESAMPLE_ADC_CH0_SEL, i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef __AUDIO_RESAMPLE__
|
|
if (!hal_cmu_get_audio_resample_status())
|
|
#endif
|
|
{
|
|
#ifdef __AUDIO_RESAMPLE__
|
|
ASSERT(codec_adc_sample_rate[rate_idx].codec_freq != CODEC_FREQ_CRYSTAL,
|
|
"%s: capture sample rate %u is for resample only", __func__,
|
|
sample_rate);
|
|
#endif
|
|
analog_aud_freq_pll_config(codec_adc_sample_rate[rate_idx].codec_freq,
|
|
codec_adc_sample_rate[rate_idx].codec_div);
|
|
hal_cmu_codec_adc_set_div(codec_adc_sample_rate[rate_idx].cmu_div *
|
|
CODEC_FREQ_EXTRA_DIV);
|
|
}
|
|
hal_codec_set_adc_down(codec_adc_ch_map,
|
|
codec_adc_sample_rate[rate_idx].adc_down);
|
|
hal_codec_set_adc_hbf_bypass_cnt(
|
|
codec_adc_ch_map, codec_adc_sample_rate[rate_idx].bypass_cnt);
|
|
}
|
|
|
|
#if !(defined(FIXED_CODEC_ADC_VOL) && defined(SINGLE_CODEC_ADC_VOL))
|
|
if (HAL_CODEC_CONFIG_VOL & cfg->set_flag) {
|
|
#ifdef SINGLE_CODEC_ADC_VOL
|
|
const CODEC_ADC_VOL_T *adc_gain_db;
|
|
adc_gain_db = hal_codec_get_adc_volume(cfg->vol);
|
|
if (adc_gain_db) {
|
|
hal_codec_set_dig_adc_gain(NORMAL_ADC_MAP, *adc_gain_db);
|
|
#ifdef SIDETONE_DEDICATED_ADC_CHAN
|
|
sidetone_adc_gain = *adc_gain_db;
|
|
hal_codec_set_dig_adc_gain(sidetone_adc_ch_map,
|
|
sidetone_adc_gain + sidetone_gain_offset);
|
|
#endif
|
|
}
|
|
#else // !SINGLE_CODEC_ADC_VOL
|
|
uint32_t vol;
|
|
|
|
mic_map = codec_mic_ch_map;
|
|
while (mic_map) {
|
|
ch_idx = get_lsb_pos(mic_map);
|
|
mic_map &= ~(1 << ch_idx);
|
|
vol = hal_codec_get_mic_chan_volume_level(1 << ch_idx);
|
|
hal_codec_set_chan_vol(AUD_STREAM_CAPTURE, (1 << ch_idx), vol);
|
|
}
|
|
#ifdef SIDETONE_DEDICATED_ADC_CHAN
|
|
if (codec_mic_ch_map & CFG_HW_AUD_SIDETONE_MIC_DEV) {
|
|
const CODEC_ADC_VOL_T *adc_gain_db;
|
|
|
|
vol = hal_codec_get_mic_chan_volume_level(CFG_HW_AUD_SIDETONE_MIC_DEV);
|
|
adc_gain_db = hal_codec_get_adc_volume(vol);
|
|
if (adc_gain_db) {
|
|
sidetone_adc_gain = *adc_gain_db;
|
|
hal_codec_set_dig_adc_gain(sidetone_adc_ch_map,
|
|
sidetone_adc_gain + sidetone_gain_offset);
|
|
}
|
|
}
|
|
#endif
|
|
#endif // !SINGLE_CODEC_ADC_VOL
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int hal_codec_anc_adc_enable(enum ANC_TYPE_T type) {
|
|
#ifdef ANC_APP
|
|
enum AUD_CHANNEL_MAP_T map;
|
|
enum AUD_CHANNEL_MAP_T mic_map;
|
|
uint8_t ch_idx;
|
|
|
|
map = 0;
|
|
mic_map = 0;
|
|
if (type == ANC_FEEDFORWARD) {
|
|
#if defined(ANC_FF_MIC_CH_L) || defined(ANC_FF_MIC_CH_R)
|
|
if (ANC_FF_MIC_CH_L) {
|
|
ch_idx = get_msb_pos(ANC_FF_MIC_CH_L);
|
|
if (ANC_FF_MIC_CH_L & AUD_CHANNEL_MAP_DIGMIC_ALL) {
|
|
ch_idx = hal_codec_get_digmic_hw_index(ch_idx);
|
|
codec->REG_0A8 =
|
|
SET_BITFIELD(codec->REG_0A8, CODEC_CODEC_PDM_MUX_CH0, ch_idx);
|
|
codec->REG_0A4 |= CODEC_CODEC_PDM_ADC_SEL_CH0;
|
|
} else {
|
|
codec->REG_084 =
|
|
SET_BITFIELD(codec->REG_084, CODEC_CODEC_ADC_IN_SEL_CH0, ch_idx);
|
|
codec->REG_0A4 &= ~CODEC_CODEC_PDM_ADC_SEL_CH0;
|
|
}
|
|
map |= AUD_CHANNEL_MAP_CH0;
|
|
mic_map |= ANC_FF_MIC_CH_L;
|
|
}
|
|
if (ANC_FF_MIC_CH_R) {
|
|
ch_idx = get_msb_pos(ANC_FF_MIC_CH_R);
|
|
if (ANC_FF_MIC_CH_R & AUD_CHANNEL_MAP_DIGMIC_ALL) {
|
|
ch_idx = hal_codec_get_digmic_hw_index(ch_idx);
|
|
codec->REG_0A8 =
|
|
SET_BITFIELD(codec->REG_0A8, CODEC_CODEC_PDM_MUX_CH1, ch_idx);
|
|
codec->REG_0A4 |= CODEC_CODEC_PDM_ADC_SEL_CH1;
|
|
} else {
|
|
codec->REG_088 =
|
|
SET_BITFIELD(codec->REG_088, CODEC_CODEC_ADC_IN_SEL_CH1, ch_idx);
|
|
codec->REG_0A4 &= ~CODEC_CODEC_PDM_ADC_SEL_CH1;
|
|
}
|
|
map |= AUD_CHANNEL_MAP_CH1;
|
|
mic_map |= ANC_FF_MIC_CH_R;
|
|
}
|
|
#else
|
|
ASSERT(false, "No ana adc ff ch defined");
|
|
#endif
|
|
} else if (type == ANC_FEEDBACK) {
|
|
#if defined(ANC_FB_MIC_CH_L) || defined(ANC_FB_MIC_CH_R)
|
|
if (ANC_FB_MIC_CH_L) {
|
|
ch_idx = get_msb_pos(ANC_FB_MIC_CH_L);
|
|
if (ANC_FB_MIC_CH_L & AUD_CHANNEL_MAP_DIGMIC_ALL) {
|
|
ch_idx = hal_codec_get_digmic_hw_index(ch_idx);
|
|
codec->REG_0A8 =
|
|
SET_BITFIELD(codec->REG_0A8, CODEC_CODEC_PDM_MUX_CH2, ch_idx);
|
|
codec->REG_0A4 |= CODEC_CODEC_PDM_ADC_SEL_CH2;
|
|
} else {
|
|
codec->REG_08C =
|
|
SET_BITFIELD(codec->REG_08C, CODEC_CODEC_ADC_IN_SEL_CH2, ch_idx);
|
|
codec->REG_0A4 &= ~CODEC_CODEC_PDM_ADC_SEL_CH2;
|
|
}
|
|
map |= AUD_CHANNEL_MAP_CH2;
|
|
mic_map |= ANC_FB_MIC_CH_L;
|
|
}
|
|
if (ANC_FB_MIC_CH_R) {
|
|
ch_idx = get_msb_pos(ANC_FB_MIC_CH_R);
|
|
if (ANC_FB_MIC_CH_R & AUD_CHANNEL_MAP_DIGMIC_ALL) {
|
|
ch_idx = hal_codec_get_digmic_hw_index(ch_idx);
|
|
codec->REG_0A8 =
|
|
SET_BITFIELD(codec->REG_0A8, CODEC_CODEC_PDM_MUX_CH3, ch_idx);
|
|
codec->REG_0A4 |= CODEC_CODEC_PDM_ADC_SEL_CH3;
|
|
} else {
|
|
codec->REG_090 =
|
|
SET_BITFIELD(codec->REG_090, CODEC_CODEC_ADC_IN_SEL_CH3, ch_idx);
|
|
codec->REG_0A4 &= ~CODEC_CODEC_PDM_ADC_SEL_CH3;
|
|
}
|
|
map |= AUD_CHANNEL_MAP_CH3;
|
|
mic_map |= ANC_FB_MIC_CH_R;
|
|
}
|
|
#else
|
|
ASSERT(false, "No ana adc fb ch defined");
|
|
#endif
|
|
}
|
|
anc_adc_ch_map |= map;
|
|
anc_mic_ch_map |= mic_map;
|
|
|
|
if (anc_mic_ch_map & AUD_CHANNEL_MAP_DIGMIC_ALL) {
|
|
hal_codec_enable_dig_mic(anc_mic_ch_map);
|
|
}
|
|
|
|
for (int i = 0; i < NORMAL_ADC_CH_NUM; i++) {
|
|
if (map & (AUD_CHANNEL_MAP_CH0 << i)) {
|
|
if ((codec->REG_080 & (CODEC_CODEC_ADC_EN_CH0 << i)) == 0) {
|
|
// Reset ADC channel
|
|
codec->REG_064 &= ~CODEC_SOFT_RSTN_ADC(1 << i);
|
|
codec->REG_064 |= CODEC_SOFT_RSTN_ADC(1 << i);
|
|
codec->REG_080 |= (CODEC_CODEC_ADC_EN_CH0 << i);
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef DAC_DRE_ENABLE
|
|
if (anc_adc_ch_map && (codec->REG_098 & CODEC_CODEC_DAC_EN)) {
|
|
hal_codec_dac_dre_disable();
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
int hal_codec_anc_adc_disable(enum ANC_TYPE_T type) {
|
|
#ifdef ANC_APP
|
|
enum AUD_CHANNEL_MAP_T map;
|
|
enum AUD_CHANNEL_MAP_T mic_map;
|
|
|
|
map = 0;
|
|
mic_map = 0;
|
|
if (type == ANC_FEEDFORWARD) {
|
|
#if defined(ANC_FF_MIC_CH_L) || defined(ANC_FF_MIC_CH_R)
|
|
if (ANC_FF_MIC_CH_L) {
|
|
map |= AUD_CHANNEL_MAP_CH0;
|
|
mic_map |= ANC_FF_MIC_CH_L;
|
|
}
|
|
if (ANC_FF_MIC_CH_R) {
|
|
map |= AUD_CHANNEL_MAP_CH1;
|
|
mic_map |= ANC_FF_MIC_CH_R;
|
|
}
|
|
#endif
|
|
} else if (type == ANC_FEEDBACK) {
|
|
#if defined(ANC_FB_MIC_CH_L) || defined(ANC_FB_MIC_CH_R)
|
|
if (ANC_FB_MIC_CH_L) {
|
|
map |= AUD_CHANNEL_MAP_CH2;
|
|
mic_map |= ANC_FB_MIC_CH_L;
|
|
}
|
|
if (ANC_FB_MIC_CH_R) {
|
|
map |= AUD_CHANNEL_MAP_CH3;
|
|
mic_map |= ANC_FB_MIC_CH_R;
|
|
}
|
|
#endif
|
|
}
|
|
anc_adc_ch_map &= ~map;
|
|
anc_mic_ch_map &= ~mic_map;
|
|
|
|
if ((anc_mic_ch_map & AUD_CHANNEL_MAP_DIGMIC_ALL) == 0 &&
|
|
((codec_mic_ch_map & AUD_CHANNEL_MAP_DIGMIC_ALL) == 0 ||
|
|
(codec->REG_000 & CODEC_ADC_ENABLE) == 0)) {
|
|
hal_codec_disable_dig_mic();
|
|
}
|
|
|
|
for (int i = 0; i < NORMAL_ADC_CH_NUM; i++) {
|
|
if ((map & (AUD_CHANNEL_MAP_CH0 << i)) == 0) {
|
|
continue;
|
|
}
|
|
if (codec->REG_000 & CODEC_ADC_ENABLE) {
|
|
if (codec_adc_ch_map & (AUD_CHANNEL_MAP_CH0 << i)) {
|
|
continue;
|
|
}
|
|
if (i == 0 &&
|
|
(codec->REG_228 &
|
|
(CODEC_CODEC_MC_ENABLE_CH0 | CODEC_CODEC_MC_ENABLE_CH1)) &&
|
|
(codec_adc_ch_map & ~EC_ADC_MAP) == 0) {
|
|
continue;
|
|
}
|
|
}
|
|
codec->REG_080 &= ~(CODEC_CODEC_ADC_EN_CH0 << i);
|
|
}
|
|
|
|
#ifdef DAC_DRE_ENABLE
|
|
if (anc_adc_ch_map == 0 && (codec->REG_098 & CODEC_CODEC_DAC_EN) &&
|
|
//(codec->REG_044 & CODEC_MODE_16BIT_DAC) == 0 &&
|
|
1) {
|
|
hal_codec_dac_dre_enable();
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
enum AUD_SAMPRATE_T hal_codec_anc_convert_rate(enum AUD_SAMPRATE_T rate) {
|
|
if (hal_cmu_get_audio_resample_status()) {
|
|
return AUD_SAMPRATE_50781;
|
|
} else if (CODEC_FREQ_48K_SERIES / rate * rate == CODEC_FREQ_48K_SERIES) {
|
|
return AUD_SAMPRATE_48000;
|
|
} else /* if (CODEC_FREQ_44_1K_SERIES / rate * rate ==
|
|
CODEC_FREQ_44_1K_SERIES) */
|
|
{
|
|
return AUD_SAMPRATE_44100;
|
|
}
|
|
}
|
|
|
|
int hal_codec_anc_dma_enable(enum HAL_CODEC_ID_T id) { return 0; }
|
|
|
|
int hal_codec_anc_dma_disable(enum HAL_CODEC_ID_T id) { return 0; }
|
|
|
|
int hal_codec_aux_mic_dma_enable(enum HAL_CODEC_ID_T id) { return 0; }
|
|
|
|
int hal_codec_aux_mic_dma_disable(enum HAL_CODEC_ID_T id) { return 0; }
|
|
|
|
uint32_t hal_codec_get_alg_dac_shift(void) { return 0; }
|
|
|
|
#ifdef ANC_APP
|
|
void hal_codec_set_anc_boost_gain_attn(float attn) {
|
|
anc_boost_gain_attn = attn;
|
|
|
|
#ifdef AUDIO_OUTPUT_SW_GAIN
|
|
hal_codec_set_sw_gain(swdac_gain);
|
|
#else
|
|
hal_codec_restore_dig_dac_gain();
|
|
#endif
|
|
hal_codec_restore_dig_adc_gain();
|
|
}
|
|
|
|
void hal_codec_apply_anc_adc_gain_offset(enum ANC_TYPE_T type, int8_t offset_l,
|
|
int8_t offset_r) {
|
|
enum AUD_CHANNEL_MAP_T map_l, map_r;
|
|
enum AUD_CHANNEL_MAP_T ch_map;
|
|
uint8_t ch_idx;
|
|
|
|
if (analog_debug_get_anc_calib_mode()) {
|
|
return;
|
|
}
|
|
|
|
map_l = 0;
|
|
map_r = 0;
|
|
|
|
#if defined(ANC_FF_MIC_CH_L) || defined(ANC_FF_MIC_CH_R)
|
|
if (type & ANC_FEEDFORWARD) {
|
|
if (ANC_FF_MIC_CH_L) {
|
|
map_l |= AUD_CHANNEL_MAP_CH0;
|
|
}
|
|
if (ANC_FF_MIC_CH_R) {
|
|
map_r |= AUD_CHANNEL_MAP_CH1;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(ANC_FB_MIC_CH_L) || defined(ANC_FB_MIC_CH_R)
|
|
if (type & ANC_FEEDBACK) {
|
|
if (ANC_FB_MIC_CH_L) {
|
|
map_l |= AUD_CHANNEL_MAP_CH2;
|
|
}
|
|
if (ANC_FB_MIC_CH_R) {
|
|
map_r |= AUD_CHANNEL_MAP_CH3;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (map_l) {
|
|
ch_map = map_l;
|
|
while (ch_map) {
|
|
ch_idx = get_msb_pos(ch_map);
|
|
ch_map &= ~(1 << ch_idx);
|
|
anc_adc_gain_offset[ch_idx] = offset_l;
|
|
}
|
|
if (offset_l) {
|
|
anc_adc_gain_offset_map |= map_l;
|
|
} else {
|
|
anc_adc_gain_offset_map &= ~map_l;
|
|
}
|
|
}
|
|
if (map_r) {
|
|
ch_map = map_r;
|
|
while (ch_map) {
|
|
ch_idx = get_msb_pos(ch_map);
|
|
ch_map &= ~(1 << ch_idx);
|
|
anc_adc_gain_offset[ch_idx] = offset_r;
|
|
}
|
|
if (offset_r) {
|
|
anc_adc_gain_offset_map |= map_r;
|
|
} else {
|
|
anc_adc_gain_offset_map &= ~map_r;
|
|
}
|
|
}
|
|
if (map_l || map_r) {
|
|
hal_codec_restore_dig_adc_gain();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef AUDIO_OUTPUT_DC_CALIB
|
|
void hal_codec_set_dac_dc_gain_attn(float attn) { dac_dc_gain_attn = attn; }
|
|
|
|
void hal_codec_set_dac_dc_offset(int16_t dc_l, int16_t dc_r) {
|
|
// DC calib values are based on 16-bit, but hardware compensation is based on
|
|
// 24-bit
|
|
dac_dc_l = dc_l << 8;
|
|
dac_dc_r = dc_r << 8;
|
|
#ifdef SDM_MUTE_NOISE_SUPPRESSION
|
|
if (dac_dc_l == 0) {
|
|
dac_dc_l = 1;
|
|
}
|
|
if (dac_dc_r == 0) {
|
|
dac_dc_r = 1;
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
void hal_codec_set_dac_reset_callback(HAL_CODEC_DAC_RESET_CALLBACK callback) {
|
|
// dac_reset_callback = callback;
|
|
}
|
|
|
|
static uint32_t POSSIBLY_UNUSED
|
|
hal_codec_get_adc_chan(enum AUD_CHANNEL_MAP_T mic_map) {
|
|
uint8_t adc_ch;
|
|
uint8_t mic_ch;
|
|
uint8_t digmic_ch0;
|
|
uint8_t en_ch;
|
|
bool digmic;
|
|
int i;
|
|
|
|
adc_ch = MAX_ADC_CH_NUM;
|
|
|
|
mic_ch = get_lsb_pos(mic_map);
|
|
|
|
if (((1 << mic_ch) & codec_mic_ch_map) == 0) {
|
|
return adc_ch;
|
|
}
|
|
|
|
digmic_ch0 = get_lsb_pos(AUD_CHANNEL_MAP_DIGMIC_CH0);
|
|
|
|
if (mic_ch >= digmic_ch0) {
|
|
mic_ch -= digmic_ch0;
|
|
digmic = true;
|
|
} else {
|
|
digmic = false;
|
|
}
|
|
|
|
for (i = 0; i < NORMAL_ADC_CH_NUM; i++) {
|
|
if (codec_adc_ch_map & (1 << i)) {
|
|
if (digmic ^ !!(codec->REG_0A4 & (CODEC_CODEC_PDM_ADC_SEL_CH0 << i))) {
|
|
continue;
|
|
}
|
|
if (digmic) {
|
|
en_ch = (codec->REG_0A8 & (CODEC_CODEC_PDM_MUX_CH0_MASK << (3 * i))) >>
|
|
(CODEC_CODEC_PDM_MUX_CH0_SHIFT + 3 * i);
|
|
} else {
|
|
en_ch =
|
|
GET_BITFIELD(*(&codec->REG_084 + i), CODEC_CODEC_ADC_IN_SEL_CH0);
|
|
}
|
|
if (mic_ch == en_ch) {
|
|
adc_ch = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return adc_ch;
|
|
}
|
|
|
|
void hal_codec_sidetone_enable(void) {
|
|
#ifdef SIDETONE_ENABLE
|
|
#if (CFG_HW_AUD_SIDETONE_MIC_DEV & (CFG_HW_AUD_SIDETONE_MIC_DEV - 1))
|
|
#error "Invalid CFG_HW_AUD_SIDETONE_MIC_DEV: only 1 mic can be defined"
|
|
#endif
|
|
#if (CFG_HW_AUD_SIDETONE_MIC_DEV == 0) || \
|
|
(CFG_HW_AUD_SIDETONE_MIC_DEV & ~NORMAL_MIC_MAP)
|
|
#error "Invalid CFG_HW_AUD_SIDETONE_MIC_DEV: bad mic channel"
|
|
#endif
|
|
int gain = CFG_HW_AUD_SIDETONE_GAIN_DBVAL;
|
|
uint32_t val;
|
|
|
|
#ifdef SIDETONE_DEDICATED_ADC_CHAN
|
|
sidetone_gain_offset = 0;
|
|
if (gain > MAX_SIDETONE_DBVAL) {
|
|
sidetone_gain_offset = gain - MAX_SIDETONE_DBVAL;
|
|
} else if (gain < MIN_SIDETONE_DBVAL) {
|
|
sidetone_gain_offset = gain - MIN_SIDETONE_DBVAL;
|
|
}
|
|
#endif
|
|
|
|
if (gain > MAX_SIDETONE_DBVAL) {
|
|
gain = MAX_SIDETONE_DBVAL;
|
|
} else if (gain < MIN_SIDETONE_DBVAL) {
|
|
gain = MIN_SIDETONE_DBVAL;
|
|
}
|
|
|
|
val = MIN_SIDETONE_REGVAL + (gain - MIN_SIDETONE_DBVAL) / SIDETONE_DBVAL_STEP;
|
|
|
|
codec->REG_080 =
|
|
SET_BITFIELD(codec->REG_080, CODEC_CODEC_SIDE_TONE_GAIN, val);
|
|
|
|
#ifdef SIDETONE_DEDICATED_ADC_CHAN
|
|
uint8_t adc_ch;
|
|
|
|
adc_ch = get_lsb_pos(sidetone_adc_ch_map);
|
|
if (adc_ch >= NORMAL_ADC_CH_NUM) {
|
|
return;
|
|
}
|
|
|
|
hal_codec_set_dig_adc_gain(sidetone_adc_ch_map,
|
|
sidetone_adc_gain + sidetone_gain_offset);
|
|
#ifdef CFG_HW_AUD_SIDETONE_GAIN_RAMP
|
|
hal_codec_get_adc_gain(sidetone_adc_ch_map, &sidetone_ded_chan_coef);
|
|
hal_codec_set_dig_adc_gain(sidetone_adc_ch_map, MIN_DIG_DBVAL);
|
|
#endif
|
|
codec->REG_080 |= (CODEC_CODEC_ADC_EN_CH0 << adc_ch);
|
|
|
|
#ifdef CFG_HW_AUD_SIDETONE_IIR_INDEX
|
|
#if (CFG_HW_AUD_SIDETONE_IIR_INDEX >= ADC_IIR_CH_NUM + 0UL)
|
|
#error "Invalid CFG_HW_AUD_SIDETONE_IIR_INDEX"
|
|
#endif
|
|
uint32_t mask;
|
|
|
|
if (CFG_HW_AUD_SIDETONE_IIR_INDEX == 0) {
|
|
mask = CODEC_CODEC_ADC_IIR_CH0_SEL_MASK;
|
|
val = CODEC_CODEC_ADC_IIR_CH0_SEL(adc_ch);
|
|
} else {
|
|
mask = CODEC_CODEC_ADC_IIR_CH1_SEL_MASK;
|
|
val = CODEC_CODEC_ADC_IIR_CH1_SEL(adc_ch);
|
|
}
|
|
codec->REG_078 = (codec->REG_078 & ~mask) | val;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
void hal_codec_sidetone_disable(void) {
|
|
#ifdef SIDETONE_ENABLE
|
|
codec->REG_080 = SET_BITFIELD(codec->REG_080, CODEC_CODEC_SIDE_TONE_GAIN,
|
|
MUTE_SIDETONE_REGVAL);
|
|
#ifdef SIDETONE_DEDICATED_ADC_CHAN
|
|
if (sidetone_adc_ch_map) {
|
|
uint8_t adc_ch;
|
|
|
|
adc_ch = get_lsb_pos(sidetone_adc_ch_map);
|
|
codec->REG_080 &= ~(CODEC_CODEC_ADC_EN_CH0 << adc_ch);
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
int hal_codec_sidetone_gain_ramp_up(float step) {
|
|
int ret = 0;
|
|
#ifdef CFG_HW_AUD_SIDETONE_GAIN_RAMP
|
|
float coef;
|
|
uint32_t val;
|
|
|
|
hal_codec_get_adc_gain(sidetone_adc_ch_map, &coef);
|
|
coef += step;
|
|
if (coef >= sidetone_ded_chan_coef) {
|
|
coef = sidetone_ded_chan_coef;
|
|
ret = 1;
|
|
}
|
|
// Gain format: 8.12
|
|
int32_t s_val = (int32_t)(coef * (1 << 12));
|
|
val = __SSAT(s_val, 20);
|
|
hal_codec_set_adc_gain_value(sidetone_adc_ch_map, val);
|
|
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
int hal_codec_sidetone_gain_ramp_down(float step) {
|
|
int ret = 0;
|
|
#ifdef CFG_HW_AUD_SIDETONE_GAIN_RAMP
|
|
float coef;
|
|
uint32_t val;
|
|
|
|
hal_codec_get_adc_gain(sidetone_adc_ch_map, &coef);
|
|
coef -= step;
|
|
if (coef <= 0) {
|
|
coef = 0;
|
|
ret = 1;
|
|
}
|
|
|
|
// Gain format: 8.12
|
|
int32_t s_val = (int32_t)(coef * (1 << 12));
|
|
val = __SSAT(s_val, 20);
|
|
hal_codec_set_adc_gain_value(sidetone_adc_ch_map, val);
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
void hal_codec_select_adc_iir_mic(uint32_t index,
|
|
enum AUD_CHANNEL_MAP_T mic_map) {
|
|
uint32_t mask, val;
|
|
uint8_t adc_ch;
|
|
|
|
ASSERT(index < ADC_IIR_CH_NUM, "%s: Bad index=%u", __func__, index);
|
|
ASSERT(mic_map && (mic_map & (mic_map - 1)) == 0, "%s: Bad mic_map=0x%X",
|
|
__func__, mic_map);
|
|
#ifdef CFG_HW_AUD_SIDETONE_IIR_INDEX
|
|
ASSERT(index != CFG_HW_AUD_SIDETONE_IIR_INDEX,
|
|
"%s: Adc iir index conflicts with sidetone", __func__);
|
|
#endif
|
|
|
|
adc_ch = hal_codec_get_adc_chan(mic_map);
|
|
if (index == 0) {
|
|
mask = CODEC_CODEC_ADC_IIR_CH0_SEL_MASK;
|
|
val = CODEC_CODEC_ADC_IIR_CH0_SEL(adc_ch);
|
|
} else {
|
|
mask = CODEC_CODEC_ADC_IIR_CH1_SEL_MASK;
|
|
val = CODEC_CODEC_ADC_IIR_CH1_SEL(adc_ch);
|
|
}
|
|
codec->REG_078 = (codec->REG_078 & ~mask) | val;
|
|
}
|
|
|
|
void hal_codec_min_phase_mode_enable(enum AUD_STREAM_T stream) {
|
|
#ifdef CODEC_MIN_PHASE
|
|
if (min_phase_cfg == 0 && codec_opened) {
|
|
hal_codec_min_phase_init();
|
|
}
|
|
|
|
min_phase_cfg |= (1 << stream);
|
|
#endif
|
|
}
|
|
|
|
void hal_codec_min_phase_mode_disable(enum AUD_STREAM_T stream) {
|
|
#ifdef CODEC_MIN_PHASE
|
|
min_phase_cfg &= ~(1 << stream);
|
|
|
|
if (min_phase_cfg == 0 && codec_opened) {
|
|
hal_codec_min_phase_term();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void hal_codec_sync_dac_enable(enum HAL_CODEC_SYNC_TYPE_T type) {
|
|
#if defined(ANC_APP)
|
|
// hal_codec_sync_dac_resample_rate_enable(type);
|
|
codec->REG_054 = SET_BITFIELD(codec->REG_054, CODEC_DAC_ENABLE_SEL, type);
|
|
#else
|
|
codec->REG_054 =
|
|
SET_BITFIELD(codec->REG_054, CODEC_CODEC_DAC_ENABLE_SEL, type);
|
|
#endif
|
|
}
|
|
|
|
void hal_codec_sync_dac_disable(void) {
|
|
#if defined(ANC_APP)
|
|
// hal_codec_sync_dac_resample_rate_disable();
|
|
codec->REG_054 = SET_BITFIELD(codec->REG_054, CODEC_DAC_ENABLE_SEL,
|
|
HAL_CODEC_SYNC_TYPE_NONE);
|
|
#else
|
|
codec->REG_054 = SET_BITFIELD(codec->REG_054, CODEC_CODEC_DAC_ENABLE_SEL,
|
|
HAL_CODEC_SYNC_TYPE_NONE);
|
|
#endif
|
|
}
|
|
|
|
void hal_codec_sync_adc_enable(enum HAL_CODEC_SYNC_TYPE_T type) {
|
|
#if defined(ANC_APP)
|
|
// hal_codec_sync_adc_resample_rate_enable(type);
|
|
codec->REG_054 = SET_BITFIELD(codec->REG_054, CODEC_ADC_ENABLE_SEL, type);
|
|
#else
|
|
codec->REG_054 =
|
|
SET_BITFIELD(codec->REG_054, CODEC_CODEC_ADC_ENABLE_SEL, type);
|
|
#endif
|
|
}
|
|
|
|
void hal_codec_sync_adc_disable(void) {
|
|
#if defined(ANC_APP)
|
|
// hal_codec_sync_adc_resample_rate_disable();
|
|
codec->REG_054 = SET_BITFIELD(codec->REG_054, CODEC_ADC_ENABLE_SEL,
|
|
HAL_CODEC_SYNC_TYPE_NONE);
|
|
#else
|
|
codec->REG_054 = SET_BITFIELD(codec->REG_054, CODEC_CODEC_ADC_ENABLE_SEL,
|
|
HAL_CODEC_SYNC_TYPE_NONE);
|
|
#endif
|
|
}
|
|
|
|
void hal_codec_sync_dac_resample_rate_enable(enum HAL_CODEC_SYNC_TYPE_T type) {
|
|
codec->REG_0E4 =
|
|
SET_BITFIELD(codec->REG_0E4, CODEC_CODEC_RESAMPLE_DAC_TRIGGER_SEL, type);
|
|
}
|
|
|
|
void hal_codec_sync_dac_resample_rate_disable(void) {
|
|
codec->REG_0E4 =
|
|
SET_BITFIELD(codec->REG_0E4, CODEC_CODEC_RESAMPLE_DAC_TRIGGER_SEL,
|
|
HAL_CODEC_SYNC_TYPE_NONE);
|
|
}
|
|
|
|
void hal_codec_sync_adc_resample_rate_enable(enum HAL_CODEC_SYNC_TYPE_T type) {
|
|
codec->REG_0E4 =
|
|
SET_BITFIELD(codec->REG_0E4, CODEC_CODEC_RESAMPLE_ADC_TRIGGER_SEL, type);
|
|
}
|
|
|
|
void hal_codec_sync_adc_resample_rate_disable(void) {
|
|
codec->REG_0E4 =
|
|
SET_BITFIELD(codec->REG_0E4, CODEC_CODEC_RESAMPLE_ADC_TRIGGER_SEL,
|
|
HAL_CODEC_SYNC_TYPE_NONE);
|
|
}
|
|
|
|
void hal_codec_sync_dac_gain_enable(enum HAL_CODEC_SYNC_TYPE_T type) {
|
|
codec->REG_09C =
|
|
SET_BITFIELD(codec->REG_09C, CODEC_CODEC_DAC_GAIN_TRIGGER_SEL, type);
|
|
}
|
|
|
|
void hal_codec_sync_dac_gain_disable(void) {
|
|
codec->REG_09C =
|
|
SET_BITFIELD(codec->REG_09C, CODEC_CODEC_DAC_GAIN_TRIGGER_SEL,
|
|
HAL_CODEC_SYNC_TYPE_NONE);
|
|
}
|
|
|
|
void hal_codec_sync_adc_gain_enable(enum HAL_CODEC_SYNC_TYPE_T type) {}
|
|
|
|
void hal_codec_sync_adc_gain_disable(void) {}
|
|
|
|
void hal_codec_gpio_trigger_debounce_enable(void) {
|
|
if (codec_opened) {
|
|
codec->REG_054 |= CODEC_GPIO_TRIGGER_DB_ENABLE;
|
|
}
|
|
}
|
|
|
|
void hal_codec_gpio_trigger_debounce_disable(void) {
|
|
if (codec_opened) {
|
|
codec->REG_054 &= ~CODEC_GPIO_TRIGGER_DB_ENABLE;
|
|
}
|
|
}
|
|
|
|
#ifdef CODEC_TIMER
|
|
uint32_t hal_codec_timer_get(void) {
|
|
if (codec_opened) {
|
|
return codec->REG_050;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint32_t hal_codec_timer_ticks_to_us(uint32_t ticks) {
|
|
uint32_t timer_freq;
|
|
|
|
timer_freq = cur_codec_freq / 4 / CODEC_FREQ_EXTRA_DIV;
|
|
|
|
return (uint32_t)((float)ticks * 1000000 / timer_freq);
|
|
}
|
|
|
|
void hal_codec_timer_trigger_read(void) {
|
|
if (codec_opened) {
|
|
codec->REG_078 ^= CODEC_GET_CNT_TRIG;
|
|
hal_codec_reg_update_delay();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef AUDIO_OUTPUT_DC_CALIB_ANA
|
|
int hal_codec_dac_sdm_reset_set(void) {
|
|
if (codec_opened) {
|
|
hal_codec_set_dac_gain_value(VALID_DAC_MAP, 0);
|
|
if (codec->REG_098 & CODEC_CODEC_DAC_EN) {
|
|
osDelay(dac_delay_ms);
|
|
}
|
|
for (int i = 0x200; i >= 0; i -= 0x100) {
|
|
hal_codec_dac_dc_offset_enable(i, i);
|
|
osDelay(1);
|
|
}
|
|
codec->REG_098 |= CODEC_CODEC_DAC_SDM_CLOSE;
|
|
osDelay(1);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int hal_codec_dac_sdm_reset_clear(void) {
|
|
if (codec_opened) {
|
|
osDelay(1);
|
|
codec->REG_098 &= ~CODEC_CODEC_DAC_SDM_CLOSE;
|
|
for (int i = 0x100; i <= 0x300; i += 0x100) {
|
|
hal_codec_dac_dc_offset_enable(i, i);
|
|
osDelay(1);
|
|
}
|
|
hal_codec_restore_dig_dac_gain();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
void hal_codec_tune_resample_rate(enum AUD_STREAM_T stream, float ratio) {
|
|
#ifdef __AUDIO_RESAMPLE__
|
|
uint32_t val;
|
|
|
|
if (!codec_opened) {
|
|
return;
|
|
}
|
|
|
|
if (stream == AUD_STREAM_PLAYBACK) {
|
|
if (codec->REG_0E4 & CODEC_CODEC_RESAMPLE_DAC_PHASE_UPDATE) {
|
|
codec->REG_0E4 &= ~CODEC_CODEC_RESAMPLE_DAC_PHASE_UPDATE;
|
|
hal_codec_reg_update_delay();
|
|
val = resample_phase_float_to_value(get_playback_resample_phase());
|
|
val += (int)(val * ratio);
|
|
codec->REG_0F4 = val;
|
|
hal_codec_reg_update_delay();
|
|
codec->REG_0E4 |= CODEC_CODEC_RESAMPLE_DAC_PHASE_UPDATE;
|
|
}
|
|
} else {
|
|
if (codec->REG_0E4 & CODEC_CODEC_RESAMPLE_ADC_PHASE_UPDATE) {
|
|
codec->REG_0E4 &= ~CODEC_CODEC_RESAMPLE_ADC_PHASE_UPDATE;
|
|
hal_codec_reg_update_delay();
|
|
val = resample_phase_float_to_value(get_capture_resample_phase());
|
|
val -= (int)(val * ratio);
|
|
codec->REG_0F8 = val;
|
|
hal_codec_reg_update_delay();
|
|
codec->REG_0E4 |= CODEC_CODEC_RESAMPLE_ADC_PHASE_UPDATE;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void hal_codec_tune_both_resample_rate(float ratio) {
|
|
#ifdef __AUDIO_RESAMPLE__
|
|
bool update[2];
|
|
uint32_t val[2];
|
|
uint32_t lock;
|
|
|
|
if (!codec_opened) {
|
|
return;
|
|
}
|
|
|
|
update[0] = !!(codec->REG_0E4 & CODEC_CODEC_RESAMPLE_DAC_PHASE_UPDATE);
|
|
update[1] = !!(codec->REG_0E4 & CODEC_CODEC_RESAMPLE_ADC_PHASE_UPDATE);
|
|
|
|
val[0] = val[1] = 0;
|
|
|
|
if (update[0]) {
|
|
codec->REG_0E4 &= ~CODEC_CODEC_RESAMPLE_DAC_PHASE_UPDATE;
|
|
val[0] = resample_phase_float_to_value(get_playback_resample_phase());
|
|
val[0] += (int)(val[0] * ratio);
|
|
}
|
|
if (update[1]) {
|
|
codec->REG_0E4 &= ~CODEC_CODEC_RESAMPLE_ADC_PHASE_UPDATE;
|
|
val[1] = resample_phase_float_to_value(get_capture_resample_phase());
|
|
val[1] -= (int)(val[1] * ratio);
|
|
}
|
|
|
|
hal_codec_reg_update_delay();
|
|
|
|
if (update[0]) {
|
|
codec->REG_0F4 = val[0];
|
|
}
|
|
if (update[1]) {
|
|
codec->REG_0F8 = val[1];
|
|
}
|
|
|
|
hal_codec_reg_update_delay();
|
|
|
|
lock = int_lock();
|
|
if (update[0]) {
|
|
codec->REG_0E4 |= CODEC_CODEC_RESAMPLE_DAC_PHASE_UPDATE;
|
|
}
|
|
if (update[1]) {
|
|
codec->REG_0E4 |= CODEC_CODEC_RESAMPLE_ADC_PHASE_UPDATE;
|
|
}
|
|
int_unlock(lock);
|
|
#endif
|
|
}
|
|
|
|
int hal_codec_select_clock_out(uint32_t cfg) {
|
|
uint32_t lock;
|
|
int ret = 1;
|
|
|
|
lock = int_lock();
|
|
|
|
if (codec_opened) {
|
|
codec->REG_060 = SET_BITFIELD(codec->REG_060, CODEC_CFG_CLK_OUT, cfg);
|
|
ret = 0;
|
|
}
|
|
|
|
int_unlock(lock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#ifdef AUDIO_ANC_FB_MC
|
|
void hal_codec_setup_mc(enum AUD_CHANNEL_NUM_T channel_num,
|
|
enum AUD_BITS_T bits) {
|
|
if (channel_num == AUD_CHANNEL_NUM_2) {
|
|
mc_dual_chan = true;
|
|
} else {
|
|
mc_dual_chan = false;
|
|
}
|
|
|
|
if (bits <= AUD_BITS_16) {
|
|
mc_16bit = true;
|
|
} else {
|
|
mc_16bit = false;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void hal_codec_swap_output(bool swap) {
|
|
#ifdef AUDIO_OUTPUT_SWAP
|
|
output_swap = swap;
|
|
|
|
if (codec_opened) {
|
|
if (output_swap) {
|
|
codec->REG_0A0 |= CODEC_CODEC_DAC_OUT_SWAP;
|
|
} else {
|
|
codec->REG_0A0 &= ~CODEC_CODEC_DAC_OUT_SWAP;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
int hal_codec_config_digmic_phase(uint8_t phase) {
|
|
#ifdef ANC_PROD_TEST
|
|
codec_digmic_phase = phase;
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static void hal_codec_general_irq_handler(void) {
|
|
uint32_t status;
|
|
|
|
status = codec->REG_00C;
|
|
codec->REG_00C = status;
|
|
|
|
status &= codec->REG_010;
|
|
|
|
for (int i = 0; i < CODEC_IRQ_TYPE_QTY; i++) {
|
|
if (codec_irq_callback[i]) {
|
|
codec_irq_callback[i](status);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void hal_codec_set_irq_handler(enum CODEC_IRQ_TYPE_T type,
|
|
HAL_CODEC_IRQ_CALLBACK cb) {
|
|
uint32_t lock;
|
|
|
|
ASSERT(type < CODEC_IRQ_TYPE_QTY, "%s: Bad type=%d", __func__, type);
|
|
|
|
lock = int_lock();
|
|
|
|
codec_irq_callback[type] = cb;
|
|
|
|
if (cb) {
|
|
if (codec_irq_map == 0) {
|
|
NVIC_SetVector(CODEC_IRQn, (uint32_t)hal_codec_general_irq_handler);
|
|
NVIC_SetPriority(CODEC_IRQn, IRQ_PRIORITY_HIGHPLUSPLUS);
|
|
NVIC_ClearPendingIRQ(CODEC_IRQn);
|
|
NVIC_EnableIRQ(CODEC_IRQn);
|
|
}
|
|
codec_irq_map |= (1 << type);
|
|
} else {
|
|
codec_irq_map &= ~(1 << type);
|
|
if (codec_irq_map == 0) {
|
|
NVIC_DisableIRQ(CODEC_IRQn);
|
|
NVIC_ClearPendingIRQ(CODEC_IRQn);
|
|
}
|
|
}
|
|
|
|
int_unlock(lock);
|
|
}
|
|
|
|
void hal_codec_anc_fb_check_set_irq_handler(HAL_CODEC_IRQ_CALLBACK cb) {
|
|
hal_codec_set_irq_handler(CODEC_IRQ_TYPE_ANC_FB_CHECK, cb);
|
|
}
|
|
|
|
/* AUDIO CODEC VOICE ACTIVE DETECTION DRIVER */
|
|
#ifdef VOICE_DETECTOR_EN
|
|
|
|
//#define CODEC_VAD_DEBUG
|
|
|
|
static inline void hal_codec_vad_set_udc(int v) {
|
|
codec->REG_14C &= ~CODEC_VAD_U_DC(0xf);
|
|
codec->REG_14C |= CODEC_VAD_U_DC(v);
|
|
}
|
|
|
|
static inline void hal_codec_vad_set_upre(int v) {
|
|
codec->REG_14C &= ~CODEC_VAD_U_PRE(0x7);
|
|
codec->REG_14C |= CODEC_VAD_U_PRE(v);
|
|
}
|
|
|
|
static inline void hal_codec_vad_set_frame_len(int v) {
|
|
codec->REG_14C &= ~CODEC_VAD_FRAME_LEN(0xff);
|
|
codec->REG_14C |= CODEC_VAD_FRAME_LEN(v);
|
|
}
|
|
|
|
static inline void hal_codec_vad_set_mvad(int v) {
|
|
codec->REG_14C &= ~CODEC_VAD_MVAD(0xf);
|
|
codec->REG_14C |= CODEC_VAD_MVAD(v);
|
|
}
|
|
|
|
static inline void hal_codec_vad_set_pre_gain(int v) {
|
|
codec->REG_14C &= ~CODEC_VAD_PRE_GAIN(0x3f);
|
|
codec->REG_14C |= CODEC_VAD_PRE_GAIN(v);
|
|
}
|
|
|
|
static inline void hal_codec_vad_set_sth(int v) {
|
|
codec->REG_14C &= ~CODEC_VAD_STH(0x3f);
|
|
codec->REG_14C |= CODEC_VAD_STH(v);
|
|
}
|
|
|
|
static inline void hal_codec_vad_set_frame_th1(int v) {
|
|
codec->REG_150 &= ~CODEC_VAD_FRAME_TH1(0xff);
|
|
codec->REG_150 |= CODEC_VAD_FRAME_TH1(v);
|
|
}
|
|
|
|
static inline void hal_codec_vad_set_frame_th2(int v) {
|
|
codec->REG_150 &= ~CODEC_VAD_FRAME_TH2(0x3ff);
|
|
codec->REG_150 |= CODEC_VAD_FRAME_TH2(v);
|
|
}
|
|
|
|
static inline void hal_codec_vad_set_frame_th3(int v) {
|
|
codec->REG_150 &= ~CODEC_VAD_FRAME_TH3(0x3fff);
|
|
codec->REG_150 |= CODEC_VAD_FRAME_TH3(v);
|
|
}
|
|
|
|
static inline void hal_codec_vad_set_range1(int v) {
|
|
codec->REG_154 &= ~CODEC_VAD_RANGE1(0x1f);
|
|
codec->REG_154 |= CODEC_VAD_RANGE1(v);
|
|
}
|
|
|
|
static inline void hal_codec_vad_set_range2(int v) {
|
|
codec->REG_154 &= ~CODEC_VAD_RANGE2(0x7f);
|
|
codec->REG_154 |= CODEC_VAD_RANGE2(v);
|
|
}
|
|
|
|
static inline void hal_codec_vad_set_range3(int v) {
|
|
codec->REG_154 &= ~CODEC_VAD_RANGE3(0x1ff);
|
|
codec->REG_154 |= CODEC_VAD_RANGE3(v);
|
|
}
|
|
|
|
static inline void hal_codec_vad_set_range4(int v) {
|
|
codec->REG_154 &= ~CODEC_VAD_RANGE4(0x3ff);
|
|
codec->REG_154 |= CODEC_VAD_RANGE4(v);
|
|
}
|
|
|
|
static inline void hal_codec_vad_set_psd_th1(int v) {
|
|
codec->REG_158 &= ~CODEC_VAD_PSD_TH1(0x7ffffff);
|
|
codec->REG_158 |= CODEC_VAD_PSD_TH1(v);
|
|
}
|
|
|
|
static inline void hal_codec_vad_set_psd_th2(int v) {
|
|
codec->REG_15C &= ~CODEC_VAD_PSD_TH2(0x7ffffff);
|
|
codec->REG_15C |= CODEC_VAD_PSD_TH2(v);
|
|
}
|
|
|
|
static inline void hal_codec_vad_en(int enable) {
|
|
if (enable) {
|
|
codec->REG_148 |= CODEC_VAD_EN; // enable vad
|
|
} else {
|
|
codec->REG_148 &= ~CODEC_VAD_EN; // disable vad
|
|
codec->REG_148 |= CODEC_VAD_FINISH;
|
|
}
|
|
}
|
|
|
|
static inline void hal_codec_vad_bypass_ds(int bypass) {
|
|
if (bypass)
|
|
codec->REG_148 |= CODEC_VAD_DS_BYPASS; // bypass ds
|
|
else
|
|
codec->REG_148 &= ~CODEC_VAD_DS_BYPASS; // not bypass ds
|
|
}
|
|
|
|
static inline void hal_codec_vad_bypass_dc(int bypass) {
|
|
if (bypass)
|
|
codec->REG_148 |= CODEC_VAD_DC_CANCEL_BYPASS; // bypass dc
|
|
else
|
|
codec->REG_148 &= ~CODEC_VAD_DC_CANCEL_BYPASS; // not bypass dc
|
|
}
|
|
|
|
static inline void hal_codec_vad_bypass_pre(int bypass) {
|
|
if (bypass)
|
|
codec->REG_148 |= CODEC_VAD_PRE_BYPASS; // bypass pre
|
|
else
|
|
codec->REG_148 &= ~CODEC_VAD_PRE_BYPASS; // not bypass pre
|
|
}
|
|
|
|
static inline void hal_codec_vad_dig_mode(int enable) {
|
|
if (enable)
|
|
codec->REG_148 |= CODEC_VAD_DIG_MODE; // digital mode
|
|
else
|
|
codec->REG_148 &= ~CODEC_VAD_DIG_MODE; // not digital mode
|
|
}
|
|
|
|
static inline void hal_codec_vad_adc_en(int enable) {
|
|
if (enable) {
|
|
codec->REG_080 |= (CODEC_CODEC_ADC_EN | CODEC_CODEC_ADC_EN_CH4);
|
|
} else {
|
|
uint32_t val;
|
|
|
|
val = codec->REG_080;
|
|
val &= ~CODEC_CODEC_ADC_EN_CH4;
|
|
if ((val & (CODEC_CODEC_ADC_EN_CH0 | CODEC_CODEC_ADC_EN_CH1 |
|
|
CODEC_CODEC_ADC_EN_CH2 | CODEC_CODEC_ADC_EN_CH3)) == 0) {
|
|
val &= ~CODEC_CODEC_ADC_EN;
|
|
}
|
|
codec->REG_080 = val;
|
|
}
|
|
}
|
|
|
|
static inline void hal_codec_vad_irq_en(int enable) {
|
|
if (enable) {
|
|
codec->REG_010 |= (CODEC_VAD_FIND_MSK | CODEC_VAD_NOT_FIND_MSK);
|
|
} else {
|
|
codec->REG_010 &= ~(CODEC_VAD_FIND_MSK | CODEC_VAD_NOT_FIND_MSK);
|
|
}
|
|
|
|
codec->REG_00C = CODEC_VAD_FIND | CODEC_VAD_NOT_FIND;
|
|
}
|
|
|
|
static inline void hal_codec_vad_adc_if_en(int enable) {
|
|
if (enable) {
|
|
codec->REG_000 |=
|
|
(CODEC_DMACTRL_RX | CODEC_ADC_ENABLE_CH4 | CODEC_ADC_ENABLE);
|
|
} else {
|
|
codec->REG_000 &=
|
|
~(CODEC_DMACTRL_RX | CODEC_ADC_ENABLE_CH4 | CODEC_ADC_ENABLE);
|
|
}
|
|
}
|
|
|
|
static inline void hal_codec_vad_adc_down(int v) {
|
|
unsigned int regval = codec->REG_094;
|
|
|
|
regval &= ~CODEC_CODEC_ADC_DOWN_SEL_CH4(0x3);
|
|
regval |= CODEC_CODEC_ADC_DOWN_SEL_CH4(v);
|
|
codec->REG_094 = regval;
|
|
}
|
|
|
|
#ifdef CODEC_VAD_DEBUG
|
|
void hal_codec_vad_reg_dump(void) {
|
|
TRACE(1, "codec base = %8x\n", (int)&(codec->REG_000));
|
|
TRACE(1, "codec->REG_000 = %x\n", codec->REG_000);
|
|
TRACE(1, "codec->REG_00C = %x\n", codec->REG_00C);
|
|
TRACE(1, "codec->REG_010 = %x\n", codec->REG_010);
|
|
TRACE(1, "codec->REG_060 = %x\n", codec->REG_060);
|
|
TRACE(1, "codec->REG_064 = %x\n", codec->REG_064);
|
|
TRACE(1, "codec->REG_080 = %x\n", codec->REG_080);
|
|
TRACE(1, "codec->REG_094 = %x\n", codec->REG_094);
|
|
TRACE(1, "codec->REG_148 = %x\n", codec->REG_148);
|
|
TRACE(1, "codec->REG_14C = %x\n", codec->REG_14C);
|
|
TRACE(1, "codec->REG_150 = %x\n", codec->REG_150);
|
|
TRACE(1, "codec->REG_154 = %x\n", codec->REG_154);
|
|
TRACE(1, "codec->REG_158 = %x\n", codec->REG_158);
|
|
TRACE(1, "codec->REG_15C = %x\n", codec->REG_15C);
|
|
}
|
|
#endif
|
|
|
|
static inline void hal_codec_vad_data_info(uint32_t *data_cnt,
|
|
uint32_t *addr_cnt) {
|
|
uint32_t regval = codec->REG_160;
|
|
|
|
*data_cnt = GET_BITFIELD(regval, CODEC_VAD_MEM_DATA_CNT) * 2;
|
|
if (*data_cnt >=
|
|
((CODEC_VAD_MEM_DATA_CNT_MASK >> CODEC_VAD_MEM_DATA_CNT_SHIFT) - 1) * 2) {
|
|
*data_cnt =
|
|
((CODEC_VAD_MEM_DATA_CNT_MASK >> CODEC_VAD_MEM_DATA_CNT_SHIFT) + 1) * 2;
|
|
}
|
|
*addr_cnt = GET_BITFIELD(regval, CODEC_VAD_MEM_ADDR_CNT) * 2;
|
|
}
|
|
|
|
uint32_t hal_codec_vad_recv_data(uint8_t *dst, uint32_t dst_size) {
|
|
uint8_t *src = (uint8_t *)CODEC_VAD_BUF_ADDR;
|
|
const uint32_t src_size = CODEC_VAD_BUF_SIZE;
|
|
uint32_t len;
|
|
uint32_t start_pos;
|
|
|
|
TRACE(5, "%s, dst=%x, dst_size=%d, vad_data_cnt=%d, vad_addr_cnt=%d",
|
|
__func__, (uint32_t)dst, dst_size, vad_data_cnt, vad_addr_cnt);
|
|
|
|
if (vad_data_cnt > src_size || vad_addr_cnt >= src_size) {
|
|
return 0;
|
|
}
|
|
|
|
if (dst == NULL) {
|
|
return vad_data_cnt;
|
|
}
|
|
|
|
if (vad_addr_cnt >= vad_data_cnt) {
|
|
start_pos = vad_addr_cnt - vad_data_cnt;
|
|
} else {
|
|
// In this case (src_size == vad_data_cnt)
|
|
start_pos = vad_addr_cnt + src_size - vad_data_cnt;
|
|
}
|
|
|
|
len = MIN(dst_size, vad_data_cnt);
|
|
|
|
if (start_pos + len <= src_size) {
|
|
memcpy(dst, src + start_pos, len);
|
|
} else {
|
|
uint32_t len1, len2;
|
|
len1 = src_size - start_pos;
|
|
len2 = len - len1;
|
|
memcpy(dst, src + start_pos, len1);
|
|
memcpy(dst + len1, src, len2);
|
|
}
|
|
|
|
TRACE(2, "%s, len=%d", __func__, len);
|
|
return len;
|
|
}
|
|
|
|
void hal_codec_get_vad_data_info(struct CODEC_VAD_BUF_INFO_T *vad_buf_info) {
|
|
vad_buf_info->base_addr = CODEC_VAD_BUF_ADDR;
|
|
vad_buf_info->buf_size = CODEC_VAD_BUF_SIZE;
|
|
vad_buf_info->data_count = vad_data_cnt;
|
|
vad_buf_info->addr_count = vad_addr_cnt;
|
|
}
|
|
|
|
static void hal_codec_vad_isr(uint32_t irq_status) {
|
|
if ((irq_status & (CODEC_VAD_FIND | CODEC_VAD_NOT_FIND)) == 0) {
|
|
return;
|
|
}
|
|
|
|
TRACE(2, "%s VAD_FIND=%d", __func__, !!(irq_status & CODEC_VAD_FIND));
|
|
|
|
if (vad_handler) {
|
|
vad_handler(!!(irq_status & CODEC_VAD_FIND));
|
|
}
|
|
}
|
|
|
|
int hal_codec_vad_config(const struct AUD_VAD_CONFIG_T *conf) {
|
|
unsigned int adc_channel_en = 0;
|
|
unsigned int cfg_set_mask = 0;
|
|
unsigned int cfg_clr_mask = 0;
|
|
|
|
if (!conf)
|
|
return -1;
|
|
|
|
vad_handler = conf->handler;
|
|
|
|
hal_codec_vad_en(0);
|
|
hal_codec_vad_irq_en(0);
|
|
|
|
hal_codec_vad_set_udc(conf->udc);
|
|
hal_codec_vad_set_upre(conf->upre);
|
|
hal_codec_vad_set_frame_len(conf->frame_len);
|
|
hal_codec_vad_set_mvad(conf->mvad);
|
|
hal_codec_vad_set_pre_gain(conf->pre_gain);
|
|
hal_codec_vad_set_sth(conf->sth);
|
|
hal_codec_vad_set_frame_th1(conf->frame_th[0]);
|
|
hal_codec_vad_set_frame_th2(conf->frame_th[1]);
|
|
hal_codec_vad_set_frame_th3(conf->frame_th[2]);
|
|
hal_codec_vad_set_range1(conf->range[0]);
|
|
hal_codec_vad_set_range2(conf->range[1]);
|
|
hal_codec_vad_set_range3(conf->range[2]);
|
|
hal_codec_vad_set_range4(conf->range[3]);
|
|
hal_codec_vad_set_psd_th1(conf->psd_th[0]);
|
|
hal_codec_vad_set_psd_th2(conf->psd_th[1]);
|
|
hal_codec_vad_dig_mode(0);
|
|
hal_codec_vad_bypass_dc(0);
|
|
hal_codec_vad_bypass_pre(0);
|
|
|
|
if (conf->sample_rate == AUD_SAMPRATE_8000) {
|
|
// select adc down 8KHz
|
|
hal_codec_vad_adc_down(1);
|
|
hal_codec_vad_bypass_ds(1);
|
|
} else if (conf->sample_rate == AUD_SAMPRATE_16000) {
|
|
// select adc down 16KHz
|
|
hal_codec_vad_adc_down(0);
|
|
hal_codec_vad_bypass_ds(0);
|
|
} else {
|
|
ASSERT(false, "%s: Bad sample rate: %u", __func__, conf->sample_rate);
|
|
}
|
|
|
|
cfg_clr_mask = CODEC_MODE_16BIT_ADC_CH0 | CODEC_MODE_16BIT_ADC_CH1 |
|
|
CODEC_MODE_16BIT_ADC_CH2 | CODEC_MODE_16BIT_ADC_CH3 |
|
|
CODEC_MODE_16BIT_ADC_CH4 | CODEC_MODE_16BIT_ADC_CH5 |
|
|
CODEC_MODE_16BIT_ADC_CH6 | CODEC_MODE_24BIT_ADC |
|
|
CODEC_MODE_32BIT_ADC;
|
|
|
|
if (conf->bits == AUD_BITS_16) {
|
|
cfg_set_mask |= CODEC_MODE_16BIT_ADC_CH0 | CODEC_MODE_16BIT_ADC_CH1 |
|
|
CODEC_MODE_16BIT_ADC_CH2 | CODEC_MODE_16BIT_ADC_CH3 |
|
|
CODEC_MODE_16BIT_ADC_CH4 | CODEC_MODE_16BIT_ADC_CH5 |
|
|
CODEC_MODE_16BIT_ADC_CH6;
|
|
} else if (conf->bits == AUD_BITS_24) {
|
|
cfg_set_mask |= CODEC_MODE_24BIT_ADC;
|
|
} else if (conf->bits == AUD_BITS_32) {
|
|
cfg_set_mask |= CODEC_MODE_32BIT_ADC;
|
|
} else {
|
|
ASSERT(false, "%s: Bad cap bits: %d", __func__, conf->bits);
|
|
}
|
|
|
|
for (int i = 0; i < MAX_ADC_CH_NUM; i++) {
|
|
adc_channel_en |= (CODEC_ADC_ENABLE_CH0 << i);
|
|
}
|
|
|
|
if (((codec->REG_000 & adc_channel_en) != 0) &&
|
|
((codec->REG_040 & cfg_set_mask) == 0)) {
|
|
ASSERT(false, "%s: Cap bits conflict: %d", __func__, conf->bits);
|
|
} else {
|
|
codec->REG_040 = (codec->REG_040 & ~cfg_clr_mask) | cfg_set_mask;
|
|
}
|
|
|
|
codec->REG_220 = 320;
|
|
codec->REG_224 = 32000 * 3; // vad timeout value
|
|
#ifdef I2C_VAD
|
|
codec->REG_230 |= CODEC_VAD_EXT_EN | CODEC_VAD_SRC_SEL;
|
|
#endif
|
|
|
|
#if !(defined(FIXED_CODEC_ADC_VOL) && defined(SINGLE_CODEC_ADC_VOL))
|
|
const CODEC_ADC_VOL_T *adc_gain_db;
|
|
|
|
#ifdef SINGLE_CODEC_ADC_VOL
|
|
adc_gain_db = hal_codec_get_adc_volume(CODEC_SADC_VOL);
|
|
#else
|
|
adc_gain_db = hal_codec_get_adc_volume(
|
|
hal_codec_get_mic_chan_volume_level(AUD_CHANNEL_MAP_CH4));
|
|
#endif
|
|
if (adc_gain_db) {
|
|
hal_codec_set_dig_adc_gain(AUD_CHANNEL_MAP_CH4, *adc_gain_db);
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
int hal_codec_vad_open(const struct AUD_VAD_CONFIG_T *conf) {
|
|
vad_type = conf->type;
|
|
|
|
// open analog vad
|
|
analog_aud_vad_adc_enable(true);
|
|
|
|
// enable vad clock
|
|
hal_cmu_codec_vad_clock_enable(1);
|
|
|
|
hal_codec_vad_config(conf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int hal_codec_vad_close(void) {
|
|
#ifdef I2C_VAD
|
|
codec->REG_230 &= ~(CODEC_VAD_EXT_EN | CODEC_VAD_SRC_SEL);
|
|
#endif
|
|
|
|
// disable vad clock
|
|
hal_cmu_codec_vad_clock_enable(0);
|
|
|
|
// close analog vad
|
|
analog_aud_vad_adc_enable(false);
|
|
|
|
vad_type = AUD_VAD_TYPE_NONE;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int hal_codec_vad_start(void) {
|
|
if (vad_enabled) {
|
|
return 0;
|
|
}
|
|
vad_enabled = true;
|
|
vad_data_cnt = 0;
|
|
vad_addr_cnt = 0;
|
|
|
|
hal_codec_vad_irq_en(1);
|
|
hal_codec_set_irq_handler(CODEC_IRQ_TYPE_VAD, hal_codec_vad_isr);
|
|
|
|
if (vad_type == AUD_VAD_TYPE_MIX || vad_type == AUD_VAD_TYPE_DIG) {
|
|
// digital vad
|
|
hal_codec_vad_en(1);
|
|
// enable adc if
|
|
hal_codec_vad_adc_if_en(1);
|
|
// enable adc
|
|
hal_codec_vad_adc_en(1);
|
|
}
|
|
|
|
analog_aud_vad_enable(vad_type, true);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int hal_codec_vad_stop(void) {
|
|
if (!vad_enabled) {
|
|
return 0;
|
|
}
|
|
vad_enabled = false;
|
|
hal_codec_vad_data_info(&vad_data_cnt, &vad_addr_cnt);
|
|
|
|
analog_aud_vad_enable(vad_type, false);
|
|
|
|
hal_codec_vad_irq_en(0);
|
|
hal_codec_set_irq_handler(CODEC_IRQ_TYPE_VAD, NULL);
|
|
|
|
if (vad_type == AUD_VAD_TYPE_MIX || vad_type == AUD_VAD_TYPE_DIG) {
|
|
hal_codec_vad_en(0);
|
|
hal_codec_vad_adc_if_en(0);
|
|
hal_codec_vad_adc_en(0);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
//********************BT trigger functions: START********************
|
|
static void hal_codec_bt_trigger_isr(uint32_t irq_status) {
|
|
if ((irq_status & CODEC_BT_TRIGGER) == 0) {
|
|
return;
|
|
}
|
|
|
|
if (bt_trigger_callback) {
|
|
TRACE(1, "[%s] bt_trigger_callback Start...", __func__);
|
|
bt_trigger_callback();
|
|
} else {
|
|
TRACE(1, "[%s] bt_trigger_callback = NULL", __func__);
|
|
}
|
|
}
|
|
|
|
static inline void hal_codec_bt_trigger_irq_en(int enable) {
|
|
if (enable)
|
|
codec->REG_010 |= CODEC_BT_TRIGGER_MSK;
|
|
else
|
|
codec->REG_010 &= ~CODEC_BT_TRIGGER_MSK;
|
|
|
|
codec->REG_00C = CODEC_BT_TRIGGER;
|
|
}
|
|
|
|
void hal_codec_set_bt_trigger_callback(HAL_CODEC_BT_TRIGGER_CALLBACK callback) {
|
|
bt_trigger_callback = callback;
|
|
}
|
|
|
|
int hal_codec_bt_trigger_start(void) {
|
|
uint32_t lock;
|
|
|
|
TRACE(1, "[%s] Start", __func__);
|
|
|
|
lock = int_lock();
|
|
|
|
hal_codec_set_irq_handler(CODEC_IRQ_TYPE_BT_TRIGGER,
|
|
hal_codec_bt_trigger_isr);
|
|
hal_codec_bt_trigger_irq_en(1);
|
|
|
|
int_unlock(lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int hal_codec_bt_trigger_stop(void) {
|
|
uint32_t lock;
|
|
|
|
TRACE(1, "[%s] Stop", __func__);
|
|
|
|
lock = int_lock();
|
|
|
|
hal_codec_bt_trigger_irq_en(0);
|
|
hal_codec_set_irq_handler(CODEC_IRQ_TYPE_BT_TRIGGER, NULL);
|
|
|
|
int_unlock(lock);
|
|
|
|
return 0;
|
|
}
|
|
//********************BT trigger functions: END********************
|