From 2466b62268c020606d20b45e007c166399e639ee Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 6 Feb 2025 01:53:08 +0900 Subject: [PATCH 01/16] ASoC: dapm: unexport dapm_mark_endpoints_dirty() The symbol provider (sound/soc/soc-dapm.c) and the symbol consumer (sound/soc/soc-core.c) belong to the same module, snd-soc-core.ko. There is no need to export it. I deleted the comment, as other modules cannot use it any more. Signed-off-by: Masahiro Yamada Link: https://patch.msgid.link/20250205165310.3466254-1-masahiroy@kernel.org Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 2 -- sound/soc/soc-dapm.c | 1 - 2 files changed, 3 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 12cd7b5a2202..7cf52c8c9cf3 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -514,8 +514,6 @@ int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, const char int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin); int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, const char *pin); unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol); - -/* Mostly internal - should not normally be used */ void dapm_mark_endpoints_dirty(struct snd_soc_card *card); /* dapm path query */ diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index a4d78af45e4b..420fe7dea31e 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -317,7 +317,6 @@ void dapm_mark_endpoints_dirty(struct snd_soc_card *card) snd_soc_dapm_mutex_unlock(card); } -EXPORT_SYMBOL_GPL(dapm_mark_endpoints_dirty); /* create a new dapm widget */ static inline struct snd_soc_dapm_widget *dapm_cnew_widget( -- 2.51.0 From 4c7518062d638837cea915e0ffe30f846780639a Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 6 Feb 2025 10:52:37 +0200 Subject: [PATCH 02/16] ASoC: SOF: ipc4: Add support for split firmware releases A split SOF release consists of a base firmware and two libraries: -openmodules.ri for processing (audio) modules -debug.ri for debug and developer modules To handle this new release model add infrastructure to try to load the two library after boot optionally. This approach will allow flexibility on handling platforms in sof-bin with single or split configuration: single release: base firmware only split release: base firmware + openmodules + debug The files for the split firmware are located at the firmware directory. Signed-off-by: Peter Ujfalusi Reviewed-by: Guennadi Liakhovetski Reviewed-by: Kai Vehmanen Reviewed-by: Ranjani Sridharan Link: https://patch.msgid.link/20250206085237.19214-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-loader.c | 143 +++++++++++++++++++++++++++++------- sound/soc/sof/ipc4-priv.h | 1 + sound/soc/sof/ipc4.c | 8 +- 3 files changed, 126 insertions(+), 26 deletions(-) diff --git a/sound/soc/sof/ipc4-loader.c b/sound/soc/sof/ipc4-loader.c index bcdb33d03682..6ad1ef0e53e8 100644 --- a/sound/soc/sof/ipc4-loader.c +++ b/sound/soc/sof/ipc4-loader.c @@ -169,21 +169,14 @@ static size_t sof_ipc4_fw_parse_basefw_ext_man(struct snd_sof_dev *sdev) return payload_offset; } -static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev, - unsigned long lib_id, const guid_t *uuid) +static int sof_ipc4_load_library(struct snd_sof_dev *sdev, unsigned long lib_id, + const char *lib_filename, bool optional) { struct sof_ipc4_fw_data *ipc4_data = sdev->private; struct sof_ipc4_fw_library *fw_lib; - const char *fw_filename; ssize_t payload_offset; int ret, i, err; - if (!sdev->pdata->fw_lib_prefix) { - dev_err(sdev->dev, - "Library loading is not supported due to not set library path\n"); - return -EINVAL; - } - if (!ipc4_data->load_library) { dev_err(sdev->dev, "Library loading is not supported on this platform\n"); return -EOPNOTSUPP; @@ -193,21 +186,26 @@ static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev, if (!fw_lib) return -ENOMEM; - fw_filename = kasprintf(GFP_KERNEL, "%s/%pUL.bin", - sdev->pdata->fw_lib_prefix, uuid); - if (!fw_filename) { - ret = -ENOMEM; - goto free_fw_lib; - } - - ret = request_firmware(&fw_lib->sof_fw.fw, fw_filename, sdev->dev); - if (ret < 0) { - dev_err(sdev->dev, "Library file '%s' is missing\n", fw_filename); - goto free_filename; + if (optional) { + ret = firmware_request_nowarn(&fw_lib->sof_fw.fw, lib_filename, + sdev->dev); + if (ret < 0) { + /* optional library, override the error */ + ret = 0; + goto free_fw_lib; + } } else { - dev_dbg(sdev->dev, "Library file '%s' loaded\n", fw_filename); + ret = request_firmware(&fw_lib->sof_fw.fw, lib_filename, + sdev->dev); + if (ret < 0) { + dev_err(sdev->dev, "Library file '%s' is missing\n", + lib_filename); + goto free_fw_lib; + } } + dev_dbg(sdev->dev, "Library file '%s' loaded\n", lib_filename); + payload_offset = sof_ipc4_fw_parse_ext_man(sdev, fw_lib); if (payload_offset <= 0) { if (!payload_offset) @@ -251,22 +249,117 @@ static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev, if (unlikely(ret)) goto release; - kfree(fw_filename); - return 0; release: release_firmware(fw_lib->sof_fw.fw); /* Allocated within sof_ipc4_fw_parse_ext_man() */ devm_kfree(sdev->dev, fw_lib->modules); -free_filename: - kfree(fw_filename); free_fw_lib: devm_kfree(sdev->dev, fw_lib); return ret; } +/** + * sof_ipc4_complete_split_release - loads the library parts of a split firmware + * @sdev: SOF device + * + * With IPC4 the firmware can be a single binary or a split release. + * - single binary: only the basefw + * - split release: basefw and two libraries (openmodules, debug) + * + * With split firmware release it is also allowed that for example only the + * debug library is present (the openmodules content is built in the basefw). + * + * To handle the permutations try to load the openmodules then the debug + * libraries as optional ones after the basefw boot. + * + * The libraries for the split release are stored alongside the basefw on the + * filesystem. + */ +int sof_ipc4_complete_split_release(struct snd_sof_dev *sdev) +{ + static const char * const lib_bundle[] = { "openmodules", "debug" }; + const char *fw_filename = sdev->pdata->fw_filename; + const char *lib_filename, *p; + size_t lib_name_base_size; + unsigned long lib_id = 1; + char *lib_name_base; + int i; + + p = strstr(fw_filename, ".ri"); + if (!p || strlen(p) != 3) { + dev_info(sdev->dev, + "%s: Firmware name '%s' is missing .ri extension\n", + __func__, fw_filename); + return 0; + } + + /* Space for the firmware basename + '\0', without the extension */ + lib_name_base_size = strlen(fw_filename) - 2; + lib_name_base = kzalloc(lib_name_base_size, GFP_KERNEL); + if (!lib_name_base) + return -ENOMEM; + + /* + * strscpy will 0 terminate the copied string, removing the '.ri' from + * the end of the fw_filename, for example: + * fw_filename: "sof-ptl.ri\0" + * lib_name_base: "sof-ptl\0" + */ + strscpy(lib_name_base, fw_filename, lib_name_base_size); + + for (i = 0; i < ARRAY_SIZE(lib_bundle); i++) { + int ret; + + lib_filename = kasprintf(GFP_KERNEL, "%s/%s-%s.ri", + sdev->pdata->fw_filename_prefix, + lib_name_base, lib_bundle[i]); + if (!lib_filename) { + kfree(lib_name_base); + return -ENOMEM; + } + + ret = sof_ipc4_load_library(sdev, lib_id, lib_filename, true); + if (ret) + dev_warn(sdev->dev, "%s: Failed to load %s: %d\n", + __func__, lib_filename, ret); + else + lib_id++; + + kfree(lib_filename); + } + + kfree(lib_name_base); + + return 0; +} + +static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev, + unsigned long lib_id, const guid_t *uuid) +{ + const char *lib_filename; + int ret; + + if (!sdev->pdata->fw_lib_prefix) { + dev_err(sdev->dev, + "Library loading is not supported due to not set library path\n"); + return -EINVAL; + } + + lib_filename = kasprintf(GFP_KERNEL, "%s/%pUL.bin", + sdev->pdata->fw_lib_prefix, uuid); + if (!lib_filename) + return -ENOMEM; + + ret = sof_ipc4_load_library(sdev, lib_id, lib_filename, false); + + kfree(lib_filename); + + return ret; +} + struct sof_ipc4_fw_module *sof_ipc4_find_module_by_uuid(struct snd_sof_dev *sdev, const guid_t *uuid) { diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h index ea3323b90343..b798810eff91 100644 --- a/sound/soc/sof/ipc4-priv.h +++ b/sound/soc/sof/ipc4-priv.h @@ -101,6 +101,7 @@ extern const struct sof_ipc_fw_tracing_ops ipc4_mtrace_ops; int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 instance_id, u32 state); int sof_ipc4_mtrace_update_pos(struct snd_sof_dev *sdev, int core); +int sof_ipc4_complete_split_release(struct snd_sof_dev *sdev); int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev); int sof_ipc4_reload_fw_libraries(struct snd_sof_dev *sdev); struct sof_ipc4_fw_module *sof_ipc4_find_module_by_uuid(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c index 4386cbae16d4..2ed0c52fb2f1 100644 --- a/sound/soc/sof/ipc4.c +++ b/sound/soc/sof/ipc4.c @@ -825,8 +825,14 @@ static void sof_ipc4_exit(struct snd_sof_dev *sdev) static int sof_ipc4_post_boot(struct snd_sof_dev *sdev) { - if (sdev->first_boot) + if (sdev->first_boot) { + int ret = sof_ipc4_complete_split_release(sdev); + + if (ret) + return ret; + return sof_ipc4_query_fw_configuration(sdev); + } return sof_ipc4_reload_fw_libraries(sdev); } -- 2.51.0 From 943116ba2a6ab472e8ad2d1e57a3f10f13485cc2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 5 Feb 2025 00:16:10 +0000 Subject: [PATCH 03/16] ASoC: add common snd_soc_ret() and use it Each soc-xxx.c is using own snd_xxx_ret(), but we want to share it. Let's add common snd_soc_ret() for it. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87frkt2qlx.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc.h | 1 + sound/soc/soc-card.c | 14 ++------------ sound/soc/soc-component.c | 38 +++++++++++++------------------------- sound/soc/soc-dai.c | 18 ++---------------- sound/soc/soc-link.c | 18 ++---------------- sound/soc/soc-pcm.c | 18 ++---------------- sound/soc/soc-utils.c | 26 ++++++++++++++++++++++++++ 7 files changed, 48 insertions(+), 85 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index fcdb5adfcd5e..16e4e488521c 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -539,6 +539,7 @@ int snd_soc_calc_bclk(int fs, int sample_size, int channels, int tdm_slots); int snd_soc_params_to_bclk(const struct snd_pcm_hw_params *parms); int snd_soc_tdm_params_to_bclk(const struct snd_pcm_hw_params *params, int tdm_width, int tdm_slots, int slot_multiple); +int snd_soc_ret(const struct device *dev, int ret, const char *fmt, ...); /* set runtime hw params */ static inline int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, diff --git a/sound/soc/soc-card.c b/sound/soc/soc-card.c index e6eb71b3010a..235427d69061 100644 --- a/sound/soc/soc-card.c +++ b/sound/soc/soc-card.c @@ -15,18 +15,8 @@ static inline int _soc_card_ret(struct snd_soc_card *card, const char *func, int ret) { - switch (ret) { - case -EPROBE_DEFER: - case -ENOTSUPP: - case 0: - break; - default: - dev_err(card->dev, - "ASoC: error at %s on %s: %d\n", - func, card->name, ret); - } - - return ret; + return snd_soc_ret(card->dev, ret, + "at %s() on %s\n", func, card->name); } struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card, diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index b67ef78f405c..25f5e543ae8d 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -13,32 +13,20 @@ #include #include -#define soc_component_ret(dai, ret) _soc_component_ret(dai, __func__, ret, -1) -#define soc_component_ret_reg_rw(dai, ret, reg) _soc_component_ret(dai, __func__, ret, reg) -static inline int _soc_component_ret(struct snd_soc_component *component, - const char *func, int ret, int reg) -{ - /* Positive/Zero values are not errors */ - if (ret >= 0) - return ret; - - /* Negative values might be errors */ - switch (ret) { - case -EPROBE_DEFER: - case -ENOTSUPP: - break; - default: - if (reg == -1) - dev_err(component->dev, - "ASoC: error at %s on %s: %d\n", - func, component->name, ret); - else - dev_err(component->dev, - "ASoC: error at %s on %s for register: [0x%08x] %d\n", - func, component->name, reg, ret); - } +#define soc_component_ret(dai, ret) _soc_component_ret(dai, __func__, ret) +static inline int _soc_component_ret(struct snd_soc_component *component, const char *func, int ret) +{ + return snd_soc_ret(component->dev, ret, + "at %s() on %s\n", func, component->name); +} - return ret; +#define soc_component_ret_reg_rw(dai, ret, reg) _soc_component_ret_reg_rw(dai, __func__, ret, reg) +static inline int _soc_component_ret_reg_rw(struct snd_soc_component *component, + const char *func, int ret, int reg) +{ + return snd_soc_ret(component->dev, ret, + "at %s() on %s for register: [0x%08x]\n", + func, component->name, reg); } static inline int soc_component_field_shift(struct snd_soc_component *component, diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index ca0308f6d41c..7c4c9127e5f3 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -14,22 +14,8 @@ static inline int _soc_dai_ret(const struct snd_soc_dai *dai, const char *func, int ret) { - /* Positive, Zero values are not errors */ - if (ret >= 0) - return ret; - - /* Negative values might be errors */ - switch (ret) { - case -EPROBE_DEFER: - case -ENOTSUPP: - break; - default: - dev_err(dai->dev, - "ASoC: error at %s on %s: %d\n", - func, dai->name, ret); - } - - return ret; + return snd_soc_ret(dai->dev, ret, + "at %s() on %s\n", func, dai->name); } /* diff --git a/sound/soc/soc-link.c b/sound/soc/soc-link.c index 7f1f1bc717e2..02fd68f2e702 100644 --- a/sound/soc/soc-link.c +++ b/sound/soc/soc-link.c @@ -12,22 +12,8 @@ static inline int _soc_link_ret(struct snd_soc_pcm_runtime *rtd, const char *func, int ret) { - /* Positive, Zero values are not errors */ - if (ret >= 0) - return ret; - - /* Negative values might be errors */ - switch (ret) { - case -EPROBE_DEFER: - case -ENOTSUPP: - break; - default: - dev_err(rtd->dev, - "ASoC: error at %s on %s: %d\n", - func, rtd->dai_link->name, ret); - } - - return ret; + return snd_soc_ret(rtd->dev, ret, + "at %s() on %s\n", func, rtd->dai_link->name); } /* diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 88b3ad5a2552..a2caa146cac2 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -30,22 +30,8 @@ static inline int _soc_pcm_ret(struct snd_soc_pcm_runtime *rtd, const char *func, int ret) { - /* Positive, Zero values are not errors */ - if (ret >= 0) - return ret; - - /* Negative values might be errors */ - switch (ret) { - case -EPROBE_DEFER: - case -ENOTSUPP: - break; - default: - dev_err(rtd->dev, - "ASoC: error at %s on %s: %d\n", - func, rtd->dai_link->name, ret); - } - - return ret; + return snd_soc_ret(rtd->dev, ret, + "at %s() on %s\n", func, rtd->dai_link->name); } /* is the current PCM operation for this FE ? */ diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index aa93e77ac937..e8958158acc1 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -15,6 +15,32 @@ #include #include +int snd_soc_ret(const struct device *dev, int ret, const char *fmt, ...) +{ + struct va_format vaf; + va_list args; + + /* Positive, Zero values are not errors */ + if (ret >= 0) + return ret; + + /* Negative values might be errors */ + switch (ret) { + case -EPROBE_DEFER: + case -ENOTSUPP: + break; + default: + va_start(args, fmt); + vaf.fmt = fmt; + vaf.va = &args; + + dev_err(dev, "ASoC error (%d): %pV", ret, &vaf); + } + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_ret); + int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots) { return sample_size * channels * tdm_slots; -- 2.51.0 From 062b7ef6b103dcbcb3c084e8ace8e74e260b2346 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 5 Feb 2025 00:16:14 +0000 Subject: [PATCH 04/16] ASoC: soc-utils: care -EOPNOTSUPP on snd_soc_ret() We get below warning by checkpatch on soc-utils. Adds EOPNOTSUPP, but not remove existing ENOTSUPP. WARNING: ENOTSUPP is not a SUSV4 error code, prefer EOPNOTSUPP Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87ed0d2qlt.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-utils.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index e8958158acc1..318b141c00b3 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -28,6 +28,7 @@ int snd_soc_ret(const struct device *dev, int ret, const char *fmt, ...) switch (ret) { case -EPROBE_DEFER: case -ENOTSUPP: + case -EOPNOTSUPP: break; default: va_start(args, fmt); -- 2.51.0 From be61cd4242e4a53f5cf989ee7573121d041444bc Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 5 Feb 2025 00:16:19 +0000 Subject: [PATCH 05/16] ASoC: soc-pcm: use snd_soc_ret() Many functions uses below style for error return dev_err(dev, "message"); return -Exxxx; We can merge these into snd_soc_ret() which can use same error format. Let's cleaup code. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87cyfx2qlo.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 96 ++++++++++++++++++--------------------------- 1 file changed, 39 insertions(+), 57 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index a2caa146cac2..ebe99d369ca9 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -238,11 +238,9 @@ static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf, int stream; char *buf; - if (fe->dai_link->num_cpus > 1) { - dev_err(fe->dev, + if (fe->dai_link->num_cpus > 1) + return snd_soc_ret(fe->dev, -EINVAL, "%s doesn't support Multi CPU yet\n", __func__); - return -EINVAL; - } buf = kmalloc(out_count, GFP_KERNEL); if (!buf) @@ -460,12 +458,9 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream, ret = snd_pcm_hw_constraint_single(substream->runtime, \ SNDRV_PCM_HW_PARAM_##NAME,\ soc_dai->symmetric_##name); \ - if (ret < 0) { \ - dev_err(soc_dai->dev, \ - "ASoC: Unable to apply %s constraint: %d\n",\ - #name, ret); \ - return ret; \ - } \ + if (ret < 0) \ + return snd_soc_ret(soc_dai->dev, ret, \ + "Unable to apply %s constraint\n", #name); \ } __soc_pcm_apply_symmetry(rate, RATE); @@ -496,12 +491,11 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, for_each_rtd_cpu_dais(rtd, i, cpu_dai) \ if (!snd_soc_dai_is_dummy(cpu_dai) && \ cpu_dai->symmetric_##xxx && \ - cpu_dai->symmetric_##xxx != d.symmetric_##xxx) { \ - dev_err(rtd->dev, "ASoC: unmatched %s symmetry: %s:%d - %s:%d\n", \ - #xxx, cpu_dai->name, cpu_dai->symmetric_##xxx, \ - d.name, d.symmetric_##xxx); \ - return -EINVAL; \ - } + cpu_dai->symmetric_##xxx != d.symmetric_##xxx) \ + return snd_soc_ret(rtd->dev, -EINVAL, \ + "unmatched %s symmetry: %s:%d - %s:%d\n", \ + #xxx, cpu_dai->name, cpu_dai->symmetric_##xxx, \ + d.name, d.symmetric_##xxx); /* reject unmatched parameters when applying symmetry */ __soc_pcm_params_symmetry(rate); @@ -846,9 +840,8 @@ static int soc_hw_sanity_check(struct snd_pcm_substream *substream) return 0; config_err: - dev_err(dev, "ASoC: %s <-> %s No matching %s\n", - name_codec, name_cpu, err_msg); - return -EINVAL; + return snd_soc_ret(dev, -EINVAL, + "%s <-> %s No matching %s\n", name_codec, name_cpu, err_msg); } /* @@ -1319,11 +1312,11 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe, fe_substream = snd_soc_dpcm_get_substream(fe, stream); be_substream = snd_soc_dpcm_get_substream(be, stream); - if (!fe_substream->pcm->nonatomic && be_substream->pcm->nonatomic) { - dev_err(be->dev, "%s: FE is atomic but BE is nonatomic, invalid configuration\n", - __func__); - return -EINVAL; - } + if (!fe_substream->pcm->nonatomic && be_substream->pcm->nonatomic) + return snd_soc_ret(be->dev, -EINVAL, + "%s: %s is atomic but %s is nonatomic, invalid configuration\n", + __func__, fe->dai_link->name, be->dai_link->name); + if (fe_substream->pcm->nonatomic && !be_substream->pcm->nonatomic) { dev_dbg(be->dev, "FE is nonatomic but BE is not, forcing BE as nonatomic\n"); be_substream->pcm->nonatomic = 1; @@ -1493,11 +1486,9 @@ int dpcm_path_get(struct snd_soc_pcm_runtime *fe, struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(fe, 0); int paths; - if (fe->dai_link->num_cpus > 1) { - dev_err(fe->dev, + if (fe->dai_link->num_cpus > 1) + return snd_soc_ret(fe->dev, -EINVAL, "%s doesn't support Multi CPU yet\n", __func__); - return -EINVAL; - } /* get number of valid DAI paths and their widgets */ paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list, @@ -2388,23 +2379,23 @@ static int dpcm_dai_trigger_fe_be(struct snd_pcm_substream *substream, ret = soc_pcm_trigger(substream, cmd); if (ret < 0) - return ret; + goto end; ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); - return ret; + goto end; } /* call trigger on the frontend after the backend. */ ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); if (ret < 0) - return ret; + goto end; dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n", fe->dai_link->name, cmd); ret = soc_pcm_trigger(substream, cmd); - - return ret; +end: + return snd_soc_ret(fe->dev, ret, "trigger FE cmd: %d failed\n", cmd); } static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd) @@ -2460,11 +2451,8 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd) goto out; } - if (ret < 0) { - dev_err(fe->dev, "ASoC: trigger FE cmd: %d failed: %d\n", - cmd, ret); + if (ret < 0) goto out; - } switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -2693,11 +2681,9 @@ static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new) if (!fe->dai_link->dynamic) return 0; - if (fe->dai_link->num_cpus > 1) { - dev_err(fe->dev, + if (fe->dai_link->num_cpus > 1) + return snd_soc_ret(fe->dev, -EINVAL, "%s doesn't support Multi CPU yet\n", __func__); - return -EINVAL; - } /* only check active links */ if (!snd_soc_dai_active(snd_soc_rtd_to_cpu(fe, 0))) @@ -2768,7 +2754,8 @@ int snd_soc_dpcm_runtime_update(struct snd_soc_card *card) out: snd_soc_dpcm_mutex_unlock(card); - return ret; + + return snd_soc_ret(card->dev, ret, "%s() failed\n", __func__); } EXPORT_SYMBOL_GPL(snd_soc_dpcm_runtime_update); @@ -2842,10 +2829,9 @@ static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd, int has_capture = 0; int i; - if (dai_link->dynamic && dai_link->num_cpus > 1) { - dev_err(rtd->dev, "DPCM doesn't support Multi CPU for Front-Ends yet\n"); - return -EINVAL; - } + if (dai_link->dynamic && dai_link->num_cpus > 1) + return snd_soc_ret(rtd->dev, -EINVAL, + "DPCM doesn't support Multi CPU for Front-Ends yet\n"); /* Adapt stream for codec2codec links */ cpu_capture = snd_soc_get_stream_cpu(dai_link, SNDRV_PCM_STREAM_CAPTURE); @@ -2887,12 +2873,9 @@ static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd, if (dai_link->capture_only) has_playback = 0; - if (!has_playback && !has_capture) { - dev_err(rtd->dev, "substream %s has no playback, no capture\n", - dai_link->stream_name); - - return -EINVAL; - } + if (!has_playback && !has_capture) + return snd_soc_ret(rtd->dev, -EINVAL, + "substream %s has no playback, no capture\n", dai_link->stream_name); *playback = has_playback; *capture = has_capture; @@ -2932,11 +2915,10 @@ static int soc_create_pcm(struct snd_pcm **pcm, ret = snd_pcm_new(rtd->card->snd_card, new_name, rtd->id, playback, capture, pcm); } - if (ret < 0) { - dev_err(rtd->card->dev, "ASoC: can't create pcm %s for dailink %s: %d\n", - new_name, rtd->dai_link->name, ret); - return ret; - } + if (ret < 0) + return snd_soc_ret(rtd->dev, ret, + "can't create pcm %s for dailink %s\n", new_name, rtd->dai_link->name); + dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n", rtd->id, new_name); return 0; -- 2.51.0 From a0ef5b4b101424b8a666ed56bf1717dafe2d37f5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 5 Feb 2025 00:16:23 +0000 Subject: [PATCH 06/16] ASoC: simple-card: use snd_soc_ret() We can use snd_soc_ret() to indicate error message when return. Let's use it. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87bjvh2qlk.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 130 +++++++++++++++++--------------- 1 file changed, 71 insertions(+), 59 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index afe7e79ffdbd..004fda4504c4 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -29,7 +29,16 @@ static const struct snd_soc_ops simple_ops = { .hw_params = simple_util_hw_params, }; -static int simple_parse_platform(struct device_node *node, struct snd_soc_dai_link_component *dlc) +#define simple_ret(priv, ret) _simple_ret(priv, __func__, ret) +static inline int _simple_ret(struct simple_util_priv *priv, + const char *func, int ret) +{ + return snd_soc_ret(simple_priv_to_dev(priv), ret, "at %s()\n", func); +} + +static int simple_parse_platform(struct simple_util_priv *priv, + struct device_node *node, + struct snd_soc_dai_link_component *dlc) { struct of_phandle_args args; int ret; @@ -43,7 +52,7 @@ static int simple_parse_platform(struct device_node *node, struct snd_soc_dai_li */ ret = of_parse_phandle_with_args(node, DAI, CELL, 0, &args); if (ret) - return ret; + return simple_ret(priv, ret); /* dai_name is not required and may not exist for plat component */ @@ -52,11 +61,12 @@ static int simple_parse_platform(struct device_node *node, struct snd_soc_dai_li return 0; } -static int simple_parse_dai(struct device *dev, +static int simple_parse_dai(struct simple_util_priv *priv, struct device_node *node, struct snd_soc_dai_link_component *dlc, int *is_single_link) { + struct device *dev = simple_priv_to_dev(priv); struct of_phandle_args args; struct snd_soc_dai *dai; int ret; @@ -70,17 +80,18 @@ static int simple_parse_dai(struct device *dev, */ ret = of_parse_phandle_with_args(node, DAI, CELL, 0, &args); if (ret) - return ret; + goto end; /* * Try to find from DAI args */ dai = snd_soc_get_dai_via_args(&args); if (dai) { + ret = -ENOMEM; dlc->dai_name = snd_soc_dai_name_get(dai); dlc->dai_args = snd_soc_copy_dai_args(dev, &args); if (!dlc->dai_args) - return -ENOMEM; + goto end; goto parse_dai_end; } @@ -106,13 +117,14 @@ static int simple_parse_dai(struct device *dev, */ ret = snd_soc_get_dlc(&args, dlc); if (ret < 0) - return ret; + goto end; parse_dai_end: if (is_single_link) *is_single_link = !args.args_count; - - return 0; + ret = 0; +end: + return simple_ret(priv, ret); } static void simple_parse_convert(struct device *dev, @@ -149,19 +161,17 @@ static int simple_parse_node(struct simple_util_priv *priv, dai = simple_props_to_dai_codec(dai_props, 0); } - ret = simple_parse_dai(dev, np, dlc, cpu); + ret = simple_parse_dai(priv, np, dlc, cpu); if (ret) - return ret; + goto end; ret = simple_util_parse_clk(dev, np, dai, dlc); if (ret) - return ret; + goto end; ret = simple_util_parse_tdm(np, dai); - if (ret) - return ret; - - return 0; +end: + return simple_ret(priv, ret); } static int simple_link_init(struct simple_util_priv *priv, @@ -183,7 +193,7 @@ static int simple_link_init(struct simple_util_priv *priv, ret = simple_util_parse_daifmt(dev, node, codec, prefix, &dai_link->dai_fmt); if (ret < 0) - return ret; + goto end; graph_util_parse_link_direction(top, &playback_only, &capture_only); graph_util_parse_link_direction(node, &playback_only, &capture_only); @@ -213,7 +223,9 @@ static int simple_link_init(struct simple_util_priv *priv, dai_link->init = simple_util_dai_init; dai_link->ops = &simple_ops; - return simple_util_set_dailink_name(dev, dai_link, name); + ret = simple_util_set_dailink_name(dev, dai_link, name); +end: + return simple_ret(priv, ret); } static int simple_dai_link_of_dpcm(struct simple_util_priv *priv, @@ -290,7 +302,7 @@ static int simple_dai_link_of_dpcm(struct simple_util_priv *priv, out_put_node: li->link++; - return ret; + return simple_ret(priv, ret); } static int simple_dai_link_of(struct simple_util_priv *priv, @@ -330,7 +342,7 @@ static int simple_dai_link_of(struct simple_util_priv *priv, if (ret < 0) goto dai_link_of_err; - ret = simple_parse_platform(plat, platforms); + ret = simple_parse_platform(priv, plat, platforms); if (ret < 0) goto dai_link_of_err; @@ -345,7 +357,7 @@ static int simple_dai_link_of(struct simple_util_priv *priv, dai_link_of_err: li->link++; - return ret; + return simple_ret(priv, ret); } static int __simple_for_each_link(struct simple_util_priv *priv, @@ -443,10 +455,10 @@ static int __simple_for_each_link(struct simple_util_priv *priv, node = of_get_next_child(top, node); } while (!is_top && node); - error: +error: of_node_put(node); - return ret; + return simple_ret(priv, ret); } static int simple_for_each_link(struct simple_util_priv *priv, @@ -479,7 +491,7 @@ static int simple_for_each_link(struct simple_util_priv *priv, break; } - return ret; + return simple_ret(priv, ret); } static void simple_depopulate_aux(void *data) @@ -500,9 +512,11 @@ static int simple_populate_aux(struct simple_util_priv *priv) ret = of_platform_populate(node, NULL, NULL, dev); if (ret) - return ret; + goto end; - return devm_add_action_or_reset(dev, simple_depopulate_aux, priv); + ret = devm_add_action_or_reset(dev, simple_depopulate_aux, priv); +end: + return simple_ret(priv, ret); } static int simple_parse_of(struct simple_util_priv *priv, struct link_info *li) @@ -512,15 +526,15 @@ static int simple_parse_of(struct simple_util_priv *priv, struct link_info *li) ret = simple_util_parse_widgets(card, PREFIX); if (ret < 0) - return ret; + goto end; ret = simple_util_parse_routing(card, PREFIX); if (ret < 0) - return ret; + goto end; ret = simple_util_parse_pin_switches(card, PREFIX); if (ret < 0) - return ret; + goto end; /* Single/Muti DAI link(s) & New style of DT node */ memset(li, 0, sizeof(*li)); @@ -528,19 +542,19 @@ static int simple_parse_of(struct simple_util_priv *priv, struct link_info *li) simple_dai_link_of, simple_dai_link_of_dpcm); if (ret < 0) - return ret; + goto end; ret = simple_util_parse_card_name(card, PREFIX); if (ret < 0) - return ret; + goto end; ret = simple_populate_aux(priv); if (ret < 0) - return ret; + goto end; ret = snd_soc_of_parse_aux_devs(card, PREFIX "aux-devs"); - - return ret; +end: + return simple_ret(priv, ret); } static int simple_count_noml(struct simple_util_priv *priv, @@ -548,12 +562,10 @@ static int simple_count_noml(struct simple_util_priv *priv, struct device_node *codec, struct link_info *li, bool is_top) { - if (li->link >= SNDRV_MAX_LINKS) { - struct device *dev = simple_priv_to_dev(priv); + int ret = -EINVAL; - dev_err(dev, "too many links\n"); - return -EINVAL; - } + if (li->link >= SNDRV_MAX_LINKS) + goto end; /* * DON'T REMOVE platforms @@ -575,8 +587,9 @@ static int simple_count_noml(struct simple_util_priv *priv, li->num[li->link].codecs = 1; li->link += 1; - - return 0; + ret = 0; +end: + return simple_ret(priv, ret); } static int simple_count_dpcm(struct simple_util_priv *priv, @@ -584,12 +597,10 @@ static int simple_count_dpcm(struct simple_util_priv *priv, struct device_node *codec, struct link_info *li, bool is_top) { - if (li->link >= SNDRV_MAX_LINKS) { - struct device *dev = simple_priv_to_dev(priv); + int ret = -EINVAL; - dev_err(dev, "too many links\n"); - return -EINVAL; - } + if (li->link >= SNDRV_MAX_LINKS) + goto end; if (li->cpu) { /* @@ -606,8 +617,9 @@ static int simple_count_dpcm(struct simple_util_priv *priv, li->link++; /* dummy-Codec */ } - - return 0; + ret = 0; +end: + return simple_ret(priv, ret); } static int simple_get_dais_count(struct simple_util_priv *priv, @@ -683,17 +695,15 @@ static int simple_soc_probe(struct snd_soc_card *card) ret = simple_util_init_hp(card, &priv->hp_jack, PREFIX); if (ret < 0) - return ret; + goto end; ret = simple_util_init_mic(card, &priv->mic_jack, PREFIX); if (ret < 0) - return ret; + goto end; ret = simple_util_init_aux_jacks(priv, PREFIX); - if (ret < 0) - return ret; - - return 0; +end: + return simple_ret(priv, ret); } static int simple_probe(struct platform_device *pdev) @@ -715,20 +725,22 @@ static int simple_probe(struct platform_device *pdev) card->probe = simple_soc_probe; card->driver_name = "simple-card"; + ret = -ENOMEM; struct link_info *li __free(kfree) = kzalloc(sizeof(*li), GFP_KERNEL); if (!li) - return -ENOMEM; + goto end; ret = simple_get_dais_count(priv, li); if (ret < 0) - return ret; + goto end; + ret = -EINVAL; if (!li->link) - return -EINVAL; + goto end; ret = simple_util_init_priv(priv, li); if (ret < 0) - return ret; + goto end; if (np && of_device_is_available(np)) { @@ -795,8 +807,8 @@ static int simple_probe(struct platform_device *pdev) return 0; err: simple_util_clean_reference(card); - - return ret; +end: + return dev_err_probe(dev, ret, "parse error\n"); } static const struct of_device_id simple_of_match[] = { -- 2.51.0 From 2d7395b23dbf4c2d60be49b73e4c4705fc446662 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 5 Feb 2025 00:16:27 +0000 Subject: [PATCH 07/16] ASoC: simple-card-utils: use snd_soc_ret() We can use snd_soc_ret() to indicate error message when return. Let's use it. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87a5b12qlg.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 8 +- sound/soc/generic/audio-graph-card.c | 6 +- sound/soc/generic/audio-graph-card2.c | 14 +-- sound/soc/generic/simple-card-utils.c | 170 +++++++++++++++----------- sound/soc/generic/simple-card.c | 4 +- 5 files changed, 115 insertions(+), 87 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 892f70532363..69a9c9c4d0e9 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -142,14 +142,14 @@ int simple_util_parse_daifmt(struct device *dev, struct device_node *codec, char *prefix, unsigned int *retfmt); -int simple_util_parse_tdm_width_map(struct device *dev, struct device_node *np, +int simple_util_parse_tdm_width_map(struct simple_util_priv *priv, struct device_node *np, struct simple_util_dai *dai); __printf(3, 4) -int simple_util_set_dailink_name(struct device *dev, +int simple_util_set_dailink_name(struct simple_util_priv *priv, struct snd_soc_dai_link *dai_link, const char *fmt, ...); -int simple_util_parse_card_name(struct snd_soc_card *card, +int simple_util_parse_card_name(struct simple_util_priv *priv, char *prefix); int simple_util_parse_clk(struct device *dev, @@ -201,7 +201,7 @@ void simple_util_remove(struct platform_device *pdev); int graph_util_card_probe(struct snd_soc_card *card); int graph_util_is_ports0(struct device_node *port); -int graph_util_parse_dai(struct device *dev, struct device_node *ep, +int graph_util_parse_dai(struct simple_util_priv *priv, struct device_node *ep, struct snd_soc_dai_link_component *dlc, int *is_single_link); void graph_util_parse_link_direction(struct device_node *np, diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 7c422535b01a..bd7ebbec0fc9 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -111,7 +111,7 @@ static int graph_parse_node(struct simple_util_priv *priv, dai = simple_props_to_dai_codec(dai_props, 0); } - ret = graph_util_parse_dai(dev, ep, dlc, cpu); + ret = graph_util_parse_dai(priv, ep, dlc, cpu); if (ret < 0) return ret; @@ -183,7 +183,7 @@ static int graph_link_init(struct simple_util_priv *priv, if (priv->ops) dai_link->ops = priv->ops; - return simple_util_set_dailink_name(dev, dai_link, name); + return simple_util_set_dailink_name(priv, dai_link, name); } static int graph_dai_link_of_dpcm(struct simple_util_priv *priv, @@ -586,7 +586,7 @@ int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev) if (ret < 0) goto err; - ret = simple_util_parse_card_name(card, NULL); + ret = simple_util_parse_card_name(priv, NULL); if (ret < 0) goto err; diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index ee94b256b770..945a16e6d691 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -409,7 +409,7 @@ static int __graph_parse_node(struct simple_util_priv *priv, dai = simple_props_to_dai_codec(dai_props, idx); } - ret = graph_util_parse_dai(dev, ep, dlc, &is_single_links); + ret = graph_util_parse_dai(priv, ep, dlc, &is_single_links); if (ret < 0) return ret; @@ -417,7 +417,7 @@ static int __graph_parse_node(struct simple_util_priv *priv, if (ret < 0) return ret; - ret = simple_util_parse_tdm_width_map(dev, ep, dai); + ret = simple_util_parse_tdm_width_map(priv, ep, dai); if (ret < 0) return ret; @@ -443,22 +443,22 @@ static int __graph_parse_node(struct simple_util_priv *priv, case GRAPH_NORMAL: /* run is_cpu only. see audio_graph2_link_normal() */ if (is_cpu) - simple_util_set_dailink_name(dev, dai_link, "%s%s-%s%s", + simple_util_set_dailink_name(priv, dai_link, "%s%s-%s%s", cpus->dai_name, cpu_multi, codecs->dai_name, codec_multi); break; case GRAPH_DPCM: if (is_cpu) - simple_util_set_dailink_name(dev, dai_link, "fe.%pOFP.%s%s", + simple_util_set_dailink_name(priv, dai_link, "fe.%pOFP.%s%s", cpus->of_node, cpus->dai_name, cpu_multi); else - simple_util_set_dailink_name(dev, dai_link, "be.%pOFP.%s%s", + simple_util_set_dailink_name(priv, dai_link, "be.%pOFP.%s%s", codecs->of_node, codecs->dai_name, codec_multi); break; case GRAPH_C2C: /* run is_cpu only. see audio_graph2_link_c2c() */ if (is_cpu) - simple_util_set_dailink_name(dev, dai_link, "c2c.%s%s-%s%s", + simple_util_set_dailink_name(priv, dai_link, "c2c.%s%s-%s%s", cpus->dai_name, cpu_multi, codecs->dai_name, codec_multi); break; @@ -1332,7 +1332,7 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev, if (ret < 0) goto err; - ret = simple_util_parse_card_name(card, NULL); + ret = simple_util_parse_card_name(priv, NULL); if (ret < 0) goto err; diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index c2445c5ccd84..51e0e434514d 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -15,6 +15,13 @@ #include #include +#define simple_ret(priv, ret) _simple_ret(priv, __func__, ret) +static inline int _simple_ret(struct simple_util_priv *priv, + const char *func, int ret) +{ + return snd_soc_ret(simple_priv_to_dev(priv), ret, "at %s()\n", func); +} + int simple_util_get_sample_fmt(struct simple_util_data *data) { int i; @@ -133,33 +140,42 @@ int simple_util_parse_daifmt(struct device *dev, } EXPORT_SYMBOL_GPL(simple_util_parse_daifmt); -int simple_util_parse_tdm_width_map(struct device *dev, struct device_node *np, +int simple_util_parse_tdm_width_map(struct simple_util_priv *priv, struct device_node *np, struct simple_util_dai *dai) { + struct device *dev = simple_priv_to_dev(priv); int n, i, ret; u32 *p; + /* + * NOTE + * + * Clang doesn't allow to use "goto end" before calling __free(), + * because it bypasses the initialization. Use simple_ret() directly. + */ + n = of_property_count_elems_of_size(np, "dai-tdm-slot-width-map", sizeof(u32)); if (n <= 0) return 0; + if (n % 3) { dev_err(dev, "Invalid number of cells for dai-tdm-slot-width-map\n"); - return -EINVAL; + return simple_ret(priv, -EINVAL); /* see NOTE */ } + ret = -ENOMEM; dai->tdm_width_map = devm_kcalloc(dev, n, sizeof(*dai->tdm_width_map), GFP_KERNEL); if (!dai->tdm_width_map) - return -ENOMEM; + return simple_ret(priv, ret); /* see NOTE */ - u32 *array_values __free(kfree) = kcalloc(n, sizeof(*array_values), - GFP_KERNEL); + u32 *array_values __free(kfree) = kcalloc(n, sizeof(*array_values), GFP_KERNEL); if (!array_values) - return -ENOMEM; + goto end; ret = of_property_read_u32_array(np, "dai-tdm-slot-width-map", array_values, n); if (ret < 0) { dev_err(dev, "Could not read dai-tdm-slot-width-map: %d\n", ret); - return ret; + goto end; } p = array_values; @@ -170,15 +186,17 @@ int simple_util_parse_tdm_width_map(struct device *dev, struct device_node *np, } dai->n_tdm_widths = i; - - return 0; + ret = 0; +end: + return simple_ret(priv, ret); } EXPORT_SYMBOL_GPL(simple_util_parse_tdm_width_map); -int simple_util_set_dailink_name(struct device *dev, +int simple_util_set_dailink_name(struct simple_util_priv *priv, struct snd_soc_dai_link *dai_link, const char *fmt, ...) { + struct device *dev = simple_priv_to_dev(priv); va_list ap; char *name = NULL; int ret = -ENOMEM; @@ -194,13 +212,14 @@ int simple_util_set_dailink_name(struct device *dev, dai_link->stream_name = name; } - return ret; + return simple_ret(priv, ret); } EXPORT_SYMBOL_GPL(simple_util_set_dailink_name); -int simple_util_parse_card_name(struct snd_soc_card *card, +int simple_util_parse_card_name(struct simple_util_priv *priv, char *prefix) { + struct snd_soc_card *card = simple_priv_to_card(priv); int ret; if (!prefix) @@ -214,13 +233,13 @@ int simple_util_parse_card_name(struct snd_soc_card *card, snprintf(prop, sizeof(prop), "%sname", prefix); ret = snd_soc_of_parse_card_name(card, prop); if (ret < 0) - return ret; + goto end; } if (!card->name && card->dai_link) card->name = card->dai_link->name; - - return 0; +end: + return simple_ret(priv, ret); } EXPORT_SYMBOL_GPL(simple_util_parse_card_name); @@ -348,7 +367,8 @@ cpu_err: break; simple_clk_disable(dai); } - return ret; + + return simple_ret(priv, ret); } EXPORT_SYMBOL_GPL(simple_util_startup); @@ -379,16 +399,19 @@ void simple_util_shutdown(struct snd_pcm_substream *substream) } EXPORT_SYMBOL_GPL(simple_util_shutdown); -static int simple_set_clk_rate(struct device *dev, - struct simple_util_dai *simple_dai, - unsigned long rate) +static int simple_set_clk_rate(struct simple_util_priv *priv, + struct simple_util_dai *simple_dai, + unsigned long rate) { + struct device *dev = simple_priv_to_dev(priv); + int ret = -EINVAL; + if (!simple_dai) return 0; if (simple_dai->clk_fixed && rate != simple_dai->sysclk) { dev_err(dev, "dai %s invalid clock rate %lu\n", simple_dai->name, rate); - return -EINVAL; + goto end; } if (!simple_dai->clk) @@ -397,12 +420,15 @@ static int simple_set_clk_rate(struct device *dev, if (clk_get_rate(simple_dai->clk) == rate) return 0; - return clk_set_rate(simple_dai->clk, rate); + ret = clk_set_rate(simple_dai->clk, rate); +end: + return simple_ret(priv, ret); } -static int simple_set_tdm(struct snd_soc_dai *dai, - struct simple_util_dai *simple_dai, - struct snd_pcm_hw_params *params) +static int simple_set_tdm(struct simple_util_priv *priv, + struct snd_soc_dai *dai, + struct simple_util_dai *simple_dai, + struct snd_pcm_hw_params *params) { int sample_bits = params_width(params); int slot_width, slot_count; @@ -430,12 +456,8 @@ static int simple_set_tdm(struct snd_soc_dai *dai, simple_dai->rx_slot_mask, slot_count, slot_width); - if (ret && ret != -ENOTSUPP) { - dev_err(dai->dev, "simple-card: set_tdm_slot error: %d\n", ret); - return ret; - } - return 0; + return simple_ret(priv, ret); } int simple_util_hw_params(struct snd_pcm_substream *substream, @@ -457,15 +479,15 @@ int simple_util_hw_params(struct snd_pcm_substream *substream, mclk = params_rate(params) * mclk_fs; for_each_prop_dai_codec(props, i, pdai) { - ret = simple_set_clk_rate(rtd->dev, pdai, mclk); + ret = simple_set_clk_rate(priv, pdai, mclk); if (ret < 0) - return ret; + goto end; } for_each_prop_dai_cpu(props, i, pdai) { - ret = simple_set_clk_rate(rtd->dev, pdai, mclk); + ret = simple_set_clk_rate(priv, pdai, mclk); if (ret < 0) - return ret; + goto end; } /* Ensure sysclk is set on all components in case any @@ -476,39 +498,40 @@ int simple_util_hw_params(struct snd_pcm_substream *substream, ret = snd_soc_component_set_sysclk(component, 0, 0, mclk, SND_SOC_CLOCK_IN); if (ret && ret != -ENOTSUPP) - return ret; + goto end; } for_each_rtd_codec_dais(rtd, i, sdai) { pdai = simple_props_to_dai_codec(props, i); ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, pdai->clk_direction); if (ret && ret != -ENOTSUPP) - return ret; + goto end; } for_each_rtd_cpu_dais(rtd, i, sdai) { pdai = simple_props_to_dai_cpu(props, i); ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, pdai->clk_direction); if (ret && ret != -ENOTSUPP) - return ret; + goto end; } } for_each_prop_dai_codec(props, i, pdai) { sdai = snd_soc_rtd_to_codec(rtd, i); - ret = simple_set_tdm(sdai, pdai, params); + ret = simple_set_tdm(priv, sdai, pdai, params); if (ret < 0) - return ret; + goto end; } for_each_prop_dai_cpu(props, i, pdai) { sdai = snd_soc_rtd_to_cpu(rtd, i); - ret = simple_set_tdm(sdai, pdai, params); + ret = simple_set_tdm(priv, sdai, pdai, params); if (ret < 0) - return ret; + goto end; } - - return 0; + ret = 0; +end: + return simple_ret(priv, ret); } EXPORT_SYMBOL_GPL(simple_util_hw_params); @@ -536,7 +559,8 @@ int simple_util_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, } EXPORT_SYMBOL_GPL(simple_util_be_hw_params_fixup); -static int simple_init_dai(struct snd_soc_dai *dai, struct simple_util_dai *simple_dai) +static int simple_init_dai(struct simple_util_priv *priv, + struct snd_soc_dai *dai, struct simple_util_dai *simple_dai) { int ret; @@ -548,7 +572,7 @@ static int simple_init_dai(struct snd_soc_dai *dai, struct simple_util_dai *simp simple_dai->clk_direction); if (ret && ret != -ENOTSUPP) { dev_err(dai->dev, "simple-card: set_sysclk error\n"); - return ret; + goto end; } } @@ -560,11 +584,12 @@ static int simple_init_dai(struct snd_soc_dai *dai, struct simple_util_dai *simp simple_dai->slot_width); if (ret && ret != -ENOTSUPP) { dev_err(dai->dev, "simple-card: set_tdm_slot error\n"); - return ret; + goto end; } } - - return 0; + ret = 0; +end: + return simple_ret(priv, ret); } static inline int simple_component_is_codec(struct snd_soc_component *component) @@ -572,7 +597,8 @@ static inline int simple_component_is_codec(struct snd_soc_component *component) return component->driver->endianness; } -static int simple_init_for_codec2codec(struct snd_soc_pcm_runtime *rtd, +static int simple_init_for_codec2codec(struct simple_util_priv *priv, + struct snd_soc_pcm_runtime *rtd, struct simple_dai_props *dai_props) { struct snd_soc_dai_link *dai_link = rtd->dai_link; @@ -604,12 +630,13 @@ static int simple_init_for_codec2codec(struct snd_soc_pcm_runtime *rtd, if (ret < 0) { dev_err(rtd->dev, "simple-card: no valid dai_link params\n"); - return ret; + goto end; } + ret = -ENOMEM; c2c_params = devm_kzalloc(rtd->dev, sizeof(*c2c_params), GFP_KERNEL); if (!c2c_params) - return -ENOMEM; + goto end; c2c_params->formats = hw.formats; c2c_params->rates = hw.rates; @@ -621,7 +648,9 @@ static int simple_init_for_codec2codec(struct snd_soc_pcm_runtime *rtd, dai_link->c2c_params = c2c_params; dai_link->num_c2c_params = 1; - return 0; + ret = 0; +end: + return simple_ret(priv, ret); } int simple_util_dai_init(struct snd_soc_pcm_runtime *rtd) @@ -632,21 +661,19 @@ int simple_util_dai_init(struct snd_soc_pcm_runtime *rtd) int i, ret; for_each_prop_dai_codec(props, i, dai) { - ret = simple_init_dai(snd_soc_rtd_to_codec(rtd, i), dai); + ret = simple_init_dai(priv, snd_soc_rtd_to_codec(rtd, i), dai); if (ret < 0) - return ret; + goto end; } for_each_prop_dai_cpu(props, i, dai) { - ret = simple_init_dai(snd_soc_rtd_to_cpu(rtd, i), dai); + ret = simple_init_dai(priv, snd_soc_rtd_to_cpu(rtd, i), dai); if (ret < 0) - return ret; + goto end; } - ret = simple_init_for_codec2codec(rtd, props); - if (ret < 0) - return ret; - - return 0; + ret = simple_init_for_codec2codec(priv, rtd, props); +end: + return simple_ret(priv, ret); } EXPORT_SYMBOL_GPL(simple_util_dai_init); @@ -831,7 +858,7 @@ int simple_util_init_aux_jacks(struct simple_util_priv *priv, char *prefix) priv->aux_jacks = devm_kcalloc(card->dev, num, sizeof(struct snd_soc_jack), GFP_KERNEL); if (!priv->aux_jacks) - return -ENOMEM; + return simple_ret(priv, -ENOMEM); for_each_card_auxs(card, component) { char id[128]; @@ -992,13 +1019,11 @@ int graph_util_card_probe(struct snd_soc_card *card) ret = simple_util_init_hp(card, &priv->hp_jack, NULL); if (ret < 0) - return ret; + goto end; ret = simple_util_init_mic(card, &priv->mic_jack, NULL); - if (ret < 0) - return ret; - - return 0; +end: + return simple_ret(priv, ret); } EXPORT_SYMBOL_GPL(graph_util_card_probe); @@ -1074,9 +1099,10 @@ static int graph_get_dai_id(struct device_node *ep) return id; } -int graph_util_parse_dai(struct device *dev, struct device_node *ep, +int graph_util_parse_dai(struct simple_util_priv *priv, struct device_node *ep, struct snd_soc_dai_link_component *dlc, int *is_single_link) { + struct device *dev = simple_priv_to_dev(priv); struct of_phandle_args args = {}; struct snd_soc_dai *dai; int ret; @@ -1092,11 +1118,12 @@ int graph_util_parse_dai(struct device *dev, struct device_node *ep, args.np = ep; dai = snd_soc_get_dai_via_args(&args); if (dai) { + ret = -ENOMEM; dlc->of_node = node; dlc->dai_name = snd_soc_dai_name_get(dai); dlc->dai_args = snd_soc_copy_dai_args(dev, &args); if (!dlc->dai_args) - return -ENOMEM; + goto end; goto parse_dai_end; } @@ -1127,13 +1154,14 @@ int graph_util_parse_dai(struct device *dev, struct device_node *ep, */ ret = snd_soc_get_dlc(&args, dlc); if (ret < 0) - return ret; + goto end; parse_dai_end: if (is_single_link) *is_single_link = of_graph_get_endpoint_count(node) == 1; - - return 0; + ret = 0; +end: + return simple_ret(priv, ret); } EXPORT_SYMBOL_GPL(graph_util_parse_dai); diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 004fda4504c4..5af6d1b308f2 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -223,7 +223,7 @@ static int simple_link_init(struct simple_util_priv *priv, dai_link->init = simple_util_dai_init; dai_link->ops = &simple_ops; - ret = simple_util_set_dailink_name(dev, dai_link, name); + ret = simple_util_set_dailink_name(priv, dai_link, name); end: return simple_ret(priv, ret); } @@ -544,7 +544,7 @@ static int simple_parse_of(struct simple_util_priv *priv, struct link_info *li) if (ret < 0) goto end; - ret = simple_util_parse_card_name(card, PREFIX); + ret = simple_util_parse_card_name(priv, PREFIX); if (ret < 0) goto end; -- 2.51.0 From 74a0ca4c7f19f1b273d665b3b53f7ae8af879658 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 5 Feb 2025 00:16:31 +0000 Subject: [PATCH 08/16] ASoC: audio-graph-card: use snd_soc_ret() We can use snd_soc_ret() to indicate error message when return. Let's use it. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/878qql2qlc.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 93 +++++++++++++++------------- 1 file changed, 50 insertions(+), 43 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index bd7ebbec0fc9..a8a3bad3df00 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -20,6 +20,13 @@ #define DPCM_SELECTABLE 1 +#define graph_ret(priv, ret) _graph_ret(priv, __func__, ret) +static inline int _graph_ret(struct simple_util_priv *priv, + const char *func, int ret) +{ + return snd_soc_ret(simple_priv_to_dev(priv), ret, "at %s()\n", func); +} + #define ep_to_port(ep) of_get_parent(ep) static struct device_node *port_to_ports(struct device_node *port) { @@ -113,17 +120,15 @@ static int graph_parse_node(struct simple_util_priv *priv, ret = graph_util_parse_dai(priv, ep, dlc, cpu); if (ret < 0) - return ret; + goto end; ret = simple_util_parse_tdm(ep, dai); if (ret < 0) - return ret; + goto end; ret = simple_util_parse_clk(dev, ep, dai, dlc); - if (ret < 0) - return ret; - - return 0; +end: + return graph_ret(priv, ret); } static int graph_link_init(struct simple_util_priv *priv, @@ -148,7 +153,7 @@ static int graph_link_init(struct simple_util_priv *priv, ret = simple_util_parse_daifmt(dev, ep_cpu, ep_codec, NULL, &dai_link->dai_fmt); if (ret < 0) - return ret; + goto end; graph_util_parse_link_direction(top, &playback_only, &capture_only); graph_util_parse_link_direction(port_cpu, &playback_only, &capture_only); @@ -183,7 +188,9 @@ static int graph_link_init(struct simple_util_priv *priv, if (priv->ops) dai_link->ops = priv->ops; - return simple_util_set_dailink_name(priv, dai_link, name); + ret = simple_util_set_dailink_name(priv, dai_link, name); +end: + return graph_ret(priv, ret); } static int graph_dai_link_of_dpcm(struct simple_util_priv *priv, @@ -215,7 +222,7 @@ static int graph_dai_link_of_dpcm(struct simple_util_priv *priv, ret = graph_parse_node(priv, cpu_ep, li, &is_single_links); if (ret) - return ret; + goto end; snprintf(dai_name, sizeof(dai_name), "fe.%pOFP.%s", cpus->of_node, cpus->dai_name); @@ -248,7 +255,7 @@ static int graph_dai_link_of_dpcm(struct simple_util_priv *priv, ret = graph_parse_node(priv, codec_ep, li, NULL); if (ret < 0) - return ret; + goto end; snprintf(dai_name, sizeof(dai_name), "be.%pOFP.%s", codecs->of_node, codecs->dai_name); @@ -267,8 +274,8 @@ static int graph_dai_link_of_dpcm(struct simple_util_priv *priv, ret = graph_link_init(priv, cpu_ep, codec_ep, li, dai_name); li->link++; - - return ret; +end: + return graph_ret(priv, ret); } static int graph_dai_link_of(struct simple_util_priv *priv, @@ -288,11 +295,11 @@ static int graph_dai_link_of(struct simple_util_priv *priv, ret = graph_parse_node(priv, cpu_ep, li, &is_single_links); if (ret < 0) - return ret; + goto end; ret = graph_parse_node(priv, codec_ep, li, NULL); if (ret < 0) - return ret; + goto end; snprintf(dai_name, sizeof(dai_name), "%s-%s", cpus->dai_name, codecs->dai_name); @@ -302,11 +309,11 @@ static int graph_dai_link_of(struct simple_util_priv *priv, ret = graph_link_init(priv, cpu_ep, codec_ep, li, dai_name); if (ret < 0) - return ret; + goto end; li->link++; - - return 0; +end: + return graph_ret(priv, ret); } static inline bool parse_as_dpcm_link(struct simple_util_priv *priv, @@ -383,13 +390,13 @@ static int __graph_for_each_link(struct simple_util_priv *priv, } if (ret < 0) - return ret; + goto end; codec_port_old = codec_port; } } - - return 0; +end: + return graph_ret(priv, ret); } static int graph_for_each_link(struct simple_util_priv *priv, @@ -422,7 +429,7 @@ static int graph_for_each_link(struct simple_util_priv *priv, break; } - return ret; + return graph_ret(priv, ret); } static int graph_count_noml(struct simple_util_priv *priv, @@ -431,11 +438,10 @@ static int graph_count_noml(struct simple_util_priv *priv, struct link_info *li) { struct device *dev = simple_priv_to_dev(priv); + int ret = -EINVAL; - if (li->link >= SNDRV_MAX_LINKS) { - dev_err(dev, "too many links\n"); - return -EINVAL; - } + if (li->link >= SNDRV_MAX_LINKS) + goto end; /* * DON'T REMOVE platforms @@ -450,8 +456,9 @@ static int graph_count_noml(struct simple_util_priv *priv, li->link += 1; /* 1xCPU-Codec */ dev_dbg(dev, "Count As Normal\n"); - - return 0; + ret = 0; +end: + return graph_ret(priv, ret); } static int graph_count_dpcm(struct simple_util_priv *priv, @@ -460,11 +467,10 @@ static int graph_count_dpcm(struct simple_util_priv *priv, struct link_info *li) { struct device *dev = simple_priv_to_dev(priv); + int ret = -EINVAL; - if (li->link >= SNDRV_MAX_LINKS) { - dev_err(dev, "too many links\n"); - return -EINVAL; - } + if (li->link >= SNDRV_MAX_LINKS) + goto end; if (li->cpu) { /* @@ -483,8 +489,9 @@ static int graph_count_dpcm(struct simple_util_priv *priv, } dev_dbg(dev, "Count As DPCM\n"); - - return 0; + ret = 0; +end: + return graph_ret(priv, ret); } static int graph_get_dais_count(struct simple_util_priv *priv, @@ -544,40 +551,41 @@ static int graph_get_dais_count(struct simple_util_priv *priv, int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev) { struct snd_soc_card *card = simple_priv_to_card(priv); - int ret; + int ret = -ENOMEM; struct link_info *li __free(kfree) = kzalloc(sizeof(*li), GFP_KERNEL); if (!li) - return -ENOMEM; + goto end; card->owner = THIS_MODULE; card->dev = dev; ret = graph_get_dais_count(priv, li); if (ret < 0) - return ret; + goto end; + ret = -EINVAL; if (!li->link) - return -EINVAL; + goto end; ret = simple_util_init_priv(priv, li); if (ret < 0) - return ret; + goto end; priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW); if (IS_ERR(priv->pa_gpio)) { ret = PTR_ERR(priv->pa_gpio); dev_err(dev, "failed to get amplifier gpio: %d\n", ret); - return ret; + goto end; } ret = simple_util_parse_widgets(card, NULL); if (ret < 0) - return ret; + goto end; ret = simple_util_parse_routing(card, NULL); if (ret < 0) - return ret; + goto end; memset(li, 0, sizeof(*li)); ret = graph_for_each_link(priv, li, @@ -599,10 +607,9 @@ int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev) goto err; return 0; - err: simple_util_clean_reference(card); - +end: return dev_err_probe(dev, ret, "parse error\n"); } EXPORT_SYMBOL_GPL(audio_graph_parse_of); -- 2.51.0 From 8d83282e53185ec257a4ce08812e8fabee2c7212 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 5 Feb 2025 00:16:36 +0000 Subject: [PATCH 09/16] ASoC: audio-graph-card2: use snd_soc_ret() We can use snd_soc_ret() to indicate error message when return. Let's use it. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/877c652ql8.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card2.c | 81 ++++++++++++++++----------- 1 file changed, 49 insertions(+), 32 deletions(-) diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index 945a16e6d691..5dcc78c551a2 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -234,6 +234,13 @@ enum graph_type { #define GRAPH_NODENAME_DPCM "dpcm" #define GRAPH_NODENAME_C2C "codec2codec" +#define graph_ret(priv, ret) _graph_ret(priv, __func__, ret) +static inline int _graph_ret(struct simple_util_priv *priv, + const char *func, int ret) +{ + return snd_soc_ret(simple_priv_to_dev(priv), ret, "at %s()\n", func); +} + #define ep_to_port(ep) of_get_parent(ep) static struct device_node *port_to_ports(struct device_node *port) { @@ -411,19 +418,19 @@ static int __graph_parse_node(struct simple_util_priv *priv, ret = graph_util_parse_dai(priv, ep, dlc, &is_single_links); if (ret < 0) - return ret; + goto end; ret = simple_util_parse_tdm(ep, dai); if (ret < 0) - return ret; + goto end; ret = simple_util_parse_tdm_width_map(priv, ep, dai); if (ret < 0) - return ret; + goto end; ret = simple_util_parse_clk(dev, ep, dai, dlc); if (ret < 0) - return ret; + goto end; /* * set DAI Name @@ -488,11 +495,12 @@ static int __graph_parse_node(struct simple_util_priv *priv, simple_util_canonicalize_cpu(cpus, is_single_links); simple_util_canonicalize_platform(platforms, cpus); } - - return 0; +end: + return graph_ret(priv, ret); } -static int graph_parse_node_multi_nm(struct snd_soc_dai_link *dai_link, +static int graph_parse_node_multi_nm(struct simple_util_priv *priv, + struct snd_soc_dai_link *dai_link, int *nm_idx, int cpu_idx, struct device_node *mcpu_port) { @@ -534,10 +542,10 @@ static int graph_parse_node_multi_nm(struct snd_soc_dai_link *dai_link, struct device_node *mcodec_port_top __free(device_node) = ep_to_port(mcodec_ep_top); struct device_node *mcodec_ports __free(device_node) = port_to_ports(mcodec_port_top); int nm_max = max(dai_link->num_cpus, dai_link->num_codecs); - int ret = 0; + int ret = -EINVAL; if (cpu_idx > dai_link->num_cpus) - return -EINVAL; + goto end; for_each_of_graph_port_endpoint(mcpu_port, mcpu_ep_n) { int codec_idx = 0; @@ -578,8 +586,8 @@ static int graph_parse_node_multi_nm(struct snd_soc_dai_link *dai_link, if (ret < 0) break; } - - return ret; +end: + return graph_ret(priv, ret); } static int graph_parse_node_multi(struct simple_util_priv *priv, @@ -633,7 +641,7 @@ static int graph_parse_node_multi(struct simple_util_priv *priv, /* CPU:Codec = N:M */ if (is_cpu && dai_link->ch_maps) { - ret = graph_parse_node_multi_nm(dai_link, &nm_idx, idx, port); + ret = graph_parse_node_multi_nm(priv, dai_link, &nm_idx, idx, port); if (ret < 0) goto multi_err; } @@ -643,7 +651,7 @@ static int graph_parse_node_multi(struct simple_util_priv *priv, ret = -EINVAL; multi_err: - return ret; + return graph_ret(priv, ret); } static int graph_parse_node_single(struct simple_util_priv *priv, @@ -651,7 +659,7 @@ static int graph_parse_node_single(struct simple_util_priv *priv, struct device_node *ep, struct link_info *li, int is_cpu) { - return __graph_parse_node(priv, gtype, ep, li, is_cpu, 0); + return graph_ret(priv, __graph_parse_node(priv, gtype, ep, li, is_cpu, 0)); } static int graph_parse_node(struct simple_util_priv *priv, @@ -660,11 +668,14 @@ static int graph_parse_node(struct simple_util_priv *priv, struct link_info *li, int is_cpu) { struct device_node *port __free(device_node) = ep_to_port(ep); + int ret; if (graph_lnk_is_multi(port)) - return graph_parse_node_multi(priv, gtype, port, li, is_cpu); + ret = graph_parse_node_multi(priv, gtype, port, li, is_cpu); else - return graph_parse_node_single(priv, gtype, ep, li, is_cpu); + ret = graph_parse_node_single(priv, gtype, ep, li, is_cpu); + + return graph_ret(priv, ret); } static void graph_parse_daifmt(struct device_node *node, unsigned int *daifmt) @@ -842,18 +853,19 @@ int audio_graph2_link_normal(struct simple_util_priv *priv, */ ret = graph_parse_node(priv, GRAPH_NORMAL, codec_ep, li, 0); if (ret < 0) - return ret; + goto end; /* * call CPU, and set DAI Name */ ret = graph_parse_node(priv, GRAPH_NORMAL, cpu_ep, li, 1); if (ret < 0) - return ret; + goto end; graph_link_init(priv, lnk, cpu_ep, codec_ep, li, 1); - return ret; +end: + return graph_ret(priv, ret); } EXPORT_SYMBOL_GPL(audio_graph2_link_normal); @@ -946,7 +958,7 @@ int audio_graph2_link_dpcm(struct simple_util_priv *priv, graph_link_init(priv, lnk, cpu_ep, codec_ep, li, is_cpu); - return ret; + return graph_ret(priv, ret); } EXPORT_SYMBOL_GPL(audio_graph2_link_dpcm); @@ -992,8 +1004,13 @@ int audio_graph2_link_c2c(struct simple_util_priv *priv, struct snd_soc_pcm_stream *c2c_conf; c2c_conf = devm_kzalloc(dev, sizeof(*c2c_conf), GFP_KERNEL); - if (!c2c_conf) - return ret; + if (!c2c_conf) { + /* + * Clang doesn't allow to use "goto end" before calling __free(), + * because it bypasses the initialization. Use graph_ret() directly. + */ + return graph_ret(priv, -ENOMEM); + } c2c_conf->formats = SNDRV_PCM_FMTBIT_S32_LE; /* update ME */ c2c_conf->rates = SNDRV_PCM_RATE_8000_384000; @@ -1019,18 +1036,18 @@ int audio_graph2_link_c2c(struct simple_util_priv *priv, */ ret = graph_parse_node(priv, GRAPH_C2C, codec1_ep, li, 0); if (ret < 0) - return ret; + goto end; /* * call CPU, and set DAI Name */ ret = graph_parse_node(priv, GRAPH_C2C, codec0_ep, li, 1); if (ret < 0) - return ret; + goto end; graph_link_init(priv, lnk, codec0_ep, codec1_ep, li, 1); - - return ret; +end: + return graph_ret(priv, ret); } EXPORT_SYMBOL_GPL(audio_graph2_link_c2c); @@ -1078,7 +1095,7 @@ static int graph_link(struct simple_util_priv *priv, li->link++; err: - return ret; + return graph_ret(priv, ret); } static int graph_counter(struct device_node *lnk) @@ -1249,7 +1266,7 @@ static int graph_count(struct simple_util_priv *priv, li->link++; err: - return ret; + return graph_ret(priv, ret); } static int graph_for_each_link(struct simple_util_priv *priv, @@ -1266,7 +1283,7 @@ static int graph_for_each_link(struct simple_util_priv *priv, struct device_node *node = dev->of_node; struct device_node *lnk; enum graph_type gtype; - int rc, ret; + int rc, ret = 0; /* loop for all listed CPU port */ of_for_each_phandle(&it, rc, node, "links", NULL, 0) { @@ -1276,10 +1293,10 @@ static int graph_for_each_link(struct simple_util_priv *priv, ret = func(priv, hooks, gtype, lnk, li); if (ret < 0) - return ret; + break; } - return 0; + return graph_ret(priv, ret); } int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev, @@ -1355,7 +1372,7 @@ err: if (ret < 0) dev_err_probe(dev, ret, "parse error\n"); - return ret; + return graph_ret(priv, ret); } EXPORT_SYMBOL_GPL(audio_graph2_parse_of); -- 2.51.0 From cb161c333927142818d6bf22a4da2b023fb2b8c9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 6 Feb 2025 21:25:15 +0200 Subject: [PATCH 10/16] ASoC: tas2781: Switch to use %ptTsr Use %ptTsr instead of open-coded variant to print contents of time64_t type in human readable form. Signed-off-by: Andy Shevchenko Link: https://patch.msgid.link/20250206192537.1133763-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- include/sound/tas2781.h | 1 - sound/pci/hda/tas2781-spi.h | 1 - sound/pci/hda/tas2781_hda_i2c.c | 8 +++----- sound/pci/hda/tas2781_hda_spi.c | 3 --- 4 files changed, 3 insertions(+), 10 deletions(-) diff --git a/include/sound/tas2781.h b/include/sound/tas2781.h index 72d2060904f6..0f1e585635bb 100644 --- a/include/sound/tas2781.h +++ b/include/sound/tas2781.h @@ -161,7 +161,6 @@ struct tasdevice_priv { struct mutex codec_lock; struct regmap *regmap; struct device *dev; - struct tm tm; enum device_catlog_id catlog_id; unsigned char cal_binaryname[TASDEVICE_MAX_CHANNELS][64]; diff --git a/sound/pci/hda/tas2781-spi.h b/sound/pci/hda/tas2781-spi.h index ecfc3c8bb821..7a0faceeb675 100644 --- a/sound/pci/hda/tas2781-spi.h +++ b/sound/pci/hda/tas2781-spi.h @@ -88,7 +88,6 @@ struct tasdevice_priv { struct mutex codec_lock; struct regmap *regmap; struct device *dev; - struct tm tm; unsigned char crc8_lkp_tbl[CRC8_TABLE_SIZE]; unsigned char coef_binaryname[64]; diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c index 0e42b87dadb8..be9a90f643eb 100644 --- a/sound/pci/hda/tas2781_hda_i2c.c +++ b/sound/pci/hda/tas2781_hda_i2c.c @@ -594,7 +594,6 @@ static int tas2781_save_calibration(struct tasdevice_priv *tas_priv) efi_guid_t efi_guid = EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d, 0x93, 0xfe, 0x5a, 0xa3, 0x5d, 0xb3); static efi_char16_t efi_name[] = L"CALI_DATA"; - struct tm *tm = &tas_priv->tm; unsigned int attr, crc; unsigned int *tmp_val; efi_status_t status; @@ -629,10 +628,9 @@ static int tas2781_save_calibration(struct tasdevice_priv *tas_priv) crc, tmp_val[21]); if (crc == tmp_val[21]) { - time64_to_tm(tmp_val[20], 0, tm); - dev_dbg(tas_priv->dev, "%4ld-%2d-%2d, %2d:%2d:%2d\n", - tm->tm_year, tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + time64_t seconds = tmp_val[20]; + + dev_dbg(tas_priv->dev, "%ptTsr\n", &seconds); tasdevice_apply_calibration(tas_priv); } else tas_priv->cali_data.total_sz = 0; diff --git a/sound/pci/hda/tas2781_hda_spi.c b/sound/pci/hda/tas2781_hda_spi.c index a42fa990e7b9..d91b19602485 100644 --- a/sound/pci/hda/tas2781_hda_spi.c +++ b/sound/pci/hda/tas2781_hda_spi.c @@ -802,7 +802,6 @@ static int tas2781_save_calibration(struct tasdevice_priv *tas_priv) static efi_char16_t efi_name[] = TASDEVICE_CALIBRATION_DATA_NAME; unsigned char data[TASDEVICE_CALIBRATION_DATA_SIZE], *buf; unsigned int attr, crc, offset, *tmp_val; - struct tm *tm = &tas_priv->tm; unsigned long total_sz = 0; efi_status_t status; @@ -849,7 +848,6 @@ static int tas2781_save_calibration(struct tasdevice_priv *tas_priv) if (crc != tmp_val[3 + tmp_val[1] * 6]) return 0; - time64_to_tm(tmp_val[2], 0, tm); for (int j = 0; j < tmp_val[1]; j++) { offset = j * 6 + 3; if (tmp_val[offset] == tas_priv->index) { @@ -882,7 +880,6 @@ static int tas2781_save_calibration(struct tasdevice_priv *tas_priv) */ crc = crc32(~0, data, 84) ^ ~0; if (crc == tmp_val[21]) { - time64_to_tm(tmp_val[20], 0, tm); for (int i = 0; i < CALIB_MAX; i++) tas_priv->cali_data[i] = tmp_val[tas_priv->index * 5 + i]; -- 2.51.0 From 91f505dc3a94c04421a2a51e8c40acf7ea67ecbc Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 7 Feb 2025 20:36:36 +0800 Subject: [PATCH 11/16] ASoC: Intel: soc-acpi-intel-ptl-match: add rt712_vb + rt1320 support s/lnl/ptl Fixes: bd40d912728f ("ASoC: Intel: soc-acpi-intel-ptl-match: add rt712_vb + rt1320 support") Signed-off-by: Peter Ujfalusi Reviewed-by: Kai Vehmanen Reviewed-by: Ranjani Sridharan Signed-off-by: Bard Liao Link: https://patch.msgid.link/20250207123637.215320-2-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-ptl-match.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c index 9eb4a43e3e7a..e487c4e1c034 100644 --- a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c @@ -270,7 +270,7 @@ static const struct snd_soc_acpi_link_adr lnl_sdw_rt713_vb_l2_rt1320_l13[] = { {} }; -static const struct snd_soc_acpi_link_adr lnl_sdw_rt712_vb_l2_rt1320_l1[] = { +static const struct snd_soc_acpi_link_adr ptl_sdw_rt712_vb_l2_rt1320_l1[] = { { .mask = BIT(2), .num_adr = ARRAY_SIZE(rt712_vb_2_group1_adr), @@ -337,10 +337,10 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = { }, { .link_mask = BIT(1) | BIT(2), - .links = lnl_sdw_rt712_vb_l2_rt1320_l1, + .links = ptl_sdw_rt712_vb_l2_rt1320_l1, .drv_name = "sof_sdw", .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, - .sof_tplg_filename = "sof-lnl-rt712-l2-rt1320-l1.tplg" + .sof_tplg_filename = "sof-ptl-rt712-l2-rt1320-l1.tplg" }, { .link_mask = BIT(1) | BIT(2) | BIT(3), -- 2.51.0 From 852c0b7204ded184924c41ab99b2ac7a70ad4dab Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 7 Feb 2025 20:36:37 +0800 Subject: [PATCH 12/16] ASoC: Intel: soc-acpi-intel-ptl-match: add rt713_vb_l2_rt1320_l13 s/lnl/ptl Fixes: a7ebb0255188 ("ASoC: Intel: soc-acpi-intel-ptl-match: add rt713_vb_l2_rt1320_l13 support") Signed-off-by: Peter Ujfalusi Reviewed-by: Kai Vehmanen Reviewed-by: Ranjani Sridharan Signed-off-by: Bard Liao Link: https://patch.msgid.link/20250207123637.215320-3-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-ptl-match.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c index e487c4e1c034..dd7993b76dee 100644 --- a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c @@ -251,7 +251,7 @@ static const struct snd_soc_acpi_link_adr ptl_rvp[] = { {} }; -static const struct snd_soc_acpi_link_adr lnl_sdw_rt713_vb_l2_rt1320_l13[] = { +static const struct snd_soc_acpi_link_adr ptl_sdw_rt713_vb_l2_rt1320_l13[] = { { .mask = BIT(2), .num_adr = ARRAY_SIZE(rt713_vb_2_adr), @@ -344,10 +344,10 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = { }, { .link_mask = BIT(1) | BIT(2) | BIT(3), - .links = lnl_sdw_rt713_vb_l2_rt1320_l13, + .links = ptl_sdw_rt713_vb_l2_rt1320_l13, .drv_name = "sof_sdw", .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, - .sof_tplg_filename = "sof-lnl-rt713-l2-rt1320-l13.tplg" + .sof_tplg_filename = "sof-ptl-rt713-l2-rt1320-l13.tplg" }, {}, }; -- 2.51.0 From 629dd55cf77bd3a8f80049150d3c05fef6d3b468 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 5 Feb 2025 11:37:52 +0000 Subject: [PATCH 13/16] ASoC: SDCA: Minor formatting and naming tweaks Fix up some variable/struct member naming, add some missing kerneldoc and fix some minor formatting/whitespace issues. Signed-off-by: Charles Keepax Reviewed-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20250205113801.3699902-2-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/sdca.h | 20 +++++------ include/sound/sdca_function.h | 64 +++++++++++++++++++++------------ sound/soc/sdca/sdca_device.c | 3 +- sound/soc/sdca/sdca_functions.c | 26 ++++++++++---- 4 files changed, 71 insertions(+), 42 deletions(-) diff --git a/include/sound/sdca.h b/include/sound/sdca.h index 973252d0adac..31b39f2297b9 100644 --- a/include/sound/sdca.h +++ b/include/sound/sdca.h @@ -17,10 +17,10 @@ struct sdw_slave; #define SDCA_MAX_FUNCTION_COUNT 8 /** - * sdca_device_desc - short descriptor for an SDCA Function - * @adr: ACPI address (used for SDCA register access) - * @type: Function topology type - * @name: human-readable string + * struct sdca_function_desc - short descriptor for an SDCA Function + * @name: Human-readable string. + * @type: Function topology type. + * @adr: ACPI address (used for SDCA register access). */ struct sdca_function_desc { const char *name; @@ -29,17 +29,17 @@ struct sdca_function_desc { }; /** - * sdca_device_data - structure containing all SDCA related information - * @sdca_interface_revision: value read from _DSD property, mainly to check - * for changes between silicon versions - * @num_functions: total number of supported SDCA functions. Invalid/unsupported + * struct sdca_device_data - structure containing all SDCA related information + * @interface_revision: Value read from _DSD property, mainly to check + * for changes between silicon versions. + * @num_functions: Total number of supported SDCA functions. Invalid/unsupported * functions will be skipped. - * @sdca_func: array of function descriptors + * @function: Array of function descriptors. */ struct sdca_device_data { u32 interface_revision; int num_functions; - struct sdca_function_desc sdca_func[SDCA_MAX_FUNCTION_COUNT]; + struct sdca_function_desc function[SDCA_MAX_FUNCTION_COUNT]; }; enum sdca_quirk { diff --git a/include/sound/sdca_function.h b/include/sound/sdca_function.h index c051c17903e8..1d1d3a1da52d 100644 --- a/include/sound/sdca_function.h +++ b/include/sound/sdca_function.h @@ -11,39 +11,57 @@ #include -/* +/** + * enum sdca_function_type - SDCA Function Type codes + * @SDCA_FUNCTION_TYPE_SMART_AMP: Amplifier with protection features. + * @SDCA_FUNCTION_TYPE_SIMPLE_AMP: Subset of SmartAmp. + * @SDCA_FUNCTION_TYPE_SMART_MIC: Smart microphone with acoustic triggers. + * @SDCA_FUNCTION_TYPE_SIMPLE_MIC: Subset of SmartMic. + * @SDCA_FUNCTION_TYPE_SPEAKER_MIC: Combination of SmartMic and SmartAmp. + * @SDCA_FUNCTION_TYPE_UAJ: 3.5mm Universal Audio jack. + * @SDCA_FUNCTION_TYPE_RJ: Retaskable jack. + * @SDCA_FUNCTION_TYPE_SIMPLE_JACK: Subset of UAJ. + * @SDCA_FUNCTION_TYPE_HID: Human Interface Device, for e.g. buttons. + * @SDCA_FUNCTION_TYPE_IMP_DEF: Implementation-defined function. + * * SDCA Function Types from SDCA specification v1.0a Section 5.1.2 - * all Function types not described are reserved + * all Function types not described are reserved. + * * Note that SIMPLE_AMP, SIMPLE_MIC and SIMPLE_JACK Function Types * are NOT defined in SDCA 1.0a, but they were defined in earlier * drafts and are planned for 1.1. */ - enum sdca_function_type { - SDCA_FUNCTION_TYPE_SMART_AMP = 0x01, /* Amplifier with protection features */ - SDCA_FUNCTION_TYPE_SIMPLE_AMP = 0x02, /* subset of SmartAmp */ - SDCA_FUNCTION_TYPE_SMART_MIC = 0x03, /* Smart microphone with acoustic triggers */ - SDCA_FUNCTION_TYPE_SIMPLE_MIC = 0x04, /* subset of SmartMic */ - SDCA_FUNCTION_TYPE_SPEAKER_MIC = 0x05, /* Combination of SmartMic and SmartAmp */ - SDCA_FUNCTION_TYPE_UAJ = 0x06, /* 3.5mm Universal Audio jack */ - SDCA_FUNCTION_TYPE_RJ = 0x07, /* Retaskable jack */ - SDCA_FUNCTION_TYPE_SIMPLE_JACK = 0x08, /* Subset of UAJ */ - SDCA_FUNCTION_TYPE_HID = 0x0A, /* Human Interface Device, for e.g. buttons */ - SDCA_FUNCTION_TYPE_IMP_DEF = 0x1F, /* Implementation-defined function */ + SDCA_FUNCTION_TYPE_SMART_AMP = 0x01, + SDCA_FUNCTION_TYPE_SIMPLE_AMP = 0x02, + SDCA_FUNCTION_TYPE_SMART_MIC = 0x03, + SDCA_FUNCTION_TYPE_SIMPLE_MIC = 0x04, + SDCA_FUNCTION_TYPE_SPEAKER_MIC = 0x05, + SDCA_FUNCTION_TYPE_UAJ = 0x06, + SDCA_FUNCTION_TYPE_RJ = 0x07, + SDCA_FUNCTION_TYPE_SIMPLE_JACK = 0x08, + SDCA_FUNCTION_TYPE_HID = 0x0A, + SDCA_FUNCTION_TYPE_IMP_DEF = 0x1F, }; /* Human-readable names used for kernel logs and Function device registration/bind */ -#define SDCA_FUNCTION_TYPE_SMART_AMP_NAME "SmartAmp" -#define SDCA_FUNCTION_TYPE_SIMPLE_AMP_NAME "SimpleAmp" -#define SDCA_FUNCTION_TYPE_SMART_MIC_NAME "SmartMic" -#define SDCA_FUNCTION_TYPE_SIMPLE_MIC_NAME "SimpleMic" -#define SDCA_FUNCTION_TYPE_SPEAKER_MIC_NAME "SpeakerMic" -#define SDCA_FUNCTION_TYPE_UAJ_NAME "UAJ" -#define SDCA_FUNCTION_TYPE_RJ_NAME "RJ" -#define SDCA_FUNCTION_TYPE_SIMPLE_NAME "SimpleJack" -#define SDCA_FUNCTION_TYPE_HID_NAME "HID" -#define SDCA_FUNCTION_TYPE_IMP_DEF_NAME "ImplementationDefined" +#define SDCA_FUNCTION_TYPE_SMART_AMP_NAME "SmartAmp" +#define SDCA_FUNCTION_TYPE_SIMPLE_AMP_NAME "SimpleAmp" +#define SDCA_FUNCTION_TYPE_SMART_MIC_NAME "SmartMic" +#define SDCA_FUNCTION_TYPE_SIMPLE_MIC_NAME "SimpleMic" +#define SDCA_FUNCTION_TYPE_SPEAKER_MIC_NAME "SpeakerMic" +#define SDCA_FUNCTION_TYPE_UAJ_NAME "UAJ" +#define SDCA_FUNCTION_TYPE_RJ_NAME "RJ" +#define SDCA_FUNCTION_TYPE_SIMPLE_NAME "SimpleJack" +#define SDCA_FUNCTION_TYPE_HID_NAME "HID" +#define SDCA_FUNCTION_TYPE_IMP_DEF_NAME "ImplementationDefined" +/** + * enum sdca_entity0_controls - SDCA Controls for Entity 0 + * + * Control Selectors for Entity 0 from SDCA specification v1.0 Section + * 6.7.1.1. + */ enum sdca_entity0_controls { SDCA_CTL_ENTITY_0_COMMIT_GROUP_MASK = 0x01, SDCA_CTL_ENTITY_0_FUNCTION_SDCA_VERSION = 0x04, diff --git a/sound/soc/sdca/sdca_device.c b/sound/soc/sdca/sdca_device.c index b6399b773986..0244cdcdd109 100644 --- a/sound/soc/sdca/sdca_device.c +++ b/sound/soc/sdca/sdca_device.c @@ -48,8 +48,7 @@ static bool sdca_device_quirk_rt712_vb(struct sdw_slave *slave) return false; for (i = 0; i < slave->sdca_data.num_functions; i++) { - if (slave->sdca_data.sdca_func[i].type == - SDCA_FUNCTION_TYPE_SMART_MIC) + if (slave->sdca_data.function[i].type == SDCA_FUNCTION_TYPE_SMART_MIC) return true; } diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c index 38071bc838b9..00d6d044c816 100644 --- a/sound/soc/sdca/sdca_functions.c +++ b/sound/soc/sdca/sdca_functions.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -21,7 +22,7 @@ static int patch_sdca_function_type(u32 interface_revision, u32 *function_type) { /* * Unfortunately early SDCA specifications used different indices for Functions, - * for backwards compatibility we have to reorder the values found + * for backwards compatibility we have to reorder the values found. */ if (interface_revision < 0x0801) { switch (*function_type) { @@ -85,7 +86,7 @@ static int find_sdca_function(struct acpi_device *adev, void *data) struct fwnode_handle *control5; /* used to identify function type */ const char *function_name; u32 function_type; - int func_index; + int function_index; u64 addr; int ret; @@ -145,24 +146,35 @@ static int find_sdca_function(struct acpi_device *adev, void *data) function_name, function_type, addr); /* store results */ - func_index = sdca_data->num_functions; - sdca_data->sdca_func[func_index].adr = addr; - sdca_data->sdca_func[func_index].type = function_type; - sdca_data->sdca_func[func_index].name = function_name; + function_index = sdca_data->num_functions; + sdca_data->function[function_index].adr = addr; + sdca_data->function[function_index].type = function_type; + sdca_data->function[function_index].name = function_name; sdca_data->num_functions++; return 0; } +/** + * sdca_lookup_functions - Parse sdca_device_desc for each Function + * @slave: SoundWire slave device to be processed. + * + * Iterate through the available SDCA Functions and fill in a short + * descriptor (struct sdca_function_desc) for each function, this + * information is stored along with the SoundWire slave device and + * used for adding drivers and quirks before the devices have fully + * probed. + */ void sdca_lookup_functions(struct sdw_slave *slave) { struct device *dev = &slave->dev; struct acpi_device *adev = to_acpi_device_node(dev->fwnode); if (!adev) { - dev_info(dev, "No matching ACPI device found, ignoring peripheral\n"); + dev_info(dev, "no matching ACPI device found, ignoring peripheral\n"); return; } + acpi_dev_for_each_child(adev, find_sdca_function, &slave->sdca_data); } EXPORT_SYMBOL_NS(sdca_lookup_functions, "SND_SOC_SDCA"); -- 2.51.0 From 996bf834d0b61cb5a1389356c1ed7db1230139d7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 5 Feb 2025 11:37:53 +0000 Subject: [PATCH 14/16] ASoC: SDCA: Add code to parse Function information Add a helper function to parse all the Function and Entity information from ACPI. In SDCA each device may have several Functions and each corresponds to a specific audio capability such as say amplifier playback or microphone capture. Each Function then contains a number of Entities that represent individual parts of the audio signal chain and are linked together in a graph similar to DAPM. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Charles Keepax Reviewed-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20250205113801.3699902-3-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/sdca.h | 2 + include/sound/sdca_function.h | 95 +++++++++++ sound/soc/sdca/sdca_functions.c | 268 ++++++++++++++++++++++++++++++++ 3 files changed, 365 insertions(+) diff --git a/include/sound/sdca.h b/include/sound/sdca.h index 31b39f2297b9..5a5d6de78d72 100644 --- a/include/sound/sdca.h +++ b/include/sound/sdca.h @@ -18,11 +18,13 @@ struct sdw_slave; /** * struct sdca_function_desc - short descriptor for an SDCA Function + * @node: firmware node for the Function. * @name: Human-readable string. * @type: Function topology type. * @adr: ACPI address (used for SDCA register access). */ struct sdca_function_desc { + struct fwnode_handle *node; const char *name; u32 type; u8 adr; diff --git a/include/sound/sdca_function.h b/include/sound/sdca_function.h index 1d1d3a1da52d..3f4031d285d6 100644 --- a/include/sound/sdca_function.h +++ b/include/sound/sdca_function.h @@ -11,6 +11,15 @@ #include +struct device; +struct sdca_function_desc; + +/* + * The addressing space for SDCA relies on 7 bits for Entities, so a + * maximum of 128 Entities per function can be represented. + */ +#define SDCA_MAX_ENTITY_COUNT 128 + /** * enum sdca_function_type - SDCA Function Type codes * @SDCA_FUNCTION_TYPE_SMART_AMP: Amplifier with protection features. @@ -90,4 +99,90 @@ enum sdca_entity0_controls { SDCA_CTL_ENTITY_0_FUNCTION_BUSY = BIT(7), }; +/** + * enum sdca_entity_type - SDCA Entity Type codes + * @SDCA_ENTITY_TYPE_IT: Input Terminal. + * @SDCA_ENTITY_TYPE_OT: Output Terminal. + * @SDCA_ENTITY_TYPE_MU: Mixer Unit. + * @SDCA_ENTITY_TYPE_SU: Selector Unit. + * @SDCA_ENTITY_TYPE_FU: Feature Unit. + * @SDCA_ENTITY_TYPE_XU: Extension Unit. + * @SDCA_ENTITY_TYPE_CS: Clock Source. + * @SDCA_ENTITY_TYPE_CX: Clock selector. + * @SDCA_ENTITY_TYPE_PDE: Power-Domain Entity. + * @SDCA_ENTITY_TYPE_GE: Group Entity. + * @SDCA_ENTITY_TYPE_SPE: Security & Privacy Entity. + * @SDCA_ENTITY_TYPE_CRU: Channel Remapping Unit. + * @SDCA_ENTITY_TYPE_UDMPU: Up-Down Mixer Processing Unit. + * @SDCA_ENTITY_TYPE_MFPU: Multi-Function Processing Unit. + * @SDCA_ENTITY_TYPE_SMPU: Smart Microphone Processing Unit. + * @SDCA_ENTITY_TYPE_SAPU: Smart Amp Processing Unit. + * @SDCA_ENTITY_TYPE_PPU: Posture Processing Unit. + * @SDCA_ENTITY_TYPE_TG: Tone Generator. + * @SDCA_ENTITY_TYPE_HIDE: Human Interface Device Entity. + * + * SDCA Entity Types from SDCA specification v1.0 Section 6.1.2 + * all Entity Types not described are reserved. + */ +enum sdca_entity_type { + SDCA_ENTITY_TYPE_IT = 0x02, + SDCA_ENTITY_TYPE_OT = 0x03, + SDCA_ENTITY_TYPE_MU = 0x05, + SDCA_ENTITY_TYPE_SU = 0x06, + SDCA_ENTITY_TYPE_FU = 0x07, + SDCA_ENTITY_TYPE_XU = 0x0A, + SDCA_ENTITY_TYPE_CS = 0x0B, + SDCA_ENTITY_TYPE_CX = 0x0C, + SDCA_ENTITY_TYPE_PDE = 0x11, + SDCA_ENTITY_TYPE_GE = 0x12, + SDCA_ENTITY_TYPE_SPE = 0x13, + SDCA_ENTITY_TYPE_CRU = 0x20, + SDCA_ENTITY_TYPE_UDMPU = 0x21, + SDCA_ENTITY_TYPE_MFPU = 0x22, + SDCA_ENTITY_TYPE_SMPU = 0x23, + SDCA_ENTITY_TYPE_SAPU = 0x24, + SDCA_ENTITY_TYPE_PPU = 0x25, + SDCA_ENTITY_TYPE_TG = 0x30, + SDCA_ENTITY_TYPE_HIDE = 0x31, +}; + +/** + * struct sdca_entity - information for one SDCA Entity + * @label: String such as "OT 12". + * @id: Identifier used for addressing. + * @type: Type code for the Entity. + * @sources: Dynamically allocated array pointing to each input Entity + * connected to this Entity. + * @num_sources: Number of sources for the Entity. + */ +struct sdca_entity { + const char *label; + int id; + enum sdca_entity_type type; + + struct sdca_entity **sources; + int num_sources; +}; + +/** + * struct sdca_function_data - top-level information for one SDCA function + * @desc: Pointer to short descriptor from initial parsing. + * @entities: Dynamically allocated array of Entities. + * @num_entities: Number of Entities reported in this Function. + * @busy_max_delay: Maximum Function busy delay in microseconds, before an + * error should be reported. + */ +struct sdca_function_data { + struct sdca_function_desc *desc; + + struct sdca_entity *entities; + int num_entities; + + unsigned int busy_max_delay; +}; + +int sdca_parse_function(struct device *dev, + struct sdca_function_desc *desc, + struct sdca_function_data *function); + #endif diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c index 00d6d044c816..72b82280918d 100644 --- a/sound/soc/sdca/sdca_functions.c +++ b/sound/soc/sdca/sdca_functions.c @@ -18,6 +18,11 @@ #include #include +/* + * Should be long enough to encompass all the MIPI DisCo properties. + */ +#define SDCA_PROPERTY_LENGTH 64 + static int patch_sdca_function_type(u32 interface_revision, u32 *function_type) { /* @@ -150,6 +155,7 @@ static int find_sdca_function(struct acpi_device *adev, void *data) sdca_data->function[function_index].adr = addr; sdca_data->function[function_index].type = function_type; sdca_data->function[function_index].name = function_name; + sdca_data->function[function_index].node = function_node; sdca_data->num_functions++; return 0; @@ -179,5 +185,267 @@ void sdca_lookup_functions(struct sdw_slave *slave) } EXPORT_SYMBOL_NS(sdca_lookup_functions, "SND_SOC_SDCA"); +static int find_sdca_entity(struct device *dev, + struct fwnode_handle *function_node, + struct fwnode_handle *entity_node, + struct sdca_entity *entity) +{ + u32 tmp; + int ret; + + ret = fwnode_property_read_string(entity_node, "mipi-sdca-entity-label", + &entity->label); + if (ret) { + dev_err(dev, "%pfwP: entity %#x: label missing: %d\n", + function_node, entity->id, ret); + return ret; + } + + ret = fwnode_property_read_u32(entity_node, "mipi-sdca-entity-type", &tmp); + if (ret) { + dev_err(dev, "%s: type missing: %d\n", entity->label, ret); + return ret; + } + + entity->type = tmp; + + dev_info(dev, "%s: entity %#x type %#x\n", + entity->label, entity->id, entity->type); + + return 0; +} + +static int find_sdca_entities(struct device *dev, + struct fwnode_handle *function_node, + struct sdca_function_data *function) +{ + struct sdca_entity *entities; + u32 *entity_list; + int num_entities; + int i, ret; + + num_entities = fwnode_property_count_u32(function_node, + "mipi-sdca-entity-id-list"); + if (num_entities <= 0) { + dev_err(dev, "%pfwP: entity id list missing: %d\n", + function_node, num_entities); + return -EINVAL; + } else if (num_entities > SDCA_MAX_ENTITY_COUNT) { + dev_err(dev, "%pfwP: maximum number of entities exceeded\n", + function_node); + return -EINVAL; + } + + entities = devm_kcalloc(dev, num_entities, sizeof(*entities), GFP_KERNEL); + if (!entities) + return -ENOMEM; + + entity_list = kcalloc(num_entities, sizeof(*entity_list), GFP_KERNEL); + if (!entity_list) + return -ENOMEM; + + fwnode_property_read_u32_array(function_node, "mipi-sdca-entity-id-list", + entity_list, num_entities); + + for (i = 0; i < num_entities; i++) + entities[i].id = entity_list[i]; + + kfree(entity_list); + + /* now read subproperties */ + for (i = 0; i < num_entities; i++) { + char entity_property[SDCA_PROPERTY_LENGTH]; + struct fwnode_handle *entity_node; + + /* DisCo uses upper-case for hex numbers */ + snprintf(entity_property, sizeof(entity_property), + "mipi-sdca-entity-id-0x%X-subproperties", entities[i].id); + + entity_node = fwnode_get_named_child_node(function_node, entity_property); + if (!entity_node) { + dev_err(dev, "%pfwP: entity node %s not found\n", + function_node, entity_property); + return -EINVAL; + } + + ret = find_sdca_entity(dev, function_node, entity_node, &entities[i]); + fwnode_handle_put(entity_node); + if (ret) + return ret; + } + + function->num_entities = num_entities; + function->entities = entities; + + return 0; +} + +static struct sdca_entity *find_sdca_entity_by_label(struct sdca_function_data *function, + const char *entity_label) +{ + int i; + + for (i = 0; i < function->num_entities; i++) { + struct sdca_entity *entity = &function->entities[i]; + + if (!strcmp(entity->label, entity_label)) + return entity; + } + + return NULL; +} + +static int find_sdca_entity_connection(struct device *dev, + struct sdca_function_data *function, + struct fwnode_handle *entity_node, + struct sdca_entity *entity) +{ + struct sdca_entity **pins; + int num_pins, pin; + u64 pin_list; + int i, ret; + + ret = fwnode_property_read_u64(entity_node, "mipi-sdca-input-pin-list", &pin_list); + if (ret == -EINVAL) { + /* Allow missing pin lists, assume no pins. */ + dev_warn(dev, "%s: missing pin list\n", entity->label); + return 0; + } else if (ret) { + dev_err(dev, "%s: failed to read pin list: %d\n", entity->label, ret); + return ret; + } else if (pin_list & BIT(0)) { + /* + * Each bit set in the pin-list refers to an entity_id in this + * Function. Entity 0 is an illegal connection since it is used + * for Function-level configurations. + */ + dev_err(dev, "%s: pin 0 used as input\n", entity->label); + return -EINVAL; + } else if (!pin_list) { + return 0; + } + + num_pins = hweight64(pin_list); + pins = devm_kcalloc(dev, num_pins, sizeof(*pins), GFP_KERNEL); + if (!pins) + return -ENOMEM; + + i = 0; + for_each_set_bit(pin, (unsigned long *)&pin_list, BITS_PER_TYPE(pin_list)) { + char pin_property[SDCA_PROPERTY_LENGTH]; + struct fwnode_handle *connected_node; + struct sdca_entity *connected_entity; + const char *connected_label; + + snprintf(pin_property, sizeof(pin_property), "mipi-sdca-input-pin-%d", pin); + + connected_node = fwnode_get_named_child_node(entity_node, pin_property); + if (!connected_node) { + dev_err(dev, "%s: pin node %s not found\n", + entity->label, pin_property); + return -EINVAL; + } + + ret = fwnode_property_read_string(connected_node, "mipi-sdca-entity-label", + &connected_label); + if (ret) { + dev_err(dev, "%s: pin %d label missing: %d\n", + entity->label, pin, ret); + fwnode_handle_put(connected_node); + return ret; + } + + connected_entity = find_sdca_entity_by_label(function, connected_label); + if (!connected_entity) { + dev_err(dev, "%s: failed to find entity with label %s\n", + entity->label, connected_label); + fwnode_handle_put(connected_node); + return -EINVAL; + } + + pins[i] = connected_entity; + + dev_info(dev, "%s -> %s\n", connected_entity->label, entity->label); + + i++; + fwnode_handle_put(connected_node); + } + + entity->num_sources = num_pins; + entity->sources = pins; + + return 0; +} + +static int find_sdca_connections(struct device *dev, + struct fwnode_handle *function_node, + struct sdca_function_data *function) +{ + int i; + + for (i = 0; i < function->num_entities; i++) { + struct sdca_entity *entity = &function->entities[i]; + char entity_property[SDCA_PROPERTY_LENGTH]; + struct fwnode_handle *entity_node; + int ret; + + /* DisCo uses upper-case for hex numbers */ + snprintf(entity_property, sizeof(entity_property), + "mipi-sdca-entity-id-0x%X-subproperties", + entity->id); + + entity_node = fwnode_get_named_child_node(function_node, entity_property); + if (!entity_node) { + dev_err(dev, "%pfwP: entity node %s not found\n", + function_node, entity_property); + return -EINVAL; + } + + ret = find_sdca_entity_connection(dev, function, entity_node, entity); + fwnode_handle_put(entity_node); + if (ret) + return ret; + } + + return 0; +} + +/** + * sdca_parse_function - parse ACPI DisCo for a Function + * @dev: Pointer to device against which function data will be allocated. + * @function_desc: Pointer to the Function short descriptor. + * @function: Pointer to the Function information, to be populated. + * + * Return: Returns 0 for success. + */ +int sdca_parse_function(struct device *dev, + struct sdca_function_desc *function_desc, + struct sdca_function_data *function) +{ + u32 tmp; + int ret; + + function->desc = function_desc; + + ret = fwnode_property_read_u32(function_desc->node, + "mipi-sdca-function-busy-max-delay", &tmp); + if (!ret) + function->busy_max_delay = tmp; + + dev_info(dev, "%pfwP: name %s delay %dus\n", function->desc->node, + function->desc->name, function->busy_max_delay); + + ret = find_sdca_entities(dev, function_desc->node, function); + if (ret) + return ret; + + ret = find_sdca_connections(dev, function_desc->node, function); + if (ret) + return ret; + + return 0; +} +EXPORT_SYMBOL_NS(sdca_parse_function, "SND_SOC_SDCA"); + MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SDCA library"); -- 2.51.0 From 19f6748abbab8523a7b32a5e371e39d4d8d4aba5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 5 Feb 2025 11:37:54 +0000 Subject: [PATCH 15/16] ASoC: SDCA: Parse initialization write table Each SDCA Function may contain a table of register writes that should be written out before the Function is used. Add code to parse this table from the DisCo tables in ACPI. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Charles Keepax Reviewed-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20250205113801.3699902-4-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/sdca_function.h | 20 +++++++++++ sound/soc/sdca/sdca_functions.c | 61 +++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/include/sound/sdca_function.h b/include/sound/sdca_function.h index 3f4031d285d6..47fc1da8e4f3 100644 --- a/include/sound/sdca_function.h +++ b/include/sound/sdca_function.h @@ -10,6 +10,7 @@ #define __SDCA_FUNCTION_H__ #include +#include struct device; struct sdca_function_desc; @@ -20,6 +21,11 @@ struct sdca_function_desc; */ #define SDCA_MAX_ENTITY_COUNT 128 +/* + * Sanity check on number of initialization writes, can be expanded if needed. + */ +#define SDCA_MAX_INIT_COUNT 2048 + /** * enum sdca_function_type - SDCA Function Type codes * @SDCA_FUNCTION_TYPE_SMART_AMP: Amplifier with protection features. @@ -65,6 +71,16 @@ enum sdca_function_type { #define SDCA_FUNCTION_TYPE_HID_NAME "HID" #define SDCA_FUNCTION_TYPE_IMP_DEF_NAME "ImplementationDefined" +/** + * struct sdca_init_write - a single initialization write + * @addr: Register address to be written + * @val: Single byte value to be written + */ +struct sdca_init_write { + u32 addr; + u8 val; +}; + /** * enum sdca_entity0_controls - SDCA Controls for Entity 0 * @@ -167,7 +183,9 @@ struct sdca_entity { /** * struct sdca_function_data - top-level information for one SDCA function * @desc: Pointer to short descriptor from initial parsing. + * @init_table: Pointer to a table of initialization writes. * @entities: Dynamically allocated array of Entities. + * @num_init_table: Number of initialization writes. * @num_entities: Number of Entities reported in this Function. * @busy_max_delay: Maximum Function busy delay in microseconds, before an * error should be reported. @@ -175,7 +193,9 @@ struct sdca_entity { struct sdca_function_data { struct sdca_function_desc *desc; + struct sdca_init_write *init_table; struct sdca_entity *entities; + int num_init_table; int num_entities; unsigned int busy_max_delay; diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c index 72b82280918d..f914ec3f86c9 100644 --- a/sound/soc/sdca/sdca_functions.c +++ b/sound/soc/sdca/sdca_functions.c @@ -9,6 +9,7 @@ #define dev_fmt(fmt) "%s: " fmt, __func__ #include +#include #include #include #include @@ -185,6 +186,62 @@ void sdca_lookup_functions(struct sdw_slave *slave) } EXPORT_SYMBOL_NS(sdca_lookup_functions, "SND_SOC_SDCA"); +static int find_sdca_init_table(struct device *dev, + struct fwnode_handle *function_node, + struct sdca_function_data *function) +{ + struct sdca_init_write *init_write; + int write_size = sizeof(init_write->addr) + sizeof(init_write->val); + u8 *init_list, *init_iter; + int num_init_writes; + + num_init_writes = fwnode_property_count_u8(function_node, + "mipi-sdca-function-initialization-table"); + if (!num_init_writes || num_init_writes == -EINVAL) { + return 0; + } else if (num_init_writes < 0) { + dev_err(dev, "%pfwP: failed to read initialization table: %d\n", + function_node, num_init_writes); + return num_init_writes; + } else if (num_init_writes % write_size != 0) { + dev_err(dev, "%pfwP: init table size invalid\n", function_node); + return -EINVAL; + } else if (num_init_writes > SDCA_MAX_INIT_COUNT) { + dev_err(dev, "%pfwP: maximum init table size exceeded\n", function_node); + return -EINVAL; + } + + init_write = devm_kcalloc(dev, num_init_writes / write_size, + sizeof(*init_write), GFP_KERNEL); + if (!init_write) + return -ENOMEM; + + init_list = kcalloc(num_init_writes, sizeof(*init_list), GFP_KERNEL); + if (!init_list) + return -ENOMEM; + + fwnode_property_read_u8_array(function_node, + "mipi-sdca-function-initialization-table", + init_list, num_init_writes); + + function->num_init_table = num_init_writes; + function->init_table = init_write; + + for (init_iter = init_list; init_iter < init_list + num_init_writes;) { + u32 *addr = (u32 *)init_iter; + + init_write->addr = le32_to_cpu(*addr); + init_iter += sizeof(init_write->addr); + + init_write->val = *init_iter; + init_iter += sizeof(init_write->val); + } + + kfree(init_list); + + return 0; +} + static int find_sdca_entity(struct device *dev, struct fwnode_handle *function_node, struct fwnode_handle *entity_node, @@ -435,6 +492,10 @@ int sdca_parse_function(struct device *dev, dev_info(dev, "%pfwP: name %s delay %dus\n", function->desc->node, function->desc->name, function->busy_max_delay); + ret = find_sdca_init_table(dev, function_desc->node, function); + if (ret) + return ret; + ret = find_sdca_entities(dev, function_desc->node, function); if (ret) return ret; -- 2.51.0 From 9ee6d50ae4b0fe14ed70a5265a05874d41e10848 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 5 Feb 2025 11:37:55 +0000 Subject: [PATCH 16/16] ASoC: SDCA: Add support for Entity 0 Within SDCA there is a special Entity called Entity 0 which is used to hold Function level controls. Whilst Entity 0 isn't a full SDCA Entity, it is helpful to add an sdca_entity structure for it. This will allow it to be treated identically in the code that handles SDCA Controls. Signed-off-by: Charles Keepax Reviewed-by: Pierre-Louis Bossart Link: https://patch.msgid.link/20250205113801.3699902-5-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/sdca_function.h | 4 ++++ sound/soc/sdca/sdca_functions.c | 14 +++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/include/sound/sdca_function.h b/include/sound/sdca_function.h index 47fc1da8e4f3..a51e3a459e36 100644 --- a/include/sound/sdca_function.h +++ b/include/sound/sdca_function.h @@ -117,6 +117,9 @@ enum sdca_entity0_controls { /** * enum sdca_entity_type - SDCA Entity Type codes + * @SDCA_ENTITY_TYPE_ENTITY_0: Entity 0, not actually from the + * specification but useful internally as an Entity structure + * is allocated for Entity 0, to hold Entity 0 controls. * @SDCA_ENTITY_TYPE_IT: Input Terminal. * @SDCA_ENTITY_TYPE_OT: Output Terminal. * @SDCA_ENTITY_TYPE_MU: Mixer Unit. @@ -141,6 +144,7 @@ enum sdca_entity0_controls { * all Entity Types not described are reserved. */ enum sdca_entity_type { + SDCA_ENTITY_TYPE_ENTITY_0 = 0x00, SDCA_ENTITY_TYPE_IT = 0x02, SDCA_ENTITY_TYPE_OT = 0x03, SDCA_ENTITY_TYPE_MU = 0x05, diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c index f914ec3f86c9..b0ca92f1bc57 100644 --- a/sound/soc/sdca/sdca_functions.c +++ b/sound/soc/sdca/sdca_functions.c @@ -293,7 +293,8 @@ static int find_sdca_entities(struct device *dev, return -EINVAL; } - entities = devm_kcalloc(dev, num_entities, sizeof(*entities), GFP_KERNEL); + /* Add 1 to make space for Entity 0 */ + entities = devm_kcalloc(dev, num_entities + 1, sizeof(*entities), GFP_KERNEL); if (!entities) return -ENOMEM; @@ -331,7 +332,13 @@ static int find_sdca_entities(struct device *dev, return ret; } - function->num_entities = num_entities; + /* + * Add Entity 0 at end of the array, makes it easy to skip during + * all the Entity searches involved in creating connections. + */ + entities[num_entities].label = "entity0"; + + function->num_entities = num_entities + 1; function->entities = entities; return 0; @@ -440,7 +447,8 @@ static int find_sdca_connections(struct device *dev, { int i; - for (i = 0; i < function->num_entities; i++) { + /* Entity 0 cannot have connections */ + for (i = 0; i < function->num_entities - 1; i++) { struct sdca_entity *entity = &function->entities[i]; char entity_property[SDCA_PROPERTY_LENGTH]; struct fwnode_handle *entity_node; -- 2.51.0