mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-15 17:41:25 +00:00
This CL adds the driver support for the WoV module which inludes the following files: - wov.c - wov_chip.h - apm.c - apm_chip.h It also supports the console commad "wov" which can test different configuration and audio quality by entering different parameters. The detail description of WoV console command is listed below: ------------------------------------------------------------------------ [Note]: Before changing any of settings, please make sure the operation mode is on the "OFF" state. (ie. run the command wov cfgmod off first) . > wov init Initialize WoV interface, including pin mux and interrupt registration etc. > wov mute <enable / disable > mute enable / disable. > wov cfgsrc <mono | stereo | left | right> set audio source, ex: wov cfgsrc left, means audio source from left MIC. > wov cfgbis <16|18|20|24> set audio resolution, ex: wov cfgbit 16 means audio resolution are 16bits. > wov cfgsfs <8000|12000|16000|24000|32000|48000> set audio sampling frequency rate, ex: wov cfgsfs 48000 means audio sampling rate are 48Khz. > wov cfgbck <32fs|48fs|64fs|128fs|256fs> set I2S bit clock rate, ex: wov cfgsfs 48000 and wov cfgbck 32fs means audio sampling rate are 1536Khz (32*48000). > wov cfgfmt <i2s|right|left|pcma|pcmb|tdm> set I2S but format, ex: wov cfgfmt right means audio I2S format are Right-Justify. > wov cfgmod <off|vad|ram|i2s|rami2s> set audio operation mode ,ex: wov cfgmod i2s means audio output via I2S bus. > wov cfgtdm <0~496 0~496 0~3> set TDM time slot, the first values is left channel delay counter, the second is right channel, and the 3rd is startup counting condition. (chosen LRCK raising or falling edge) . [Note: this command is just working on cfgmod equal to tdm] > wov cfgget retrieve above settings. > wov vadsens (currently not support, reserve for next version) > wov gain (0~31) set audio data gain value, ex: wov gain 10 means setting audio digital gain are 10dB. > wov cfgdck <1.0 | 2.4 | 3.0 > set digital MIC PDM clock rate. ex: wov cfgdck 2.4 means PDM clock are 2.4Mhz. ----------------------------------------------------------------------- This CL also adds the chip ID (0x24) for npcx7m7w. So the console command "version" can show the chip is npcx7m7w. BRANCH=none BUG=none TEST=No build errors for make buildall. TEST="BOARD=npcx7_evb make"; Flash the image on EVB; Test WoV function with console commands described above. Change-Id: Ief2b3e89edbd3e6d2a9d82d317a93c9f0b7a20cd Signed-off-by: Dror Goldstein <dror.goldstein@nuvoton.com> Signed-off-by: Simon Liang <CMLiang@nuvoton.com> Signed-off-by: CHLin <CHLIN56@nuvoton.com> Reviewed-on: https://chromium-review.googlesource.com/897314 Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com> Tested-by: CH Lin <chlin56@nuvoton.com> Reviewed-by: Scott Collyer <scollyer@chromium.org>
621 lines
15 KiB
C
621 lines
15 KiB
C
/* Copyright (c) 2018 The Chromium OS Authors. All rights reserved.
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
/* NPCX-specific APM module for Chrome EC */
|
|
|
|
#include "apm_chip.h"
|
|
#include "common.h"
|
|
#include "registers.h"
|
|
#include "util.h"
|
|
#include "wov_chip.h"
|
|
|
|
static struct apm_config apm_conf;
|
|
static struct apm_auto_gain_config apm_gain_conf;
|
|
|
|
|
|
static uint32_t apm_indirect_reg[][3] = {
|
|
{(NPCX_APM_BASE_ADDR + 0x034), (NPCX_APM_BASE_ADDR + 0x038)},
|
|
{(NPCX_APM_BASE_ADDR + 0x04C), (NPCX_APM_BASE_ADDR + 0x050)},
|
|
{(NPCX_APM_BASE_ADDR + 0x05C), (NPCX_APM_BASE_ADDR + 0x060)}
|
|
};
|
|
|
|
#define APM_CNTRL_REG 0
|
|
#define APM_DATA_REG 1
|
|
|
|
/**
|
|
* Reads data indirect register.
|
|
*
|
|
* @param reg_offset - Indirect register APM_MIX_REG, APM_ADC_AGC_REG or
|
|
* APM_VAD_REG.
|
|
* @param indirect_addr - Indirect access address.
|
|
* @return The read data.
|
|
*/
|
|
static uint8_t apm_read_indirect_data(enum apm_indirect_reg_offset reg_offset,
|
|
uint8_t indirect_addr)
|
|
{
|
|
/* Set the indirect access address. */
|
|
SET_FIELD(REG8(apm_indirect_reg[reg_offset][APM_CNTRL_REG]),
|
|
NPCX_APM_CONTROL_ADD, indirect_addr);
|
|
|
|
/* Read command. */
|
|
CLEAR_BIT(REG8(apm_indirect_reg[reg_offset][APM_CNTRL_REG]),
|
|
NPCX_APM_CONTROL_LOAD);
|
|
|
|
/* Get the data. */
|
|
return REG8(apm_indirect_reg[reg_offset][APM_DATA_REG]);
|
|
}
|
|
|
|
/**
|
|
* Writes data indirect register.
|
|
*
|
|
* @param reg_offset - Indirect register APM_MIX_REG, APM_ADC_AGC_REG or
|
|
* APM_VAD_REG.
|
|
* @param indirect_addr - Indirect access address.
|
|
* @param value - Written value.
|
|
* @return None
|
|
*/
|
|
static void apm_write_indirect_data(enum apm_indirect_reg_offset reg_offset,
|
|
uint8_t indirect_addr, uint8_t value)
|
|
{
|
|
/* Set the data. */
|
|
REG8(apm_indirect_reg[reg_offset][APM_DATA_REG]) = value;
|
|
|
|
/* Set the indirect access address. */
|
|
SET_FIELD(REG8(apm_indirect_reg[reg_offset][APM_CNTRL_REG]),
|
|
NPCX_APM_CONTROL_ADD, indirect_addr);
|
|
|
|
/* Write command. */
|
|
SET_BIT(REG8(apm_indirect_reg[reg_offset][APM_CNTRL_REG]),
|
|
NPCX_APM_CONTROL_LOAD);
|
|
CLEAR_BIT(REG8(apm_indirect_reg[reg_offset][APM_CNTRL_REG]),
|
|
NPCX_APM_CONTROL_LOAD);
|
|
}
|
|
|
|
/**
|
|
* Sets the ADC DMIC rate.
|
|
*
|
|
* @param rate - ADC digital microphone rate
|
|
* @return None
|
|
*/
|
|
void apm_set_adc_dmic_config_l(enum apm_dmic_rate rate)
|
|
{
|
|
SET_FIELD(NPCX_APM_CR_DMIC, NPCX_APM_CR_DMIC_ADC_DMIC_RATE, rate);
|
|
}
|
|
|
|
/**
|
|
* Sets VAD DMIC rate.
|
|
*
|
|
* @param rate - VAD DMIC rate
|
|
*
|
|
* @return None
|
|
*/
|
|
void apm_set_vad_dmic_rate_l(enum apm_dmic_rate rate)
|
|
{
|
|
uint8_t vad_data;
|
|
|
|
vad_data = apm_read_indirect_data(APM_VAD_REG, APM_INDIRECT_VAD_0_REG);
|
|
|
|
/* Set VAD_0 register. */
|
|
SET_FIELD(vad_data, NPCX_VAD_0_VAD_DMIC_FREQ, rate);
|
|
|
|
apm_write_indirect_data(APM_VAD_REG, APM_INDIRECT_VAD_0_REG, vad_data);
|
|
}
|
|
|
|
/**
|
|
* Translates from ADC real value to frequency code
|
|
*
|
|
* @param adc_freq_val - ADC frequency.
|
|
* @return ADC frequency code, 0xFFFF in case of wrong value.
|
|
*/
|
|
static enum apm_adc_frequency apm_adc_freq_val_2_code(uint32_t adc_freq_val)
|
|
{
|
|
enum apm_adc_frequency freq_code;
|
|
|
|
switch (adc_freq_val) {
|
|
case 8000:
|
|
freq_code = APM_ADC_FREQ_8_000_KHZ;
|
|
break;
|
|
case 12000:
|
|
freq_code = APM_ADC_FREQ_12_000_KHZ;
|
|
break;
|
|
case 16000:
|
|
freq_code = APM_ADC_FREQ_16_000_KHZ;
|
|
break;
|
|
case 24000:
|
|
freq_code = APM_ADC_FREQ_24_000_KHZ;
|
|
break;
|
|
case 32000:
|
|
freq_code = APM_ADC_FREQ_32_000_KHZ;
|
|
break;
|
|
case 48000:
|
|
freq_code = APM_ADC_FREQ_48_000_KHZ;
|
|
break;
|
|
default:
|
|
freq_code = APM_ADC_FREQ_UNSUPPORTED;
|
|
break;
|
|
}
|
|
|
|
return freq_code;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* IC specific low-level driver */
|
|
|
|
/**
|
|
* Initiate APM module local parameters..
|
|
*
|
|
* @param enable - enabled flag, 1 means enable
|
|
* @return None
|
|
*/
|
|
void apm_init(void)
|
|
{
|
|
apm_conf.adc_dmic_rate = APM_DMIC_RATE_3_0;
|
|
apm_conf.gain_coupling = APM_ADC_CHAN_GAINS_INDEPENDENT;
|
|
apm_conf.left_chan_gain = 0;
|
|
apm_conf.right_chan_gain = 0;
|
|
|
|
apm_gain_conf.stereo_enable = 0;
|
|
apm_gain_conf.agc_target = APM_ADC_MAX_TARGET_LEVEL_19_5;
|
|
apm_gain_conf.nois_gate_en = 0;
|
|
apm_gain_conf.nois_gate_thold = APM_MIN_NOISE_GET_THRESHOLD;
|
|
apm_gain_conf.hold_time = APM_HOLD_TIME_128;
|
|
apm_gain_conf.attack_time = APM_GAIN_RAMP_TIME_160;
|
|
apm_gain_conf.decay_time = APM_GAIN_RAMP_TIME_160;
|
|
apm_gain_conf.gain_max = APM_GAIN_VALUE_42_5;
|
|
apm_gain_conf.gain_min = APM_GAIN_VALUE_0_0;
|
|
}
|
|
|
|
/**
|
|
* Enables/Disables APM module.
|
|
*
|
|
* @param enable - enabled flag, 1 means enable
|
|
* @return None
|
|
*/
|
|
void apm_enable(int enable)
|
|
{
|
|
if (enable) {
|
|
CLEAR_BIT(NPCX_APM_CR_APM, NPCX_APM_CR_APM_PD);
|
|
|
|
/* Work around that enable the AGC. */
|
|
SET_FIELD(NPCX_APM_CR_APM, NPCX_APM_CR_APM_AGC_DIS, 0x00);
|
|
|
|
} else
|
|
SET_BIT(NPCX_APM_CR_APM, NPCX_APM_CR_APM_PD);
|
|
}
|
|
|
|
/**
|
|
* Enables/Disables voice activity detected interrupt.
|
|
*
|
|
* @param enable - enabled flag, 1 means enable
|
|
* @return APM interrupt mode.
|
|
*/
|
|
void apm_enable_vad_interrupt(int enable)
|
|
{
|
|
wov_interrupt_enable(WOV_VAD_INT_INDX, enable);
|
|
wov_interrupt_enable(WOV_VAD_WAKE_INDX, enable);
|
|
if (enable)
|
|
CLEAR_BIT(NPCX_APM_IMR, NPCX_APM_IMR_VAD_DTC_MASK);
|
|
else
|
|
SET_BIT(NPCX_APM_IMR, NPCX_APM_IMR_VAD_DTC_MASK);
|
|
}
|
|
|
|
/**
|
|
* Enables/Disables ADC.
|
|
*
|
|
* @param enable - enabled flag, 1 means enable
|
|
* @return None
|
|
*/
|
|
void apm_adc_enable(int enable)
|
|
{
|
|
if (enable) {
|
|
CLEAR_BIT(NPCX_APM_AICR_ADC, NPCX_APM_AICR_ADC_PD_AICR_ADC);
|
|
SET_FIELD(NPCX_APM_AICR_ADC,
|
|
NPCX_APM_AICR_ADC_ADC_AUDIOIF, 0x00);
|
|
} else {
|
|
SET_BIT(NPCX_APM_AICR_ADC, NPCX_APM_AICR_ADC_PD_AICR_ADC);
|
|
SET_FIELD(NPCX_APM_AICR_ADC,
|
|
NPCX_APM_AICR_ADC_ADC_AUDIOIF, 0x03);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* sets the ADC frequency.
|
|
*
|
|
* @param adc_freq - ADC frequency.
|
|
* @return None
|
|
*/
|
|
void apm_adc_set_freq(enum apm_adc_frequency adc_freq)
|
|
{
|
|
SET_FIELD(NPCX_APM_FCR_ADC, NPCX_APM_FCR_ADC_ADC_FREQ, adc_freq);
|
|
}
|
|
|
|
/**
|
|
* Configures the ADC.
|
|
*
|
|
* @param hpf_enable - High pass filter enabled flag, 1 means enable
|
|
* @param filter_mode - ADC wind noise filter mode.
|
|
* @param adc_freq - ADC frequency.
|
|
* @return None
|
|
*/
|
|
void apm_adc_config(int hpf_enable,
|
|
enum apm_adc_wind_noise_filter_mode filter_mode,
|
|
enum apm_adc_frequency adc_freq)
|
|
{
|
|
if (hpf_enable)
|
|
SET_BIT(NPCX_APM_FCR_ADC, NPCX_APM_FCR_ADC_ADC_HPF);
|
|
else
|
|
CLEAR_BIT(NPCX_APM_FCR_ADC, NPCX_APM_FCR_ADC_ADC_HPF);
|
|
|
|
SET_FIELD(NPCX_APM_FCR_ADC, NPCX_APM_FCR_ADC_ADC_WNF, filter_mode);
|
|
|
|
SET_FIELD(NPCX_APM_FCR_ADC, NPCX_APM_FCR_ADC_ADC_FREQ, adc_freq);
|
|
}
|
|
|
|
/**
|
|
* Enables/Disables Digital Microphone.
|
|
*
|
|
* @param enable - enabled flag, 1 means enable
|
|
* @return None
|
|
*/
|
|
void apm_dmic_enable(int enable)
|
|
{
|
|
if (enable)
|
|
CLEAR_BIT(NPCX_APM_CR_DMIC, NPCX_APM_CR_DMIC_PD_DMIC);
|
|
else
|
|
SET_BIT(NPCX_APM_CR_DMIC, NPCX_APM_CR_DMIC_PD_DMIC);
|
|
}
|
|
|
|
/**
|
|
* Sets the ADC DMIC rate.
|
|
*
|
|
* @param rate - ADC digital microphone rate
|
|
* @return None
|
|
*/
|
|
void apm_set_adc_dmic_config(enum apm_dmic_rate rate)
|
|
{
|
|
apm_conf.adc_dmic_rate = rate;
|
|
}
|
|
|
|
/**
|
|
* Configures Digital Mixer
|
|
*
|
|
* @param mix_left - Mixer left channel output selection on ADC path.
|
|
* @param mix_right - Mixer right channel output selection on ADC path.
|
|
* @return None
|
|
*/
|
|
void apm_digital_mixer_config(enum apm_dig_mix mix_left,
|
|
enum apm_dig_mix mix_right)
|
|
{
|
|
uint8_t mix_2 = 0;
|
|
|
|
SET_FIELD(mix_2, NPCX_APM_MIX_2_AIADCL_SEL, mix_left);
|
|
SET_FIELD(mix_2, NPCX_APM_MIX_2_AIADCR_SEL, mix_right);
|
|
|
|
apm_write_indirect_data(APM_MIX_REG, APM_INDIRECT_MIX_2_REG, mix_2);
|
|
}
|
|
|
|
/**
|
|
* Enables/Disables the VAD functionality.
|
|
*
|
|
* @param enable - enabled flag, 1 means enable
|
|
* @return None
|
|
*/
|
|
void apm_vad_enable(int enable)
|
|
{
|
|
if (enable)
|
|
SET_BIT(NPCX_APM_CR_VAD, NPCX_APM_CR_VAD_VAD_EN);
|
|
else
|
|
CLEAR_BIT(NPCX_APM_CR_VAD, NPCX_APM_CR_VAD_VAD_EN);
|
|
}
|
|
|
|
/**
|
|
* Enables/Disables VAD ADC wakeup
|
|
*
|
|
* @param enable - 1 enable, 0 disable.
|
|
*
|
|
* @return None
|
|
*/
|
|
void apm_vad_adc_wakeup_enable(int enable)
|
|
{
|
|
uint8_t vad_data;
|
|
|
|
vad_data = apm_read_indirect_data(APM_VAD_REG, APM_INDIRECT_VAD_0_REG);
|
|
|
|
if (enable)
|
|
SET_BIT(vad_data, NPCX_VAD_0_VAD_ADC_WAKEUP);
|
|
else
|
|
CLEAR_BIT(vad_data, NPCX_VAD_0_VAD_ADC_WAKEUP);
|
|
|
|
apm_write_indirect_data(APM_VAD_REG, APM_INDIRECT_VAD_0_REG, vad_data);
|
|
}
|
|
|
|
/**
|
|
* Sets VAD DMIC rate.
|
|
*
|
|
* @param rate - VAD DMIC rate
|
|
*
|
|
* @return None
|
|
*/
|
|
void apm_set_vad_dmic_rate(enum apm_dmic_rate rate)
|
|
{
|
|
apm_conf.vad_dmic_rate = rate;
|
|
}
|
|
|
|
/**
|
|
* Sets VAD Input chanel.
|
|
*
|
|
* @param chan_src - Processed digital microphone channel
|
|
* selection.
|
|
* @return None
|
|
*/
|
|
void apm_set_vad_input_channel(enum apm_vad_in_channel_src chan_src)
|
|
{
|
|
uint8_t vad_data;
|
|
|
|
vad_data = apm_read_indirect_data(APM_VAD_REG, APM_INDIRECT_VAD_0_REG);
|
|
|
|
SET_FIELD(vad_data, NPCX_VAD_0_VAD_INSEL, chan_src);
|
|
|
|
apm_write_indirect_data(APM_VAD_REG, APM_INDIRECT_VAD_0_REG, vad_data);
|
|
}
|
|
|
|
/**
|
|
* Sets VAD sensitivity.
|
|
*
|
|
* @param sensitivity_db - VAD sensitivity in db.
|
|
* @return None
|
|
*/
|
|
void apm_set_vad_sensitivity(uint8_t sensitivity_db)
|
|
{
|
|
uint8_t vad_data;
|
|
|
|
vad_data = apm_read_indirect_data(APM_VAD_REG, APM_INDIRECT_VAD_1_REG);
|
|
|
|
SET_FIELD(vad_data, NPCX_VAD_1_VAD_POWER_SENS, sensitivity_db);
|
|
|
|
apm_write_indirect_data(APM_VAD_REG, APM_INDIRECT_VAD_1_REG, vad_data);
|
|
}
|
|
|
|
/**
|
|
* Gets VAD sensitivity.
|
|
*
|
|
* @param None.
|
|
* @return VAD sensitivity in db
|
|
*/
|
|
uint8_t apm_get_vad_sensitivity(void)
|
|
{
|
|
uint8_t vad_data;
|
|
|
|
vad_data = apm_read_indirect_data(APM_VAD_REG, APM_INDIRECT_VAD_1_REG);
|
|
|
|
return GET_FIELD(vad_data, NPCX_VAD_1_VAD_POWER_SENS);
|
|
}
|
|
|
|
/**
|
|
* Restarts VAD functionality.
|
|
*
|
|
* @param None
|
|
* @return None
|
|
*/
|
|
void apm_vad_restart(void)
|
|
{
|
|
SET_BIT(NPCX_APM_CR_VAD_CMD, NPCX_APM_CR_VAD_CMD_VAD_RESTART);
|
|
}
|
|
|
|
/**
|
|
* Restarts VAD functionality.
|
|
*
|
|
* @param gain_coupling - ADC digital gain coupling (independent or
|
|
* rigth tracks left).
|
|
* @param left_chan_gain - Left channel ADC digital gain programming value.
|
|
* @param right_chan_gain - Right channel ADC digital gain programming value.
|
|
* @return EC_ERROR_INVAL or EC_SUCCESS
|
|
*/
|
|
enum ec_error_list apm_adc_gain_config(enum apm_adc_gain_coupling gain_coupling,
|
|
uint8_t left_chan_gain, uint8_t right_chan_gain)
|
|
{
|
|
/* Check parameters validity. */
|
|
if ((left_chan_gain > 0x2B) || (right_chan_gain > 0x2B))
|
|
return EC_ERROR_INVAL;
|
|
|
|
/*
|
|
* Store the parameters in order to use them in case the function
|
|
* was called prioe calling to wov_set_mode.
|
|
*/
|
|
apm_conf.gain_coupling = gain_coupling;
|
|
apm_conf.left_chan_gain = left_chan_gain;
|
|
apm_conf.right_chan_gain = right_chan_gain;
|
|
|
|
/* Set gain coupling.*/
|
|
if (gain_coupling == APM_ADC_CHAN_GAINS_INDEPENDENT)
|
|
CLEAR_BIT(NPCX_APM_GCR_ADCL, NPCX_APM_GCR_ADCL_LRGID);
|
|
else
|
|
SET_BIT(NPCX_APM_GCR_ADCL, NPCX_APM_GCR_ADCL_LRGID);
|
|
|
|
/* set channels gains. */
|
|
SET_FIELD(NPCX_APM_GCR_ADCL, NPCX_APM_GCR_ADCL_GIDL, left_chan_gain);
|
|
SET_FIELD(NPCX_APM_GCR_ADCR, NPCX_APM_GCR_ADCR_GIDR, right_chan_gain);
|
|
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* Enables/Disables the automatic gain.
|
|
*
|
|
* @param enable - enabled flag, 1 means enable
|
|
* @return None
|
|
*/
|
|
void apm_auto_gain_cntrl_enable(int enable)
|
|
{
|
|
if (enable)
|
|
SET_BIT(NPCX_APM_CR_ADC_AGC, NPCX_APM_CR_ADC_AGC_ADC_AGC_EN);
|
|
else
|
|
CLEAR_BIT(NPCX_APM_CR_ADC_AGC, NPCX_APM_CR_ADC_AGC_ADC_AGC_EN);
|
|
}
|
|
|
|
/**
|
|
* Enables/Disables the automatic gain.
|
|
*
|
|
* @param gain_cfg - struct of apm auto gain config
|
|
* @return EC_ERROR_INVAL or EC_SUCCESS
|
|
*/
|
|
enum ec_error_list apm_adc_auto_gain_config(
|
|
struct apm_auto_gain_config *gain_cfg)
|
|
{
|
|
uint8_t gain_data = 0;
|
|
|
|
/* Check parameters validity. */
|
|
|
|
if (gain_cfg->gain_min > gain_cfg->gain_max)
|
|
return EC_ERROR_INVAL;
|
|
|
|
/*
|
|
* Store the parameters in order to use them in case the function
|
|
* was called prioe calling to wov_set_mode.
|
|
*/
|
|
apm_gain_conf.stereo_enable = gain_cfg->stereo_enable;
|
|
apm_gain_conf.agc_target = gain_cfg->agc_target;
|
|
apm_gain_conf.nois_gate_en = gain_cfg->nois_gate_en;
|
|
apm_gain_conf.nois_gate_thold = gain_cfg->nois_gate_thold;
|
|
apm_gain_conf.hold_time = gain_cfg->hold_time;
|
|
apm_gain_conf.attack_time = gain_cfg->attack_time;
|
|
apm_gain_conf.decay_time = gain_cfg->decay_time;
|
|
apm_gain_conf.gain_max = gain_cfg->gain_max;
|
|
apm_gain_conf.gain_min = gain_cfg->gain_min;
|
|
|
|
/* Set the parameters. */
|
|
|
|
if (gain_cfg->stereo_enable)
|
|
CLEAR_BIT(gain_data, NPCX_ADC_AGC_0_AGC_STEREO);
|
|
else
|
|
SET_BIT(gain_data, NPCX_ADC_AGC_0_AGC_STEREO);
|
|
|
|
SET_FIELD(gain_data, NPCX_ADC_AGC_0_AGC_TARGET, gain_cfg->agc_target);
|
|
|
|
apm_write_indirect_data(APM_ADC_AGC_REG, APM_INDIRECT_ADC_AGC_0_REG,
|
|
gain_data);
|
|
|
|
gain_data = 0;
|
|
|
|
if (gain_cfg->stereo_enable)
|
|
SET_BIT(gain_data, NPCX_ADC_AGC_1_NG_EN);
|
|
else
|
|
CLEAR_BIT(gain_data, NPCX_ADC_AGC_1_NG_EN);
|
|
SET_FIELD(gain_data, NPCX_ADC_AGC_1_NG_THR, gain_cfg->nois_gate_thold);
|
|
SET_FIELD(gain_data, NPCX_ADC_AGC_1_HOLD, gain_cfg->hold_time);
|
|
|
|
apm_write_indirect_data(APM_ADC_AGC_REG, APM_INDIRECT_ADC_AGC_1_REG,
|
|
gain_data);
|
|
|
|
gain_data = 0;
|
|
|
|
SET_FIELD(gain_data, NPCX_ADC_AGC_2_ATK, gain_cfg->attack_time);
|
|
SET_FIELD(gain_data, NPCX_ADC_AGC_2_DCY, gain_cfg->decay_time);
|
|
|
|
apm_write_indirect_data(APM_ADC_AGC_REG, APM_INDIRECT_ADC_AGC_2_REG,
|
|
gain_data);
|
|
|
|
gain_data = 0;
|
|
|
|
SET_FIELD(gain_data, NPCX_ADC_AGC_3_AGC_MAX, gain_cfg->gain_max);
|
|
|
|
apm_write_indirect_data(APM_ADC_AGC_REG, APM_INDIRECT_ADC_AGC_3_REG,
|
|
gain_data);
|
|
|
|
gain_data = 0;
|
|
|
|
SET_FIELD(gain_data, NPCX_ADC_AGC_4_AGC_MIN, gain_cfg->gain_min);
|
|
|
|
apm_write_indirect_data(APM_ADC_AGC_REG, APM_INDIRECT_ADC_AGC_4_REG,
|
|
gain_data);
|
|
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* Sets APM mode (enables & disables APN sub modules accordingly
|
|
* to the APM mode).
|
|
*
|
|
* @param apm_mode - APM mode, DEFAULT, DETECTION, RECORD or INDEPENDENT modes.
|
|
* @return None
|
|
*/
|
|
void apm_set_mode(enum wov_modes wov_mode)
|
|
{
|
|
apm_enable(0);
|
|
|
|
switch (wov_mode) {
|
|
case WOV_MODE_OFF:
|
|
apm_vad_enable(0);
|
|
apm_enable_vad_interrupt(0);
|
|
apm_dmic_enable(0);
|
|
apm_adc_enable(0);
|
|
apm_vad_adc_wakeup_enable(0);
|
|
wov_apm_active(0);
|
|
break;
|
|
|
|
case WOV_MODE_VAD:
|
|
apm_clear_vad_detected_bit();
|
|
wov_apm_active(1);
|
|
apm_vad_restart();
|
|
apm_vad_enable(1);
|
|
apm_enable_vad_interrupt(1);
|
|
apm_set_vad_sensitivity(wov_conf.sensitivity_db);
|
|
apm_set_vad_dmic_rate_l(apm_conf.vad_dmic_rate);
|
|
apm_dmic_enable(1);
|
|
apm_adc_enable(0);
|
|
apm_vad_adc_wakeup_enable(1);
|
|
break;
|
|
|
|
case WOV_MODE_RAM:
|
|
case WOV_MODE_I2S:
|
|
case WOV_MODE_RAM_AND_I2S:
|
|
wov_apm_active(1);
|
|
apm_vad_enable(0);
|
|
apm_enable_vad_interrupt(0);
|
|
apm_set_adc_dmic_config_l(apm_conf.adc_dmic_rate);
|
|
apm_dmic_enable(1);
|
|
apm_adc_enable(1);
|
|
apm_vad_adc_wakeup_enable(0);
|
|
break;
|
|
|
|
default:
|
|
apm_set_vad_dmic_rate_l(APM_DMIC_RATE_1_0);
|
|
apm_set_adc_dmic_config_l(APM_DMIC_RATE_1_0);
|
|
apm_vad_enable(0);
|
|
apm_enable_vad_interrupt(0);
|
|
apm_dmic_enable(0);
|
|
apm_adc_enable(0);
|
|
apm_vad_adc_wakeup_enable(0);
|
|
wov_apm_active(0);
|
|
break;
|
|
}
|
|
|
|
apm_adc_gain_config(apm_conf.gain_coupling,
|
|
apm_conf.left_chan_gain,
|
|
apm_conf.right_chan_gain);
|
|
|
|
apm_adc_auto_gain_config(&apm_gain_conf);
|
|
|
|
apm_adc_set_freq(apm_adc_freq_val_2_code(wov_conf.sample_per_sec));
|
|
|
|
if (wov_mode != WOV_MODE_OFF)
|
|
apm_enable(1);
|
|
}
|
|
|
|
/**
|
|
* Clears VAD detected bit in IFR register.
|
|
*
|
|
* @param None
|
|
* @return None.
|
|
*/
|
|
void apm_clear_vad_detected_bit(void)
|
|
{
|
|
apm_vad_enable(0);
|
|
|
|
APM_CLEAR_VAD_INTERRUPT;
|
|
|
|
apm_vad_enable(1);
|
|
}
|