// SPDX-License-Identifier: GPL-2.0-only
//
// Driver for Cirrus Logic CS35L56 smart amp
//
// Copyright (C) 2023 Cirrus Logic, Inc. and
// Cirrus Logic International Semiconductor Ltd.
#include <linux/acpi.h>
#include <linux/array_size.h>
#include <linux/completion.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/math.h>
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/soundwire/sdw.h>
#include <linux/types.h>
#include <linux/workqueue.h>
#include <sound/cs-amp-lib.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
#include "wm_adsp.h"
#include "cs35l56.h"
static int cs35l56_dsp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
static void cs35l56_wait_dsp_ready(struct cs35l56_private *cs35l56)
{
/* Wait for patching to complete */
flush_work(&cs35l56->dsp_work);
}
static int cs35l56_dspwait_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
cs35l56_wait_dsp_ready(cs35l56);
return snd_soc_get_volsw(kcontrol, ucontrol);
}
static int cs35l56_dspwait_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
cs35l56_wait_dsp_ready(cs35l56);
return snd_soc_put_volsw(kcontrol, ucontrol);
}
static DECLARE_TLV_DB_SCALE(vol_tlv, -10000, 25, 0);
static const struct snd_kcontrol_new cs35l56_controls[] = {
SOC_SINGLE_EXT("Speaker Switch",
CS35L56_MAIN_RENDER_USER_MUTE, 0, 1, 1,
cs35l56_dspwait_get_volsw, cs35l56_dspwait_put_volsw),
SOC_SINGLE_S_EXT_TLV("Speaker Volume",
CS35L56_MAIN_RENDER_USER_VOLUME,
CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT,
CS35L56_MAIN_RENDER_USER_VOLUME_MIN,
CS35L56_MAIN_RENDER_USER_VOLUME_MAX,
CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT,
0,
cs35l56_dspwait_get_volsw,
cs35l56_dspwait_put_volsw,
vol_tlv),
SOC_SINGLE_EXT("Posture Number", CS35L56_MAIN_POSTURE_NUMBER,
0, 255, 0,
cs35l56_dspwait_get_volsw, cs35l56_dspwait_put_volsw),
};
static const struct snd_kcontrol_new cs35l63_controls[] = {
SOC_SINGLE_EXT("Speaker Switch",
CS35L63_MAIN_RENDER_USER_MUTE, 0, 1, 1,
cs35l56_dspwait_get_volsw, cs35l56_dspwait_put_volsw),
SOC_SINGLE_S_EXT_TLV("Speaker Volume",
CS35L63_MAIN_RENDER_USER_VOLUME,
CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT,
CS35L56_MAIN_RENDER_USER_VOLUME_MIN,
CS35L56_MAIN_RENDER_USER_VOLUME_MAX,
CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT,
0,
cs35l56_dspwait_get_volsw,
cs35l56_dspwait_put_volsw,
vol_tlv),
SOC_SINGLE_EXT("Posture Number", CS35L63_MAIN_POSTURE_NUMBER,
0, 255, 0,
cs35l56_dspwait_get_volsw, cs35l56_dspwait_put_volsw),
};
static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx1_enum,
CS35L56_ASP1TX1_INPUT,
0, CS35L56_ASP_TXn_SRC_MASK,
cs35l56_tx_input_texts,
cs35l56_tx_input_values);
static const struct snd_kcontrol_new asp1_tx1_mux =
SOC_DAPM_ENUM("ASP1TX1 SRC", cs35l56_asp1tx1_enum);
static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx2_enum,
CS35L56_ASP1TX2_INPUT,
0, CS35L56_ASP_TXn_SRC_MASK,
cs35l56_tx_input_texts,
cs35l56_tx_input_values);
static const struct snd_kcontrol_new asp1_tx2_mux =
SOC_DAPM_ENUM("ASP1TX2 SRC", cs35l56_asp1tx2_enum);
static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx3_enum,
CS35L56_ASP1TX3_INPUT,
0, CS35L56_ASP_TXn_SRC_MASK,
cs35l56_tx_input_texts,
cs35l56_tx_input_values);
static const struct snd_kcontrol_new asp1_tx3_mux =
SOC_DAPM_ENUM("ASP1TX3 SRC", cs35l56_asp1tx3_enum);
static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx4_enum,
CS35L56_ASP1TX4_INPUT,
0, CS35L56_ASP_TXn_SRC_MASK,
cs35l56_tx_input_texts,
cs35l56_tx_input_values);
static const struct snd_kcontrol_new asp1_tx4_mux =
SOC_DAPM_ENUM("ASP1TX4 SRC", cs35l56_asp1tx4_enum);
static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_sdw1tx1_enum,
CS35L56_SWIRE_DP3_CH1_INPUT,
0, CS35L56_SWIRETXn_SRC_MASK,
cs35l56_tx_input_texts,
cs35l56_tx_input_values);
static const struct snd_kcontrol_new sdw1_tx1_mux =
SOC_DAPM_ENUM("SDW1TX1 SRC", cs35l56_sdw1tx1_enum);
static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_sdw1tx2_enum,
CS35L56_SWIRE_DP3_CH2_INPUT,
0, CS35L56_SWIRETXn_SRC_MASK,
cs35l56_tx_input_texts,
cs35l56_tx_input_values);
static const struct snd_kcontrol_new sdw1_tx2_mux =
SOC_DAPM_ENUM("SDW1TX2 SRC", cs35l56_sdw1tx2_enum);
static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_sdw1tx3_enum,
CS35L56_SWIRE_DP3_CH3_INPUT,
0, CS35L56_SWIRETXn_SRC_MASK,
cs35l56_tx_input_texts,
cs35l56_tx_input_values);
static const struct snd_kcontrol_new sdw1_tx3_mux =
SOC_DAPM_ENUM("SDW1TX3 SRC", cs35l56_sdw1tx3_enum);
static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_sdw1tx4_enum,
CS35L56_SWIRE_DP3_CH4_INPUT,
0, CS35L56_SWIRETXn_SRC_MASK,
cs35l56_tx_input_texts,
cs35l56_tx_input_values);
static const struct snd_kcontrol_new sdw1_tx4_mux =
SOC_DAPM_ENUM("SDW1TX4 SRC", cs35l56_sdw1tx4_enum);
static int cs35l56_play_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
unsigned int val;
int ret;
dev_dbg(cs35l56->base.dev, "play: %d\n", event);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
/* Don't wait for ACK, we check in POST_PMU that it completed */
return regmap_write(cs35l56->base.regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
CS35L56_MBOX_CMD_AUDIO_PLAY);
case SND_SOC_DAPM_POST_PMU:
/* Wait for firmware to enter PS0 power state */
ret = regmap_read_poll_timeout(cs35l56->base.regmap,
cs35l56->base.fw_reg->transducer_actual_ps
|