blob: d06a9a6d8f58ef0e18eb39ed8423e6fae7bb741b [file] [edit]
// SPDX-License-Identifier: GPL-2.0-only
/*
* Google Whitechapel AoC ALSA Driver - Mixer controls
*
* Copyright (c) 2019 Google LLC
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "aoc_alsa.h"
/* Volume maximum and minimum */
#define CTRL_VOL_MIN 0
#define CTRL_VOL_MAX 1000
#define AOC_MIC_RECORD_GAIN_IN_DB_MIN -40
#define AOC_MIC_RECORD_GAIN_IN_DB_MAX 30
#define MMAP_MIC_RECORD_GAIN_IN_DB_MIN -300
#define MMAP_MIC_RECORD_GAIN_IN_DB_MAX 0
#define COMPRE_OFFLOAD_GAIN_MIN 0
#define COMPRE_OFFLOAD_GAIN_MAX 8388608 /* 2^23 = 8388608 */
#define AOC_CHIRP_INTERVAL_KEY 0
#define AOC_CHIRP_ENABLE_KEY 1
#define AOC_CHIRP_MODE_KEY 2
/*
* Redefined the macro from soc.h so that the control value can be negative.
* In orginal definition, xmin can be a negative value, but the min control
* value is always zero.
*/
#define SOC_SINGLE_RANGE_EXT_TLV_modified(xname, xreg, xshift, xmin, xmax, count, xhandler_get, \
xhandler_put, tlv_array) \
{ \
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE, \
.tlv.p = (tlv_array), .info = snd_soc_info_volsw_range_modified, \
.get = xhandler_get, .put = xhandler_put, \
.private_value = (uintptr_t) & (struct soc_mixer_control) \
{ \
.reg = xreg, .rreg = xreg, .shift = xshift, .rshift = count, .min = xmin, \
.max = xmax, .platform_max = xmax, .invert = 0 \
} \
}
static int snd_soc_info_volsw_range_modified(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = (mc->rshift <= 1) ? 1 : mc->rshift;
uinfo->value.integer.min = mc->min;
uinfo->value.integer.max = mc->max;
return 0;
}
static int snd_aoc_ctl_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = CTRL_VOL_MIN;
uinfo->value.integer.max = CTRL_VOL_MAX;
} else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 1;
} else if (kcontrol->private_value == BUILDIN_MIC_POWER_STATE) {
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->count = NUM_OF_BUILTIN_MIC;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 1;
} else if (kcontrol->private_value == BUILDIN_MIC_CAPTURE_LIST) {
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = NUM_OF_BUILTIN_MIC;
uinfo->value.integer.min = -1;
uinfo->value.integer.max = NUM_OF_BUILTIN_MIC - 1;
} else if (kcontrol->private_value == BUILDIN_US_MIC_CAPTURE_LIST) {
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = NUM_OF_BUILTIN_MIC;
uinfo->value.integer.min = -1;
uinfo->value.integer.max = NUM_OF_BUILTIN_MIC - 1;
} else if (kcontrol->private_value == A2DP_ENCODER_PARAMETERS) {
uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
uinfo->count = sizeof(struct AUDIO_OUTPUT_BT_A2DP_ENC_CFG);
}
return 0;
}
static int snd_aoc_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
BUG_ON(!chip && !(chip->avail_substreams & AVAIL_SUBSTREAMS_MASK));
if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
ucontrol->value.integer.value[0] = chip2alsa(chip->volume);
else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
ucontrol->value.integer.value[0] = chip->mute;
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int
snd_aoc_buildin_mic_power_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int i;
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
for (i = 0; i < NUM_OF_BUILTIN_MIC; i++)
ucontrol->value.integer.value[i] =
aoc_get_builtin_mic_power_state(chip, i);
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int
snd_aoc_buildin_mic_power_ctl_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int i;
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
for (i = 0; i < NUM_OF_BUILTIN_MIC; i++)
aoc_set_builtin_mic_power_state(
chip, i, ucontrol->value.integer.value[i]);
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int
snd_aoc_buildin_mic_capture_list_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int i;
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
for (i = 0; i < NUM_OF_BUILTIN_MIC; i++)
ucontrol->value.integer.value[i] =
chip->buildin_mic_id_list[i]; // geting power state;
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int
snd_aoc_buildin_mic_capture_list_ctl_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int i;
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
for (i = 0; i < NUM_OF_BUILTIN_MIC; i++)
chip->buildin_mic_id_list[i] =
ucontrol->value.integer.value[i]; // geting power state;
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int
snd_aoc_buildin_us_mic_capture_list_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int i;
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
for (i = 0; i < NUM_OF_BUILTIN_MIC; i++)
ucontrol->value.integer.value[i] =
chip->buildin_us_mic_id_list[i];
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int
snd_aoc_buildin_us_mic_capture_list_ctl_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int i;
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
for (i = 0; i < NUM_OF_BUILTIN_MIC; i++)
chip->buildin_us_mic_id_list[i] =
ucontrol->value.integer.value[i];
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int incall_capture_enable_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_enum *mc = (struct soc_enum *)kcontrol->private_value;
int stream = mc->shift_l;
int err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
err = aoc_incall_capture_enable_get(chip, stream, &ucontrol->value.integer.value[0]);
if (err < 0)
pr_err("ERR:%d get incall capture stream %d fail\n", err, stream);
mutex_unlock(&chip->audio_mutex);
return err;
}
static int incall_capture_enable_ctl_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_enum *mc = (struct soc_enum *)kcontrol->private_value;
int stream = mc->shift_l;
int err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
err = aoc_incall_capture_enable_set(chip, stream, ucontrol->value.integer.value[0]);
if (err < 0)
pr_err("ERR:%d set voice call capture stream %d fail\n", err, stream);
mutex_unlock(&chip->audio_mutex);
return err;
}
static int incall_playback_enable_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
int playback_stream = mc->shift;
int err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
err = aoc_incall_playback_enable_get(chip, playback_stream,
&ucontrol->value.integer.value[0]);
if (err < 0)
pr_err("ERR:%d get incall playback stream %d fail\n", err, playback_stream);
mutex_unlock(&chip->audio_mutex);
return err;
}
static int incall_playback_enable_ctl_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
int playback_stream = mc->shift;
int err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
err = aoc_incall_playback_enable_set(chip, playback_stream,
ucontrol->value.integer.value[0]);
if (err < 0)
pr_err("ERR:%d set voice call playback stream %d fail\n", err, playback_stream);
mutex_unlock(&chip->audio_mutex);
return err;
}
static int mic_power_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
u32 mic_idx = (u32)mc->shift;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
/* geting power statef from AoC ; */
ucontrol->value.integer.value[0] =
aoc_get_builtin_mic_power_state(chip, mic_idx);
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int mic_power_ctl_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
u32 mic_idx = (u32)mc->shift;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
aoc_set_builtin_mic_power_state(chip, mic_idx,
ucontrol->value.integer.value[0]);
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int mic_clock_rate_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.integer.value[0] = aoc_mic_clock_rate_get(chip);
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int mic_hw_gain_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
u32 state = (u32)mc->shift;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.integer.value[0] = aoc_mic_hw_gain_get(chip, state);
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int mic_hw_gain_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
u32 state = (u32)mc->shift;
if (ucontrol->value.integer.value[0] < MIC_HW_GAIN_IN_CB_MIN ||
ucontrol->value.integer.value[0] > MIC_HW_GAIN_IN_CB_MAX)
return -EINVAL;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
aoc_mic_hw_gain_set(chip, state, ucontrol->value.integer.value[0]);
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int sidetone_enable_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.integer.value[0] = chip->sidetone_enable;
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int incall_mic_sink_mute_ctl_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
int param = mc->shift;
int val, err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
val = ucontrol->value.integer.value[0];
err = aoc_incall_mic_sink_mute_set(chip, param, val);
if (err < 0)
pr_err("ERR:%d incall %s mute set to %d fail\n", err, (param == 0) ? "mic" : "sink",
val);
mutex_unlock(&chip->audio_mutex);
return err;
}
static int incall_mic_sink_mute_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
int param = mc->shift;
int err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
err = aoc_incall_mic_sink_mute_get(chip, param, &ucontrol->value.integer.value[0]);
if (err < 0)
pr_err("ERR:%d incall %s mute get fail\n", err, (param == 0) ? "mic" : "sink");
mutex_unlock(&chip->audio_mutex);
return err;
}
static int incall_playback_mic_channel_ctl_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
int stream = mc->shift;
int val, err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
val = ucontrol->value.integer.value[0];
err = aoc_incall_playback_mic_channel_set(chip, stream, val);
if (err < 0)
pr_err("ERR:%d incall playback mic source set fail for ring %d: mic %d\n", err,
stream, val);
mutex_unlock(&chip->audio_mutex);
return err;
}
static int incall_playback_mic_channel_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
int stream = mc->shift;
int err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
err = aoc_incall_playback_mic_channel_get(chip, stream, &ucontrol->value.integer.value[0]);
if (err < 0)
pr_err("ERR:%d incall playback mic source get fail for ring %d\n", err, stream);
mutex_unlock(&chip->audio_mutex);
return err;
}
static int mic_record_gain_ctl_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
int val, err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
val = ucontrol->value.integer.value[0];
err = aoc_mic_record_gain_set(chip, val);
if (err < 0)
pr_err("ERR:%d mic record gain set to %d fail\n", err, val);
mutex_unlock(&chip->audio_mutex);
return err;
}
static int mic_record_gain_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
int err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
err = aoc_mic_record_gain_get(chip, &ucontrol->value.integer.value[0]);
if (err < 0)
pr_err("ERR:%d mic record gain get fail\n", err);
mutex_unlock(&chip->audio_mutex);
return err;
}
static int mmap_record_gain_ctl_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
int val, err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
val = ucontrol->value.integer.value[0];
err = aoc_mmap_record_gain_set(chip, val);
if (err < 0)
pr_err("ERR:%d mmap record gain set to %d fail\n", err, val);
mutex_unlock(&chip->audio_mutex);
return err;
}
static int mmap_record_gain_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
int err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
err = aoc_mmap_record_gain_get(chip, &ucontrol->value.integer.value[0]);
if (err < 0)
pr_err("ERR:%d mmap record gain get fail\n", err);
mutex_unlock(&chip->audio_mutex);
return err;
}
static int lvm_enable_ctl_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
int val, err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
val = ucontrol->value.integer.value[0];
err = aoc_lvm_enable_set(chip, val);
if (err < 0)
pr_err("ERR:%d lvm %s fail\n", err, val ? "Enable" : "Disable");
mutex_unlock(&chip->audio_mutex);
return err;
}
static int lvm_enable_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
int err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
err = aoc_lvm_enable_get(chip, &ucontrol->value.integer.value[0]);
if (err < 0)
pr_err("ERR:%d lvm enable get fail\n", err);
mutex_unlock(&chip->audio_mutex);
return err;
}
static int decoder_ref_enable_ctl_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
int val, err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
val = ucontrol->value.integer.value[0];
err = aoc_decoder_ref_enable_set(chip, val);
if (err < 0)
pr_err("ERR:%d lvm %s fail\n", err, val ? "Enable" : "Disable");
mutex_unlock(&chip->audio_mutex);
return err;
}
static int decoder_ref_enable_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
int err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
err = aoc_decoder_ref_enable_get(chip, &ucontrol->value.integer.value[0]);
if (err < 0)
pr_err("ERR:%d lvm enable get fail\n", err);
mutex_unlock(&chip->audio_mutex);
return err;
}
static int audio_capture_eraser_enable_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.integer.value[0] = chip->capture_eraser_enable;
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int audio_capture_eraser_enable_ctl_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
int err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
chip->capture_eraser_enable = ucontrol->value.integer.value[0];
err = aoc_audio_capture_eraser_enable(chip, chip->capture_eraser_enable);
if (err < 0)
pr_err("ERR:%d capture eraser %s fail\n", err,
(chip->capture_eraser_enable) ? "Enable" : "Disable");
mutex_unlock(&chip->audio_mutex);
return err;
}
static int hotword_tap_enable_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (chip->hotword_supported) {
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.integer.value[0] = chip->hotword_tap_enable;
mutex_unlock(&chip->audio_mutex);
return 0;
} else {
pr_err("WARN:hotword is not supported on this device\n");
return 0;
}
}
static int hotword_tap_enable_ctl_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (chip->hotword_supported) {
int err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
chip->hotword_tap_enable = ucontrol->value.integer.value[0];
err = aoc_hotword_tap_enable(chip, chip->hotword_tap_enable);
if (err < 0)
pr_err("ERR:%d hotword_tap %s fail\n", err,
(chip->hotword_tap_enable) ? "Enable" : "Disable");
mutex_unlock(&chip->audio_mutex);
return err;
}
else {
pr_err("WARN:hotword is not supported on this device\n");
return 0;
}
}
static int audio_cca_module_load_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.integer.value[0] = chip->cca_module_loaded;
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int audio_cca_module_load_ctl_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
int err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
chip->cca_module_loaded = ucontrol->value.integer.value[0];
err = aoc_load_cca_module(chip, chip->cca_module_loaded);
if (err < 0)
pr_err("ERR:%d %s CCA fail\n", err,
(chip->cca_module_loaded) ? "Load" : "Unload");
mutex_unlock(&chip->audio_mutex);
return err;
}
static int audio_gapless_offload_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.integer.value[0] = chip->gapless_offload_enable;
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int audio_gapless_offload_ctl_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
int err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
chip->gapless_offload_enable = ucontrol->value.integer.value[0];
mutex_unlock(&chip->audio_mutex);
return err;
}
static int sidetone_enable_ctl_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
int err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
chip->sidetone_enable = ucontrol->value.integer.value[0];
err = aoc_sidetone_enable(chip, chip->sidetone_enable);
if (err < 0)
pr_err("ERR:%d sidetone %s fail\n", err,
(chip->sidetone_enable) ? "Enable" : "Disable");
mutex_unlock(&chip->audio_mutex);
return err;
}
static int aoc_sidetone_cfg_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
u32 param = (u32)mc->shift;
int err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
err = aoc_sidetone_cfg_get(chip, param, &ucontrol->value.integer.value[0]);
if (err < 0)
pr_err("ERR:%d sidetone config fail to get param %d\n", err, param);
mutex_unlock(&chip->audio_mutex);
return err;
}
static int aoc_sidetone_cfg_ctl_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
u32 param = (u32)mc->shift;
int err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
err = aoc_sidetone_cfg_set(chip, param, ucontrol->value.integer.value[0]);
if (err < 0)
pr_err("ERR:%d sidetone config fail to set param %d\n", err, param);
mutex_unlock(&chip->audio_mutex);
return err;
}
static int aoc_sidetone_eq_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
u32 biquad_idx = (u32)mc->shift;
int err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
err = aoc_sidetone_eq_get(chip, biquad_idx, ucontrol->value.integer.value);
if (err < 0)
pr_err("ERR:%d sidetone EQ biquad %d fail to get parameter\n", err, biquad_idx);
mutex_unlock(&chip->audio_mutex);
return err;
}
static int aoc_sidetone_eq_ctl_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
u32 biquad_idx = (u32)mc->shift;
int err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
err = aoc_sidetone_eq_set(chip, biquad_idx, ucontrol->value.integer.value);
if (err < 0)
pr_err("ERR:%d sidetone EQ biquad %d fail to set parameter\n", err, biquad_idx);
mutex_unlock(&chip->audio_mutex);
return err;
}
static int mic_dc_blocker_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.integer.value[0] = aoc_mic_dc_blocker_get(chip);
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int mic_dc_blocker_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
aoc_mic_dc_blocker_set(chip, ucontrol->value.integer.value[0]);
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int compr_offload_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if(chip->compr_offload_volume<0 || chip->compr_offload_volume>1000)
return -EINVAL;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.integer.value[0] = chip->compr_offload_volume;
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int compr_offload_volume_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
chip->compr_offload_volume = ucontrol->value.integer.value[0];
/* temporary solution */
aoc_audio_volume_set(chip, chip->compr_offload_volume, OFF_LOAD, ASNK_SPEAKER);
aoc_audio_volume_set(chip, chip->compr_offload_volume, OFF_LOAD, ASNK_USB);
aoc_audio_volume_set(chip, chip->compr_offload_volume, OFF_LOAD, ASNK_BT);
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int aoc_compr_offload_gain_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
int err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
err = aoc_compr_offload_linear_gain_get(chip, &ucontrol->value.integer.value[0]);
if (err < 0)
pr_err("ERR:%d compr offload linear gain get fail\n", err);
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int aoc_compr_offload_gain_ctl_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
int err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
err = aoc_compr_offload_linear_gain_set(chip, &ucontrol->value.integer.value[0]);
if (err < 0)
pr_err("ERR:%d compr offload linear gain set fail\n", err);
mutex_unlock(&chip->audio_mutex);
return err;
}
static int pcm_wait_time_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.integer.value[0] = chip->pcm_wait_time_in_ms;
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int pcm_wait_time_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
int val = ucontrol->value.integer.value[0];
if (val < 0 || val > DEFAULT_PCM_WAIT_TIME_IN_MSECS)
return -EINVAL;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
chip->pcm_wait_time_in_ms = val;
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int voice_pcm_wait_time_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.integer.value[0] = chip->voice_pcm_wait_time_in_ms;
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int voice_pcm_wait_time_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
int val = ucontrol->value.integer.value[0];
if (val < 0 || val > DEFAULT_PCM_WAIT_TIME_IN_MSECS)
return -EINVAL;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
chip->voice_pcm_wait_time_in_ms = val;
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int audio_capture_mic_source_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.integer.value[0] = chip->audio_capture_mic_source;
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int audio_capture_mic_source_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
int err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
chip->audio_capture_mic_source = ucontrol->value.integer.value[0];
if (chip->audio_capture_mic_source == DEFAULT_MIC)
chip->audio_capture_mic_source = BUILTIN_MIC;
pr_info("mic source set: %d\n", chip->audio_capture_mic_source);
if (err < 0)
pr_err("ERR:%d in audio capture mic source set\n", err);
mutex_unlock(&chip->audio_mutex);
return err;
}
static int eraser_aec_ref_source_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.integer.value[0] = chip->eraser_aec_ref_source;
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int eraser_aec_ref_source_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
int err;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
if (ucontrol->value.integer.value[0] < NUM_AEC_REF_SOURCE) {
chip->eraser_aec_ref_source = ucontrol->value.integer.value[0];
err = aoc_eraser_aec_reference_set(chip, chip->eraser_aec_ref_source);
if (err < 0)
pr_err("ERR:%d in Eraser aec ref source set\n", err);
} else {
err = -EINVAL;
pr_err("ERR:%d invalid ft aec ref source\n", err);
}
mutex_unlock(&chip->audio_mutex);
return err;
}
static int ft_aec_ref_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.integer.value[0] = chip->ft_aec_ref_source;
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int ft_aec_ref_source_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
int err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
if (ucontrol->value.integer.value[0] < NUM_AEC_REF_SOURCE)
chip->ft_aec_ref_source = ucontrol->value.integer.value[0];
else {
err = -EINVAL;
pr_err("ERR:%d invalid ft aec ref source\n", err);
}
mutex_unlock(&chip->audio_mutex);
return err;
}
static int voice_call_mic_source_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.integer.value[0] = chip->voice_call_mic_source;
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int voice_call_mic_source_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
chip->voice_call_mic_source = ucontrol->value.integer.value[0];
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int voice_call_mic_mute_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.integer.value[0] = chip->voice_call_mic_mute;
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int voice_call_mic_mute_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
if (chip->voice_call_mic_mute != ucontrol->value.integer.value[0]) {
chip->voice_call_mic_mute = ucontrol->value.integer.value[0];
aoc_voice_call_mic_mute(chip, ucontrol->value.integer.value[0]);
}
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int voice_call_audio_enable_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.integer.value[0] = chip->voice_call_audio_enable;
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int voice_call_audio_enable_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
if (chip->voice_call_audio_enable != ucontrol->value.integer.value[0]) {
chip->voice_call_audio_enable = ucontrol->value.integer.value[0];
}
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int mic_spatial_module_enable_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.integer.value[0] = chip->mic_spatial_module_enable;
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int mic_spatial_module_enable_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
chip->mic_spatial_module_enable = ucontrol->value.integer.value[0];
if (chip->mic_spatial_module_enable)
aoc_spatial_module_start(chip);
else
aoc_spatial_module_stop(chip);
mutex_unlock(&chip->audio_mutex);
return 0;
}
static const char *dsp_state_texts[] = { "Idle", "Playback", "Telephony" };
static int aoc_dsp_state_ctl_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(dsp_state_texts),
dsp_state_texts);
}
static int aoc_asp_mode_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_enum *mc = (struct soc_enum *)kcontrol->private_value;
u32 block = (u32)mc->shift_l;
u32 component = (u32)(0x00ff & mc->reg);
u32 key = (u32)(0xff00 & mc->reg) >> 8;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.enumerated.item[0] =
aoc_get_asp_mode(chip, block, component, key);
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int aoc_asp_mode_ctl_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_enum *mc = (struct soc_enum *)kcontrol->private_value;
u32 block = (u32)mc->shift_l;
u32 component = (u32)(0x00ff & mc->reg);
u32 key = (u32)(0xff00 & mc->reg) >> 8;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
aoc_set_asp_mode(chip, block, component, key,
ucontrol->value.enumerated.item[0]);
pr_debug("asp mode set: block %d component %d - %d\n", block, component,
ucontrol->value.enumerated.item[0]);
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int aoc_audio_dsp_mode_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
aoc_get_audio_dsp_mode(chip, (long *)&(ucontrol->value.enumerated.item[0]));
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int aoc_audio_dsp_mode_ctl_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
aoc_set_audio_dsp_mode(chip, ucontrol->value.enumerated.item[0]);
pr_debug("Audio dsp mode set: %d", ucontrol->value.enumerated.item[0]);
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int
aoc_builtin_mic_process_mode_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.enumerated.item[0] =
aoc_get_builtin_mic_process_mode(chip);
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int aoc_builtin_mic_process_mode_ctl_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
int mode, err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
mode = ucontrol->value.enumerated.item[0];
err = aoc_set_builtin_mic_process_mode(chip, mode);
if (err < 0)
pr_err("ERR:%d builtin mic process mode set to %d fail", err, mode);
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int aoc_sink_mode_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_enum *mc = (struct soc_enum *)kcontrol->private_value;
u32 sink_idx = (u32)mc->shift_l;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.enumerated.item[0] = aoc_get_sink_mode(chip, sink_idx);
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int aoc_sink_mode_ctl_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_enum *mc = (struct soc_enum *)kcontrol->private_value;
u32 sink_idx = (u32)mc->shift_l;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
aoc_set_sink_mode(chip, sink_idx, ucontrol->value.enumerated.item[0]);
pr_debug("sink mode set: %d - %d\n", sink_idx,
ucontrol->value.enumerated.item[0]);
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int usb_cfg_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
u32 idx = (u32)mc->shift;
int val;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
switch (idx) {
case USB_DEV_ID:
val = chip->usb_sink_cfg.dev_id;
break;
case USB_TX_EP_ID:
val = chip->usb_sink_cfg.tx_ep_num;
break;
case USB_TX_SR:
val = chip->usb_sink_cfg.tx_sr;
break;
case USB_TX_CH:
val = chip->usb_sink_cfg.tx_ch;
break;
case USB_TX_BW:
val = chip->usb_sink_cfg.tx_width;
break;
case USB_RX_EP_ID:
val = chip->usb_sink_cfg.rx_ep_num;
break;
case USB_RX_SR:
val = chip->usb_sink_cfg.rx_sr;
break;
case USB_RX_CH:
val = chip->usb_sink_cfg.rx_ch;
break;
case USB_RX_BW:
val = chip->usb_sink_cfg.rx_width;
break;
case USB_CFG_TO_AOC:
val = 0;
break;
default:
val = -1;
pr_err("ERR: incorrect index for USB config in %s\n", __func__);
}
ucontrol->value.enumerated.item[0] = val;
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int usb_cfg_ctl_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
u32 idx = (u32)mc->shift;
int err = 0;
int val = ucontrol->value.enumerated.item[0];
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
switch (idx) {
case USB_DEV_ID:
chip->usb_sink_cfg.dev_id = val;
break;
case USB_TX_EP_ID:
chip->usb_sink_cfg.tx_ep_num = val;
break;
case USB_TX_SR:
chip->usb_sink_cfg.tx_sr = val;
break;
case USB_TX_CH:
chip->usb_sink_cfg.tx_ch = val;
break;
case USB_TX_BW:
chip->usb_sink_cfg.tx_width = val;
break;
case USB_RX_EP_ID:
chip->usb_sink_cfg.rx_ep_num = val;
break;
case USB_RX_SR:
chip->usb_sink_cfg.rx_sr = val;
break;
case USB_RX_CH:
chip->usb_sink_cfg.rx_ch = val;
break;
case USB_RX_BW:
chip->usb_sink_cfg.rx_width = val;
break;
case USB_CFG_TO_AOC:
err = aoc_set_usb_config(chip);
if (err < 0)
pr_err("ERR:%d fail to update aoc usb config!\n", err);
break;
default:
err = -EINVAL;
pr_err("ERR: %d incorrect index for USB config\n", err);
}
mutex_unlock(&chip->audio_mutex);
return err;
}
static int usb_cfg_v2_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
u32 idx = (u32)mc->shift;
int val;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
switch (idx) {
case USB_BUS_ID:
val = chip->usb_sink_cfg_v2.bus_id;
break;
case USB_DEV_ID:
val = chip->usb_sink_cfg_v2.dev_num;
break;
case USB_TX_EP_ID:
val = chip->usb_sink_cfg_v2.tx_ep_num;
break;
case USB_TX_FORMAT:
val = chip->usb_sink_cfg_v2.tx_format;
break;
case USB_TX_SR:
val = chip->usb_sink_cfg_v2.tx_sr;
break;
case USB_TX_CH:
val = chip->usb_sink_cfg_v2.tx_ch;
break;
case USB_TX_BW:
val = chip->usb_sink_cfg_v2.tx_width;
break;
case USB_RX_EP_ID:
val = chip->usb_sink_cfg_v2.rx_ep_num;
break;
case USB_RX_FORMAT:
val = chip->usb_sink_cfg_v2.rx_format;
break;
case USB_RX_SR:
val = chip->usb_sink_cfg_v2.rx_sr;
break;
case USB_RX_CH:
val = chip->usb_sink_cfg_v2.rx_ch;
break;
case USB_RX_BW:
val = chip->usb_sink_cfg_v2.rx_width;
break;
case USB_CFG_TO_AOC:
val = 0;
break;
default:
val = -1;
pr_err("ERR: incorrect index for USB config v2 in %s\n", __func__);
}
ucontrol->value.enumerated.item[0] = val;
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int usb_cfg_v2_ctl_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
u32 idx = (u32)mc->shift;
int err = 0;
int val = ucontrol->value.enumerated.item[0];
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
switch (idx) {
case USB_BUS_ID:
chip->usb_sink_cfg_v2.bus_id = val;
break;
case USB_DEV_ID:
chip->usb_sink_cfg_v2.dev_num = val;
break;
case USB_TX_EP_ID:
chip->usb_sink_cfg_v2.tx_ep_num = val;
break;
case USB_TX_FORMAT:
chip->usb_sink_cfg_v2.tx_format = val;
break;
case USB_TX_SR:
chip->usb_sink_cfg_v2.tx_sr = val;
break;
case USB_TX_CH:
chip->usb_sink_cfg_v2.tx_ch = val;
break;
case USB_TX_BW:
chip->usb_sink_cfg_v2.tx_width = val;
break;
case USB_RX_EP_ID:
chip->usb_sink_cfg_v2.rx_ep_num = val;
break;
case USB_RX_FORMAT:
chip->usb_sink_cfg_v2.rx_format = val;
break;
case USB_RX_SR:
chip->usb_sink_cfg_v2.rx_sr = val;
break;
case USB_RX_CH:
chip->usb_sink_cfg_v2.rx_ch = val;
break;
case USB_RX_BW:
chip->usb_sink_cfg_v2.rx_width = val;
break;
case USB_CFG_TO_AOC:
err = aoc_set_usb_config_v2(chip);
if (err < 0)
pr_err("ERR:%d fail to update aoc usb config v2!\n", err);
break;
default:
err = -EINVAL;
pr_err("ERR: %d incorrect index for USB config v2\n", err);
}
mutex_unlock(&chip->audio_mutex);
return err;
}
static int aoc_dsp_state_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.enumerated.item[0] = aoc_get_dsp_state(chip);
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int aoc_sink_state_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_enum *mc = (struct soc_enum *)kcontrol->private_value;
u32 sink_idx = (u32)mc->shift_l;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.enumerated.item[0] = aoc_get_sink_state(chip, sink_idx);
pr_debug("sink %d - %d\n", sink_idx,
ucontrol->value.enumerated.item[0]);
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int aoc_sink_channel_bitmap_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
u32 sink_idx = (u32)mc->shift;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.enumerated.item[0] =
aoc_get_sink_channel_bitmap(chip, sink_idx);
pr_debug("sink %d channel bitmap - %d\n", sink_idx,
ucontrol->value.enumerated.item[0]);
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int aoc_audio_chirp_enable_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
int err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
chip->chirp_enable = ucontrol->value.integer.value[0];
err = aoc_audio_set_chirp_parameter(chip, AOC_CHIRP_ENABLE_KEY, chip->chirp_enable);
mutex_unlock(&chip->audio_mutex);
return err;
}
static int aoc_audio_chirp_enable_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.integer.value[0] = chip->chirp_enable;
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int aoc_audio_chirp_interval_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
int err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
chip->chirp_interval = ucontrol->value.integer.value[0];
err = aoc_audio_set_chirp_parameter(chip, AOC_CHIRP_INTERVAL_KEY, chip->chirp_interval);
mutex_unlock(&chip->audio_mutex);
return err;
}
static int aoc_audio_chirp_interval_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.integer.value[0] = chip->chirp_interval;
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int aoc_audio_chirp_mode_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
int err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
chip->chirp_mode = ucontrol->value.integer.value[0];
err = aoc_audio_set_chirp_parameter(chip, AOC_CHIRP_MODE_KEY, chip->chirp_mode);
mutex_unlock(&chip->audio_mutex);
return err;
}
static int aoc_audio_chirp_mode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.integer.value[0] = chip->chirp_mode;
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int aoc_audio_chre_src_gain_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) {
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
int chre_path = mc->shift;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.integer.value[0] = chip->chre_src_gain[chre_path];
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int aoc_audio_chre_src_gain_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
int err = 0;
int chre_path = mc->shift;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
chip->chre_src_gain[chre_path] = ucontrol->value.integer.value[0];
switch (chre_path) {
case CHRE_GAIN_PATH_PDM:
err = aoc_audio_set_chre_src_pdm_gain(chip, chip->chre_src_gain[chre_path]);
break;
case CHRE_GAIN_PATH_AEC:
err = aoc_audio_set_chre_src_aec_gain(chip, chip->chre_src_gain[chre_path]);
break;
default:
pr_err("Unknown CHRE gain path: %d", chre_path);
break;
}
mutex_unlock(&chip->audio_mutex);
return err;
}
static int aoc_audio_chre_src_aec_timeout_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) {
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
ucontrol->value.integer.value[0] = chip->chre_src_aec_timeout;
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int aoc_audio_chre_src_aec_timeout_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
int err = 0;
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
chip->chre_src_aec_timeout = ucontrol->value.integer.value[0];
err = aoc_audio_set_chre_src_aec_timeout(chip, chip->chre_src_aec_timeout);
mutex_unlock(&chip->audio_mutex);
return err;
}
static int a2dp_encoder_parameters_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
int para_size = sizeof(chip->a2dp_encoder_cfg);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
memcpy(&chip->a2dp_encoder_cfg, ucontrol->value.bytes.data, para_size);
aoc_a2dp_set_enc_param(chip, &chip->a2dp_encoder_cfg);
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int a2dp_encoder_parameters_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
memcpy(ucontrol->value.bytes.data, &chip->a2dp_encoder_cfg,
sizeof(chip->a2dp_encoder_cfg));
mutex_unlock(&chip->audio_mutex);
return 0;
}
static int us_record_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
return 0;
}
static int us_record_ctl_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct aoc_chip *chip = snd_kcontrol_chip(kcontrol);
if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
aoc_audio_us_record(chip, ucontrol->value.integer.value[0]);
mutex_unlock(&chip->audio_mutex);
return 0;
}
/* TODO: this has to be consistent to enum APMicProcessIndex in aoc-interface.h */
static const char *builtin_mic_process_mode_texts[] = { "Raw", "Spatial" };
static SOC_ENUM_SINGLE_DECL(builtin_mic_process_mode_enum, 1, 0,
builtin_mic_process_mode_texts);
/* TODO: this has to be consistent to BT/USB Mode enum in aoc_alsa.h */
static const char *bt_mode_texts[] = { "Unconfigured", "SCO",
"ESCO", "ESCO_SWB",
"A2DP_ENC_SBC", "A2DP_ENC_AAC",
"A2DP_ENC_LC3", "BLE_ENC_LC3",
"BLE_CONVERSATION", "A2DP_ENC_OPUS",
"A2DP_RAW", "ESCO_LC3" };
static SOC_ENUM_SINGLE_DECL(bt_mode_enum, 1, SINK_BT, bt_mode_texts);
/* TODO: seek better way to create a series of controls */
static const char *block_asp_mode_texts[] = { "ASP_OFF", "ASP_ON", "ASP_BYPASS",
"ASP_GROUND" };
static SOC_ENUM_SINGLE_DECL(block_16_state_enum, 2, 16, block_asp_mode_texts);
static SOC_ENUM_SINGLE_DECL(block_17_state_enum, 2, 17, block_asp_mode_texts);
static SOC_ENUM_SINGLE_DECL(block_18_state_enum, 2, 18, block_asp_mode_texts);
/* ASR mode: block 19, module 15, key 0 for FT*/
static SOC_ENUM_SINGLE_DECL(block_19_state_enum, 15, 19, block_asp_mode_texts);
/* ASR mode: block 19, module 15, key 1 for ASRC*/
static SOC_ENUM_SINGLE_DECL(block_19_15_1_state_enum, (15|(1<<8)), 19, block_asp_mode_texts);
static SOC_ENUM_SINGLE_DECL(block_20_state_enum, 2, 20, block_asp_mode_texts);
/* TODO: seek better way to create a series of controls */
static const char *sink_processing_state_texts[] = { "Idle", "Active",
"Bypass" };
static SOC_ENUM_SINGLE_DECL(sink_0_state_enum, 1, 0,
sink_processing_state_texts);
static SOC_ENUM_SINGLE_DECL(sink_1_state_enum, 1, 1,
sink_processing_state_texts);
static SOC_ENUM_SINGLE_DECL(sink_2_state_enum, 1, 2,
sink_processing_state_texts);
static SOC_ENUM_SINGLE_DECL(sink_3_state_enum, 1, 3,
sink_processing_state_texts);
static SOC_ENUM_SINGLE_DECL(sink_4_state_enum, 1, 4,
sink_processing_state_texts);
/* audio dsp state switch */
static const char *audio_dsp_state_switch_texts[] = { "Ambient", "Record", "Telephony",
"RESERVED_0", "RESERVED_1", "RESERVED_2",
"Telephony_APMG3"};
static SOC_ENUM_SINGLE_DECL(audio_dsp_state_switch_enum, 1, 0, audio_dsp_state_switch_texts);
/* incall capture stream state */
static const char *incall_capture_stream_texts[] = { "Off", "UL", "DL", "UL_DL", "3MIC" };
static SOC_ENUM_SINGLE_DECL(incall_capture_stream0_enum, 1, 0, incall_capture_stream_texts);
static SOC_ENUM_SINGLE_DECL(incall_capture_stream1_enum, 1, 1, incall_capture_stream_texts);
static SOC_ENUM_SINGLE_DECL(incall_capture_stream2_enum, 1, 2, incall_capture_stream_texts);
/* audio capture mic source */
static const char *audio_capture_mic_source_texts[] = { "Default", "Builtin_MIC", "USB_MIC",
"BT_MIC", "No MIC", "ERASER" };
static SOC_ENUM_SINGLE_DECL(audio_capture_mic_source_enum, 1, 0, audio_capture_mic_source_texts);
/* Voice call mic source */
static const char *voice_call_mic_source_texts[] = { "Default", "Builtin_MIC", "USB_MIC", "BT_MIC",
"IN_CALL_MUSIC" };
static SOC_ENUM_SINGLE_DECL(voice_call_mic_source_enum, 1, 0,
voice_call_mic_source_texts);
/* AEC reference source */
static const char *eraser_aec_ref_source_texts[NUM_AEC_REF_SOURCE] = { "Default", "SPEAKER", "USB",
"BT" };
static SOC_ENUM_SINGLE_DECL(eraser_aec_ref_source_enum, 1, 0, eraser_aec_ref_source_texts);
static const char *ft_aec_ref_source_texts[NUM_AEC_REF_SOURCE] = { "Default", "SPEAKER", "USB",
"BT" };
static SOC_ENUM_SINGLE_DECL(ft_aec_ref_source_enum, 1, 0, ft_aec_ref_source_texts);
static struct snd_kcontrol_new snd_aoc_ctl[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "PCM Playback Volume",
.index = 0,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ,
.private_value = PCM_PLAYBACK_VOLUME,
.info = snd_aoc_ctl_info,
.get = snd_aoc_ctl_get,
.put = NULL,
.count = 1,
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "PCM Playback Switch",
.index = 0,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.private_value = PCM_PLAYBACK_MUTE,
.info = snd_aoc_ctl_info,
.get = snd_aoc_ctl_get,
.put = NULL,
.count = 1,
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "BUILDIN MIC POWER STATE",
.index = 0,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.private_value = BUILDIN_MIC_POWER_STATE,
.info = snd_aoc_ctl_info,
.get = snd_aoc_buildin_mic_power_ctl_get,
.put = snd_aoc_buildin_mic_power_ctl_put,
.count = 1,
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "BUILDIN MIC ID CAPTURE LIST",
.index = 0,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.private_value = BUILDIN_MIC_CAPTURE_LIST,
.info = snd_aoc_ctl_info,
.get = snd_aoc_buildin_mic_capture_list_ctl_get,
.put = snd_aoc_buildin_mic_capture_list_ctl_put,
.count = 1,
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "BUILDIN US MIC ID CAPTURE LIST",
.index = 0,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.private_value = BUILDIN_US_MIC_CAPTURE_LIST,
.info = snd_aoc_ctl_info,
.get = snd_aoc_buildin_us_mic_capture_list_ctl_get,
.put = snd_aoc_buildin_us_mic_capture_list_ctl_put,
.count = 1,
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Audio DSP State",
.index = 0,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.info = aoc_dsp_state_ctl_info,
.get = aoc_dsp_state_ctl_get,
.count = 1,
},
SOC_ENUM_EXT("AoC Speaker Mixer ASP Mode", block_16_state_enum,
aoc_asp_mode_ctl_get, aoc_asp_mode_ctl_set),
SOC_ENUM_EXT("AoC Headphone Mixer ASP Mode", block_17_state_enum,
aoc_asp_mode_ctl_get, aoc_asp_mode_ctl_set),
SOC_ENUM_EXT("AoC BT Mixer ASP Mode", block_18_state_enum,
aoc_asp_mode_ctl_get, aoc_asp_mode_ctl_set),
SOC_ENUM_EXT("AoC Modem Mixer ASP Mode", block_19_state_enum,
aoc_asp_mode_ctl_get, aoc_asp_mode_ctl_set),
SOC_ENUM_EXT("AoC USB Mixer ASP Mode", block_20_state_enum,
aoc_asp_mode_ctl_get, aoc_asp_mode_ctl_set),
SOC_ENUM_EXT("AoC Modem Downlink ASRC Mode", block_19_15_1_state_enum,
aoc_asp_mode_ctl_get, aoc_asp_mode_ctl_set),
SOC_ENUM_EXT("Audio DSP Mode", audio_dsp_state_switch_enum,
aoc_audio_dsp_mode_ctl_get, aoc_audio_dsp_mode_ctl_set),
SOC_ENUM_EXT("BUILTIN MIC Process Mode", builtin_mic_process_mode_enum,
aoc_builtin_mic_process_mode_ctl_get, aoc_builtin_mic_process_mode_ctl_set),
SOC_ENUM_EXT("BT Mode", bt_mode_enum, aoc_sink_mode_ctl_get,
aoc_sink_mode_ctl_set),
SOC_SINGLE_EXT("USB Dev ID", SND_SOC_NOPM, USB_DEV_ID, 100, 0,
usb_cfg_ctl_get, usb_cfg_ctl_set),
SOC_SINGLE_EXT("USB Playback EP ID", SND_SOC_NOPM, USB_TX_EP_ID, 100, 0,
usb_cfg_ctl_get, usb_cfg_ctl_set),
SOC_SINGLE_EXT("USB Playback SR", SND_SOC_NOPM, USB_TX_SR, 48000, 0,
usb_cfg_ctl_get, usb_cfg_ctl_set),
SOC_SINGLE_EXT("USB Playback CH", SND_SOC_NOPM, USB_TX_CH, 2, 0,
usb_cfg_ctl_get, usb_cfg_ctl_set),
SOC_SINGLE_EXT("USB Playback BW", SND_SOC_NOPM, USB_TX_BW, 32, 0,
usb_cfg_ctl_get, usb_cfg_ctl_set),
SOC_SINGLE_EXT("USB Capture EP ID", SND_SOC_NOPM, USB_RX_EP_ID, 100, 0,
usb_cfg_ctl_get, usb_cfg_ctl_set),
SOC_SINGLE_EXT("USB Capture SR", SND_SOC_NOPM, USB_RX_SR, 48000, 0,
usb_cfg_ctl_get, usb_cfg_ctl_set),
SOC_SINGLE_EXT("USB Capture CH", SND_SOC_NOPM, USB_RX_CH, 2, 0,
usb_cfg_ctl_get, usb_cfg_ctl_set),
SOC_SINGLE_EXT("USB Capture BW", SND_SOC_NOPM, USB_RX_BW, 32, 0,
usb_cfg_ctl_get, usb_cfg_ctl_set),
SOC_SINGLE_EXT("USB Config To AoC", SND_SOC_NOPM, USB_CFG_TO_AOC, 1, 0,
usb_cfg_ctl_get, usb_cfg_ctl_set),
SOC_SINGLE_EXT("USB Bus ID v2", SND_SOC_NOPM, USB_BUS_ID, 100, 0,
usb_cfg_v2_ctl_get, usb_cfg_v2_ctl_set),
SOC_SINGLE_EXT("USB Dev ID v2", SND_SOC_NOPM, USB_DEV_ID, 100, 0,
usb_cfg_v2_ctl_get, usb_cfg_v2_ctl_set),
SOC_SINGLE_EXT("USB Playback EP ID v2", SND_SOC_NOPM, USB_TX_EP_ID, 100, 0,
usb_cfg_v2_ctl_get, usb_cfg_v2_ctl_set),
SOC_SINGLE_EXT("USB Playback FORMAT v2", SND_SOC_NOPM, USB_TX_FORMAT, 100, 0,
usb_cfg_v2_ctl_get, usb_cfg_v2_ctl_set),
SOC_SINGLE_EXT("USB Playback SR v2", SND_SOC_NOPM, USB_TX_SR, 48000, 0,
usb_cfg_v2_ctl_get, usb_cfg_v2_ctl_set),
SOC_SINGLE_EXT("USB Playback CH v2", SND_SOC_NOPM, USB_TX_CH, 2, 0,
usb_cfg_v2_ctl_get, usb_cfg_v2_ctl_set),
SOC_SINGLE_EXT("USB Playback BW v2", SND_SOC_NOPM, USB_TX_BW, 32, 0,
usb_cfg_v2_ctl_get, usb_cfg_v2_ctl_set),
SOC_SINGLE_EXT("USB Capture EP ID v2", SND_SOC_NOPM, USB_RX_EP_ID, 100, 0,
usb_cfg_v2_ctl_get, usb_cfg_v2_ctl_set),
SOC_SINGLE_EXT("USB Capture FORMAT v2", SND_SOC_NOPM, USB_RX_FORMAT, 100, 0,
usb_cfg_v2_ctl_get, usb_cfg_v2_ctl_set),
SOC_SINGLE_EXT("USB Capture SR v2", SND_SOC_NOPM, USB_RX_SR, 48000, 0,
usb_cfg_v2_ctl_get, usb_cfg_v2_ctl_set),
SOC_SINGLE_EXT("USB Capture CH v2", SND_SOC_NOPM, USB_RX_CH, 2, 0,
usb_cfg_v2_ctl_get, usb_cfg_v2_ctl_set),
SOC_SINGLE_EXT("USB Capture BW v2", SND_SOC_NOPM, USB_RX_BW, 32, 0,
usb_cfg_v2_ctl_get, usb_cfg_v2_ctl_set),
SOC_SINGLE_EXT("USB Config To AoC v2", SND_SOC_NOPM, USB_CFG_TO_AOC, 1, 0,
usb_cfg_v2_ctl_get, usb_cfg_v2_ctl_set),
SOC_ENUM_EXT("Audio Sink 0 Processing State", sink_0_state_enum,
aoc_sink_state_ctl_get, NULL),
SOC_ENUM_EXT("Audio Sink 1 Processing State", sink_1_state_enum,
aoc_sink_state_ctl_get, NULL),
SOC_ENUM_EXT("Audio Sink 2 Processing State", sink_2_state_enum,
aoc_sink_state_ctl_get, NULL),
SOC_ENUM_EXT("Audio Sink 3 Processing State", sink_3_state_enum,
aoc_sink_state_ctl_get, NULL),
SOC_ENUM_EXT("Audio Sink 4 Processing State", sink_4_state_enum,
aoc_sink_state_ctl_get, NULL),
/* 16 bit for each sink */
SOC_SINGLE_EXT("AoC Speaker Sink Channel Bitmap", SND_SOC_NOPM, 0,
0x00ffff, 0, aoc_sink_channel_bitmap_ctl_get, NULL),
SOC_SINGLE_EXT("AoC Headphone Sink Channel Bitmap", SND_SOC_NOPM, 1,
0x00ffff, 0, aoc_sink_channel_bitmap_ctl_get, NULL),
SOC_SINGLE_EXT("AoC BT Sink Channel Bitmap", SND_SOC_NOPM, 2, 0x00ffff,
0, aoc_sink_channel_bitmap_ctl_get, NULL),
SOC_SINGLE_EXT("AoC Modem Sink Channel Bitmap", SND_SOC_NOPM, 3,
0x00ffff, 0, aoc_sink_channel_bitmap_ctl_get, NULL),
SOC_SINGLE_EXT("AoC USB Sink Channel Bitmap", SND_SOC_NOPM, 4, 0x00ffff,
0, aoc_sink_channel_bitmap_ctl_get, NULL),
SOC_SINGLE_EXT("Audio Capture Eraser Enable", SND_SOC_NOPM, 0, 1, 0,
audio_capture_eraser_enable_ctl_get, audio_capture_eraser_enable_ctl_set),
SOC_SINGLE_EXT("Hotword Tap Enable", SND_SOC_NOPM, 0, 1, 0,
hotword_tap_enable_ctl_get, hotword_tap_enable_ctl_set),
SOC_ENUM_EXT("Audio Capture Mic Source", audio_capture_mic_source_enum,
audio_capture_mic_source_get, audio_capture_mic_source_set),
SOC_ENUM_EXT("Eraser AEC Reference Source", eraser_aec_ref_source_enum,
eraser_aec_ref_source_get, eraser_aec_ref_source_set),
SOC_ENUM_EXT("FT AEC Reference Source", ft_aec_ref_source_enum,
ft_aec_ref_source_get, ft_aec_ref_source_set),
SOC_ENUM_EXT("Voice Call Mic Source", voice_call_mic_source_enum,
voice_call_mic_source_get, voice_call_mic_source_set),
SOC_SINGLE_EXT("Voice Call Mic Mute", SND_SOC_NOPM, 0, 1, 0,
voice_call_mic_mute_get, voice_call_mic_mute_set),
SOC_SINGLE_EXT("Voice Call Audio Enable", SND_SOC_NOPM, 0, 1, 0,
voice_call_audio_enable_get,
voice_call_audio_enable_set),
SOC_SINGLE_EXT("Mic Spatial Module Enable", SND_SOC_NOPM, 0, 1, 0,
mic_spatial_module_enable_get,
mic_spatial_module_enable_set),
SOC_ENUM_EXT("Incall Capture Stream0", incall_capture_stream0_enum,
incall_capture_enable_ctl_get, incall_capture_enable_ctl_set),
SOC_ENUM_EXT("Incall Capture Stream1", incall_capture_stream1_enum,
incall_capture_enable_ctl_get, incall_capture_enable_ctl_set),
SOC_ENUM_EXT("Incall Capture Stream2", incall_capture_stream2_enum,
incall_capture_enable_ctl_get, incall_capture_enable_ctl_set),
SOC_SINGLE_EXT("Incall Playback Stream0", SND_SOC_NOPM, 0, 1, 0,
incall_playback_enable_ctl_get, incall_playback_enable_ctl_set),
SOC_SINGLE_EXT("Incall Playback Stream1", SND_SOC_NOPM, 1, 1, 0,
incall_playback_enable_ctl_get, incall_playback_enable_ctl_set),
SOC_SINGLE_EXT("MIC0", SND_SOC_NOPM, BUILTIN_MIC0, 1, 0,
mic_power_ctl_get, mic_power_ctl_set),
SOC_SINGLE_EXT("MIC1", SND_SOC_NOPM, BUILTIN_MIC1, 1, 0,
mic_power_ctl_get, mic_power_ctl_set),
SOC_SINGLE_EXT("MIC2", SND_SOC_NOPM, BUILTIN_MIC2, 1, 0,
mic_power_ctl_get, mic_power_ctl_set),
SOC_SINGLE_EXT("MIC3", SND_SOC_NOPM, BUILTIN_MIC3, 1, 0,
mic_power_ctl_get, mic_power_ctl_set),
SOC_SINGLE_EXT("MIC Clock Rate", SND_SOC_NOPM, 0, 20000000, 0,
mic_clock_rate_get, NULL),
SOC_SINGLE_EXT("MIC DC Blocker", SND_SOC_NOPM, 0, 1, 0,
mic_dc_blocker_get, mic_dc_blocker_set),
SOC_SINGLE_RANGE_EXT_TLV_modified(
"MIC HW Gain At Lower Power Mode (cB)", SND_SOC_NOPM,
MIC_LOW_POWER_GAIN, MIC_HW_GAIN_IN_CB_MIN,
MIC_HW_GAIN_IN_CB_MAX, 0, mic_hw_gain_get, mic_hw_gain_set,
NULL),
SOC_SINGLE_RANGE_EXT_TLV_modified(
"MIC HW Gain At High Power Mode (cB)", SND_SOC_NOPM,
MIC_HIGH_POWER_GAIN, MIC_HW_GAIN_IN_CB_MIN,
MIC_HW_GAIN_IN_CB_MAX, 0, mic_hw_gain_get, mic_hw_gain_set,
NULL),
SOC_SINGLE_RANGE_EXT_TLV_modified(
"MIC HW Gain (cB)", SND_SOC_NOPM, MIC_CURRENT_GAIN,
MIC_HW_GAIN_IN_CB_MIN, MIC_HW_GAIN_IN_CB_MAX, 0,
mic_hw_gain_get, NULL, NULL),
/* Incall mic and sink mute */
SOC_SINGLE_EXT("Incall Mic Mute", SND_SOC_NOPM, 0, 1, 0, incall_mic_sink_mute_ctl_get,
incall_mic_sink_mute_ctl_set),
SOC_SINGLE_EXT("Incall Sink Mute", SND_SOC_NOPM, 1, 1, 0, incall_mic_sink_mute_ctl_get,
incall_mic_sink_mute_ctl_set),
/* Incall playback0 and playback1 mic source choice */
SOC_SINGLE_EXT("Incall Playback0 Mic Channel", SND_SOC_NOPM, 0, 2, 0, incall_playback_mic_channel_ctl_get,
incall_playback_mic_channel_ctl_set),
SOC_SINGLE_EXT("Incall Playback1 Mic Channel", SND_SOC_NOPM, 1, 2, 0, incall_playback_mic_channel_ctl_get,
incall_playback_mic_channel_ctl_set),
/* UltraSonic Record enable */
SOC_SINGLE_EXT("US Record Enable", SND_SOC_NOPM, 0, 1, 0,
us_record_ctl_get, us_record_ctl_set),
/* LVM enable 1/0 for comp offload */
SOC_SINGLE_EXT("LVM Enable", SND_SOC_NOPM, 0, 1, 0,
lvm_enable_ctl_get, lvm_enable_ctl_set),
SOC_SINGLE_EXT("Decoder Reference Enable", SND_SOC_NOPM, 0, 1, 0,
decoder_ref_enable_ctl_get, decoder_ref_enable_ctl_set),
/* Sidetone switch and tuning parameters */
SOC_SINGLE_EXT("Sidetone Enable", SND_SOC_NOPM, 0, 1, 0,
sidetone_enable_ctl_get, sidetone_enable_ctl_set),
SOC_SINGLE_RANGE_EXT_TLV_modified("Sidetone Volume", SND_SOC_NOPM, SIDETONE_CFG_VOL,
SIDETONE_VOL_MIN, SIDETONE_VOL_MAX, 0,
aoc_sidetone_cfg_ctl_get, aoc_sidetone_cfg_ctl_set, NULL),
SOC_SINGLE_RANGE_EXT_TLV_modified(
"Sidetone Selected Mic", SND_SOC_NOPM, SIDETONE_CFG_MIC_ID, SIDETONE_MIC_ID_MIN,
SIDETONE_MIC_ID_MAX, 0, aoc_sidetone_cfg_ctl_get, aoc_sidetone_cfg_ctl_set, NULL),
SOC_SINGLE_RANGE_EXT_TLV_modified("Sidetone EQ Stage Number", SND_SOC_NOPM,
SIDETONE_CFG_STAGE_NUM, SIDETONE_EQ_STAGE_NUM_MIN,
SIDETONE_EQ_STAGE_NUM_MAX, 0, aoc_sidetone_cfg_ctl_get,
aoc_sidetone_cfg_ctl_set, NULL),
SOC_SINGLE_RANGE_EXT_TLV_modified("Sidetone Biquad0", SND_SOC_NOPM, BIQUAD0,
SIDETONE_BIQUAD_PARAM_MIN, SIDETONE_BIQUAD_PARAM_MAX,
SIDETONE_BIQUAD_PARAM_NUM, aoc_sidetone_eq_ctl_get,
aoc_sidetone_eq_ctl_set, NULL),
SOC_SINGLE_RANGE_EXT_TLV_modified("Sidetone Biquad1", SND_SOC_NOPM, BIQUAD1,
SIDETONE_BIQUAD_PARAM_MIN, SIDETONE_BIQUAD_PARAM_MAX,
SIDETONE_BIQUAD_PARAM_NUM, aoc_sidetone_eq_ctl_get,
aoc_sidetone_eq_ctl_set, NULL),
SOC_SINGLE_RANGE_EXT_TLV_modified("Sidetone Biquad2", SND_SOC_NOPM, BIQUAD2,
SIDETONE_BIQUAD_PARAM_MIN, SIDETONE_BIQUAD_PARAM_MAX,
SIDETONE_BIQUAD_PARAM_NUM, aoc_sidetone_eq_ctl_get,
aoc_sidetone_eq_ctl_set, NULL),
SOC_SINGLE_RANGE_EXT_TLV_modified("Sidetone Biquad3", SND_SOC_NOPM, BIQUAD3,
SIDETONE_BIQUAD_PARAM_MIN, SIDETONE_BIQUAD_PARAM_MAX,
SIDETONE_BIQUAD_PARAM_NUM, aoc_sidetone_eq_ctl_get,
aoc_sidetone_eq_ctl_set, NULL),
SOC_SINGLE_RANGE_EXT_TLV_modified("Sidetone Biquad4", SND_SOC_NOPM, BIQUAD4,
SIDETONE_BIQUAD_PARAM_MIN, SIDETONE_BIQUAD_PARAM_MAX,
SIDETONE_BIQUAD_PARAM_NUM, aoc_sidetone_eq_ctl_get,
aoc_sidetone_eq_ctl_set, NULL),
SOC_SINGLE_RANGE_EXT_TLV_modified("MIC Record Soft Gain (dB)", SND_SOC_NOPM, 0,
AOC_MIC_RECORD_GAIN_IN_DB_MIN,
AOC_MIC_RECORD_GAIN_IN_DB_MAX, 1, mic_record_gain_ctl_get,
mic_record_gain_ctl_set, NULL),
SOC_SINGLE_RANGE_EXT_TLV_modified("Mmap Record Gain", SND_SOC_NOPM, 0,
MMAP_MIC_RECORD_GAIN_IN_DB_MIN,
MMAP_MIC_RECORD_GAIN_IN_DB_MAX, 1,
mmap_record_gain_ctl_get,
mmap_record_gain_ctl_set, NULL),
SOC_SINGLE_EXT("Compress Offload Volume", SND_SOC_NOPM, 0, 100, 0, compr_offload_volume_get,
compr_offload_volume_set),
SOC_SINGLE_RANGE_EXT_TLV_modified("Compress Offload Gain (L and R)", SND_SOC_NOPM, 0,
COMPRE_OFFLOAD_GAIN_MIN, COMPRE_OFFLOAD_GAIN_MAX, 2,
aoc_compr_offload_gain_ctl_get,
aoc_compr_offload_gain_ctl_set, NULL),
SOC_SINGLE_EXT("Voice Call Rx Volume", SND_SOC_NOPM, 0, 100, 0, NULL,
NULL),
SOC_SINGLE_EXT("VOIP Rx Volume", SND_SOC_NOPM, 0, 100, 0, NULL, NULL),
SOC_SINGLE_EXT("PCM Stream Wait Time in MSec", SND_SOC_NOPM, 0, 1000000, 0, pcm_wait_time_get,
pcm_wait_time_set),
SOC_SINGLE_EXT("CCA Module Load", SND_SOC_NOPM, 0, 1, 0,
audio_cca_module_load_ctl_get, audio_cca_module_load_ctl_set),
SOC_SINGLE_EXT("Gapless Offload Enable", SND_SOC_NOPM, 0, 1, 0,
audio_gapless_offload_ctl_get, audio_gapless_offload_ctl_set),
SOC_SINGLE_EXT("Voice PCM Stream Wait Time in MSec", SND_SOC_NOPM, 0, 10000, 0,
voice_pcm_wait_time_get, voice_pcm_wait_time_set),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "A2DP Encoder Parameters",
.index = 0,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.private_value = A2DP_ENCODER_PARAMETERS,
.info = snd_aoc_ctl_info,
.get = a2dp_encoder_parameters_get,
.put = a2dp_encoder_parameters_put,
.count = 1,
},
SOC_SINGLE_EXT("AoC Chirp Enable", SND_SOC_NOPM, 0, 1, 0,
aoc_audio_chirp_enable_get, aoc_audio_chirp_enable_set),
SOC_SINGLE_RANGE_EXT_TLV_modified("AoC Chirp Interval", SND_SOC_NOPM,
0, 20, 200, 0, aoc_audio_chirp_interval_get, aoc_audio_chirp_interval_set, NULL),
SOC_SINGLE_RANGE_EXT_TLV_modified("AoC Chirp Mode", SND_SOC_NOPM,
0, 0, 10, 0, aoc_audio_chirp_mode_get, aoc_audio_chirp_mode_set, NULL),
SOC_SINGLE_RANGE_EXT_TLV_modified("CHRE SRC PDM Gain (cB)", SND_SOC_NOPM,
CHRE_GAIN_PATH_PDM, -1280, 1280, 0, aoc_audio_chre_src_gain_get, aoc_audio_chre_src_gain_set, NULL),
SOC_SINGLE_RANGE_EXT_TLV_modified("CHRE SRC AEC Gain (cB)", SND_SOC_NOPM,
CHRE_GAIN_PATH_AEC, -1280, 1280, 0, aoc_audio_chre_src_gain_get, aoc_audio_chre_src_gain_set, NULL),
SOC_SINGLE_RANGE_EXT_TLV_modified("CHRE SRC AEC Timeout in MSec", SND_SOC_NOPM,
0, 0, 60000, 0, aoc_audio_chre_src_aec_timeout_get, aoc_audio_chre_src_aec_timeout_set, NULL),
};
int snd_aoc_new_ctl(struct aoc_chip *chip)
{
int err;
unsigned int idx;
strcpy(chip->card->mixername, "Aoc Mixer");
for (idx = 0; idx < ARRAY_SIZE(snd_aoc_ctl); idx++) {
err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_aoc_ctl[idx], chip));
if (err < 0)
return err;
}
return 0;
}
EXPORT_SYMBOL_GPL(snd_aoc_new_ctl);