diff options
Diffstat (limited to 'chip/npcx/wov.c')
-rw-r--r-- | chip/npcx/wov.c | 2071 |
1 files changed, 0 insertions, 2071 deletions
diff --git a/chip/npcx/wov.c b/chip/npcx/wov.c deleted file mode 100644 index c4f68f5369..0000000000 --- a/chip/npcx/wov.c +++ /dev/null @@ -1,2071 +0,0 @@ -/* Copyright 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 WOV module for Chrome EC */ - -#include "apm_chip.h" -#include "clock.h" -#include "console.h" -#include "gpio.h" -#include "hooks.h" -#include "registers.h" -#include "task.h" -#include "timer.h" -#include "util.h" -#include "wov_chip.h" - -#ifndef NPCX_WOV_SUPPORT -#error "Do not enable CONFIG_AUDIO_CODEC_* if npcx ec doesn't support WOV !" -#endif - -/* Console output macros */ -#ifndef DEBUG_AUDIO_CODEC -#define CPUTS(...) -#define CPRINTS(...) -#else -#define CPUTS(outstr) cputs(CC_AUDIO_CODEC, outstr) -#define CPRINTS(format, args...) cprints(CC_AUDIO_CODEC, format, ## args) -#endif - -/* WOV FIFO status. */ -#define WOV_STATUS_OFFSET NPCX_WOV_STATUS_CFIFO_OIT -#define WOV_IS_CFIFO_INT_THRESHOLD(sts) \ - IS_BIT_SET(sts, (NPCX_WOV_STATUS_CFIFO_OIT - WOV_STATUS_OFFSET)) -#define WOV_IS_CFIFO_WAKE_THRESHOLD(sts) \ - IS_BIT_SET(sts, (NPCX_WOV_STATUS_CFIFO_OWT - WOV_STATUS_OFFSET)) -#define WOV_IS_CFIFO_OVERRUN(sts) \ - IS_BIT_SET(sts, (NPCX_WOV_STATUS_CFIFO_OVRN - WOV_STATUS_OFFSET)) -#define WOV_IS_I2S_FIFO_OVERRUN(sts) \ - IS_BIT_SET(sts, (NPCX_WOV_STATUS_I2S_FIFO_OVRN - WOV_STATUS_OFFSET)) -#define WOV_IS_I2S_FIFO_UNDERRUN(sts) \ - IS_BIT_SET(sts, (NPCX_WOV_STATUS_I2S_FIFO_UNDRN - WOV_STATUS_OFFSET)) - -/* Core FIFO threshold. */ -#define WOV_SET_FIFO_WAKE_THRESHOLD(n) \ - SET_FIELD(NPCX_WOV_FIFO_CNT, NPCX_WOV_FIFO_CNT_FIFO_WTHRSH, n) - -#define WOV_SET_FIFO_INT_THRESHOLD(n) \ - SET_FIELD(NPCX_WOV_FIFO_CNT, NPCX_WOV_FIFO_CNT_FIFO_ITHRSH, n) -#define WOV_GET_FIFO_INT_THRESHOLD \ - GET_FIELD(NPCX_WOV_FIFO_CNT, NPCX_WOV_FIFO_CNT_FIFO_ITHRSH) - -#define WOV_PLL_IS_NOT_LOCK \ - (!IS_BIT_SET(NPCX_WOV_PLL_CNTL1, NPCX_WOV_PLL_CNTL1_PLL_LOCKI)) - -/* mask definitions that clear reserved fields for WOV registers.*/ -#define WOV_CLK_CTRL_REG_RESERVED_MASK 0x037F7FFF - -#define WOV_GET_FIFO_WAKE_THRESHOLD \ - GET_FIELD(NPCX_WOV_FIFO_CNT, NPCX_WOV_FIFO_CNT_FIFO_WTHRSH) - -/* Wait time 4ms for FMUL2 enabled and for configuration tuning sequence. */ -#define WOV_FMUL2_CLK_TUNING_DELAY_TIME (4 * 1000) - -/* The size of RAM buffer to store the voice data */ -#define VOICE_BUF_SIZE 16000 - -/* PLL setting options. */ -struct wov_pll_set_options_val { - uint8_t pll_indv; /* Input Divider */ - uint16_t pll_fbdv; /* Feedback Divider */ - uint8_t pll_otdv1; /* Output devide 1. */ - uint8_t pll_otdv2; /* Output devide 2. */ - uint32_t pll_ext_div; /* Index for the table pll_ext_div */ -}; - -/* PLL External Divider Load Values. */ -struct wov_pll_ext_div_val { - uint8_t pll_ediv; /* Required PLL external divider */ - uint8_t pll_ediv_dc; /* Required PLL external divider DC */ -}; - -static const struct wov_pll_ext_div_val pll_ext_div[] = { - {0x2F, 0x78}, /* 12 */ - {0x57, 0x7C}, /* 13 */ - {0x2B, 0x7C}, /* 14 */ - {0x55, 0x7E}, /* 15 */ - {0x2A, 0x7E}, /* 16 */ - {0x15, 0x7F}, /* 17 */ - {0x4A, 0x7F}, /* 18 */ - {0x65, 0x3F}, /* 19 */ - {0x32, 0x3F}, /* 20 */ - {0x19, 0x5F}, /* 21 */ - {0x4C, 0x5F}, /* 22 */ - {0x66, 0x2F}, /* 23 */ - {0x73, 0x2F}, /* 24 */ - {0x39, 0x57}, /* 25 */ - {0x5C, 0x57}, /* 26 */ - {0x6E, 0x2B}, /* 27 */ - {0x77, 0x2B}, /* 28 */ - {0x3B, 0x55}, /* 29 */ - {0x5D, 0x55}, /* 30 */ - {0x2E, 0x2A}, /* 31 */ - {0x17, 0x2A}, /* 32 */ - {0x4B, 0x15}, /* 33 */ - {0x25, 0x15}, /* 34 */ - {0x52, 0x4A}, /* 35 */ - {0x69, 0x4A}, /* 36 */ - {0x34, 0x65}, /* 37 */ - {0x1A, 0x65}, /* 38 */ - {0x0D, 0x32}, /* 39 */ - {0x46, 0x32}, /* 40 */ - {0x63, 0x19}, /* 41 */ - {0x31, 0x19}, /* 42 */ - {0x58, 0x4C}, /* 43 */ - {0x6C, 0x4C}, /* 44 */ - {0x76, 0x66}, /* 45 */ - {0x7B, 0x66}, /* 46 */ - {0x3D, 0x73}, /* 47 */ - {0x5E, 0x73}, /* 48 */ - {0x6F, 0x39}, /* 49 */ - {0x37, 0x39}, /* 50 */ - {0x5B, 0x5C}, /* 51 */ - {0x2D, 0x5C}, /* 52 */ - {0x56, 0x6E}, /* 53 */ - {0x6B, 0x6E}, /* 54 */ - {0x35, 0x77}, /* 55 */ - {0x5A, 0x77}, /* 56 */ - {0x6D, 0x3B}, /* 57 */ - {0x36, 0x3B}, /* 58 */ - {0x1B, 0x5D}, /* 59 */ - {0x4D, 0x5D}, /* 60 */ - {0x26, 0x2E}, /* 61 */ - {0x13, 0x2E}, /* 62 */ - {0x49, 0x17}, /* 63 */ - {0x24, 0x17}, /* 64 */ - {0x12, 0x4B}, /* 65 */ - {0x09, 0x4B}, /* 66 */ - {0x44, 0x25} /* 67 */ -}; - -/* WOV interrupts */ -static const uint8_t wov_interupts[] = { - 0, /* VAD_INTEN */ - 1, /* VAD_WKEN */ - 8, /* CFIFO_NE_IE */ - 9, /* CFIFO_OIT_IE */ - 10, /* CFIFO_OWT_WE */ - 11, /* CFIFO_OVRN_IE */ - 12, /* I2S_FIFO_OVRN_IE */ - 13 /* I2S_FIFO_UNDRN_IE */ -}; - -struct wov_ppl_divider { - uint16_t pll_frame_len; /* PLL frame length. */ - uint16_t pll_fbdv; /* PLL feedback divider. */ - uint8_t pll_indv; /* PLL Input Divider. */ - uint8_t pll_otdv1; /* PLL Output Divider 1. */ - uint8_t pll_otdv2; /* PLL Output Divider 2. */ - uint8_t pll_ediv; /* PLL External Divide Factor. */ -}; - -struct wov_cfifo_buf { - uint32_t *buf; /* Pointer to a buffer. */ - int size; /* Buffer size in words. */ -}; - -struct wov_config wov_conf; - -static struct wov_cfifo_buf cfifo_buf; -static wov_call_back_t callback_fun; - -#define WOV_RATE_ERROR_THRESH_MSEC 10 -#define WOV_RATE_ERROR_THRESH 5 - -static int irq_underrun_count; -static int irq_overrun_count; -static uint32_t wov_i2s_underrun_tstamp; -static uint32_t wov_i2s_overrun_tstamp; - -#define WOV_CALLBACK(event) \ - { \ - if (callback_fun != NULL) \ - callback_fun(event); \ - } - -#define CONFIG_WOV_FIFO_THRESH_WORDS WOV_FIFO_THRESHOLD_80_DATA_WORDS - -/** - * Reads data from the core fifo. - * - * @param num_elements - Number of elements (Dword) to read. - * - * @return None - */ -void wov_cfifo_read_handler_l(uint32_t num_elements) -{ - uint32_t index; - - for (index = 0; index < num_elements; index++) - cfifo_buf.buf[index] = NPCX_WOV_FIFO_OUT; - - cfifo_buf.buf = &cfifo_buf.buf[index]; - cfifo_buf.size -= num_elements; -} - -static enum ec_error_list wov_calc_pll_div_s(int32_t d_in, - int32_t total_div, int32_t vco_freq, - struct wov_ppl_divider *pll_div) -{ - int32_t d_1, d_2, d_e; - - /* - * Please see comments in wov_calc_pll_div_l function below. - */ - for (d_e = 4; d_e < 75; d_e++) { - for (d_2 = 1; d_2 < 7; d_2++) { - for (d_1 = 1; d_1 < 7; d_1++) { - if ((vco_freq / (d_1 * d_2)) > 900) - continue; - - if (total_div == (d_in * d_e * d_1 * d_2)) { - pll_div->pll_indv = d_in; - pll_div->pll_otdv1 = d_1; - pll_div->pll_otdv2 = d_2; - pll_div->pll_ediv = d_e; - return EC_SUCCESS; - } - } - } - } - return EC_ERROR_INVAL; -} - -/** - * Gets the PLL divider value accordingly to the i2S clock frequency. - * - * @param i2s_clk_freq - i2S clock frequency - * @param sample_rate - Sample rate in KHz (16KHz or 48KHz) - * @param pll_div - PLL dividers. - * - * @return None - */ -static enum ec_error_list wov_calc_pll_div_l(uint32_t i2s_clk_freq, - uint32_t sample_rate, struct wov_ppl_divider *pll_div) -{ - int32_t d_f; - int32_t total_div; - int32_t d_in; - int32_t n; - int32_t vco_freq; - int32_t i2s_clk_freq_khz; - - n = i2s_clk_freq / sample_rate; - if (i2s_clk_freq != (sample_rate * n)) - return EC_ERROR_INVAL; - - if ((n < 32) || (n >= 257)) - return EC_ERROR_INVAL; - - pll_div->pll_frame_len = n; - - i2s_clk_freq_khz = i2s_clk_freq / 1000; - - /* - * The code below implemented the “PLL setting option” table as - * describe in the NPCX7m7wb specification document. - * - Total_div is VCO frequency in MHz / 12 MHz - * - d_f is the Feedback Divider - * - d_in is the Input Divider (PLL_INDV) - * - d_e is the PLL Ext Divider - * - d_2 is the Output Divide 2 (PLL_OTDV2) - * - d_1 is the Output Divide 1 (PLL_OTDV1) - * It is preferred that d_f will be as smaller as possible, after that - * the d_in will be as smaller as possible and so on, this is the - * reason that d_f (calculated from total_div) is in the external loop - * and d-1 is in the internal loop (as it may contain the bigger value). - * The “PLL setting option” code divided to 2 function in order to - * fulfil the coding style indentation rule. - */ - - /* total div is min_vco/12 400/12=33. */ - for (total_div = 33; total_div < 1500; total_div++) { - d_f = (total_div * 12000) / i2s_clk_freq_khz; - if ((total_div * 12000) == (d_f * i2s_clk_freq_khz)) { - for (d_in = 1; d_in < 10; d_in++) { - if (((i2s_clk_freq / 1000) / d_in) <= 500) - continue; - - vco_freq = total_div * 12 / d_in; - if ((vco_freq < 500) || (vco_freq > 1600)) - continue; - if (wov_calc_pll_div_s(d_in, total_div, - vco_freq, pll_div) == - EC_SUCCESS) { - pll_div->pll_fbdv = d_f; - return EC_SUCCESS; - } - - } - } - } - - return EC_ERROR_INVAL; -} - -/** - * Check if PLL is locked. - * - * @param None - * - * @return EC_SUCCESS if PLL is locked, EC_ERROR_UNKNOWN otherwise . - */ -enum ec_error_list wov_wait_for_pll_lock_l(void) -{ - volatile uint32_t index; - - for (index = 0; WOV_PLL_IS_NOT_LOCK; index++) { - /* PLL doesn't reach to lock state. */ - if (index > 0xFFFF) - return EC_ERROR_UNKNOWN; - } - - return EC_SUCCESS; -} - -/** - * Configure I2S bus. (Parameters determined via common config functions.) - * - * @param None. - * - * @return none. - */ -static enum ec_error_list wov_set_i2s_config_l(void) -{ - struct wov_ppl_divider pll_div; - enum ec_error_list ret_code; - enum wov_i2s_chan_trigger trigger_0, trigger_1; - int32_t start_delay_0, start_delay_1; - - ret_code = wov_calc_pll_div_l(wov_conf.i2s_clock, - wov_conf.sample_per_sec, &pll_div); - if (ret_code == EC_SUCCESS) { - /* Configure the PLL. */ - ret_code = wov_pll_clk_div_config( - pll_div.pll_otdv1, pll_div.pll_otdv2, pll_div.pll_fbdv, - pll_div.pll_indv); - if (ret_code != EC_SUCCESS) - return ret_code; - - ret_code = wov_pll_clk_ext_div_config( - (enum wov_pll_ext_div_sel)(pll_div.pll_ediv > 15), - pll_div.pll_ediv); - if (ret_code != EC_SUCCESS) - return ret_code; - - wov_i2s_global_config( - (enum wov_floating_mode)(wov_conf.dai_format == - WOV_DAI_FMT_PCM_TDM), - WOV_FLOATING_DRIVEN, WOV_CLK_NORMAL, 0, WOV_PULL_DOWN, - 0, WOV_PULL_DOWN, WOV_NORMAL_MODE); - - /* Configure DAI format. */ - switch (wov_conf.dai_format) { - case WOV_DAI_FMT_I2S: - trigger_0 = WOV_I2S_SAMPLED_0_AFTER_1; - trigger_1 = WOV_I2S_SAMPLED_1_AFTER_0; - start_delay_0 = 1; - start_delay_1 = 1; - break; - - case WOV_DAI_FMT_RIGHT_J: - trigger_0 = WOV_I2S_SAMPLED_1_AFTER_0; - trigger_1 = WOV_I2S_SAMPLED_0_AFTER_1; - start_delay_0 = (pll_div.pll_frame_len / 2) - - wov_conf.bit_depth; - start_delay_1 = (pll_div.pll_frame_len / 2) - - wov_conf.bit_depth; - break; - - case WOV_DAI_FMT_LEFT_J: - trigger_0 = WOV_I2S_SAMPLED_1_AFTER_0; - trigger_1 = WOV_I2S_SAMPLED_0_AFTER_1; - start_delay_0 = 0; - start_delay_1 = 0; - break; - - case WOV_DAI_FMT_PCM_A: - trigger_0 = WOV_I2S_SAMPLED_1_AFTER_0; - trigger_1 = WOV_I2S_SAMPLED_1_AFTER_0; - start_delay_0 = 1; - start_delay_1 = wov_conf.bit_depth + 1; - break; - - case WOV_DAI_FMT_PCM_B: - trigger_0 = WOV_I2S_SAMPLED_1_AFTER_0; - trigger_1 = WOV_I2S_SAMPLED_1_AFTER_0; - start_delay_0 = 0; - start_delay_1 = wov_conf.bit_depth; - break; - - case WOV_DAI_FMT_PCM_TDM: - trigger_0 = WOV_I2S_SAMPLED_1_AFTER_0; - trigger_1 = WOV_I2S_SAMPLED_1_AFTER_0; - start_delay_0 = wov_conf.i2s_start_delay_0; - start_delay_1 = wov_conf.i2s_start_delay_1; - break; - - default: - return EC_ERROR_INVALID_CONFIG; - } - - udelay(100); - - ret_code = wov_i2s_channel_config(0, wov_conf.bit_depth, - trigger_0, start_delay_0); - - ret_code = wov_i2s_channel_config(1, wov_conf.bit_depth, - trigger_1, start_delay_1); - } - - return EC_SUCCESS; -} - -/** - * wov_i2s_channel1_disable - * - * @param disable - disabled flag, 1 means disable - * - * @return None - */ -static void wov_i2s_channel1_disable(int disable) -{ - if (disable) - SET_BIT(NPCX_WOV_I2S_CNTL(1), NPCX_WOV_I2S_CNTL1_I2S_CHN1_DIS); - else - CLEAR_BIT(NPCX_WOV_I2S_CNTL(1), - NPCX_WOV_I2S_CNTL1_I2S_CHN1_DIS); -} - -/** - * Sets microphone source. - * - * | Left | Right | Mono | Stereo - *------------------|-----------|---------------|---------------|-------------- - *FIFO_CNT. |0x0 or 0x2 | 0x0 or 0x2 | 0x1 or 0x3 |0x1 or 0x3 - *CFIFI_ISEL | (left) |(left) |(left & Right) |(left & right) - *------------------|-----------|---------------|---------------|-------------- - *CR_DMIC. | 0x1 | 0x1 | 0x2 | 0x1 - *ADC_DMIC_SEL_LEFT | (left) | (left) | (average) | (left) - *------------------|-----------|---------------|---------------|-------------- - *CR_DMIC. | 0x1 | 0x1 | 0x2 | 0x1 - *ADC_DMIC_SEL_RIGHT| (right) | (right) | (average) | (right) - *------------------|-----------|---------------|---------------|-------------- - *MIX_2. | 0x0 | 0x1 | 0x0 | 0x0 - *AIADCL_SEL | (normal) |(cross inputs) | (normal) | (normal) - *------------------|-----------|---------------|---------------|-------------- - *MIX_2. | 0x3 | 0x3 | 0x0 | 0x0 - *AIADCR_SEL |(no input) | (no input) | (normal) | (normal) - *------------------|-----------|---------------|---------------|-------------- - *VAD_0. | 0x0 | 0x1 | 0x2 | Not - *VAD_INSEL | (left) | (right) | (average) | applicable - * - * @param None. - * @return return EC_SUCCESS if mic source valid othewise return error code. - */ -static enum ec_error_list wov_set_mic_source_l(void) -{ - switch (wov_conf.mic_src) { - case WOV_SRC_LEFT: - if (wov_conf.bit_depth == 16) - SET_FIELD(NPCX_WOV_FIFO_CNT, - NPCX_WOV_FIFO_CNT_CFIFO_ISEL, 0x00); - else - SET_FIELD(NPCX_WOV_FIFO_CNT, - NPCX_WOV_FIFO_CNT_CFIFO_ISEL, 0x02); - SET_FIELD(NPCX_APM_CR_DMIC, NPCX_APM_CR_DMIC_ADC_DMIC_SEL_LEFT, - 0x01); - SET_FIELD(NPCX_APM_CR_DMIC, NPCX_APM_CR_DMIC_ADC_DMIC_SEL_RIGHT, - 0x01); - apm_digital_mixer_config(APM_OUT_MIX_NORMAL_INPUT, - APM_OUT_MIX_NO_INPUT); - apm_set_vad_input_channel(APM_IN_LEFT); - wov_i2s_channel1_disable(1); - break; - - case WOV_SRC_RIGHT: - if (wov_conf.bit_depth == 16) - SET_FIELD(NPCX_WOV_FIFO_CNT, - NPCX_WOV_FIFO_CNT_CFIFO_ISEL, 0x00); - else - SET_FIELD(NPCX_WOV_FIFO_CNT, - NPCX_WOV_FIFO_CNT_CFIFO_ISEL, 0x02); - SET_FIELD(NPCX_APM_CR_DMIC, NPCX_APM_CR_DMIC_ADC_DMIC_SEL_LEFT, - 0x01); - SET_FIELD(NPCX_APM_CR_DMIC, NPCX_APM_CR_DMIC_ADC_DMIC_SEL_RIGHT, - 0x01); - apm_digital_mixer_config(APM_OUT_MIX_CROSS_INPUT, - APM_OUT_MIX_NO_INPUT); - apm_set_vad_input_channel(APM_IN_RIGHT); - wov_i2s_channel1_disable(1); - break; - - case WOV_SRC_MONO: - if (wov_conf.bit_depth == 16) - SET_FIELD(NPCX_WOV_FIFO_CNT, - NPCX_WOV_FIFO_CNT_CFIFO_ISEL, 0x01); - else - SET_FIELD(NPCX_WOV_FIFO_CNT, - NPCX_WOV_FIFO_CNT_CFIFO_ISEL, 0x03); - SET_FIELD(NPCX_APM_CR_DMIC, NPCX_APM_CR_DMIC_ADC_DMIC_SEL_LEFT, - 0x02); - SET_FIELD(NPCX_APM_CR_DMIC, NPCX_APM_CR_DMIC_ADC_DMIC_SEL_RIGHT, - 0x02); - apm_digital_mixer_config(APM_OUT_MIX_NORMAL_INPUT, - APM_OUT_MIX_NORMAL_INPUT); - apm_set_vad_input_channel(APM_IN_AVERAGE_LEFT_RIGHT); - wov_i2s_channel1_disable(0); - break; - - case WOV_SRC_STEREO: - if (wov_conf.bit_depth == 16) - SET_FIELD(NPCX_WOV_FIFO_CNT, - NPCX_WOV_FIFO_CNT_CFIFO_ISEL, 0x01); - else - SET_FIELD(NPCX_WOV_FIFO_CNT, - NPCX_WOV_FIFO_CNT_CFIFO_ISEL, 0x03); - SET_FIELD(NPCX_APM_CR_DMIC, NPCX_APM_CR_DMIC_ADC_DMIC_SEL_LEFT, - 0x01); - SET_FIELD(NPCX_APM_CR_DMIC, NPCX_APM_CR_DMIC_ADC_DMIC_SEL_RIGHT, - 0x01); - apm_digital_mixer_config(APM_OUT_MIX_NORMAL_INPUT, - APM_OUT_MIX_NORMAL_INPUT); - wov_i2s_channel1_disable(0); - break; - - default: - return EC_ERROR_INVAL; - } - - return EC_SUCCESS; -} - -static void wov_over_under_deferred(void) -{ - CPRINTS("wov: Under/Over run error: under = %d, over = %d", - irq_underrun_count, irq_overrun_count); -} -DECLARE_DEFERRED(wov_over_under_deferred); - -static void wov_under_over_error_handler(int *count, uint32_t *last_time) -{ - uint32_t time_delta_msec; - uint32_t current_time = get_time().le.lo; - - if (!(*count)) { - *last_time = current_time; - (*count)++; - } else { - time_delta_msec = (current_time - *last_time) / MSEC; - *last_time = current_time; - if (time_delta_msec < WOV_RATE_ERROR_THRESH_MSEC) - (*count)++; - else - *count = 0; - - if (*count >= WOV_RATE_ERROR_THRESH) { - wov_stop_i2s_capture(); - hook_call_deferred(&wov_over_under_deferred_data, 0); - } - } -} - -/** - * WoV interrupt handler. - * - * @param None - * - * @return None - */ -void wov_interrupt_handler(void) -{ - uint32_t wov_status; - uint32_t wov_inten; - - wov_inten = GET_FIELD(NPCX_WOV_WOV_INTEN, NPCX_WOV_STATUS_BITS); - wov_status = wov_inten & - GET_FIELD(NPCX_WOV_STATUS, NPCX_WOV_STATUS_BITS); - - /* - * Voice activity detected. - */ - if (APM_IS_VOICE_ACTIVITY_DETECTED) { - apm_enable_vad_interrupt(0); - APM_CLEAR_VAD_INTERRUPT; - WOV_CALLBACK(WOV_EVENT_VAD); - } - - /* Core FIFO is overrun. Reset the Core FIFO and inform the FW */ - if (WOV_IS_CFIFO_OVERRUN(wov_status)) { - WOV_CALLBACK(WOV_EVENT_ERROR_CORE_FIFO_OVERRUN); - wov_core_fifo_reset(); - } else if (WOV_IS_CFIFO_INT_THRESHOLD(wov_status) && - (cfifo_buf.buf != NULL)) { - /* - * Core FIFO threshold or FIFO not empty event occurred. - * - Read data from core FIFO to the buffer. - * - In case data ready or no space for data, inform the FW. - */ - - /* Copy data from CFIFO to RAM. */ - wov_cfifo_read_handler_l((WOV_GET_CORE_FIFO_THRESHOLD * 2)); - - if (cfifo_buf.size < (WOV_GET_CORE_FIFO_THRESHOLD * 2)) { - cfifo_buf.buf = NULL; - cfifo_buf.size = 0; - WOV_CALLBACK(WOV_EVENT_DATA_READY); - } - } - - /* I2S FIFO is overrun. Reset the I2S FIFO and inform the FW. */ - if (WOV_IS_I2S_FIFO_OVERRUN(wov_status)) { - WOV_CALLBACK(WOV_EVENT_ERROR_I2S_FIFO_OVERRUN); - wov_under_over_error_handler(&irq_overrun_count, - &wov_i2s_overrun_tstamp); - wov_i2s_fifo_reset(); - } - - /* I2S FIFO is underrun. Reset the I2S FIFO and inform the FW. */ - if (WOV_IS_I2S_FIFO_UNDERRUN(wov_status)) { - WOV_CALLBACK(WOV_EVENT_ERROR_I2S_FIFO_UNDERRUN); - wov_under_over_error_handler(&irq_underrun_count, - &wov_i2s_underrun_tstamp); - wov_i2s_fifo_reset(); - } - - - /* Clear the WoV status register. */ - SET_FIELD(NPCX_WOV_STATUS, NPCX_WOV_STATUS_BITS, wov_status); -} - -DECLARE_IRQ(NPCX_IRQ_WOV, wov_interrupt_handler, 4); - -/** - * Enable FMUL2. - * - * @param enable - enabled flag, true for enable - * @return None - */ -static void wov_fmul2_enable(int enable) -{ - if (enable) { - - /* If clock disabled, then enable it. */ - if (IS_BIT_SET(NPCX_FMUL2_FM2CTRL, - NPCX_FMUL2_FM2CTRL_FMUL2_DIS)) { - /* Enable clock tuning. */ - CLEAR_BIT(NPCX_FMUL2_FM2CTRL, - NPCX_FMUL2_FM2CTRL_TUNE_DIS); - /* Enable clock. */ - CLEAR_BIT(NPCX_FMUL2_FM2CTRL, - NPCX_FMUL2_FM2CTRL_FMUL2_DIS); - - udelay(WOV_FMUL2_CLK_TUNING_DELAY_TIME); - - } - } else - SET_BIT(NPCX_FMUL2_FM2CTRL, NPCX_FMUL2_FM2CTRL_FMUL2_DIS); -} - -#define WOV_FMUL2_MAX_RETRIES 0x000FFFFF - -/* FMUL2 clock multipliers values. */ -struct wov_fmul2_multiplier_setting_val { - uint8_t fm2mh; - uint8_t fm2ml; - uint8_t fm2n; -}; - -/** - * Configure FMUL2 clock tunning. - * - * @param None - * @return None - */ -void wov_fmul2_conf_tuning(void) -{ - /* Check if FMUL2 is enabled, then do nothing. */ - if (IS_BIT_SET(NPCX_FMUL2_FM2CTRL, NPCX_FMUL2_FM2CTRL_FMUL2_DIS) == - 0x00) - return; - - /* Enable clock tuning. */ - CLEAR_BIT(NPCX_FMUL2_FM2CTRL, NPCX_FMUL2_FM2CTRL_TUNE_DIS); - - udelay(WOV_FMUL2_CLK_TUNING_DELAY_TIME); - - /* Disable clock tuning. */ - SET_BIT(NPCX_FMUL2_FM2CTRL, NPCX_FMUL2_FM2CTRL_TUNE_DIS); -} - -static int wov_get_cfifo_threshold_l(void) -{ - int fifo_threshold; - - fifo_threshold = WOV_GET_FIFO_INT_THRESHOLD; - - if (fifo_threshold == 0) - return 1; - else - return (fifo_threshold * 2); -} - -/** - * Gets clock source FMUL2 or PLL. - * - * @param None. - * - * NOTE: - * - * @return The clock source FMUL2 (WOV_FMUL2_CLK_SRC) and - * PLL (WOV_PLL_CLK_SRC) - */ -static enum wov_clk_src_sel wov_get_clk_selection(void) -{ - if (IS_BIT_SET(NPCX_WOV_CLOCK_CNTL, NPCX_WOV_CLOCK_CNT_CLK_SEL)) - return WOV_PLL_CLK_SRC; - else - return WOV_FMUL2_CLK_SRC; -} - -/*************************************************************************** - * - * Exported function. - * - **************************************************************************/ - -/** - * Set FMUL2 clock divider. - * - * @param None - * @return None - */ -void wov_fmul2_set_clk_divider(enum fmul2_clk_divider clk_div) -{ - SET_FIELD(NPCX_FMUL2_FM2P, NPCX_FMUL2_FM2P_WFPRED, clk_div); -} - -/** - * Configure DMIC clock. - * - * @param enable - DMIC enabled , 1 means enable - * @param clk_div - DMIC clock division factor (disable, divide by 2 - * divide by 4) - * @return None - */ -void wov_dmic_clk_config(int enable, enum wov_dmic_clk_div_sel clk_div) -{ - /* If DMIC enabled then configured its clock.*/ - if (enable) { - if (clk_div != WOV_DMIC_DIV_DISABLE) { - SET_BIT(NPCX_WOV_CLOCK_CNTL, - NPCX_WOV_CLOCK_CNT_DMIC_CKDIV_EN); - if (clk_div == WOV_DMIC_DIV_BY_2) - CLEAR_BIT(NPCX_WOV_CLOCK_CNTL, - NPCX_WOV_CLOCK_CNT_DMIC_CKDIV_SEL); - else - SET_BIT(NPCX_WOV_CLOCK_CNTL, - NPCX_WOV_CLOCK_CNT_DMIC_CKDIV_SEL); - } else - CLEAR_BIT(NPCX_WOV_CLOCK_CNTL, - NPCX_WOV_CLOCK_CNT_DMIC_CKDIV_EN); - - SET_BIT(NPCX_WOV_CLOCK_CNTL, NPCX_WOV_CLOCK_CNT_DMIC_EN); - } else - CLEAR_BIT(NPCX_WOV_CLOCK_CNTL, NPCX_WOV_CLOCK_CNT_DMIC_EN); -} - -/** - * Sets WoV mode - * - * @param wov_mode - WoV mode - * @return EC_ERROR_INVAL or EC_SUCCESS - */ -enum ec_error_list wov_set_mode(enum wov_modes wov_mode) -{ - enum ec_error_list ret_code; - enum wov_clk_src_sel prev_clock; - - /* If mode is OFF, then power down and exit. */ - if (wov_mode == WOV_MODE_OFF) { - wov_stop_i2s_capture(); - wov_stop_ram_capture(); - wov_set_clk_selection(WOV_FMUL2_CLK_SRC); - wov_dmic_clk_config(0, WOV_DMIC_DIV_DISABLE); - wov_mute(1); - apm_set_mode(WOV_MODE_OFF); - wov_fmul2_enable(0); - wov_conf.mode = WOV_MODE_OFF; - return EC_SUCCESS; - } - - switch (wov_mode) { - case WOV_MODE_VAD: - if (apm_get_vad_dmic_rate() == APM_DMIC_RATE_0_75) - wov_dmic_clk_config(1, WOV_DMIC_DIV_BY_4); - else if (apm_get_vad_dmic_rate() == APM_DMIC_RATE_1_2) - wov_dmic_clk_config(1, WOV_DMIC_DIV_BY_2); - else - wov_dmic_clk_config(1, WOV_DMIC_DIV_DISABLE); - wov_stop_i2s_capture(); - wov_stop_ram_capture(); - wov_set_clk_selection(WOV_FMUL2_CLK_SRC); - apm_set_mode(wov_mode); - ret_code = wov_set_mic_source_l(); - if (ret_code != EC_SUCCESS) - return ret_code; - break; - case WOV_MODE_RAM: - if ((wov_conf.bit_depth != 16) && (wov_conf.bit_depth != 24)) - return EC_ERROR_INVAL; - - if (apm_get_adc_ram_dmic_rate() == APM_DMIC_RATE_0_75) - wov_dmic_clk_config(1, WOV_DMIC_DIV_BY_4); - else if (apm_get_adc_ram_dmic_rate() == APM_DMIC_RATE_1_2) - wov_dmic_clk_config(1, WOV_DMIC_DIV_BY_2); - else - wov_dmic_clk_config(1, WOV_DMIC_DIV_DISABLE); - wov_stop_i2s_capture(); - wov_set_clk_selection(WOV_FMUL2_CLK_SRC); - apm_set_mode(wov_mode); - ret_code = wov_set_mic_source_l(); - if (ret_code != EC_SUCCESS) - return ret_code; - wov_start_ram_capture(); - break; - case WOV_MODE_RAM_AND_I2S: - if ((wov_conf.bit_depth != 16) && (wov_conf.bit_depth != 24)) - return EC_ERROR_INVAL; - case WOV_MODE_I2S: - if (apm_get_adc_i2s_dmic_rate() == APM_DMIC_RATE_0_75) - wov_dmic_clk_config(1, WOV_DMIC_DIV_BY_4); - else if (apm_get_adc_i2s_dmic_rate() == APM_DMIC_RATE_1_2) - wov_dmic_clk_config(1, WOV_DMIC_DIV_BY_2); - else - wov_dmic_clk_config(1, WOV_DMIC_DIV_DISABLE); - prev_clock = wov_get_clk_selection(); - if (prev_clock != WOV_PLL_CLK_SRC) { - wov_set_i2s_config_l(); - wov_set_clk_selection(WOV_PLL_CLK_SRC); - } - apm_set_mode(wov_mode); - ret_code = wov_set_mic_source_l(); - if (ret_code != EC_SUCCESS) - return ret_code; - wov_start_i2s_capture(); - if (wov_mode == WOV_MODE_RAM_AND_I2S) - wov_start_ram_capture(); - else - wov_stop_ram_capture(); - break; - default: - wov_dmic_clk_config(0, WOV_DMIC_DIV_DISABLE); - wov_fmul2_enable(0); - wov_mute(1); - return EC_ERROR_INVAL; - } - - wov_mute(0); - - wov_conf.mode = wov_mode; - - return EC_SUCCESS; -} - -/** - * Gets WoV mode - * - * @param None - * @return WoV mode - */ -enum wov_modes wov_get_mode(void) -{ - return wov_conf.mode; -} - -/** - * Initiates WoV. - * - * @param callback - Pointer to callback function. - * - * @return None - */ -void wov_init(void) -{ - apm_init(); - - wov_apm_active(1); - wov_mute(1); - - wov_conf.mode = WOV_MODE_OFF; - wov_conf.sample_per_sec = 16000; - wov_conf.bit_depth = 16; - wov_conf.mic_src = WOV_SRC_LEFT; - wov_conf.left_chan_gain = 0; - wov_conf.right_chan_gain = 0; - wov_conf.i2s_start_delay_0 = 0; - wov_conf.i2s_start_delay_1 = 0; - wov_conf.i2s_clock = 0; - wov_conf.dai_format = WOV_DAI_FMT_I2S; - wov_conf.sensitivity_db = 5; - - /* Set DMIC clock signal output to use fast transitions. */ - SET_BIT(NPCX_DEVALT(0xE), NPCX_DEVALTE_DMCLK_FAST); - - callback_fun = wov_handle_event; - - wov_cfifo_config(WOV_CFIFO_IN_LEFT_CHAN_2_CONS_16_BITS, - WOV_FIFO_THRESHOLD_80_DATA_WORDS); - - apm_set_vad_dmic_rate(APM_DMIC_RATE_0_75); - apm_set_adc_ram_dmic_config(APM_DMIC_RATE_0_75); - apm_set_adc_i2s_dmic_config(APM_DMIC_RATE_3_0); -} - -/** - * Select clock source FMUL2 or PLL. - * - * @param clk_src - select between FMUL2 (WOV_FMUL2_CLK_SRC) and - * PLL (WOV_PLL_CLK_SRC) - * - * NOTE: THIS FUNCTION RESETS THE APM and RETURN ITS REGISSTERS TO THEIR - * DEFAULT VALUES !!!!!!! - * - * @return None - */ -void wov_set_clk_selection(enum wov_clk_src_sel clk_src) -{ - int is_apm_disable; - - /* - * Be sure that both clocks are active, as both of them need to - * be active when modify the CLK_SEL bit. - */ - if (IS_BIT_SET(NPCX_WOV_PLL_CNTL1, NPCX_WOV_PLL_CNTL1_PLL_PWDEN)) - wov_pll_enable(1); - - if (IS_BIT_SET(NPCX_FMUL2_FM2CTRL, NPCX_FMUL2_FM2CTRL_FMUL2_DIS)) - wov_fmul2_enable(1); - - is_apm_disable = IS_BIT_SET(NPCX_APM_CR_APM, NPCX_APM_CR_APM_PD); - - apm_enable(0); - - if (clk_src == WOV_FMUL2_CLK_SRC) - CLEAR_BIT(NPCX_WOV_CLOCK_CNTL, NPCX_WOV_CLOCK_CNT_CLK_SEL); - else if (wov_wait_for_pll_lock_l() == EC_SUCCESS) - SET_BIT(NPCX_WOV_CLOCK_CNTL, NPCX_WOV_CLOCK_CNT_CLK_SEL); - - udelay(100); - - if (!is_apm_disable) - apm_enable(1); - - /* Disable the unneeded clock. */ - if (clk_src == WOV_PLL_CLK_SRC) - wov_fmul2_enable(0); - else - wov_pll_enable(0); - -} - -/** - * Configure PLL clock. - * - * @param ext_div_sel - PLL external divider selector. - * @param div_factor - When ext_div_sel is WOV_PLL_EXT_DIV_BIN_CNT - * then it is the 4 LSBits of this field, - * otherwise this field is an index to - * PLL External Divider Load Values table. - * @return EC_ERROR_INVAL or EC_SUCCESS - */ -enum ec_error_list wov_pll_clk_ext_div_config( - enum wov_pll_ext_div_sel ext_div_sel, - uint32_t div_factor) -{ - /* Sets the clock division factor for the PLL external divider. - * The divide factor should be in the range of 2 to 67. - * When ext_div_sel is WOV_PLL_EXT_DIV_BIN_CNT, then the 4 least - * significant bits of div_factor are used to set the divide - * ratio. - * In this case the divide ration legal values are from 2 to 15 - * For WOV_PLL_EXT_DIV_LFSR, this parameter is used as index for - * pll_ext_div table. - */ - if (ext_div_sel == WOV_PLL_EXT_DIV_BIN_CNT) - CLEAR_BIT(NPCX_WOV_CLOCK_CNTL, NPCX_WOV_CLOCK_CNT_PLL_EDIV_SEL); - else - SET_BIT(NPCX_WOV_CLOCK_CNTL, NPCX_WOV_CLOCK_CNT_PLL_EDIV_SEL); - - if (ext_div_sel == WOV_PLL_EXT_DIV_BIN_CNT) { - if ((div_factor > 15) || (div_factor < 2)) - return EC_ERROR_INVAL; - - SET_FIELD(NPCX_WOV_CLOCK_CNTL, NPCX_WOV_CLOCK_CNT_PLL_EDIV, - (div_factor)); - } else { - if ((div_factor > 67) || (div_factor < 12)) - return EC_ERROR_INVAL; - - SET_FIELD(NPCX_WOV_CLOCK_CNTL, NPCX_WOV_CLOCK_CNT_PLL_EDIV, - pll_ext_div[div_factor - 12].pll_ediv); - - SET_FIELD(NPCX_WOV_CLOCK_CNTL, NPCX_WOV_CLOCK_CNT_PLL_EDIV_DC, - pll_ext_div[div_factor - 12].pll_ediv_dc); - } - - return EC_SUCCESS; -} - -/** - * PLL power down. - * - * @param enable - 1 enable the PLL or 0 PLL disable - * @return None - */ -void wov_pll_enable(int enable) -{ - if (enable) - CLEAR_BIT(NPCX_WOV_PLL_CNTL1, NPCX_WOV_PLL_CNTL1_PLL_PWDEN); - else - SET_BIT(NPCX_WOV_PLL_CNTL1, NPCX_WOV_PLL_CNTL1_PLL_PWDEN); - - udelay(100); -} - -/** - * Configures PLL clock dividers.. - * - * @param out_div_1 - PLL output divider #1, valid values 1-7 - * @param out_div_2 - PLL output divider #2, valid values 1-7 - * @param feedback_div - PLL feadback divider (Default is 375 decimal) - * @param in_div - PLL input divider - * @return EC_ERROR_INVAL or EC_SUCCESS - */ -enum ec_error_list wov_pll_clk_div_config(uint32_t out_div_1, - uint32_t out_div_2, - uint32_t feedback_div, - uint32_t in_div) -{ - /* Parameter check. */ - if ((out_div_1 < 1) || (out_div_1 > 7) || - (out_div_2 < 1) || (out_div_2 > 7)) - return EC_ERROR_INVAL; - - /* - * PLL configuration sequence: - * 1. Set PLL_PWDEN bit to 1. - * 2. Set PLL divider values. - * 3. Wait 1usec. - * 4. Clear PLL_PWDEN bit to 0 while not changing other PLL parameters. - */ - SET_BIT(NPCX_WOV_PLL_CNTL1, NPCX_WOV_PLL_CNTL1_PLL_PWDEN); - - SET_FIELD(NPCX_WOV_PLL_CNTL1, NPCX_WOV_PLL_CNTL1_PLL_OTDV1, out_div_1); - SET_FIELD(NPCX_WOV_PLL_CNTL1, NPCX_WOV_PLL_CNTL1_PLL_OTDV2, out_div_2); - - SET_FIELD(NPCX_WOV_PLL_CNTL2, NPCX_WOV_PLL_CNTL2_PLL_FBDV, - feedback_div); - - SET_FIELD(NPCX_WOV_PLL_CNTL2, NPCX_WOV_PLL_CNTL2_PLL_INDV, in_div); - - udelay(100); - - CLEAR_BIT(NPCX_WOV_PLL_CNTL1, NPCX_WOV_PLL_CNTL1_PLL_PWDEN); - - udelay(100); - - return EC_SUCCESS; -} - -/** - * Enables/Disables WoV interrupt. - * - * @param int_index - Interrupt ID. - * @param enable - enabled flag, 1 means enable - * - * @return None. - */ -void wov_interrupt_enable(enum wov_interrupt_index int_index, int enable) -{ - if (enable) - SET_BIT(NPCX_WOV_WOV_INTEN, wov_interupts[int_index]); - else - CLEAR_BIT(NPCX_WOV_WOV_INTEN, wov_interupts[int_index]); -} - -/** - * Sets core FIFO threshold. - * - * @param in_sel - Core FIFO input select - * @param threshold - Core FIFO threshold - * - * @return None - */ -void wov_cfifo_config(enum wov_core_fifo_in_sel in_sel, - enum wov_fifo_threshold threshold) -{ - /* Set core FIFO input selection. */ - SET_FIELD(NPCX_WOV_FIFO_CNT, NPCX_WOV_FIFO_CNT_CFIFO_ISEL, in_sel); - - /* Set wake & interrupt core FIFO threshold. */ - WOV_SET_FIFO_WAKE_THRESHOLD(threshold); - WOV_SET_FIFO_INT_THRESHOLD(threshold); -} - -/** - * Start the actual capturing of the Voice data to the RAM. - * Note that the pointer to the RAM buffer must be precisely - * set by calling wov_set_buffer(); - * - * @param None - * - * @return None - */ -void wov_start_ram_capture(void) -{ - /* Clear the CFIFO status bits in WoV status register. */ - SET_FIELD(NPCX_WOV_STATUS, NPCX_WOV_STATUS_BITS, 0x27); - - CLEAR_BIT(NPCX_WOV_FIFO_CNT, NPCX_WOV_FIFO_CNT_CORE_FFRST); - - wov_interrupt_enable(WOV_CFIFO_OVERRUN_INT_INDX, 1); - wov_interrupt_enable(WOV_CFIFO_THRESHOLD_INT_INDX, 1); - wov_interrupt_enable(WOV_CFIFO_THRESHOLD_WAKE_INDX, 1); -} - -/** - * Stop the capturing of the Voice data to the RAM. - * - * @param none - * - * @return None - */ -void wov_stop_ram_capture(void) -{ - SET_BIT(NPCX_WOV_FIFO_CNT, NPCX_WOV_FIFO_CNT_CORE_FFRST); - - wov_interrupt_enable(WOV_CFIFO_OVERRUN_INT_INDX, 0); - wov_interrupt_enable(WOV_CFIFO_THRESHOLD_INT_INDX, 0); - wov_interrupt_enable(WOV_CFIFO_THRESHOLD_WAKE_INDX, 0); - - udelay(100); -} - -/** - * Rests the Core FIFO. - * - * @param None - * - * @return None - */ -void wov_core_fifo_reset(void) -{ - SET_BIT(NPCX_WOV_FIFO_CNT, NPCX_WOV_FIFO_CNT_CORE_FFRST); - - udelay(1000); - - /* Clear the CFIFO status bits in WoV status register. */ - SET_FIELD(NPCX_WOV_STATUS, NPCX_WOV_STATUS_BITS, 0x27); - - CLEAR_BIT(NPCX_WOV_FIFO_CNT, NPCX_WOV_FIFO_CNT_CORE_FFRST); -} - -/** - * Rests the I2S FIFO. - * - * @param None - * - * @return None - */ -void wov_i2s_fifo_reset(void) -{ - int disable; - - disable = IS_BIT_SET(NPCX_WOV_FIFO_CNT, NPCX_WOV_FIFO_CNT_I2S_FFRST); - - SET_BIT(NPCX_WOV_FIFO_CNT, NPCX_WOV_FIFO_CNT_I2S_FFRST); - - udelay(1000); - - /* Clear the I2S status bits in WoV status register. */ - SET_FIELD(NPCX_WOV_STATUS, NPCX_WOV_STATUS_BITS, 0x18); - - if (!disable) - CLEAR_BIT(NPCX_WOV_FIFO_CNT, NPCX_WOV_FIFO_CNT_I2S_FFRST); -} - -/** - * Start the capturing of the Voice data via I2S. - * - * @param None - * - * @return None - */ -void wov_start_i2s_capture(void) -{ - /* Clear counters used to track for underrun/overrun errors */ - irq_underrun_count = 0; - irq_overrun_count = 0; - - /* Clear the I2S status bits in WoV status register. */ - SET_FIELD(NPCX_WOV_STATUS, NPCX_WOV_STATUS_BITS, 0x18); - - CLEAR_BIT(NPCX_WOV_FIFO_CNT, NPCX_WOV_FIFO_CNT_I2S_FFRST); - - wov_interrupt_enable(WOV_I2SFIFO_OVERRUN_INT_INDX, 1); - wov_interrupt_enable(WOV_I2SFIFO_UNDERRUN_INT_INDX, 1); -} - -/** - * Stop the capturing of the Voice data via I2S. - * - * @param none - * - * @return None - */ -void wov_stop_i2s_capture(void) -{ - SET_BIT(NPCX_WOV_FIFO_CNT, NPCX_WOV_FIFO_CNT_I2S_FFRST); - - wov_interrupt_enable(WOV_I2SFIFO_OVERRUN_INT_INDX, 0); - wov_interrupt_enable(WOV_I2SFIFO_UNDERRUN_INT_INDX, 0); - - udelay(100); -} - -/** - * Sets data buffer for reading from core FIFO - * - * @param buff - Pointer to the read buffer, buffer must be 32 bits - * aligned. - * @param size_in_words - Size must be a multiple of CONFIG_WOV_THRESHOLD_WORDS - * (defaulte = 80 words) - * - * @return None - * - * Note - When the data buffer will be full the FW will be notifyed - * about it, and the FW will need to recall to this function. - */ -int wov_set_buffer(uint32_t *buf, int size_in_words) -{ - int cfifo_threshold; - - cfifo_threshold = wov_get_cfifo_threshold_l(); - if (size_in_words != - ((size_in_words / cfifo_threshold) * cfifo_threshold)) - return EC_ERROR_INVAL; - - cfifo_buf.buf = buf; - cfifo_buf.size = size_in_words; - - return EC_SUCCESS; -} - -/** - * Resets the APM. - * - * @param enable - enabled flag, 1 means enable - * @return None - */ -void wov_apm_active(int enable) -{ - /* For APM it is negativ logic. */ - if (enable) - CLEAR_BIT(NPCX_WOV_APM_CTRL, NPCX_WOV_APM_CTRL_APM_RST); - else - SET_BIT(NPCX_WOV_APM_CTRL, NPCX_WOV_APM_CTRL_APM_RST); -} - -/** - * I2S golobal configuration - * - * @param i2s_hiz_data - Defines when the I2S data output is floating. - * @param i2s_hiz - Defines if the I2S data output is always floating. - * @param clk_invert - Defines the I2S bit clock edge sensitivity - * @param out_pull_en - Enable a pull-up or a pull-down resistor on - * I2S output - * @param out_pull_mode - Select a pull-up or a pull-down resistor on - * I2S output - * @param in_pull_en - Enable a pull-up or a pull-down resistor on - * I2S input - * @param in_pull_mode - Select a pull-up or a pull-down resistor on - * I2S intput - * @param test_mode - Selects I2S test mode - * - * @return EC_ERROR_INVAL or EC_SUCCESS - */ -enum ec_error_list wov_i2s_global_config( - enum wov_floating_mode i2s_hiz_data, - enum wov_floating_mode i2s_hiz, - enum wov_clk_inverted_mode clk_invert, - int out_pull_en, - enum wov_pull_upd_down_sel out_pull_mode, - int in_pull_en, - enum wov_pull_upd_down_sel in_pull_mode, - enum wov_test_mode test_mode) -{ - /* Check the parameters correctness. */ - if ((i2s_hiz_data == WOV_FLOATING) && - ((GET_FIELD(NPCX_WOV_I2S_CNTL(0), - NPCX_WOV_I2S_CNTL_I2S_ST_DEL) == 0) || - (GET_FIELD(NPCX_WOV_I2S_CNTL(1), - NPCX_WOV_I2S_CNTL_I2S_ST_DEL) == 0))) - return EC_ERROR_INVAL; - - /* Set the parameters. */ - if (i2s_hiz_data == WOV_FLOATING_DRIVEN) - CLEAR_BIT(NPCX_WOV_I2S_CNTL(0), NPCX_WOV_I2S_CNTL0_I2S_HIZD); - else - SET_BIT(NPCX_WOV_I2S_CNTL(0), NPCX_WOV_I2S_CNTL0_I2S_HIZD); - - if (i2s_hiz == WOV_FLOATING_DRIVEN) - CLEAR_BIT(NPCX_WOV_I2S_CNTL(0), NPCX_WOV_I2S_CNTL0_I2S_HIZ); - else - SET_BIT(NPCX_WOV_I2S_CNTL(0), NPCX_WOV_I2S_CNTL0_I2S_HIZ); - - if (clk_invert == WOV_CLK_NORMAL) - CLEAR_BIT(NPCX_WOV_I2S_CNTL(0), - NPCX_WOV_I2S_CNTL0_I2S_SCLK_INV); - else - SET_BIT(NPCX_WOV_I2S_CNTL(0), NPCX_WOV_I2S_CNTL0_I2S_SCLK_INV); - - if (out_pull_en) - SET_BIT(NPCX_WOV_I2S_CNTL(0), NPCX_WOV_I2S_CNTL0_I2S_OPE); - else - CLEAR_BIT(NPCX_WOV_I2S_CNTL(0), NPCX_WOV_I2S_CNTL0_I2S_OPE); - - if (out_pull_mode == WOV_PULL_DOWN) - CLEAR_BIT(NPCX_WOV_I2S_CNTL(0), NPCX_WOV_I2S_CNTL0_I2S_OPS); - else - SET_BIT(NPCX_WOV_I2S_CNTL(0), NPCX_WOV_I2S_CNTL0_I2S_OPS); - - if (in_pull_en) - SET_BIT(NPCX_WOV_I2S_CNTL(0), NPCX_WOV_I2S_CNTL0_I2S_IPE); - else - CLEAR_BIT(NPCX_WOV_I2S_CNTL(0), NPCX_WOV_I2S_CNTL0_I2S_IPE); - - if (in_pull_mode == WOV_PULL_DOWN) - CLEAR_BIT(NPCX_WOV_I2S_CNTL(0), NPCX_WOV_I2S_CNTL0_I2S_IPS); - else - SET_BIT(NPCX_WOV_I2S_CNTL(0), NPCX_WOV_I2S_CNTL0_I2S_IPS); - - if (test_mode == WOV_NORMAL_MODE) - CLEAR_BIT(NPCX_WOV_I2S_CNTL(0), NPCX_WOV_I2S_CNTL0_I2S_TST); - else - SET_BIT(NPCX_WOV_I2S_CNTL(0), NPCX_WOV_I2S_CNTL0_I2S_TST); - - /* I2S should be reset in order I2S interface to function correctly. */ - wov_i2s_fifo_reset(); - - return EC_SUCCESS; -} - -/** - * I2S channel configuration - * - * @param channel_num - I2S channel number, 0 or 1. - * @param bit_count - I2S channel bit count. - * @param trigger - Define the I2S chanel trigger 1->0 or 0->1 - * @param start_delay - Defines the delay from the trigger defined for - * the channel till the first bit (MSB) of the data. - * - * @return EC_ERROR_INVAL or EC_SUCCESS - */ -enum ec_error_list wov_i2s_channel_config(uint32_t channel_num, - uint32_t bit_count, - enum wov_i2s_chan_trigger trigger, - int32_t start_delay) -{ - /* Check the parameters correctnes. */ - if ((channel_num != 0) && (channel_num != 1)) - return EC_ERROR_INVAL; - - if ((start_delay < 0) || (start_delay > 496)) - return EC_ERROR_INVAL; - - if ((bit_count != 16) && (bit_count != 18) && (bit_count != 20) && - (bit_count != 24)) - return EC_ERROR_INVAL; - - /* Set the parameters. */ - SET_FIELD(NPCX_WOV_I2S_CNTL(channel_num), NPCX_WOV_I2S_CNTL_I2S_BCNT, - (bit_count - 1)); - - if (trigger == WOV_I2S_SAMPLED_1_AFTER_0) - CLEAR_BIT(NPCX_WOV_I2S_CNTL(channel_num), - NPCX_WOV_I2S_CNTL_I2S_TRIG); - else - SET_BIT(NPCX_WOV_I2S_CNTL(channel_num), - NPCX_WOV_I2S_CNTL_I2S_TRIG); - - SET_FIELD(NPCX_WOV_I2S_CNTL(channel_num), NPCX_WOV_I2S_CNTL_I2S_ST_DEL, - start_delay); - - /* I2S should be reset in order I2S interface to function correctly. */ - wov_i2s_fifo_reset(); - - return EC_SUCCESS; -} - -/** - * Sets sampling rate. - * - * @param samples_per_second - Valid sample rate. - * @return In case sample rate is valid return EC_SUCCESS othewise return - * error code. - */ -int wov_set_sample_rate(uint32_t samples_per_second) -{ - if (wov_conf.mode != WOV_MODE_OFF) - return EC_ERROR_INVALID_CONFIG; - - switch (samples_per_second) { - case 8000: - case 12000: - case 16000: - case 24000: - case 32000: - case 48000: - wov_conf.sample_per_sec = samples_per_second; - return EC_SUCCESS; - default: - return EC_ERROR_INVAL; - } -} - -/** - * Gets sampling rate. - * - * @param None - * @return the current sampling rate. - */ -uint32_t wov_get_sample_rate(void) -{ - return wov_conf.sample_per_sec; -} - -/** - * Sets sampling depth. - * - * @param bits_num - Valid sample depth in bits. - * @return In case sample depth is valid return EC_SUCCESS othewise return - * error code. - */ -int wov_set_sample_depth(int bits_num) -{ - if (wov_conf.mode != WOV_MODE_OFF) - return EC_ERROR_INVALID_CONFIG; - - if ((bits_num != 16) && (bits_num != 18) && - (bits_num != 20) && (bits_num != 24)) - return EC_ERROR_INVAL; - - wov_conf.bit_depth = bits_num; - - return EC_SUCCESS; -} - -/** - * Gets sampling depth. - * - * @param None. - * @return sample depth in bits. - */ -int wov_get_sample_depth(void) -{ - return wov_conf.bit_depth; -} - -/** - * Sets microphone source. - * - * @param mic_src - Valid microphone source - * @return return EC_SUCCESS if mic source valid othewise return error code. - */ -int wov_set_mic_source(enum wov_mic_source mic_src) -{ - wov_conf.mic_src = mic_src; - - return wov_set_mic_source_l(); -} - -/** - * Gets microphone source. - * - * @param None. - * @return sample depth in bits. - */ -enum wov_mic_source wov_get_mic_source(void) -{ - return wov_conf.mic_src; -} - -/** - * Mutes the WoV. - * - * @param enable - enabled flag, 1 means enable - * @return None - */ -void wov_mute(int enable) -{ - if (enable) - SET_BIT(NPCX_APM_CR_ADC, NPCX_APM_CR_ADC_ADC_SOFT_MUTE); - else - CLEAR_BIT(NPCX_APM_CR_ADC, NPCX_APM_CR_ADC_ADC_SOFT_MUTE); -} - -/** - * Sets gain - * - * @param left_chan_gain - Left channel gain. - * @param right_chan_gain - Right channel gain - * @return None - */ -void wov_set_gain(int left_chan_gain, int right_chan_gain) -{ - wov_conf.left_chan_gain = left_chan_gain; - wov_conf.right_chan_gain = right_chan_gain; - - (void) apm_adc_gain_config(APM_ADC_CHAN_GAINS_INDEPENDENT, - left_chan_gain, right_chan_gain); -} - -/** - * Gets gain values - * - * @param left_chan_gain - address of left channel gain response. - * @param right_chan_gain - address of right channel gain response. - * @return None - */ -void wov_get_gain(int *left_chan_gain, int *right_chan_gain) -{ - *left_chan_gain = wov_conf.left_chan_gain; - *right_chan_gain = wov_conf.right_chan_gain; -} - -/** - * Enables/Disables ADC. - * - * @param enable - enabled flag, 1 means enable - * @return None - */ -void wov_enable_agc(int enable) -{ - apm_auto_gain_cntrl_enable(enable); -} - -/** - * Enables/Disables the automatic gain. - * - * @param stereo - Stereo enabled flag, 1 means enable. - * @param target - Target output level of the ADC. - * @param noise_gate_threshold - Noise Gate system select. 1 means enable. - * @param hold_time - Hold time before starting AGC adjustment to - * the TARGET value. - * @param attack_time - Attack time - gain ramp down. - * @param decay_time - Decay time - gain ramp up. - * @param max_applied_gain - Maximum Gain Value to apply to the ADC path. - * @param min_applied_gain - Minimum Gain Value to apply to the ADC path. - * @return EC_ERROR_INVAL or EC_SUCCESS - */ -enum ec_error_list wov_set_agc_config(int stereo, float target, - int noise_gate_threshold, uint8_t hold_time, - uint16_t attack_time, uint16_t decay_time, - float max_applied_gain, float min_applied_gain) -{ - int target_code; - int ngth_code; - int attack_time_code; - int decay_time_code; - int max_applied_gain_code; - int min_applied_gain_code; - enum ec_error_list ret_code; - struct apm_auto_gain_config gain_cfg; - - for (target_code = 0; target_code < 16; target_code++) { - if (((float)target_code * (-1.5)) == target) - break; - } - if (target_code == 16) - return EC_ERROR_INVAL; - - if (noise_gate_threshold == 0) - ngth_code = 0; - else { - for (ngth_code = 0; ngth_code <= 0x07; ngth_code++) { - if ((-68 + ngth_code * 6) == noise_gate_threshold) - break; - } - if (ngth_code * 6 > 42) - return EC_ERROR_INVAL; - } - - if (hold_time > 15) - return EC_ERROR_INVAL; - - for (attack_time_code = 0; attack_time_code <= 0x0F; - attack_time_code++) { - if (((attack_time_code + 1) * 32) == attack_time) - break; - } - if (attack_time_code > 0x0F) - return EC_ERROR_INVAL; - - for (decay_time_code = 0; decay_time_code <= 0x0F; decay_time_code++) { - if (((decay_time_code + 1) * 32) == decay_time) - break; - } - if (decay_time_code > 0x0F) - return EC_ERROR_INVAL; - - for (max_applied_gain_code = 0; max_applied_gain_code < 16; - max_applied_gain_code++) { - if ((max_applied_gain_code * 1.5) == max_applied_gain) - break; - } - if (max_applied_gain_code == 16) { - for (max_applied_gain_code = 18; max_applied_gain_code < 32; - max_applied_gain_code++) { - if (((max_applied_gain_code * 1.5) - 4) == - max_applied_gain) - break; - } - } - if (max_applied_gain_code >= 32) - return EC_ERROR_INVAL; - - for (min_applied_gain_code = 0; min_applied_gain_code < 16; - min_applied_gain_code++) { - if ((min_applied_gain_code * 1.5) == min_applied_gain) - break; - } - if (min_applied_gain_code == 16) { - for (min_applied_gain_code = 18; min_applied_gain_code < 32; - min_applied_gain_code++) { - if (((min_applied_gain_code * 1.5) - 4) == - min_applied_gain) - break; - } - } - if (min_applied_gain_code > 32) - return EC_ERROR_INVAL; - - gain_cfg.stereo_enable = stereo, - gain_cfg.agc_target = (enum apm_adc_target_out_level) target_code; - gain_cfg.nois_gate_en = (noise_gate_threshold != 0); - gain_cfg.nois_gate_thold = (enum apm_noise_gate_threshold) ngth_code; - gain_cfg.hold_time = (enum apm_agc_adj_hold_time) hold_time; - gain_cfg.attack_time = (enum apm_gain_ramp_time) attack_time_code; - gain_cfg.decay_time = (enum apm_gain_ramp_time) decay_time_code; - gain_cfg.gain_max = (enum apm_gain_values) max_applied_gain_code; - gain_cfg.gain_min = (enum apm_gain_values) min_applied_gain_code; - - ret_code = apm_adc_auto_gain_config(&gain_cfg); - - return ret_code; -} - -/** - * Sets VAD sensitivity. - * - * @param sensitivity_db - VAD sensitivity in db. - * @return None - */ -int wov_set_vad_sensitivity(int sensitivity_db) -{ - - if ((sensitivity_db < 0) || (sensitivity_db > 31)) - return EC_ERROR_INVAL; - - wov_conf.sensitivity_db = sensitivity_db; - - apm_set_vad_sensitivity(sensitivity_db); - - return EC_SUCCESS; -} - -/** - * Gets VAD sensitivity. - * - * @param None. - * @return VAD sensitivity in db - */ -int wov_get_vad_sensitivity(void) -{ - return wov_conf.sensitivity_db; -} - -/** - * Configure I2S bus format. (Sample rate and size are determined via common - * config functions.) - * - * @param format - one of the following: I2S mode, Right Justified mode, - * Left Justified mode, PCM A Audio, PCM B Audio and - * Time Division Multiplexing - * @return EC error code. - */ -void wov_set_i2s_fmt(enum wov_dai_format format) -{ - if (wov_conf.mode != WOV_MODE_OFF) - return; - - wov_conf.dai_format = format; -} - -/** - * Configure I2S bus clock. (Sample rate and size are determined via common - * config functions.) - * - * @param i2s_clock - I2S clock frequency in Hz (needed in order to - * configure the internal PLL for 12MHz) - * @return EC error code. - */ -void wov_set_i2s_bclk(uint32_t i2s_clock) -{ - if (wov_conf.mode != WOV_MODE_OFF) - return; - - wov_conf.i2s_clock = i2s_clock; -} - -/** - * Configure I2S bus. (Sample rate and size are determined via common - * config functions.) - * - * @param ch0_delay - 0 to 496. Defines the delay from the SYNC till the - * first bit (MSB) of channel 0 (left channel) - * @param ch1_delay - -1 to 496. Defines the delay from the SYNC till the - * first bit (MSB) of channel 1 (right channel). - * If channel 1 is not used set this field to -1. - * - * @param flags - WOV_TDM_ADJACENT_TO_CH0 = BIT(0). There is a - * channel adjacent to channel 0, so float SDAT when - * driving the last bit (LSB) of the channel during the - * second half of the clock cycle to avoid bus contention. - * - * WOV_TDM_ADJACENT_TO_CH1 = BIT(1). There is a channel - * adjacent to channel 1. - * - * @return EC error code. - */ -enum ec_error_list wov_set_i2s_tdm_config(int ch0_delay, int ch1_delay, - uint32_t flags) -{ - if (wov_conf.mode != WOV_MODE_OFF) - return EC_ERROR_INVALID_CONFIG; - - if ((ch0_delay < 0) || (ch0_delay > 496) || - (ch1_delay < -1) || (ch1_delay > 496)) - return EC_ERROR_INVAL; - - wov_conf.i2s_start_delay_0 = ch0_delay; - wov_conf.i2s_start_delay_1 = ch1_delay; - - SET_FIELD(NPCX_WOV_I2S_CNTL(0), NPCX_WOV_I2S_CNTL_I2S_ST_DEL, - ch0_delay); - - if (ch1_delay == -1) - wov_i2s_channel1_disable(1); - else { - wov_i2s_channel1_disable(0); - SET_FIELD(NPCX_WOV_I2S_CNTL(1), NPCX_WOV_I2S_CNTL_I2S_ST_DEL, - ch1_delay); - } - - if (flags & 0x0001) - SET_BIT(NPCX_WOV_I2S_CNTL(0), NPCX_WOV_I2S_CNTL_I2S_LBHIZ); - else - CLEAR_BIT(NPCX_WOV_I2S_CNTL(0), NPCX_WOV_I2S_CNTL_I2S_LBHIZ); - - if (flags & 0x0002) - SET_BIT(NPCX_WOV_I2S_CNTL(1), NPCX_WOV_I2S_CNTL_I2S_LBHIZ); - else - CLEAR_BIT(NPCX_WOV_I2S_CNTL(1), NPCX_WOV_I2S_CNTL_I2S_LBHIZ); - - /* I2S should be reset in order I2S interface to function correctly. */ - wov_i2s_fifo_reset(); - - return EC_SUCCESS; -} - -static void wov_system_init(void) -{ - /* Set WoV module to be operational. */ - clock_enable_peripheral(CGC_OFFSET_WOV, CGC_WOV_MASK, - CGC_MODE_RUN | CGC_MODE_SLEEP); - /* Configure pins from GPIOs to WOV */ - gpio_config_module(MODULE_WOV, 1); - wov_init(); - - task_enable_irq(NPCX_IRQ_WOV); - - CPRINTS("WoV init done"); -} -DECLARE_HOOK(HOOK_INIT, wov_system_init, HOOK_PRIO_DEFAULT); - -void wov_handle_event(enum wov_events event) -{ - if (event == WOV_EVENT_DATA_READY) { - CPRINTS("ram data ready and stop ram capture"); - /* just capture one times on RAM*/ - wov_stop_ram_capture(); - } - if (event == WOV_EVENT_VAD) - CPRINTS("got vad"); - if (event == WOV_EVENT_ERROR_CORE_FIFO_OVERRUN) - CPRINTS("error: cfifo overrun"); -} - -#ifdef DEBUG_AUDIO_CODEC -static uint32_t voice_buffer[VOICE_BUF_SIZE] = {0}; - -/* voice data 16Khz 2ch 16bit 1s */ -static int command_wov(int argc, char **argv) -{ - static int bit_clk; - static enum wov_dai_format i2s_fmt; - - if (argc == 2) { - if (strcasecmp(argv[1], "init") == 0) { - wov_system_init(); - return EC_SUCCESS; - } - if (strcasecmp(argv[1], "cfgget") == 0) { - CPRINTS("mode:%d", wov_get_mode()); - CPRINTS("sample rate:%d", wov_get_sample_rate()); - CPRINTS("sample bits:%d", wov_get_sample_depth()); - CPRINTS("mic source:%d", wov_get_mic_source()); - CPRINTS("vad sensitivity :%d", - wov_get_vad_sensitivity()); - return EC_SUCCESS; - } - /* Start to capature voice data and store in RAM buffer */ - if (strcasecmp(argv[1], "capram") == 0) { - if (wov_set_buffer((uint32_t *)voice_buffer, - sizeof(voice_buffer) / sizeof(uint32_t)) - == EC_SUCCESS) { - CPRINTS("Start RAM Catpure..."); - wov_start_ram_capture(); - return EC_SUCCESS; - } - CPRINTS("Init fail: voice buffer size"); - return EC_ERROR_INVAL; - } - } else if (argc == 3) { - if (strcasecmp(argv[1], "cfgsrc") == 0) { - if (strcasecmp(argv[2], "mono") == 0) - wov_set_mic_source(WOV_SRC_MONO); - else if (strcasecmp(argv[2], "stereo") == 0) - wov_set_mic_source(WOV_SRC_STEREO); - else if (strcasecmp(argv[2], "left") == 0) - wov_set_mic_source(WOV_SRC_LEFT); - else if (strcasecmp(argv[2], "right") == 0) - wov_set_mic_source(WOV_SRC_RIGHT); - else - return EC_ERROR_INVAL; - - wov_i2s_fifo_reset(); - return EC_SUCCESS; - } - if (strcasecmp(argv[1], "cfgbit") == 0) { - int bits; - - bits = atoi(argv[2]); - if ((bits == 16) || (bits == 18) || (bits == 20) || - (bits == 24)) { - return wov_set_sample_depth(bits); - } - } - if (strcasecmp(argv[1], "cfgsfs") == 0) { - int fs; - - fs = atoi(argv[2]); - return wov_set_sample_rate(fs); - } - if (strcasecmp(argv[1], "cfgbck") == 0) { - int fs; - - fs = wov_get_sample_rate(); - if (strcasecmp(argv[2], "32fs") == 0) - bit_clk = fs * 32; - else if (strcasecmp(argv[2], "48fs") == 0) - bit_clk = fs * 48; - else if (strcasecmp(argv[2], "64fs") == 0) - bit_clk = fs * 64; - else if (strcasecmp(argv[2], "128fs") == 0) - bit_clk = fs * 128; - else if (strcasecmp(argv[2], "256fs") == 0) - bit_clk = fs * 256; - else - return EC_ERROR_INVAL; - - wov_set_i2s_fmt(i2s_fmt); - wov_set_i2s_bclk(bit_clk); - return EC_SUCCESS; - } - if (strcasecmp(argv[1], "cfgfmt") == 0) { - if (strcasecmp(argv[2], "i2s") == 0) - i2s_fmt = WOV_DAI_FMT_I2S; - else if (strcasecmp(argv[2], "right") == 0) - i2s_fmt = WOV_DAI_FMT_RIGHT_J; - else if (strcasecmp(argv[2], "left") == 0) - i2s_fmt = WOV_DAI_FMT_LEFT_J; - else if (strcasecmp(argv[2], "pcma") == 0) - i2s_fmt = WOV_DAI_FMT_PCM_A; - else if (strcasecmp(argv[2], "pcmb") == 0) - i2s_fmt = WOV_DAI_FMT_PCM_B; - else if (strcasecmp(argv[2], "tdm") == 0) - i2s_fmt = WOV_DAI_FMT_PCM_TDM; - else - return EC_ERROR_INVAL; - - wov_set_i2s_fmt(i2s_fmt); - wov_set_i2s_bclk(bit_clk); - return EC_SUCCESS; - } - if (strcasecmp(argv[1], "cfgdckV") == 0) { - if (strcasecmp(argv[2], "1.0") == 0) - apm_set_vad_dmic_rate(APM_DMIC_RATE_1_0); - else if (strcasecmp(argv[2], "1.2") == 0) - apm_set_vad_dmic_rate(APM_DMIC_RATE_1_2); - else if (strcasecmp(argv[2], "2.4") == 0) - apm_set_vad_dmic_rate(APM_DMIC_RATE_2_4); - else if (strcasecmp(argv[2], "3.0") == 0) - apm_set_vad_dmic_rate(APM_DMIC_RATE_3_0); - else if (strcasecmp(argv[2], "0.75") == 0) - apm_set_vad_dmic_rate(APM_DMIC_RATE_0_75); - else - return EC_ERROR_INVAL; - return EC_SUCCESS; - } - if (strcasecmp(argv[1], "cfgdckR") == 0) { - if (strcasecmp(argv[2], "1.0") == 0) - apm_set_adc_ram_dmic_config(APM_DMIC_RATE_1_0); - else if (strcasecmp(argv[2], "1.2") == 0) - apm_set_adc_ram_dmic_config(APM_DMIC_RATE_1_2); - else if (strcasecmp(argv[2], "2.4") == 0) - apm_set_adc_ram_dmic_config(APM_DMIC_RATE_2_4); - else if (strcasecmp(argv[2], "3.0") == 0) - apm_set_adc_ram_dmic_config(APM_DMIC_RATE_3_0); - else if (strcasecmp(argv[2], "0.75") == 0) - apm_set_adc_ram_dmic_config(APM_DMIC_RATE_0_75); - else - return EC_ERROR_INVAL; - return EC_SUCCESS; - } - if (strcasecmp(argv[1], "cfgdckI") == 0) { - if (strcasecmp(argv[2], "1.0") == 0) - apm_set_adc_i2s_dmic_config(APM_DMIC_RATE_1_0); - else if (strcasecmp(argv[2], "1.2") == 0) - apm_set_adc_i2s_dmic_config(APM_DMIC_RATE_1_2); - else if (strcasecmp(argv[2], "2.4") == 0) - apm_set_adc_i2s_dmic_config(APM_DMIC_RATE_2_4); - else if (strcasecmp(argv[2], "3.0") == 0) - apm_set_adc_i2s_dmic_config(APM_DMIC_RATE_3_0); - else if (strcasecmp(argv[2], "0.75") == 0) - apm_set_adc_i2s_dmic_config(APM_DMIC_RATE_0_75); - else - return EC_ERROR_INVAL; - return EC_SUCCESS; - } - - if (strcasecmp(argv[1], "cfgmod") == 0) { - if (strcasecmp(argv[2], "off") == 0) { - wov_set_mode(WOV_MODE_OFF); - wov_stop_ram_capture(); - } else if (strcasecmp(argv[2], "vad") == 0) { - wov_set_mode(WOV_MODE_VAD); - } else if (strcasecmp(argv[2], "ram") == 0) { - if (wov_set_buffer((uint32_t *)voice_buffer, - sizeof(voice_buffer) / sizeof(uint32_t)) - == EC_SUCCESS) - wov_set_mode(WOV_MODE_RAM); - else - return EC_ERROR_INVAL; - } else if (strcasecmp(argv[2], "i2s") == 0) { - wov_set_mode(WOV_MODE_I2S); - } else if (strcasecmp(argv[2], "rami2s") == 0) { - if (wov_set_buffer((uint32_t *)voice_buffer, - sizeof(voice_buffer) / sizeof(uint32_t)) - == EC_SUCCESS) - wov_set_mode(WOV_MODE_RAM_AND_I2S); - else - return EC_ERROR_INVAL; - } else { - return EC_ERROR_INVAL; - } - wov_i2s_fifo_reset(); - return EC_SUCCESS; - } - if (strcasecmp(argv[1], "mute") == 0) { - if (strcasecmp(argv[2], "enable") == 0) { - wov_mute(1); - return EC_SUCCESS; - } - if (strcasecmp(argv[2], "disable") == 0) { - wov_mute(0); - return EC_SUCCESS; - } - } - if (strcasecmp(argv[1], "fmul2") == 0) { - if (strcasecmp(argv[2], "enable") == 0) { - CLEAR_BIT(NPCX_FMUL2_FM2CTRL, - NPCX_FMUL2_FM2CTRL_TUNE_DIS); - return EC_SUCCESS; - } - if (strcasecmp(argv[2], "disable") == 0) { - SET_BIT(NPCX_FMUL2_FM2CTRL, - NPCX_FMUL2_FM2CTRL_TUNE_DIS); - return EC_SUCCESS; - } - } - if (strcasecmp(argv[1], "vadsens") == 0) - return wov_set_vad_sensitivity(atoi(argv[2])); - - if (strcasecmp(argv[1], "gain") == 0) { - wov_set_gain(atoi(argv[2]), atoi(argv[2])); - return EC_SUCCESS; - } - } else if (argc == 5) { - if (strcasecmp(argv[1], "cfgtdm") == 0) { - int delay0, delay1; - uint32_t flags; - - delay0 = atoi(argv[2]); - delay1 = atoi(argv[3]); - flags = atoi(argv[4]); - if ((delay0 > 496) || (delay1 > 496) || (flags > 3) || - (delay0 < 0) || (delay1 < 0)) { - return EC_ERROR_INVAL; - } - wov_set_i2s_tdm_config(delay0, delay1, flags); - return EC_SUCCESS; - } - } - - return EC_ERROR_INVAL; -} - -DECLARE_CONSOLE_COMMAND(wov, command_wov, - "init\n" - "mute <enable|disable>\n" - "capram\n" - "cfgsrc <mono|stereo|left|right>\n" - "cfgbit <16|18|20|24>\n" - "cfgsfs <8000|12000|16000|24000|32000|48000>\n" - "cfgbck <32fs|48fs|64fs|128fs|256fs>\n" - "cfgfmt <i2s|right|left|pcma|pcmb|tdm>\n" - "cfgmod <off|vad|ram|i2s|rami2s>\n" - "cfgtdm [0~496 0~496 0~3]>\n" - "cfgdckV <0.75|1.0|1.2|2.4|3.0>\n" - "cfgdckR <0.75|1.0|1.2|2.4|3.0>\n" - "cfgdckI <0.75|1.0|1.2|2.4|3.0>\n" - "cfgget\n" - "fmul2 <enable|disable>\n" - "vadsens <0~31>\n" - "gain <0~31>", - "wov configuration"); -#endif |