From: Richard Fitzgerald Date: Tue, 11 Nov 2025 13:08:49 +0000 (+0000) Subject: ASoC: cs35l56: Add control to read CAL_SET_STATUS X-Git-Tag: v6.19-rc1~156^2~3^2~51^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=69f3474a01e9867dd99fc4b703fa834ea1835c7d;p=thirdparty%2Fkernel%2Flinux.git ASoC: cs35l56: Add control to read CAL_SET_STATUS Create an ALSA control to read the value of the firmware CAL_SET_STATUS control. This reports whether the firmware is using a calibration blob or the default calibration from the .bin file. The firmware only reports a valid value in this register while audio is actually playing and the internal PLL is locked to the audio clock. Otherwise it returns a status of "unknown". Signed-off-by: Richard Fitzgerald Link: https://patch.msgid.link/20251111130850.513969-2-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h index 0a740a99ad314..bd13958bf19db 100644 --- a/include/sound/cs35l56.h +++ b/include/sound/cs35l56.h @@ -16,6 +16,8 @@ #include #include +struct snd_ctl_elem_value; + #define CS35L56_DEVID 0x0000000 #define CS35L56_REVID 0x0000004 #define CS35L56_RELID 0x000000C @@ -268,6 +270,10 @@ #define CS35L56_CAL_STATUS_SUCCESS 1 #define CS35L56_CAL_STATUS_OUT_OF_RANGE 3 +#define CS35L56_CAL_SET_STATUS_UNKNOWN 0 +#define CS35L56_CAL_SET_STATUS_DEFAULT 1 +#define CS35L56_CAL_SET_STATUS_SET 2 + #define CS35L56_CONTROL_PORT_READY_US 2200 #define CS35L56_HALO_STATE_POLL_US 1000 #define CS35L56_HALO_STATE_TIMEOUT_US 250000 @@ -363,6 +369,7 @@ extern const struct regmap_config cs35l63_regmap_i2c; extern const struct regmap_config cs35l63_regmap_sdw; extern const struct cirrus_amp_cal_controls cs35l56_calibration_controls; +extern const char * const cs35l56_cal_set_status_text[3]; extern const char * const cs35l56_tx_input_texts[CS35L56_NUM_INPUT_SRC]; extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC]; @@ -396,6 +403,8 @@ ssize_t cs35l56_cal_data_debugfs_write(struct cs35l56_base *cs35l56_base, void cs35l56_create_cal_debugfs(struct cs35l56_base *cs35l56_base, const struct cs35l56_cal_debugfs_fops *fops); void cs35l56_remove_cal_debugfs(struct cs35l56_base *cs35l56_base); +int cs35l56_cal_set_status_get(struct cs35l56_base *cs35l56_base, + struct snd_ctl_elem_value *uvalue); int cs35l56_read_prot_status(struct cs35l56_base *cs35l56_base, bool *fw_missing, unsigned int *fw_version); void cs35l56_log_tuning(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_dsp); diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index fe0693c3f7dee..4fba4127c40c6 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -1262,6 +1262,54 @@ void cs35l56_remove_cal_debugfs(struct cs35l56_base *cs35l56_base) } EXPORT_SYMBOL_NS_GPL(cs35l56_remove_cal_debugfs, "SND_SOC_CS35L56_SHARED"); +const char * const cs35l56_cal_set_status_text[] = { + "Unknown", "Default", "Set", +}; +EXPORT_SYMBOL_NS_GPL(cs35l56_cal_set_status_text, "SND_SOC_CS35L56_SHARED"); + +int cs35l56_cal_set_status_get(struct cs35l56_base *cs35l56_base, + struct snd_ctl_elem_value *uvalue) +{ + struct cs_dsp *dsp = cs35l56_base->dsp; + __be32 cal_set_status_be; + int alg_id; + int ret; + + switch (cs35l56_base->type) { + case 0x54: + case 0x56: + case 0x57: + alg_id = 0x9f210; + break; + default: + alg_id = 0xbf210; + break; + } + + scoped_guard(mutex, &dsp->pwr_lock) { + ret = cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(dsp, + "CAL_SET_STATUS", + WMFW_ADSP2_YM, alg_id), + 0, &cal_set_status_be, + sizeof(cal_set_status_be)); + } + if (ret) { + uvalue->value.enumerated.item[0] = CS35L56_CAL_SET_STATUS_UNKNOWN; + return 0; + } + + switch (be32_to_cpu(cal_set_status_be)) { + case CS35L56_CAL_SET_STATUS_DEFAULT: + case CS35L56_CAL_SET_STATUS_SET: + uvalue->value.enumerated.item[0] = be32_to_cpu(cal_set_status_be); + return 0; + default: + uvalue->value.enumerated.item[0] = CS35L56_CAL_SET_STATUS_UNKNOWN; + return 0; + } +} +EXPORT_SYMBOL_NS_GPL(cs35l56_cal_set_status_get, "SND_SOC_CS35L56_SHARED"); + int cs35l56_read_prot_status(struct cs35l56_base *cs35l56_base, bool *fw_missing, unsigned int *fw_version) { diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index 091a723255078..e1eb7360b0584 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -66,6 +66,18 @@ static int cs35l56_dspwait_put_volsw(struct snd_kcontrol *kcontrol, static DECLARE_TLV_DB_SCALE(vol_tlv, -10000, 25, 0); +static SOC_ENUM_SINGLE_DECL(cs35l56_cal_set_status_enum, SND_SOC_NOPM, 0, + cs35l56_cal_set_status_text); + +static int cs35l56_cal_set_status_ctl_get(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); + + return cs35l56_cal_set_status_get(&cs35l56->base, ucontrol); +} + static const struct snd_kcontrol_new cs35l56_controls[] = { SOC_SINGLE_EXT("Speaker Switch", CS35L56_MAIN_RENDER_USER_MUTE, 0, 1, 1, @@ -83,6 +95,8 @@ static const struct snd_kcontrol_new cs35l56_controls[] = { SOC_SINGLE_EXT("Posture Number", CS35L56_MAIN_POSTURE_NUMBER, 0, 255, 0, cs35l56_dspwait_get_volsw, cs35l56_dspwait_put_volsw), + SOC_ENUM_EXT("CAL_SET_STATUS", cs35l56_cal_set_status_enum, + cs35l56_cal_set_status_ctl_get, NULL), }; static const struct snd_kcontrol_new cs35l63_controls[] = { @@ -102,6 +116,8 @@ static const struct snd_kcontrol_new cs35l63_controls[] = { SOC_SINGLE_EXT("Posture Number", CS35L63_MAIN_POSTURE_NUMBER, 0, 255, 0, cs35l56_dspwait_get_volsw, cs35l56_dspwait_put_volsw), + SOC_ENUM_EXT("CAL_SET_STATUS", cs35l56_cal_set_status_enum, + cs35l56_cal_set_status_ctl_get, NULL), }; static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx1_enum,