coreboot-libre-fam15h-rdimm/3rdparty/chromeec/chip/npcx/audio_codec.c

166 lines
4.3 KiB
C

/* 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.
*/
/* Audio codec interface for NPCX */
#include "common.h"
#include "console.h"
#include "ec_commands.h"
#include "host_command.h"
#include "wov_chip.h"
#define EC_WOV_I2S_SAMPLE_RATE 48000
typedef enum ec_status (*codec_i2s_func)(struct host_cmd_handler_args *args);
static enum ec_status codec_set_sample_depth(struct host_cmd_handler_args *args)
{
struct ec_param_codec_i2s *param =
(struct ec_param_codec_i2s *)args->params;
/*
* The number of bits comes from the enum ec_sample_depth_value where
* the 1st value is for 16 bits and the 2nd value is for 24 bits.
*/
int bits_num = param->depth == EC_CODEC_SAMPLE_DEPTH_24 ? 24 : 16;
args->response_size = 0;
/* Sample depth can only be changed when mode is WOV_MODE_OFF */
wov_set_mode(WOV_MODE_OFF);
if (wov_set_sample_depth(bits_num))
return EC_RES_ERROR;
return EC_RES_SUCCESS;
}
static enum ec_status codec_set_gain(struct host_cmd_handler_args *args)
{
struct ec_param_codec_i2s *param =
(struct ec_param_codec_i2s *)args->params;
args->response_size = 0;
wov_set_gain(param->gain.left, param->gain.right);
return EC_RES_SUCCESS;
}
static enum ec_status codec_get_gain(struct host_cmd_handler_args *args)
{
struct ec_codec_i2s_gain *resp =
(struct ec_codec_i2s_gain *)args->response;
int left_gain;
int right_gain;
args->response_size = sizeof(struct ec_codec_i2s_gain);
/* Get the gains set in the wov driver */
wov_get_gain(&left_gain, &right_gain);
resp->left = left_gain;
resp->right = right_gain;
return EC_RES_SUCCESS;
}
static enum ec_status codec_i2s_enable(struct host_cmd_handler_args *args)
{
struct ec_param_codec_i2s *param =
(struct ec_param_codec_i2s *)args->params;
int rv;
args->response_size = 0;
if (param->i2s_enable) {
/*
* The mic source and sample rate don't need to be set each time
* an i2s stream is started, but the audio codec does not
* contain a method to select these as they must be the values
* set below for proper i2s operation. Since the default values
* set in wov.c are different than what's required, they are set
* each time an i2s stream is started.
*/
wov_set_mic_source(WOV_SRC_STEREO);
/* Mode must be WOV_MODE_OFF to change sample rate */
wov_set_mode(WOV_MODE_OFF);
wov_set_sample_rate(EC_WOV_I2S_SAMPLE_RATE);
/* Start i2s stream */
rv = wov_set_mode(WOV_MODE_I2S);
} else {
/* Stop i2s stream */
rv = wov_set_mode(WOV_MODE_OFF);
}
return rv ? EC_RES_ERROR : EC_RES_SUCCESS;
}
static enum ec_status codec_i2s_set_fmt(struct host_cmd_handler_args *args)
{
struct ec_param_codec_i2s *param =
(struct ec_param_codec_i2s *)args->params;
args->response_size = 0;
/* To change mode setting it must be set to WOV_MODE_OFF */
wov_set_mode(WOV_MODE_OFF);
wov_set_i2s_fmt(param->i2s_config);
return EC_RES_SUCCESS;
}
static enum ec_status
codec_i2s_set_tdm_config(struct host_cmd_handler_args *args)
{
struct ec_param_codec_i2s *param =
(struct ec_param_codec_i2s *)args->params;
uint32_t flags;
args->response_size = 0;
flags = (!!param->tdm_param.adjacent_to_ch0) |
((!!param->tdm_param.adjacent_to_ch1) << 1);
if (wov_set_i2s_tdm_config(param->tdm_param.ch0_delay,
param->tdm_param.ch1_delay, flags))
return EC_RES_ERROR;
return EC_RES_SUCCESS;
}
static enum ec_status codec_i2s_set_bclk(struct host_cmd_handler_args *args)
{
struct ec_param_codec_i2s *param =
(struct ec_param_codec_i2s *)args->params;
args->response_size = 0;
/* To change bclk setting it must be set to WOV_MODE_OFF */
wov_set_mode(WOV_MODE_OFF);
wov_set_i2s_bclk(param->bclk);
return EC_RES_SUCCESS;
}
static enum ec_status codec_i2s(struct host_cmd_handler_args *args)
{
struct ec_param_codec_i2s *param =
(struct ec_param_codec_i2s *)args->params;
codec_i2s_func codec_i2s_func_tbl[] = {
codec_set_sample_depth,
codec_set_gain,
codec_get_gain,
codec_i2s_enable,
codec_i2s_set_fmt,
codec_i2s_set_tdm_config,
codec_i2s_set_bclk,
};
if (param->cmd < EC_CODEC_I2S_SUBCMD_COUNT)
return codec_i2s_func_tbl[param->cmd](args);
else
return EC_RES_INVALID_PARAM;
}
DECLARE_HOST_COMMAND(EC_CMD_CODEC_I2S,
codec_i2s,
EC_VER_MASK(0));