[PATCH v3] ASoC: codecs: wsa883x: add control, dapm widgets and map
Add controls, dapm widgets along with route.
Signed-off-by: Srinivas Kandagatla srinivas.kandagatla@linaro.org --- Changes since v2: - updated dev mode text entries to start with Capital letter
sound/soc/codecs/wsa883x.c | 200 +++++++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+)
diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c index 856709ec017e..e8f519e89213 100644 --- a/sound/soc/codecs/wsa883x.c +++ b/sound/soc/codecs/wsa883x.c @@ -473,6 +473,19 @@ enum wsa_port_ids { WSA883X_PORT_VISENSE, };
+static const char * const wsa_dev_mode_text[] = { + "Speaker", "Receiver", "Ultrasound" +}; + +enum { + SPEAKER, + RECEIVER, + ULTRASOUND, +}; + +static const struct soc_enum wsa_dev_mode_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wsa_dev_mode_text), wsa_dev_mode_text); + /* 4 ports */ static struct sdw_dpn_prop wsa_sink_dpn_prop[WSA883X_MAX_SWR_PORTS] = { { @@ -1066,6 +1079,94 @@ static struct sdw_slave_ops wsa883x_slave_ops = { .port_prep = wsa883x_port_prep, };
+static int wsa_dev_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component); + + ucontrol->value.enumerated.item[0] = wsa883x->dev_mode; + + return 0; +} + +static int wsa_dev_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component); + + if (wsa883x->dev_mode == ucontrol->value.enumerated.item[0]) + return 0; + + wsa883x->dev_mode = ucontrol->value.enumerated.item[0]; + + return 1; +} + +static const DECLARE_TLV_DB_SCALE(pa_gain, -300, 150, -300); + +static int wsa883x_get_swr_port(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); + struct wsa883x_priv *data = snd_soc_component_get_drvdata(comp); + struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value; + int portidx = mixer->reg; + + ucontrol->value.integer.value[0] = data->port_enable[portidx]; + + return 0; +} + +static int wsa883x_set_swr_port(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); + struct wsa883x_priv *data = snd_soc_component_get_drvdata(comp); + struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value; + int portidx = mixer->reg; + + if (ucontrol->value.integer.value[0]) { + if (data->port_enable[portidx]) + return 0; + + data->port_enable[portidx] = true; + } else { + if (!data->port_enable[portidx]) + return 0; + + data->port_enable[portidx] = false; + } + + return 1; +} + +static int wsa883x_get_comp_offset(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = wsa883x->comp_offset; + + return 0; +} + +static int wsa883x_set_comp_offset(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component); + + if (wsa883x->comp_offset == ucontrol->value.integer.value[0]) + return 0; + + wsa883x->comp_offset = ucontrol->value.integer.value[0]; + + return 1; +} + static int wsa883x_codec_probe(struct snd_soc_component *comp) { struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(comp); @@ -1075,9 +1176,108 @@ static int wsa883x_codec_probe(struct snd_soc_component *comp) return 0; }
+static int wsa883x_spkr_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 wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + switch (wsa883x->dev_mode) { + case RECEIVER: + snd_soc_component_write_field(component, WSA883X_CDC_PATH_MODE, + WSA883X_RXD_MODE_MASK, + WSA883X_RXD_MODE_HIFI); + snd_soc_component_write_field(component, WSA883X_SPKR_PWM_CLK_CTL, + WSA883X_SPKR_PWM_FREQ_SEL_MASK, + WSA883X_SPKR_PWM_FREQ_F600KHZ); + snd_soc_component_write_field(component, WSA883X_DRE_CTL_0, + WSA883X_DRE_PROG_DELAY_MASK, 0x0); + break; + case SPEAKER: + snd_soc_component_write_field(component, WSA883X_CDC_PATH_MODE, + WSA883X_RXD_MODE_MASK, + WSA883X_RXD_MODE_NORMAL); + snd_soc_component_write_field(component, WSA883X_SPKR_PWM_CLK_CTL, + WSA883X_SPKR_PWM_FREQ_SEL_MASK, + WSA883X_SPKR_PWM_FREQ_F300KHZ); + snd_soc_component_write_field(component, WSA883X_DRE_CTL_0, + WSA883X_DRE_PROG_DELAY_MASK, 0x9); + default: + break; + } + + snd_soc_component_write_field(component, WSA883X_DRE_CTL_1, + WSA883X_DRE_GAIN_EN_MASK, + WSA883X_DRE_GAIN_FROM_CSR); + if (wsa883x->port_enable[WSA883X_PORT_COMP]) + snd_soc_component_write_field(component, WSA883X_DRE_CTL_0, + WSA883X_DRE_OFFSET_MASK, + wsa883x->comp_offset); + snd_soc_component_write_field(component, WSA883X_VBAT_ADC_FLT_CTL, + WSA883X_VBAT_ADC_COEF_SEL_MASK, + WSA883X_VBAT_ADC_COEF_F_1DIV16); + snd_soc_component_write_field(component, WSA883X_VBAT_ADC_FLT_CTL, + WSA883X_VBAT_ADC_FLT_EN_MASK, 0x1); + snd_soc_component_write_field(component, WSA883X_PDM_WD_CTL, + WSA883X_PDM_EN_MASK, + WSA883X_PDM_ENABLE); + snd_soc_component_write_field(component, WSA883X_PA_FSM_CTL, + WSA883X_GLOBAL_PA_EN_MASK, + WSA883X_GLOBAL_PA_ENABLE); + + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_component_write_field(component, WSA883X_VBAT_ADC_FLT_CTL, + WSA883X_VBAT_ADC_FLT_EN_MASK, 0x0); + snd_soc_component_write_field(component, WSA883X_VBAT_ADC_FLT_CTL, + WSA883X_VBAT_ADC_COEF_SEL_MASK, + WSA883X_VBAT_ADC_COEF_F_1DIV2); + snd_soc_component_write_field(component, WSA883X_PA_FSM_CTL, + WSA883X_GLOBAL_PA_EN_MASK, 0); + snd_soc_component_write_field(component, WSA883X_PDM_WD_CTL, + WSA883X_PDM_EN_MASK, 0); + break; + } + return 0; +} + +static const struct snd_soc_dapm_widget wsa883x_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("IN"), + SND_SOC_DAPM_SPK("SPKR", wsa883x_spkr_event), +}; + +static const struct snd_kcontrol_new wsa883x_snd_controls[] = { + SOC_SINGLE_RANGE_TLV("PA Volume", WSA883X_DRE_CTL_1, 1, + 0x0, 0x1f, 1, pa_gain), + SOC_ENUM_EXT("WSA MODE", wsa_dev_mode_enum, + wsa_dev_mode_get, wsa_dev_mode_put), + SOC_SINGLE_EXT("COMP Offset", SND_SOC_NOPM, 0, 4, 0, + wsa883x_get_comp_offset, wsa883x_set_comp_offset), + SOC_SINGLE_EXT("DAC Switch", WSA883X_PORT_DAC, 0, 1, 0, + wsa883x_get_swr_port, wsa883x_set_swr_port), + SOC_SINGLE_EXT("COMP Switch", WSA883X_PORT_COMP, 0, 1, 0, + wsa883x_get_swr_port, wsa883x_set_swr_port), + SOC_SINGLE_EXT("BOOST Switch", WSA883X_PORT_BOOST, 0, 1, 0, + wsa883x_get_swr_port, wsa883x_set_swr_port), + SOC_SINGLE_EXT("VISENSE Switch", WSA883X_PORT_VISENSE, 0, 1, 0, + wsa883x_get_swr_port, wsa883x_set_swr_port), +}; + +static const struct snd_soc_dapm_route wsa883x_audio_map[] = { + {"SPKR", NULL, "IN"}, +}; + static const struct snd_soc_component_driver wsa883x_component_drv = { .name = "WSA883x", .probe = wsa883x_codec_probe, + .controls = wsa883x_snd_controls, + .num_controls = ARRAY_SIZE(wsa883x_snd_controls), + .dapm_widgets = wsa883x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wsa883x_dapm_widgets), + .dapm_routes = wsa883x_audio_map, + .num_dapm_routes = ARRAY_SIZE(wsa883x_audio_map), };
static int wsa883x_hw_params(struct snd_pcm_substream *substream,
On Thu, 30 Jun 2022 13:36:33 +0100, Srinivas Kandagatla wrote:
Add controls, dapm widgets along with route.
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
Thanks!
[1/1] ASoC: codecs: wsa883x: add control, dapm widgets and map commit: cdb09e6231433b65e31c40fbe298099db6513a7f
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
participants (2)
-
Mark Brown
-
Srinivas Kandagatla