From 77fffb83933ad9e514ea0c7fd93b28cabcdea311 Mon Sep 17 00:00:00 2001 From: Vincent Knecht Date: Sun, 31 Oct 2021 22:09:55 +0100 Subject: [PATCH 001/327] ASoC: dt-bindings: nxp, tfa989x: Add rcv-gpios property for tfa9897 Add optional rcv-gpios property specific to tfa9897 receiver mode. Signed-off-by: Vincent Knecht Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20211031210956.812101-2-vincent.knecht@mailoo.org Signed-off-by: Mark Brown --- .../bindings/sound/nxp,tfa989x.yaml | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml b/Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml index 7667471be1e48..b9b1dba40856d 100644 --- a/Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml +++ b/Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml @@ -24,11 +24,23 @@ properties: '#sound-dai-cells': const: 0 + rcv-gpios: + description: optional GPIO to be asserted when receiver mode is enabled. + sound-name-prefix: true vddd-supply: description: regulator phandle for the VDDD power supply. +if: + not: + properties: + compatible: + const: nxp,tfa9897 +then: + properties: + rcv-gpios: false + required: - compatible - reg @@ -55,3 +67,32 @@ examples: #sound-dai-cells = <0>; }; }; + + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + speaker_codec_top: audio-codec@34 { + compatible = "nxp,tfa9897"; + reg = <0x34>; + vddd-supply = <&pm8916_l6>; + rcv-gpios = <&msmgpio 50 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&speaker_top_default>; + sound-name-prefix = "Speaker Top"; + #sound-dai-cells = <0>; + }; + + speaker_codec_bottom: audio-codec@36 { + compatible = "nxp,tfa9897"; + reg = <0x36>; + vddd-supply = <&pm8916_l6>; + rcv-gpios = <&msmgpio 111 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&speaker_bottom_default>; + sound-name-prefix = "Speaker Bottom"; + #sound-dai-cells = <0>; + }; + }; From 9da52c39b33e7bd9c1f56175c0466fa468d7f145 Mon Sep 17 00:00:00 2001 From: Vincent Knecht Date: Sun, 31 Oct 2021 22:09:56 +0100 Subject: [PATCH 002/327] ASoC: codecs: tfa989x: Add support for tfa9897 optional rcv-gpios Some OEM use a GPIO in addition to the tfa9897 RCV bit to switch between loudspeaker and earpiece/receiver mode. Add support for the GPIO switching by specifying rcv-gpios in DT. Signed-off-by: Vincent Knecht Link: https://lore.kernel.org/r/20211031210956.812101-3-vincent.knecht@mailoo.org Signed-off-by: Mark Brown --- sound/soc/codecs/tfa989x.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/tfa989x.c b/sound/soc/codecs/tfa989x.c index eb2a7870148de..dc86852752c50 100644 --- a/sound/soc/codecs/tfa989x.c +++ b/sound/soc/codecs/tfa989x.c @@ -7,6 +7,7 @@ * Copyright (C) 2013 Sony Mobile Communications Inc. */ +#include #include #include #include @@ -56,6 +57,7 @@ struct tfa989x_rev { struct tfa989x { const struct tfa989x_rev *rev; struct regulator *vddd_supply; + struct gpio_desc *rcv_gpiod; }; static bool tfa989x_writeable_reg(struct device *dev, unsigned int reg) @@ -99,10 +101,20 @@ static const struct snd_soc_dapm_route tfa989x_dapm_routes[] = { {"Amp Input", "Right", "AIFINR"}, }; +static int tfa989x_put_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct tfa989x *tfa989x = snd_soc_component_get_drvdata(component); + + gpiod_set_value_cansleep(tfa989x->rcv_gpiod, ucontrol->value.enumerated.item[0]); + + return snd_soc_put_enum_double(kcontrol, ucontrol); +} + static const char * const mode_text[] = { "Speaker", "Receiver" }; static SOC_ENUM_SINGLE_DECL(mode_enum, TFA989X_I2SREG, TFA989X_I2SREG_RCV, mode_text); static const struct snd_kcontrol_new tfa989x_mode_controls[] = { - SOC_ENUM("Mode", mode_enum), + SOC_ENUM_EXT("Mode", mode_enum, snd_soc_get_enum_double, tfa989x_put_mode), }; static int tfa989x_probe(struct snd_soc_component *component) @@ -301,6 +313,12 @@ static int tfa989x_i2c_probe(struct i2c_client *i2c) return dev_err_probe(dev, PTR_ERR(tfa989x->vddd_supply), "Failed to get vddd regulator\n"); + if (tfa989x->rev->rev == TFA9897_REVISION) { + tfa989x->rcv_gpiod = devm_gpiod_get_optional(dev, "rcv", GPIOD_OUT_LOW); + if (IS_ERR(tfa989x->rcv_gpiod)) + return PTR_ERR(tfa989x->rcv_gpiod); + } + regmap = devm_regmap_init_i2c(i2c, &tfa989x_regmap); if (IS_ERR(regmap)) return PTR_ERR(regmap); From 168eed447129899611098219b70ef97b605bc6e1 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 2 Nov 2021 12:10:17 +0200 Subject: [PATCH 003/327] ASoC: SOF: IPC: Add new IPC command to free trace DMA Add a new SOF_IPC_TRACE_DMA_FREE IPC command to stop and free trace DMA in the FW. Signed-off-by: Ranjani Sridharan Reviewed-by: Kai Vehmanen Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20211102101019.14037-2-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/header.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/sound/sof/header.h b/include/sound/sof/header.h index 4c747c52e01b1..b97a76bcb6555 100644 --- a/include/sound/sof/header.h +++ b/include/sound/sof/header.h @@ -119,6 +119,7 @@ #define SOF_IPC_TRACE_DMA_POSITION SOF_CMD_TYPE(0x002) #define SOF_IPC_TRACE_DMA_PARAMS_EXT SOF_CMD_TYPE(0x003) #define SOF_IPC_TRACE_FILTER_UPDATE SOF_CMD_TYPE(0x004) /**< ABI3.17 */ +#define SOF_IPC_TRACE_DMA_FREE SOF_CMD_TYPE(0x005) /**< ABI3.20 */ /* debug */ #define SOF_IPC_DEBUG_MEM_USAGE SOF_CMD_TYPE(0x001) From b4e2d7ce132bc4337916662f8e699420377132d9 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 2 Nov 2021 12:10:18 +0200 Subject: [PATCH 004/327] ASoC: SOF: IPC: update ipc_log_header() Parse all the trace DMA IPC commands in ipc_log_header(). Signed-off-by: Ranjani Sridharan Reviewed-by: Kai Vehmanen Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20211102101019.14037-3-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index e6c53c6c470e4..a4036d0b3d3ab 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -173,7 +173,22 @@ static void ipc_log_header(struct device *dev, u8 *text, u32 cmd) } break; case SOF_IPC_GLB_TRACE_MSG: - str = "GLB_TRACE_MSG"; break; + str = "GLB_TRACE_MSG"; + switch (type) { + case SOF_IPC_TRACE_DMA_PARAMS: + str2 = "DMA_PARAMS"; break; + case SOF_IPC_TRACE_DMA_POSITION: + str2 = "DMA_POSITION"; break; + case SOF_IPC_TRACE_DMA_PARAMS_EXT: + str2 = "DMA_PARAMS_EXT"; break; + case SOF_IPC_TRACE_FILTER_UPDATE: + str2 = "FILTER_UPDATE"; break; + case SOF_IPC_TRACE_DMA_FREE: + str2 = "DMA_FREE"; break; + default: + str2 = "unknown type"; break; + } + break; case SOF_IPC_GLB_TEST_MSG: str = "GLB_TEST_MSG"; switch (type) { From 48b5b6a56002569881d18be56deaddad045df918 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 2 Nov 2021 12:10:19 +0200 Subject: [PATCH 005/327] ASoC: SOF: trace: send DMA_TRACE_FREE IPC during release Send the DMA_TRACE_FREE IPC during release to stop and free the trace DMA in the DSP. Signed-off-by: Ranjani Sridharan Reviewed-by: Kai Vehmanen Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20211102101019.14037-4-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/core.c | 2 +- sound/soc/sof/trace.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 2c3de295f11fe..9ec9ef8ed525f 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -363,6 +363,7 @@ int snd_sof_device_remove(struct device *dev) cancel_work_sync(&sdev->probe_work); if (sdev->fw_state > SOF_FW_BOOT_NOT_STARTED) { + snd_sof_free_trace(sdev); ret = snd_sof_dsp_power_down_notify(sdev); if (ret < 0) dev_warn(dev, "error: %d failed to prepare DSP for device removal", @@ -370,7 +371,6 @@ int snd_sof_device_remove(struct device *dev) snd_sof_ipc_free(sdev); snd_sof_free_debug(sdev); - snd_sof_free_trace(sdev); } /* diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index e3afc3dac7d17..f13024c8ebf2f 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -539,6 +539,10 @@ EXPORT_SYMBOL(snd_sof_trace_notify_for_error); void snd_sof_release_trace(struct snd_sof_dev *sdev) { + struct sof_ipc_fw_ready *ready = &sdev->fw_ready; + struct sof_ipc_fw_version *v = &ready->version; + struct sof_ipc_cmd_hdr hdr; + struct sof_ipc_reply ipc_reply; int ret; if (!sdev->dtrace_is_supported || !sdev->dtrace_is_enabled) @@ -549,6 +553,20 @@ void snd_sof_release_trace(struct snd_sof_dev *sdev) dev_err(sdev->dev, "error: snd_sof_dma_trace_trigger: stop: %d\n", ret); + /* + * stop and free trace DMA in the DSP. TRACE_DMA_FREE is only supported from + * ABI 3.20.0 onwards + */ + if (v->abi_version >= SOF_ABI_VER(3, 20, 0)) { + hdr.size = sizeof(hdr); + hdr.cmd = SOF_IPC_GLB_TRACE_MSG | SOF_IPC_TRACE_DMA_FREE; + + ret = sof_ipc_tx_message(sdev->ipc, hdr.cmd, &hdr, hdr.size, + &ipc_reply, sizeof(ipc_reply)); + if (ret < 0) + dev_err(sdev->dev, "DMA_TRACE_FREE failed with error: %d\n", ret); + } + ret = snd_sof_dma_trace_release(sdev); if (ret < 0) dev_err(sdev->dev, From dd31ddd81904070d0a9cafd5499d3210a322f8af Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 27 Oct 2021 10:18:15 +0800 Subject: [PATCH 006/327] ASoC: intel: sof_sdw: return the original error number We don't want to convert create_sdw_dailink()'s return value to -ENOMEM. Signed-off-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20211027021824.24776-2-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 77219c3f8766c..6d59462880fbf 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1203,7 +1203,7 @@ static int sof_card_dai_links_create(struct device *dev, &ignore_pch_dmic); if (ret < 0) { dev_err(dev, "failed to create dai link %d", be_id); - return -ENOMEM; + return ret; } } From 0527b19fa4f390a6054612e1fa1dd4f8efc96739 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 27 Oct 2021 10:18:16 +0800 Subject: [PATCH 007/327] ASoC: Intel: sof_sdw: fix jack detection on HP Spectre x360 convertible Tests on device show the JD2 mode does not work at all, the 'Headphone Jack' and 'Headset Mic Jack' are shown as 'on' always. JD1 seems to be the better option, with at least a change between the two cases. Jack not plugged-in: [root@fedora ~]# amixer -Dhw:0 cget numid=12 numid=12,iface=CARD,name='Headphone Jack' ; type=BOOLEAN,access=r-------,values=1 : values=off [root@fedora ~]# amixer -Dhw:0 cget numid=13 numid=13,iface=CARD,name='Headset Mic Jack' ; type=BOOLEAN,access=r-------,values=1 : values=off Jack plugged-in: [root@fedora ~]# amixer -Dhw:0 cget numid=13 numid=13,iface=CARD,name='Headset Mic Jack' ; type=BOOLEAN,access=r-------,values=1 : values=on [root@fedora ~]# amixer -Dhw:0 cget numid=13 numid=13,iface=CARD,name='Headset Mic Jack' ; type=BOOLEAN,access=r-------,values=1 : values=on The 'Headset Mic Jack' is updated with a delay which seems normal with additional calibration needed. Fixes: d92e279dee56 ('ASoC: Intel: sof_sdw: add quirk for HP Spectre x360 convertible') Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20211027021824.24776-3-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 6d59462880fbf..c5b1a1621fb5c 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -188,7 +188,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | SOF_SDW_PCH_DMIC | - RT711_JD2), + RT711_JD1), }, { /* NUC15 'Bishop County' LAPBC510 and LAPBC710 skews */ From 1071f2415b6b4ee653869acabfb26de1a27da9cd Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 27 Oct 2021 10:18:17 +0800 Subject: [PATCH 008/327] ASoC: Intel: sof_sdw: add SKU for Dell Latitude 9520 Different SKUs seem to be used for the same design. BugLink: https://github.com/thesofproject/linux/issues/3206 Signed-off-by: Pierre-Louis Bossart Reviewed-by: Kai Vehmanen Reviewed-by: Ranjani Sridharan Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20211027021824.24776-4-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index c5b1a1621fb5c..1c6c22cb7cab8 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -129,6 +129,17 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { RT711_JD2 | SOF_RT715_DAI_ID_FIX), }, + { + /* another SKU of Dell Latitude 9520 */ + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3F") + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2 | + SOF_RT715_DAI_ID_FIX), + }, { /* Dell XPS 9710 */ .callback = sof_sdw_quirk_cb, From b63137cf5167b73d9d68a2334b835996bfc3b941 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 27 Oct 2021 10:18:18 +0800 Subject: [PATCH 009/327] ASoC: intel: sof_sdw: rename be_index/link_id to link_index The link_id variable in sof_card_dai_links_create() and be_index argument in create_sdw_dailink() is actually links' index. Rename them to link_index to be consistent. Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20211027021824.24776-5-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 48 +++++++++++++++++--------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 1c6c22cb7cab8..2492cd3556a88 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -899,7 +899,7 @@ static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link, } static int create_sdw_dailink(struct snd_soc_card *card, - struct device *dev, int *be_index, + struct device *dev, int *link_index, struct snd_soc_dai_link *dai_links, int sdw_be_num, int sdw_cpu_dai_num, struct snd_soc_dai_link_component *cpus, @@ -1002,8 +1002,12 @@ static int create_sdw_dailink(struct snd_soc_card *card, cpus[cpu_dai_index++].dai_name = cpu_name; } - if (*be_index >= sdw_be_num) { - dev_err(dev, " invalid be dai index %d", *be_index); + /* + * We create sdw dai links at first stage, so link index should + * not be larger than sdw_be_num + */ + if (*link_index >= sdw_be_num) { + dev_err(dev, "invalid dai link index %d", *link_index); return -EINVAL; } @@ -1014,18 +1018,19 @@ static int create_sdw_dailink(struct snd_soc_card *card, playback = (stream == SNDRV_PCM_STREAM_PLAYBACK); capture = (stream == SNDRV_PCM_STREAM_CAPTURE); - init_dai_link(dev, dai_links + *be_index, *be_index, name, + init_dai_link(dev, dai_links + *link_index, *link_index, name, playback, capture, cpus + *cpu_id, cpu_dai_num, codecs, codec_num, NULL, &sdw_ops); + /* * SoundWire DAILINKs use 'stream' functions and Bank Switch operations * based on wait_for_completion(), tag them as 'nonatomic'. */ - dai_links[*be_index].nonatomic = true; + dai_links[*link_index].nonatomic = true; - ret = set_codec_init_func(card, link, dai_links + (*be_index)++, + ret = set_codec_init_func(card, link, dai_links + (*link_index)++, playback, group_id); if (ret < 0) { dev_err(dev, "failed to init codec %d", codec_index); @@ -1106,7 +1111,7 @@ static int sof_card_dai_links_create(struct device *dev, bool group_generated[SDW_MAX_GROUPS]; int ssp_codec_index, ssp_mask; struct snd_soc_dai_link *links; - int num_links, link_id = 0; + int num_links, link_index = 0; char *name, *cpu_name; int total_cpu_dai_num; int sdw_cpu_dai_num; @@ -1206,23 +1211,20 @@ static int sof_card_dai_links_create(struct device *dev, group_generated[endpoint->group_id]) continue; - ret = create_sdw_dailink(card, dev, &be_id, links, sdw_be_num, + ret = create_sdw_dailink(card, dev, &link_index, links, sdw_be_num, sdw_cpu_dai_num, cpus, adr_link, &cpu_id, group_generated, codec_conf, codec_conf_count, &codec_conf_index, &ignore_pch_dmic); if (ret < 0) { - dev_err(dev, "failed to create dai link %d", be_id); + dev_err(dev, "failed to create dai link %d", link_index); return ret; } } - /* non-sdw DAI follows sdw DAI */ - link_id = be_id; - /* get BE ID for non-sdw DAI */ - be_id = get_next_be_id(links, be_id); + be_id = get_next_be_id(links, link_index); SSP: /* SSP */ @@ -1263,17 +1265,17 @@ static int sof_card_dai_links_create(struct device *dev, playback = info->direction[SNDRV_PCM_STREAM_PLAYBACK]; capture = info->direction[SNDRV_PCM_STREAM_CAPTURE]; - init_dai_link(dev, links + link_id, be_id, name, + init_dai_link(dev, links + link_index, be_id, name, playback, capture, cpus + cpu_id, 1, ssp_components, 1, NULL, info->ops); - ret = info->init(card, NULL, links + link_id, info, 0); + ret = info->init(card, NULL, links + link_index, info, 0); if (ret < 0) return ret; - INC_ID(be_id, cpu_id, link_id); + INC_ID(be_id, cpu_id, link_index); } DMIC: @@ -1284,21 +1286,21 @@ static int sof_card_dai_links_create(struct device *dev, goto HDMI; } cpus[cpu_id].dai_name = "DMIC01 Pin"; - init_dai_link(dev, links + link_id, be_id, "dmic01", + init_dai_link(dev, links + link_index, be_id, "dmic01", 0, 1, // DMIC only supports capture cpus + cpu_id, 1, dmic_component, 1, sof_sdw_dmic_init, NULL); - INC_ID(be_id, cpu_id, link_id); + INC_ID(be_id, cpu_id, link_index); cpus[cpu_id].dai_name = "DMIC16k Pin"; - init_dai_link(dev, links + link_id, be_id, "dmic16k", + init_dai_link(dev, links + link_index, be_id, "dmic16k", 0, 1, // DMIC only supports capture cpus + cpu_id, 1, dmic_component, 1, /* don't call sof_sdw_dmic_init() twice */ NULL, NULL); - INC_ID(be_id, cpu_id, link_id); + INC_ID(be_id, cpu_id, link_index); } HDMI: @@ -1336,12 +1338,12 @@ static int sof_card_dai_links_create(struct device *dev, return -ENOMEM; cpus[cpu_id].dai_name = cpu_name; - init_dai_link(dev, links + link_id, be_id, name, + init_dai_link(dev, links + link_index, be_id, name, 1, 0, // HDMI only supports playback cpus + cpu_id, 1, idisp_components + i, 1, sof_sdw_hdmi_init, NULL); - INC_ID(be_id, cpu_id, link_id); + INC_ID(be_id, cpu_id, link_index); } if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { @@ -1365,7 +1367,7 @@ static int sof_card_dai_links_create(struct device *dev, return -ENOMEM; cpus[cpu_id].dai_name = cpu_name; - init_dai_link(dev, links + link_id, be_id, name, 1, 1, + init_dai_link(dev, links + link_index, be_id, name, 1, 1, cpus + cpu_id, 1, ssp_components, 1, NULL, NULL); } From d471c034f83201f84330e9ed46ad5139d32e77ce Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 27 Oct 2021 10:18:19 +0800 Subject: [PATCH 010/327] ASoC: intel: sof_sdw: Use a fixed DAI link id for AMP Currently, we assign SoundWire DAI link id according to the order in the link address table, with the assumption that the headset codec is listed first, then amplifiers and last capture devices. If the headset codec is not present in a platform, the dai link for amplifiers will be shifted, which can be handled in two ways a) modify the topology to renumber the dailink changes b) keep the dailink numbers constant in topology but also avoid the variations in the machine driver. This patch adds support for option b), the dailink index for amplifiers and capture devices becomes fixed. Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20211027021824.24776-6-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 26 ++++++++++++++++++++++--- sound/soc/intel/boards/sof_sdw_common.h | 6 ++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 2492cd3556a88..1be5c4754337d 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -462,6 +462,7 @@ static struct sof_sdw_codec_info codec_info_list[] = { .direction = {true, true}, .dai_name = "rt700-aif1", .init = sof_sdw_rt700_init, + .codec_type = SOF_SDW_CODEC_TYPE_JACK, }, { .part_id = 0x711, @@ -470,6 +471,7 @@ static struct sof_sdw_codec_info codec_info_list[] = { .dai_name = "rt711-sdca-aif1", .init = sof_sdw_rt711_sdca_init, .exit = sof_sdw_rt711_sdca_exit, + .codec_type = SOF_SDW_CODEC_TYPE_JACK, }, { .part_id = 0x711, @@ -478,6 +480,7 @@ static struct sof_sdw_codec_info codec_info_list[] = { .dai_name = "rt711-aif1", .init = sof_sdw_rt711_init, .exit = sof_sdw_rt711_exit, + .codec_type = SOF_SDW_CODEC_TYPE_JACK, }, { .part_id = 0x1308, @@ -486,12 +489,14 @@ static struct sof_sdw_codec_info codec_info_list[] = { .dai_name = "rt1308-aif", .ops = &sof_sdw_rt1308_i2s_ops, .init = sof_sdw_rt1308_init, + .codec_type = SOF_SDW_CODEC_TYPE_AMP, }, { .part_id = 0x1316, .direction = {true, true}, .dai_name = "rt1316-aif", .init = sof_sdw_rt1316_init, + .codec_type = SOF_SDW_CODEC_TYPE_AMP, }, { .part_id = 0x714, @@ -500,6 +505,7 @@ static struct sof_sdw_codec_info codec_info_list[] = { .ignore_pch_dmic = true, .dai_name = "rt715-aif2", .init = sof_sdw_rt715_sdca_init, + .codec_type = SOF_SDW_CODEC_TYPE_MIC, }, { .part_id = 0x715, @@ -508,6 +514,7 @@ static struct sof_sdw_codec_info codec_info_list[] = { .ignore_pch_dmic = true, .dai_name = "rt715-aif2", .init = sof_sdw_rt715_sdca_init, + .codec_type = SOF_SDW_CODEC_TYPE_MIC, }, { .part_id = 0x714, @@ -516,6 +523,7 @@ static struct sof_sdw_codec_info codec_info_list[] = { .ignore_pch_dmic = true, .dai_name = "rt715-aif2", .init = sof_sdw_rt715_init, + .codec_type = SOF_SDW_CODEC_TYPE_MIC, }, { .part_id = 0x715, @@ -524,6 +532,7 @@ static struct sof_sdw_codec_info codec_info_list[] = { .ignore_pch_dmic = true, .dai_name = "rt715-aif2", .init = sof_sdw_rt715_init, + .codec_type = SOF_SDW_CODEC_TYPE_MIC, }, { .part_id = 0x8373, @@ -531,12 +540,14 @@ static struct sof_sdw_codec_info codec_info_list[] = { .dai_name = "max98373-aif1", .init = sof_sdw_mx8373_init, .codec_card_late_probe = sof_sdw_mx8373_late_probe, + .codec_type = SOF_SDW_CODEC_TYPE_AMP, }, { .part_id = 0x5682, .direction = {true, true}, .dai_name = "rt5682-sdw", .init = sof_sdw_rt5682_init, + .codec_type = SOF_SDW_CODEC_TYPE_JACK, }, { .part_id = 0xaaaa, /* generic codec mockup */ @@ -544,6 +555,7 @@ static struct sof_sdw_codec_info codec_info_list[] = { .direction = {true, true}, .dai_name = "sdw-mockup-aif1", .init = NULL, + .codec_type = SOF_SDW_CODEC_TYPE_JACK, }, { .part_id = 0xaa55, /* headset codec mockup */ @@ -551,6 +563,7 @@ static struct sof_sdw_codec_info codec_info_list[] = { .direction = {true, true}, .dai_name = "sdw-mockup-aif1", .init = NULL, + .codec_type = SOF_SDW_CODEC_TYPE_JACK, }, { .part_id = 0x55aa, /* amplifier mockup */ @@ -558,6 +571,7 @@ static struct sof_sdw_codec_info codec_info_list[] = { .direction = {true, false}, .dai_name = "sdw-mockup-aif1", .init = NULL, + .codec_type = SOF_SDW_CODEC_TYPE_AMP, }, { .part_id = 0x5555, @@ -565,6 +579,7 @@ static struct sof_sdw_codec_info codec_info_list[] = { .direction = {false, true}, .dai_name = "sdw-mockup-aif1", .init = sof_sdw_mic_codec_mockup_init, + .codec_type = SOF_SDW_CODEC_TYPE_MIC, }, }; @@ -906,7 +921,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, const struct snd_soc_acpi_link_adr *link, int *cpu_id, bool *group_generated, struct snd_soc_codec_conf *codec_conf, - int codec_count, + int codec_count, int *link_id, int *codec_conf_index, bool *ignore_pch_dmic) { @@ -964,6 +979,11 @@ static int create_sdw_dailink(struct snd_soc_card *card, if (codec_info_list[codec_index].ignore_pch_dmic) *ignore_pch_dmic = true; + /* Shift the first amplifier's *link_id to SDW_AMP_DAI_ID */ + if (codec_info_list[codec_index].codec_type == SOF_SDW_CODEC_TYPE_AMP && + *link_id < SDW_AMP_DAI_ID) + *link_id = SDW_AMP_DAI_ID; + cpu_dai_index = *cpu_id; for_each_pcm_streams(stream) { char *name, *cpu_name; @@ -1018,7 +1038,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, playback = (stream == SNDRV_PCM_STREAM_PLAYBACK); capture = (stream == SNDRV_PCM_STREAM_CAPTURE); - init_dai_link(dev, dai_links + *link_index, *link_index, name, + init_dai_link(dev, dai_links + *link_index, (*link_id)++, name, playback, capture, cpus + *cpu_id, cpu_dai_num, codecs, codec_num, @@ -1215,7 +1235,7 @@ static int sof_card_dai_links_create(struct device *dev, sdw_cpu_dai_num, cpus, adr_link, &cpu_id, group_generated, codec_conf, codec_conf_count, - &codec_conf_index, + &be_id, &codec_conf_index, &ignore_pch_dmic); if (ret < 0) { dev_err(dev, "failed to create dai link %d", link_index); diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h index b35f5a9b96f5a..c6200aa14089a 100644 --- a/sound/soc/intel/boards/sof_sdw_common.h +++ b/sound/soc/intel/boards/sof_sdw_common.h @@ -15,6 +15,7 @@ #define MAX_NO_PROPS 2 #define MAX_HDMI_NUM 4 +#define SDW_AMP_DAI_ID 2 #define SDW_DMIC_DAI_ID 4 #define SDW_MAX_CPU_DAIS 16 #define SDW_INTEL_BIDIR_PDI_BASE 2 @@ -52,9 +53,14 @@ enum { (((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK) #define SOF_SSP_BT_OFFLOAD_PRESENT BIT(18) +#define SOF_SDW_CODEC_TYPE_JACK 0 +#define SOF_SDW_CODEC_TYPE_AMP 1 +#define SOF_SDW_CODEC_TYPE_MIC 2 + struct sof_sdw_codec_info { const int part_id; const int version_id; + const int codec_type; int amp_num; const u8 acpi_id[ACPI_ID_LEN]; const bool direction[2]; // playback & capture support From bf605cb042307d162fbcb094738bab5d767f1261 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 27 Oct 2021 10:18:20 +0800 Subject: [PATCH 011/327] ASoC: intel: sof_sdw: move DMIC link id overwrite to create_sdw_dailink We can apply the fixed dai link id for DMICs in create_sdw_dailink(). No need to set it in each DMIC's callback. The fixed dai link id is not only for rt715 and rt715-sdca, but for all DMICs, therefore we remove the SOF_RT715_DAI_ID_FIX check as well. Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20211027021824.24776-7-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 8 ++++++++ sound/soc/intel/boards/sof_sdw_rt715.c | 7 ------- sound/soc/intel/boards/sof_sdw_rt715_sdca.c | 7 ------- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 1be5c4754337d..b00c1731c2c32 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -984,6 +984,14 @@ static int create_sdw_dailink(struct snd_soc_card *card, *link_id < SDW_AMP_DAI_ID) *link_id = SDW_AMP_DAI_ID; + /* + * DAI ID is fixed at SDW_DMIC_DAI_ID for MICs to + * keep sdw DMIC and HDMI setting static in UCM + */ + if (codec_info_list[codec_index].codec_type == SOF_SDW_CODEC_TYPE_MIC && + *link_id < SDW_DMIC_DAI_ID) + *link_id = SDW_DMIC_DAI_ID; + cpu_dai_index = *cpu_id; for_each_pcm_streams(stream) { char *name, *cpu_name; diff --git a/sound/soc/intel/boards/sof_sdw_rt715.c b/sound/soc/intel/boards/sof_sdw_rt715.c index c8af3780cbc3e..7c068dc6b9cf6 100644 --- a/sound/soc/intel/boards/sof_sdw_rt715.c +++ b/sound/soc/intel/boards/sof_sdw_rt715.c @@ -30,13 +30,6 @@ int sof_sdw_rt715_init(struct snd_soc_card *card, struct sof_sdw_codec_info *info, bool playback) { - /* - * DAI ID is fixed at SDW_DMIC_DAI_ID for 715 to - * keep sdw DMIC and HDMI setting static in UCM - */ - if (sof_sdw_quirk & SOF_RT715_DAI_ID_FIX) - dai_links->id = SDW_DMIC_DAI_ID; - dai_links->init = rt715_rtd_init; return 0; diff --git a/sound/soc/intel/boards/sof_sdw_rt715_sdca.c b/sound/soc/intel/boards/sof_sdw_rt715_sdca.c index 85d3d8c355cc1..ca0cf3db2e4d8 100644 --- a/sound/soc/intel/boards/sof_sdw_rt715_sdca.c +++ b/sound/soc/intel/boards/sof_sdw_rt715_sdca.c @@ -30,13 +30,6 @@ int sof_sdw_rt715_sdca_init(struct snd_soc_card *card, struct sof_sdw_codec_info *info, bool playback) { - /* - * DAI ID is fixed at SDW_DMIC_DAI_ID for 715-SDCA to - * keep sdw DMIC and HDMI setting static in UCM - */ - if (sof_sdw_quirk & SOF_RT715_DAI_ID_FIX) - dai_links->id = SDW_DMIC_DAI_ID; - dai_links->init = rt715_sdca_rtd_init; return 0; From f8f8312263e2d0c38dd0330a4503dcdcc94d0cd5 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 27 Oct 2021 10:18:21 +0800 Subject: [PATCH 012/327] ASoC: intel: sof_sdw: remove SOF_RT715_DAI_ID_FIX quirk SOF_RT715_DAI_ID_FIX is not used anywhere. Remove it. Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20211027021824.24776-8-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 23 +++++------------------ sound/soc/intel/boards/sof_sdw_common.h | 1 - 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index b00c1731c2c32..72bc7da2d21ef 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -36,8 +36,6 @@ static void log_quirks(struct device *dev) if (SOF_SSP_GET_PORT(sof_sdw_quirk)) dev_dbg(dev, "SSP port %ld\n", SOF_SSP_GET_PORT(sof_sdw_quirk)); - if (sof_sdw_quirk & SOF_RT715_DAI_ID_FIX) - dev_dbg(dev, "quirk SOF_RT715_DAI_ID_FIX enabled\n"); if (sof_sdw_quirk & SOF_SDW_NO_AGGREGATION) dev_dbg(dev, "quirk SOF_SDW_NO_AGGREGATION enabled\n"); } @@ -64,8 +62,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "09C6") }, - .driver_data = (void *)(RT711_JD2 | - SOF_RT715_DAI_ID_FIX), + .driver_data = (void *)RT711_JD2, }, { /* early version of SKU 09C6 */ @@ -74,8 +71,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0983") }, - .driver_data = (void *)(RT711_JD2 | - SOF_RT715_DAI_ID_FIX), + .driver_data = (void *)RT711_JD2, }, { .callback = sof_sdw_quirk_cb, @@ -84,7 +80,6 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"), }, .driver_data = (void *)(RT711_JD2 | - SOF_RT715_DAI_ID_FIX | SOF_SDW_FOUR_SPK), }, { @@ -94,7 +89,6 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"), }, .driver_data = (void *)(RT711_JD2 | - SOF_RT715_DAI_ID_FIX | SOF_SDW_FOUR_SPK), }, /* IceLake devices */ @@ -126,8 +120,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3E") }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - RT711_JD2 | - SOF_RT715_DAI_ID_FIX), + RT711_JD2), }, { /* another SKU of Dell Latitude 9520 */ @@ -137,8 +130,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3F") }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - RT711_JD2 | - SOF_RT715_DAI_ID_FIX), + RT711_JD2), }, { /* Dell XPS 9710 */ @@ -149,7 +141,6 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | RT711_JD2 | - SOF_RT715_DAI_ID_FIX | SOF_SDW_FOUR_SPK), }, { @@ -160,7 +151,6 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | RT711_JD2 | - SOF_RT715_DAI_ID_FIX | SOF_SDW_FOUR_SPK), }, { @@ -221,7 +211,6 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | RT711_JD2 | - SOF_RT715_DAI_ID_FIX | SOF_SDW_FOUR_SPK), }, { @@ -231,8 +220,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A45") }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - RT711_JD2 | - SOF_RT715_DAI_ID_FIX), + RT711_JD2), }, /* AlderLake devices */ { @@ -243,7 +231,6 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { }, .driver_data = (void *)(RT711_JD2_100K | SOF_SDW_TGL_HDMI | - SOF_RT715_DAI_ID_FIX | SOF_BT_OFFLOAD_SSP(2) | SOF_SSP_BT_OFFLOAD_PRESENT), }, diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h index c6200aa14089a..e2457738a332e 100644 --- a/sound/soc/intel/boards/sof_sdw_common.h +++ b/sound/soc/intel/boards/sof_sdw_common.h @@ -43,7 +43,6 @@ enum { #define SOF_SDW_PCH_DMIC BIT(6) #define SOF_SSP_PORT(x) (((x) & GENMASK(5, 0)) << 7) #define SOF_SSP_GET_PORT(quirk) (((quirk) >> 7) & GENMASK(5, 0)) -#define SOF_RT715_DAI_ID_FIX BIT(13) #define SOF_SDW_NO_AGGREGATION BIT(14) /* BT audio offload: reserve 3 bits for future */ From bd98394a811c7dc39bcd189cf5f33925f0c30ae2 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 27 Oct 2021 10:18:22 +0800 Subject: [PATCH 013/327] ASoC: intel: sof_sdw: remove sof_sdw_mic_codec_mockup_init Now, we set DAI link id as SDW_DMIC_DAI_ID for all DMICs. No need to set it in sof_sdw_mic_codec_mockup_init. Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20211027021824.24776-9-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 72bc7da2d21ef..aac493aea0026 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -429,20 +429,6 @@ static const struct snd_soc_ops sdw_ops = { .shutdown = sdw_shutdown, }; -static int sof_sdw_mic_codec_mockup_init(struct snd_soc_card *card, - const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback) -{ - /* - * force DAI link to use same ID as RT715 and DMIC - * to reuse topologies - */ - dai_links->id = SDW_DMIC_DAI_ID; - return 0; -} - static struct sof_sdw_codec_info codec_info_list[] = { { .part_id = 0x700, @@ -565,7 +551,6 @@ static struct sof_sdw_codec_info codec_info_list[] = { .version_id = 0, .direction = {false, true}, .dai_name = "sdw-mockup-aif1", - .init = sof_sdw_mic_codec_mockup_init, .codec_type = SOF_SDW_CODEC_TYPE_MIC, }, }; From 4ed65d6ead29a992c4803e1138a6042caa6ec2a3 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 27 Oct 2021 10:18:23 +0800 Subject: [PATCH 014/327] ASoC: intel: sof_sdw: remove get_next_be_id DAI link id will not be set from sdw codec init feedback function, and be_id is changed by create_sdw_dailink() now. So we don't need get_next_be_id() anymore. Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20211027021824.24776-10-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index aac493aea0026..df29f7b478a4c 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1044,17 +1044,6 @@ static int create_sdw_dailink(struct snd_soc_card *card, return 0; } -/* - * DAI link ID of SSP & DMIC & HDMI are based on last - * link ID used by sdw link. Since be_id may be changed - * in init func of sdw codec, it is not equal to be_id - */ -static inline int get_next_be_id(struct snd_soc_dai_link *links, - int be_id) -{ - return links[be_id - 1].id + 1; -} - #define IDISP_CODEC_MASK 0x4 static int sof_card_codec_conf_alloc(struct device *dev, @@ -1223,9 +1212,6 @@ static int sof_card_dai_links_create(struct device *dev, } } - /* get BE ID for non-sdw DAI */ - be_id = get_next_be_id(links, link_index); - SSP: /* SSP */ if (!ssp_num) From 296c789ce1e501be8b46ebb24da4ba53063cc10a Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 27 Oct 2021 10:18:24 +0800 Subject: [PATCH 015/327] ASoC: intel: sof_sdw: add link adr order check We assume the adr order described in a snd_soc_acpi_link_adr array is jack -> amp -> mic. We follow the same order to implement the topology. We will need a special topology if we configure a snd_soc_acpi_link_adr array with different order. Adding a check and a warning message can remind people to keep the order when adding a new snd_soc_acpi_link_adr array. Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20211027021824.24776-11-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index df29f7b478a4c..de303a9808791 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -599,10 +599,11 @@ static inline int find_codec_info_acpi(const u8 *acpi_id) * Since some sdw slaves may be aggregated, the CPU DAI number * may be larger than the number of BE dailinks. */ -static int get_sdw_dailink_info(const struct snd_soc_acpi_link_adr *links, +static int get_sdw_dailink_info(struct device *dev, const struct snd_soc_acpi_link_adr *links, int *sdw_be_num, int *sdw_cpu_dai_num) { const struct snd_soc_acpi_link_adr *link; + int _codec_type = SOF_SDW_CODEC_TYPE_JACK; bool group_visited[SDW_MAX_GROUPS]; bool no_aggregation; int i; @@ -628,6 +629,12 @@ static int get_sdw_dailink_info(const struct snd_soc_acpi_link_adr *links, if (codec_index < 0) return codec_index; + if (codec_info_list[codec_index].codec_type < _codec_type) + dev_warn(dev, + "Unexpected address table ordering. Expected order: jack -> amp -> mic\n"); + + _codec_type = codec_info_list[codec_index].codec_type; + endpoint = link->adr_d->endpoints; /* count DAI number for playback and capture */ @@ -1136,7 +1143,7 @@ static int sof_card_dai_links_create(struct device *dev, ssp_num = ssp_codec_index >= 0 ? hweight_long(ssp_mask) : 0; comp_num = hdmi_num + ssp_num; - ret = get_sdw_dailink_info(mach_params->links, + ret = get_sdw_dailink_info(dev, mach_params->links, &sdw_be_num, &sdw_cpu_dai_num); if (ret < 0) { dev_err(dev, "failed to get sdw link info %d", ret); From 0f9710603e803ae9b64ed3b54019170b323968d7 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Thu, 28 Oct 2021 15:09:02 +0100 Subject: [PATCH 016/327] ASoC: dt-bindings: cs42l42: Convert binding to yaml Replace the old .txt binding with a new schema binding. At the same time, some of the descriptions are updated to make them clearer, fix errors, or just make them fit better into the style of schema binding. The cirrus,hs-bias-ramp-rate property was missing from the old .txt binding and has been added to the yaml. Signed-off-by: Richard Fitzgerald Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20211028140902.11786-4-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- .../bindings/sound/cirrus,cs42l42.yaml | 225 ++++++++++++++++++ .../devicetree/bindings/sound/cs42l42.txt | 115 --------- MAINTAINERS | 1 + 3 files changed, 226 insertions(+), 115 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/cirrus,cs42l42.yaml delete mode 100644 Documentation/devicetree/bindings/sound/cs42l42.txt diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs42l42.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs42l42.yaml new file mode 100644 index 0000000000000..31800f70e9d91 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cirrus,cs42l42.yaml @@ -0,0 +1,225 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/cirrus,cs42l42.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Cirrus Logic CS42L42 audio CODEC + +maintainers: + - patches@opensource.cirrus.com + +description: + The CS42L42 is a low-power audio codec designed for portable applications. + It provides a high-dynamic range, stereo DAC for audio playback and a mono + high-dynamic-range ADC for audio capture. There is an integrated headset + detection block. + +properties: + compatible: + enum: + - cirrus,cs42l42 + + reg: + description: + The I2C address of the CS42L42. + maxItems: 1 + + VP-supply: + description: + VP power supply. + + VCP-supply: + description: + Charge pump power supply. + + VD_FILT-supply: + description: + FILT+ power supply. + + VL-supply: + description: + Logic power supply. + + VA-supply: + description: + Analog power supply. + + reset-gpios: + description: + This pin will be asserted and then deasserted to reset the + CS42L42 before communication starts. + maxItems: 1 + + interrupts: + description: + Interrupt for CS42L42 IRQ line. + maxItems: 1 + + cirrus,ts-inv: + description: | + Sets the behaviour of the jack plug detect switch. + + 0 - (Default) Shorted to tip when unplugged, open when plugged. + This is "inverted tip sense (ITS)" in the datasheet. + + 1 - Open when unplugged, shorted to tip when plugged. + This is "normal tip sense (TS)" in the datasheet. + + The CS42L42_TS_INV_* defines are available for this. + $ref: "/schemas/types.yaml#/definitions/uint32" + minimum: 0 + maximum: 1 + + cirrus,ts-dbnc-rise: + description: | + Debounce the rising edge of TIP_SENSE_PLUG. With no + debounce, the tip sense pin might be noisy on a plug event. + + 0 - 0ms + 1 - 125ms + 2 - 250ms + 3 - 500ms + 4 - 750ms + 5 - 1s (Default) + 6 - 1.25s + 7 - 1.5s + + The CS42L42_TS_DBNCE_* defines are available for this. + $ref: "/schemas/types.yaml#/definitions/uint32" + minimum: 0 + maximum: 7 + + cirrus,ts-dbnc-fall: + description: | + Debounce the falling edge of TIP_SENSE_UNPLUG. With no + debounce, the tip sense pin might be noisy on an unplug event. + + 0 - 0ms + 1 - 125ms + 2 - 250ms + 3 - 500ms + 4 - 750ms + 5 - 1s (Default) + 6 - 1.25s + 7 - 1.5s + + The CS42L42_TS_DBNCE_* defines are available for this. + $ref: "/schemas/types.yaml#/definitions/uint32" + minimum: 0 + maximum: 7 + + cirrus,btn-det-init-dbnce: + description: | + This sets how long to wait after enabling button detection + interrupts before servicing button interrupts, to allow the + HS bias time to settle. Value is in milliseconds. + There may be erroneous button interrupts if this debounce time + is too short. + + 0ms - 200ms, + Default = 100ms + $ref: "/schemas/types.yaml#/definitions/uint32" + minimum: 0 + maximum: 200 + + cirrus,btn-det-event-dbnce: + description: | + This sets how long to wait after receiving a button press + interrupt before processing it. Allows time for the button + press to make a clean connection with the bias resistors. + Value is in milliseconds. + + 0ms - 20ms, + Default = 10ms + $ref: "/schemas/types.yaml#/definitions/uint32" + minimum: 0 + maximum: 20 + + cirrus,bias-lvls: + description: | + For a level-detect headset button scheme, each button will bias + the mic pin to a certain voltage. To determine which button was + pressed, the voltage is compared to sequential, decreasing + voltages, until the compared voltage < bias voltage. + For different hardware setups, a designer might want to tweak this. + This is an array of descending values for the comparator voltage, + given as percent of the HSBIAS voltage. + + Array of 4 values, each 0-63 + < x1 x2 x3 x4 > + Default = < 15 8 4 1 > + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 4 + maxItems: 4 + items: + minimum: 0 + maximum: 63 + + cirrus,hs-bias-ramp-rate: + description: | + If present this sets the rate that the HS bias should rise and fall. + The actual rise and fall times depend on external hardware (the + datasheet gives several rise and fall time examples). + + 0 - Fast rise time; slow, load-dependent fall time + 1 - Fast + 2 - Slow (default) + 3 - Slowest + + The CS42L42_HSBIAS_RAMP_* defines are available for this. + $ref: "/schemas/types.yaml#/definitions/uint32" + minimum: 0 + maximum: 3 + + cirrus,hs-bias-sense-disable: + description: | + If present the HSBIAS sense is disabled. Configures HSBIAS output + current sense through the external 2.21-k resistor. HSBIAS_SENSE + is a hardware feature to reduce the potential pop noise when the + headset plug is removed slowly. But on some platforms ESD voltage + will affect it causing plug detection to fail, especially with CTIA + headset type. For different hardware setups, a designer might want + to tweak default behavior. + type: boolean + +required: + - compatible + - reg + - VP-supply + - VCP-supply + - VD_FILT-supply + - VL-supply + - VA-supply + +additionalProperties: false + +examples: + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + cs42l42: cs42l42@48 { + compatible = "cirrus,cs42l42"; + reg = <0x48>; + VA-supply = <&dummy_vreg>; + VP-supply = <&dummy_vreg>; + VCP-supply = <&dummy_vreg>; + VD_FILT-supply = <&dummy_vreg>; + VL-supply = <&dummy_vreg>; + + reset-gpios = <&axi_gpio_0 1 0>; + interrupt-parent = <&gpio0>; + interrupts = <55 8>; + + cirrus,ts-inv = ; + cirrus,ts-dbnc-rise = ; + cirrus,ts-dbnc-fall = ; + cirrus,btn-det-init-dbnce = <100>; + cirrus,btn-det-event-dbnce = <10>; + cirrus,bias-lvls = <0x0F 0x08 0x04 0x01>; + cirrus,hs-bias-ramp-rate = ; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/cs42l42.txt b/Documentation/devicetree/bindings/sound/cs42l42.txt deleted file mode 100644 index 3b77056239808..0000000000000 --- a/Documentation/devicetree/bindings/sound/cs42l42.txt +++ /dev/null @@ -1,115 +0,0 @@ -CS42L42 audio CODEC - -Required properties: - - - compatible : "cirrus,cs42l42" - - - reg : the I2C address of the device for I2C. - - - VP-supply, VCP-supply, VD_FILT-supply, VL-supply, VA-supply : - power supplies for the device, as covered in - Documentation/devicetree/bindings/regulator/regulator.txt. - -Optional properties: - - - reset-gpios : a GPIO spec for the reset pin. If specified, it will be - deasserted before communication to the codec starts. - - - interrupts : IRQ line info CS42L42. - (See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt - for further information relating to interrupt properties) - - - cirrus,ts-inv : Boolean property. Sets the behaviour of the jack plug - detect switch. - - 0 = (Default) Shorted to tip when unplugged, open when plugged. - This is "inverted tip sense (ITS)" in the datasheet. - - 1 = Open when unplugged, shorted to tip when plugged. - This is "normal tip sense (TS)" in the datasheet. - - - cirrus,ts-dbnc-rise : Debounce the rising edge of TIP_SENSE_PLUG. With no - debounce, the tip sense pin might be noisy on a plug event. - - 0 - 0ms, - 1 - 125ms, - 2 - 250ms, - 3 - 500ms, - 4 - 750ms, - 5 - (Default) 1s, - 6 - 1.25s, - 7 - 1.5s, - - - cirrus,ts-dbnc-fall : Debounce the falling edge of TIP_SENSE_UNPLUG. - With no debounce, the tip sense pin might be noisy on an unplug event. - - 0 - 0ms, - 1 - 125ms, - 2 - 250ms, - 3 - 500ms, - 4 - 750ms, - 5 - (Default) 1s, - 6 - 1.25s, - 7 - 1.5s, - - - cirrus,btn-det-init-dbnce : This sets how long the driver sleeps after - enabling button detection interrupts. After auto-detection and before - servicing button interrupts, the HS bias needs time to settle. If you - don't wait, there is possibility for erroneous button interrupt. - - 0ms - 200ms, - Default = 100ms - - - cirrus,btn-det-event-dbnce : This sets how long the driver delays after - receiving a button press interrupt. With level detect interrupts, you want - to wait a small amount of time to make sure the button press is making a - clean connection with the bias resistors. - - 0ms - 20ms, - Default = 10ms - - - cirrus,bias-lvls : For a level-detect headset button scheme, each button - will bias the mic pin to a certain voltage. To determine which button was - pressed, the driver will compare this biased voltage to sequential, - decreasing voltages and will stop when a comparator is tripped, - indicating a comparator voltage < bias voltage. This value represents a - percentage of the internally generated HS bias voltage. For different - hardware setups, a designer might want to tweak this. This is an array of - descending values for the comparator voltage. - - Array of 4 values - Each 0-63 - < x1 x2 x3 x4 > - Default = < 15 8 4 1> - - - cirrus,hs-bias-sense-disable: This is boolean property. If present the - HSBIAS sense is disabled. Configures HSBIAS output current sense through - the external 2.21-k resistor. HSBIAS_SENSE is hardware feature to reduce - the potential pop noise during the headset plug out slowly. But on some - platforms ESD voltage will affect it causing test to fail, especially - with CTIA headset type. For different hardware setups, a designer might - want to tweak default behavior. - -Example: - -cs42l42: cs42l42@48 { - compatible = "cirrus,cs42l42"; - reg = <0x48>; - VA-supply = <&dummy_vreg>; - VP-supply = <&dummy_vreg>; - VCP-supply = <&dummy_vreg>; - VD_FILT-supply = <&dummy_vreg>; - VL-supply = <&dummy_vreg>; - - reset-gpios = <&axi_gpio_0 1 0>; - interrupt-parent = <&gpio0>; - interrupts = <55 8> - - cirrus,ts-inv = <0x00>; - cirrus,ts-dbnc-rise = <0x05>; - cirrus,ts-dbnc-fall = <0x00>; - cirrus,btn-det-init-dbnce = <100>; - cirrus,btn-det-event-dbnce = <10>; - cirrus,bias-lvls = <0x0F 0x08 0x04 0x01>; - cirrus,hs-bias-ramp-rate = <0x02>; -}; diff --git a/MAINTAINERS b/MAINTAINERS index 7a2345ce85213..09734251e1de9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4514,6 +4514,7 @@ M: David Rhodes L: alsa-devel@alsa-project.org (moderated for non-subscribers) L: patches@opensource.cirrus.com S: Maintained +F: Documentation/devicetree/bindings/sound/cirrus,cs* F: sound/soc/codecs/cs* CIRRUS LOGIC DSP FIRMWARE DRIVER From bae9e13fc55cbc5ae25409385b2f1ba9187082d0 Mon Sep 17 00:00:00 2001 From: David Rhodes Date: Fri, 29 Oct 2021 16:40:28 -0500 Subject: [PATCH 017/327] ASoC: cs35l41: DSP Support Support for HALO DSP and firmware Signed-off-by: David Rhodes Reviewed-by: Charles Keepax Link: https://lore.kernel.org/r/20211029214028.401284-2-drhodes@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/cs35l41-tables.c | 96 +++++++++ sound/soc/codecs/cs35l41.c | 312 +++++++++++++++++++++++++++++- sound/soc/codecs/cs35l41.h | 20 ++ 4 files changed, 426 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 326f2d611ad4e..3fe62df322386 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -343,11 +343,15 @@ config SND_SOC_WM_ADSP default y if SND_SOC_WM5102=y default y if SND_SOC_WM5110=y default y if SND_SOC_WM2200=y + default y if SND_SOC_CS35L41_SPI=y + default y if SND_SOC_CS35L41_I2C=y default m if SND_SOC_MADERA=m default m if SND_SOC_CS47L24=m default m if SND_SOC_WM5102=m default m if SND_SOC_WM5110=m default m if SND_SOC_WM2200=m + default m if SND_SOC_CS35L41_SPI=m + default m if SND_SOC_CS35L41_I2C=m config SND_SOC_AB8500_CODEC tristate diff --git a/sound/soc/codecs/cs35l41-tables.c b/sound/soc/codecs/cs35l41-tables.c index 964e530afa277..9d1a7d7dd24d1 100644 --- a/sound/soc/codecs/cs35l41-tables.c +++ b/sound/soc/codecs/cs35l41-tables.c @@ -200,6 +200,83 @@ bool cs35l41_readable_reg(struct device *dev, unsigned int reg) case CS35L41_DIE_STS2: case CS35L41_TEMP_CAL1: case CS35L41_TEMP_CAL2: + case CS35L41_DSP1_TIMESTAMP_COUNT: + case CS35L41_DSP1_SYS_ID: + case CS35L41_DSP1_SYS_VERSION: + case CS35L41_DSP1_SYS_CORE_ID: + case CS35L41_DSP1_SYS_AHB_ADDR: + case CS35L41_DSP1_SYS_XSRAM_SIZE: + case CS35L41_DSP1_SYS_YSRAM_SIZE: + case CS35L41_DSP1_SYS_PSRAM_SIZE: + case CS35L41_DSP1_SYS_PM_BOOT_SIZE: + case CS35L41_DSP1_SYS_FEATURES: + case CS35L41_DSP1_SYS_FIR_FILTERS: + case CS35L41_DSP1_SYS_LMS_FILTERS: + case CS35L41_DSP1_SYS_XM_BANK_SIZE: + case CS35L41_DSP1_SYS_YM_BANK_SIZE: + case CS35L41_DSP1_SYS_PM_BANK_SIZE: + case CS35L41_DSP1_RX1_RATE: + case CS35L41_DSP1_RX2_RATE: + case CS35L41_DSP1_RX3_RATE: + case CS35L41_DSP1_RX4_RATE: + case CS35L41_DSP1_RX5_RATE: + case CS35L41_DSP1_RX6_RATE: + case CS35L41_DSP1_RX7_RATE: + case CS35L41_DSP1_RX8_RATE: + case CS35L41_DSP1_TX1_RATE: + case CS35L41_DSP1_TX2_RATE: + case CS35L41_DSP1_TX3_RATE: + case CS35L41_DSP1_TX4_RATE: + case CS35L41_DSP1_TX5_RATE: + case CS35L41_DSP1_TX6_RATE: + case CS35L41_DSP1_TX7_RATE: + case CS35L41_DSP1_TX8_RATE: + case CS35L41_DSP1_SCRATCH1: + case CS35L41_DSP1_SCRATCH2: + case CS35L41_DSP1_SCRATCH3: + case CS35L41_DSP1_SCRATCH4: + case CS35L41_DSP1_CCM_CORE_CTRL: + case CS35L41_DSP1_CCM_CLK_OVERRIDE: + case CS35L41_DSP1_XM_MSTR_EN: + case CS35L41_DSP1_XM_CORE_PRI: + case CS35L41_DSP1_XM_AHB_PACK_PL_PRI: + case CS35L41_DSP1_XM_AHB_UP_PL_PRI: + case CS35L41_DSP1_XM_ACCEL_PL0_PRI: + case CS35L41_DSP1_XM_NPL0_PRI: + case CS35L41_DSP1_YM_MSTR_EN: + case CS35L41_DSP1_YM_CORE_PRI: + case CS35L41_DSP1_YM_AHB_PACK_PL_PRI: + case CS35L41_DSP1_YM_AHB_UP_PL_PRI: + case CS35L41_DSP1_YM_ACCEL_PL0_PRI: + case CS35L41_DSP1_YM_NPL0_PRI: + case CS35L41_DSP1_MPU_XM_ACCESS0: + case CS35L41_DSP1_MPU_YM_ACCESS0: + case CS35L41_DSP1_MPU_WNDW_ACCESS0: + case CS35L41_DSP1_MPU_XREG_ACCESS0: + case CS35L41_DSP1_MPU_YREG_ACCESS0: + case CS35L41_DSP1_MPU_XM_ACCESS1: + case CS35L41_DSP1_MPU_YM_ACCESS1: + case CS35L41_DSP1_MPU_WNDW_ACCESS1: + case CS35L41_DSP1_MPU_XREG_ACCESS1: + case CS35L41_DSP1_MPU_YREG_ACCESS1: + case CS35L41_DSP1_MPU_XM_ACCESS2: + case CS35L41_DSP1_MPU_YM_ACCESS2: + case CS35L41_DSP1_MPU_WNDW_ACCESS2: + case CS35L41_DSP1_MPU_XREG_ACCESS2: + case CS35L41_DSP1_MPU_YREG_ACCESS2: + case CS35L41_DSP1_MPU_XM_ACCESS3: + case CS35L41_DSP1_MPU_YM_ACCESS3: + case CS35L41_DSP1_MPU_WNDW_ACCESS3: + case CS35L41_DSP1_MPU_XREG_ACCESS3: + case CS35L41_DSP1_MPU_YREG_ACCESS3: + case CS35L41_DSP1_MPU_XM_VIO_ADDR: + case CS35L41_DSP1_MPU_XM_VIO_STATUS: + case CS35L41_DSP1_MPU_YM_VIO_ADDR: + case CS35L41_DSP1_MPU_YM_VIO_STATUS: + case CS35L41_DSP1_MPU_PM_VIO_ADDR: + case CS35L41_DSP1_MPU_PM_VIO_STATUS: + case CS35L41_DSP1_MPU_LOCK_CONFIG: + case CS35L41_DSP1_MPU_WDT_RST_CTRL: case CS35L41_OTP_TRIM_1: case CS35L41_OTP_TRIM_2: case CS35L41_OTP_TRIM_3: @@ -237,6 +314,13 @@ bool cs35l41_readable_reg(struct device *dev, unsigned int reg) case CS35L41_OTP_TRIM_35: case CS35L41_OTP_TRIM_36: case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31: + case CS35L41_DSP1_XMEM_PACK_0 ... CS35L41_DSP1_XMEM_PACK_3068: + case CS35L41_DSP1_XMEM_UNPACK32_0 ... CS35L41_DSP1_XMEM_UNPACK32_2046: + case CS35L41_DSP1_XMEM_UNPACK24_0 ... CS35L41_DSP1_XMEM_UNPACK24_4093: + case CS35L41_DSP1_YMEM_PACK_0 ... CS35L41_DSP1_YMEM_PACK_1532: + case CS35L41_DSP1_YMEM_UNPACK32_0 ... CS35L41_DSP1_YMEM_UNPACK32_1022: + case CS35L41_DSP1_YMEM_UNPACK24_0 ... CS35L41_DSP1_YMEM_UNPACK24_2045: + case CS35L41_DSP1_PMEM_0 ... CS35L41_DSP1_PMEM_5114: /*test regs*/ case CS35L41_PLL_OVR: case CS35L41_BST_TEST_DUTY: @@ -251,6 +335,9 @@ bool cs35l41_precious_reg(struct device *dev, unsigned int reg) { switch (reg) { case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31: + case CS35L41_DSP1_XMEM_PACK_0 ... CS35L41_DSP1_XMEM_PACK_3068: + case CS35L41_DSP1_YMEM_PACK_0 ... CS35L41_DSP1_YMEM_PACK_1532: + case CS35L41_DSP1_PMEM_0 ... CS35L41_DSP1_PMEM_5114: return true; default: return false; @@ -342,6 +429,15 @@ bool cs35l41_volatile_reg(struct device *dev, unsigned int reg) case CS35L41_OTP_TRIM_34: case CS35L41_OTP_TRIM_35: case CS35L41_OTP_TRIM_36: + case CS35L41_DSP_MBOX_1 ... CS35L41_DSP_VIRT2_MBOX_8: + case CS35L41_DSP1_XMEM_PACK_0 ... CS35L41_DSP1_XMEM_PACK_3068: + case CS35L41_DSP1_XMEM_UNPACK32_0 ... CS35L41_DSP1_XMEM_UNPACK32_2046: + case CS35L41_DSP1_XMEM_UNPACK24_0 ... CS35L41_DSP1_XMEM_UNPACK24_4093: + case CS35L41_DSP1_YMEM_PACK_0 ... CS35L41_DSP1_YMEM_PACK_1532: + case CS35L41_DSP1_YMEM_UNPACK32_0 ... CS35L41_DSP1_YMEM_UNPACK32_1022: + case CS35L41_DSP1_YMEM_UNPACK24_0 ... CS35L41_DSP1_YMEM_UNPACK24_2045: + case CS35L41_DSP1_PMEM_0 ... CS35L41_DSP1_PMEM_5114: + case CS35L41_DSP1_CCM_CORE_CTRL ... CS35L41_DSP1_WDT_STATUS: case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31: return true; default: diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c index 9d0530dde9967..afb07d2991ba4 100644 --- a/sound/soc/codecs/cs35l41.c +++ b/sound/soc/codecs/cs35l41.c @@ -197,6 +197,122 @@ static SOC_ENUM_SINGLE_DECL(pcm_sft_ramp, CS35L41_AMP_DIG_VOL_CTRL, 0, cs35l41_pcm_sftramp_text); +static int cs35l41_dsp_preload_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + int ret; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + return wm_adsp_early_event(w, kcontrol, event); + case SND_SOC_DAPM_PRE_PMD: + ret = wm_adsp_early_event(w, kcontrol, event); + if (ret) + return ret; + + return wm_adsp_event(w, kcontrol, event); + default: + return 0; + } +} + +static bool cs35l41_check_cspl_mbox_sts(enum cs35l41_cspl_mbox_cmd cmd, + enum cs35l41_cspl_mbox_status sts) +{ + switch (cmd) { + case CSPL_MBOX_CMD_NONE: + case CSPL_MBOX_CMD_UNKNOWN_CMD: + return true; + case CSPL_MBOX_CMD_PAUSE: + return (sts == CSPL_MBOX_STS_PAUSED); + case CSPL_MBOX_CMD_RESUME: + return (sts == CSPL_MBOX_STS_RUNNING); + case CSPL_MBOX_CMD_REINIT: + return (sts == CSPL_MBOX_STS_RUNNING); + case CSPL_MBOX_CMD_STOP_PRE_REINIT: + return (sts == CSPL_MBOX_STS_RDY_FOR_REINIT); + default: + return false; + } +} + +static int cs35l41_set_cspl_mbox_cmd(struct cs35l41_private *cs35l41, + enum cs35l41_cspl_mbox_cmd cmd) +{ + unsigned int sts = 0, i; + int ret; + + // Set mailbox cmd + ret = regmap_write(cs35l41->regmap, CS35L41_DSP_VIRT1_MBOX_1, cmd); + if (ret < 0) { + dev_err(cs35l41->dev, "Failed to write MBOX: %d\n", ret); + return ret; + } + + // Read mailbox status and verify it is appropriate for the given cmd + for (i = 0; i < 5; i++) { + usleep_range(1000, 1100); + + ret = regmap_read(cs35l41->regmap, CS35L41_DSP_MBOX_2, &sts); + if (ret < 0) { + dev_err(cs35l41->dev, "Failed to read MBOX STS: %d\n", ret); + continue; + } + + if (!cs35l41_check_cspl_mbox_sts(cmd, sts)) { + dev_dbg(cs35l41->dev, + "[%u] cmd %u returned invalid sts %u", + i, cmd, sts); + } else { + return 0; + } + } + + dev_err(cs35l41->dev, + "Failed to set mailbox cmd %u (status %u)\n", + cmd, sts); + + return -ENOMSG; +} + +static int cs35l41_dsp_audio_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(component); + unsigned int fw_status; + int ret; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if (!cs35l41->dsp.cs_dsp.running) + return wm_adsp_event(w, kcontrol, event); + + ret = regmap_read(cs35l41->regmap, CS35L41_DSP_MBOX_2, &fw_status); + if (ret < 0) { + dev_err(cs35l41->dev, + "Failed to read firmware status: %d\n", ret); + return ret; + } + + switch (fw_status) { + case CSPL_MBOX_STS_RUNNING: + case CSPL_MBOX_STS_PAUSED: + break; + default: + dev_err(cs35l41->dev, "Firmware status is invalid: %u\n", + fw_status); + return -EINVAL; + } + + return cs35l41_set_cspl_mbox_cmd(cs35l41, CSPL_MBOX_CMD_RESUME); + case SND_SOC_DAPM_PRE_PMD: + return cs35l41_set_cspl_mbox_cmd(cs35l41, CSPL_MBOX_CMD_PAUSE); + default: + return 0; + } +} + static const char * const cs35l41_pcm_source_texts[] = {"ASP", "DSP"}; static const unsigned int cs35l41_pcm_source_values[] = {0x08, 0x32}; static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_pcm_source_enum, @@ -255,6 +371,24 @@ static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_asptx4_enum, static const struct snd_kcontrol_new asp_tx4_mux = SOC_DAPM_ENUM("ASPTX4 SRC", cs35l41_asptx4_enum); +static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_dsprx1_enum, + CS35L41_DSP1_RX1_SRC, + 0, CS35L41_ASP_SOURCE_MASK, + cs35l41_tx_input_texts, + cs35l41_tx_input_values); + +static const struct snd_kcontrol_new dsp_rx1_mux = + SOC_DAPM_ENUM("DSPRX1 SRC", cs35l41_dsprx1_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_dsprx2_enum, + CS35L41_DSP1_RX2_SRC, + 0, CS35L41_ASP_SOURCE_MASK, + cs35l41_tx_input_texts, + cs35l41_tx_input_values); + +static const struct snd_kcontrol_new dsp_rx2_mux = + SOC_DAPM_ENUM("DSPRX2 SRC", cs35l41_dsprx2_enum); + static const struct snd_kcontrol_new cs35l41_aud_controls[] = { SOC_SINGLE_SX_TLV("Digital PCM Volume", CS35L41_AMP_DIG_VOL_CTRL, 3, 0x4CF, 0x391, dig_vol_tlv), @@ -282,6 +416,8 @@ static const struct snd_kcontrol_new cs35l41_aud_controls[] = { CS35L41_AMP_INV_PCM_SHIFT, 1, 0), SOC_SINGLE("Amp Gain ZC", CS35L41_AMP_GAIN_CTRL, CS35L41_AMP_GAIN_ZC_SHIFT, 1, 0), + WM_ADSP2_PRELOAD_SWITCH("DSP1", 1), + WM_ADSP_FW_CONTROL("DSP1", 0), }; static const struct cs35l41_otp_map_element_t *cs35l41_find_otp_map(u32 otp_id) @@ -603,6 +739,14 @@ static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w, } static const struct snd_soc_dapm_widget cs35l41_dapm_widgets[] = { + SND_SOC_DAPM_SPK("DSP1 Preload", NULL), + SND_SOC_DAPM_SUPPLY_S("DSP1 Preloader", 100, SND_SOC_NOPM, 0, 0, + cs35l41_dsp_preload_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_OUT_DRV_E("DSP1", SND_SOC_NOPM, 0, 0, NULL, 0, + cs35l41_dsp_audio_ev, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_OUTPUT("SPK"), SND_SOC_DAPM_AIF_IN("ASPRX1", NULL, 0, CS35L41_SP_ENABLES, 16, 0), @@ -618,11 +762,18 @@ static const struct snd_soc_dapm_widget cs35l41_dapm_widgets[] = { SND_SOC_DAPM_SIGGEN("VBST"), SND_SOC_DAPM_SIGGEN("TEMP"), - SND_SOC_DAPM_ADC("VMON ADC", NULL, CS35L41_PWR_CTRL2, 12, 0), - SND_SOC_DAPM_ADC("IMON ADC", NULL, CS35L41_PWR_CTRL2, 13, 0), - SND_SOC_DAPM_ADC("VPMON ADC", NULL, CS35L41_PWR_CTRL2, 8, 0), - SND_SOC_DAPM_ADC("VBSTMON ADC", NULL, CS35L41_PWR_CTRL2, 9, 0), - SND_SOC_DAPM_ADC("TEMPMON ADC", NULL, CS35L41_PWR_CTRL2, 10, 0), + SND_SOC_DAPM_SUPPLY("VMON", CS35L41_PWR_CTRL2, 12, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("IMON", CS35L41_PWR_CTRL2, 13, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("VPMON", CS35L41_PWR_CTRL2, 8, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("VBSTMON", CS35L41_PWR_CTRL2, 9, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("TEMPMON", CS35L41_PWR_CTRL2, 10, 0, NULL, 0), + + SND_SOC_DAPM_ADC("VMON ADC", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("IMON ADC", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("VPMON ADC", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("VBSTMON ADC", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("TEMPMON ADC", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("CLASS H", NULL, CS35L41_PWR_CTRL3, 4, 0), SND_SOC_DAPM_OUT_DRV_E("Main AMP", CS35L41_PWR_CTRL2, 0, 0, NULL, 0, @@ -633,33 +784,51 @@ static const struct snd_soc_dapm_widget cs35l41_dapm_widgets[] = { SND_SOC_DAPM_MUX("ASP TX2 Source", SND_SOC_NOPM, 0, 0, &asp_tx2_mux), SND_SOC_DAPM_MUX("ASP TX3 Source", SND_SOC_NOPM, 0, 0, &asp_tx3_mux), SND_SOC_DAPM_MUX("ASP TX4 Source", SND_SOC_NOPM, 0, 0, &asp_tx4_mux), + SND_SOC_DAPM_MUX("DSP RX1 Source", SND_SOC_NOPM, 0, 0, &dsp_rx1_mux), + SND_SOC_DAPM_MUX("DSP RX2 Source", SND_SOC_NOPM, 0, 0, &dsp_rx2_mux), SND_SOC_DAPM_MUX("PCM Source", SND_SOC_NOPM, 0, 0, &pcm_source_mux), SND_SOC_DAPM_SWITCH("DRE", SND_SOC_NOPM, 0, 0, &dre_ctrl), }; static const struct snd_soc_dapm_route cs35l41_audio_map[] = { + {"DSP RX1 Source", "ASPRX1", "ASPRX1"}, + {"DSP RX1 Source", "ASPRX2", "ASPRX2"}, + {"DSP RX2 Source", "ASPRX1", "ASPRX1"}, + {"DSP RX2 Source", "ASPRX2", "ASPRX2"}, + + {"DSP1", NULL, "DSP RX1 Source"}, + {"DSP1", NULL, "DSP RX2 Source"}, + {"ASP TX1 Source", "VMON", "VMON ADC"}, {"ASP TX1 Source", "IMON", "IMON ADC"}, {"ASP TX1 Source", "VPMON", "VPMON ADC"}, {"ASP TX1 Source", "VBSTMON", "VBSTMON ADC"}, + {"ASP TX1 Source", "DSPTX1", "DSP1"}, + {"ASP TX1 Source", "DSPTX2", "DSP1"}, {"ASP TX1 Source", "ASPRX1", "ASPRX1" }, {"ASP TX1 Source", "ASPRX2", "ASPRX2" }, {"ASP TX2 Source", "VMON", "VMON ADC"}, {"ASP TX2 Source", "IMON", "IMON ADC"}, {"ASP TX2 Source", "VPMON", "VPMON ADC"}, {"ASP TX2 Source", "VBSTMON", "VBSTMON ADC"}, + {"ASP TX2 Source", "DSPTX1", "DSP1"}, + {"ASP TX2 Source", "DSPTX2", "DSP1"}, {"ASP TX2 Source", "ASPRX1", "ASPRX1" }, {"ASP TX2 Source", "ASPRX2", "ASPRX2" }, {"ASP TX3 Source", "VMON", "VMON ADC"}, {"ASP TX3 Source", "IMON", "IMON ADC"}, {"ASP TX3 Source", "VPMON", "VPMON ADC"}, {"ASP TX3 Source", "VBSTMON", "VBSTMON ADC"}, + {"ASP TX3 Source", "DSPTX1", "DSP1"}, + {"ASP TX3 Source", "DSPTX2", "DSP1"}, {"ASP TX3 Source", "ASPRX1", "ASPRX1" }, {"ASP TX3 Source", "ASPRX2", "ASPRX2" }, {"ASP TX4 Source", "VMON", "VMON ADC"}, {"ASP TX4 Source", "IMON", "IMON ADC"}, {"ASP TX4 Source", "VPMON", "VPMON ADC"}, {"ASP TX4 Source", "VBSTMON", "VBSTMON ADC"}, + {"ASP TX4 Source", "DSPTX1", "DSP1"}, + {"ASP TX4 Source", "DSPTX2", "DSP1"}, {"ASP TX4 Source", "ASPRX1", "ASPRX1" }, {"ASP TX4 Source", "ASPRX2", "ASPRX2" }, {"ASPTX1", NULL, "ASP TX1 Source"}, @@ -671,12 +840,27 @@ static const struct snd_soc_dapm_route cs35l41_audio_map[] = { {"AMP Capture", NULL, "ASPTX3"}, {"AMP Capture", NULL, "ASPTX4"}, + {"DSP1", NULL, "VMON"}, + {"DSP1", NULL, "IMON"}, + {"DSP1", NULL, "VPMON"}, + {"DSP1", NULL, "VBSTMON"}, + {"DSP1", NULL, "TEMPMON"}, + + {"VMON ADC", NULL, "VMON"}, + {"IMON ADC", NULL, "IMON"}, + {"VPMON ADC", NULL, "VPMON"}, + {"VBSTMON ADC", NULL, "VBSTMON"}, + {"TEMPMON ADC", NULL, "TEMPMON"}, + {"VMON ADC", NULL, "VSENSE"}, {"IMON ADC", NULL, "ISENSE"}, {"VPMON ADC", NULL, "VP"}, {"VBSTMON ADC", NULL, "VBST"}, {"TEMPMON ADC", NULL, "TEMP"}, + {"DSP1 Preload", NULL, "DSP1 Preloader"}, + {"DSP1", NULL, "DSP1 Preloader"}, + {"ASPRX1", NULL, "AMP Playback"}, {"ASPRX2", NULL, "AMP Playback"}, {"DRE", "Switch", "CLASS H"}, @@ -685,9 +869,18 @@ static const struct snd_soc_dapm_route cs35l41_audio_map[] = { {"SPK", NULL, "Main AMP"}, {"PCM Source", "ASP", "ASPRX1"}, + {"PCM Source", "DSP", "DSP1"}, {"CLASS H", NULL, "PCM Source"}, }; +static const struct cs_dsp_region cs35l41_dsp1_regions[] = { + { .type = WMFW_HALO_PM_PACKED, .base = CS35L41_DSP1_PMEM_0 }, + { .type = WMFW_HALO_XM_PACKED, .base = CS35L41_DSP1_XMEM_PACK_0 }, + { .type = WMFW_HALO_YM_PACKED, .base = CS35L41_DSP1_YMEM_PACK_0 }, + {. type = WMFW_ADSP2_XM, .base = CS35L41_DSP1_XMEM_UNPACK24_0}, + {. type = WMFW_ADSP2_YM, .base = CS35L41_DSP1_YMEM_UNPACK24_0}, +}; + static int cs35l41_set_channel_map(struct snd_soc_dai *dai, unsigned int tx_num, unsigned int *tx_slot, unsigned int rx_num, unsigned int *rx_slot) @@ -1098,6 +1291,20 @@ static int cs35l41_irq_gpio_config(struct cs35l41_private *cs35l41) return irq_pol; } +static int cs35l41_component_probe(struct snd_soc_component *component) +{ + struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(component); + + return wm_adsp2_component_probe(&cs35l41->dsp, component); +} + +static void cs35l41_component_remove(struct snd_soc_component *component) +{ + struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(component); + + wm_adsp2_component_remove(&cs35l41->dsp, component); +} + static const struct snd_soc_dai_ops cs35l41_ops = { .startup = cs35l41_pcm_startup, .set_fmt = cs35l41_set_dai_fmt, @@ -1131,6 +1338,8 @@ static struct snd_soc_dai_driver cs35l41_dai[] = { static const struct snd_soc_component_driver soc_component_dev_cs35l41 = { .name = "cs35l41-codec", + .probe = cs35l41_component_probe, + .remove = cs35l41_component_remove, .dapm_widgets = cs35l41_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(cs35l41_dapm_widgets), @@ -1237,6 +1446,90 @@ static const struct reg_sequence cs35l41_revb2_errata_patch[] = { { 0x00000040, 0x00003333 }, }; +static const struct reg_sequence cs35l41_fs_errata_patch[] = { + { CS35L41_DSP1_RX1_RATE, 0x00000001 }, + { CS35L41_DSP1_RX2_RATE, 0x00000001 }, + { CS35L41_DSP1_RX3_RATE, 0x00000001 }, + { CS35L41_DSP1_RX4_RATE, 0x00000001 }, + { CS35L41_DSP1_RX5_RATE, 0x00000001 }, + { CS35L41_DSP1_RX6_RATE, 0x00000001 }, + { CS35L41_DSP1_RX7_RATE, 0x00000001 }, + { CS35L41_DSP1_RX8_RATE, 0x00000001 }, + { CS35L41_DSP1_TX1_RATE, 0x00000001 }, + { CS35L41_DSP1_TX2_RATE, 0x00000001 }, + { CS35L41_DSP1_TX3_RATE, 0x00000001 }, + { CS35L41_DSP1_TX4_RATE, 0x00000001 }, + { CS35L41_DSP1_TX5_RATE, 0x00000001 }, + { CS35L41_DSP1_TX6_RATE, 0x00000001 }, + { CS35L41_DSP1_TX7_RATE, 0x00000001 }, + { CS35L41_DSP1_TX8_RATE, 0x00000001 }, +}; + +static int cs35l41_dsp_init(struct cs35l41_private *cs35l41) +{ + struct wm_adsp *dsp; + int ret; + + dsp = &cs35l41->dsp; + dsp->part = "cs35l41"; + dsp->cs_dsp.num = 1; + dsp->cs_dsp.type = WMFW_HALO; + dsp->cs_dsp.rev = 0; + dsp->fw = 9; /* 9 is WM_ADSP_FW_SPK_PROT in wm_adsp.c */ + dsp->cs_dsp.dev = cs35l41->dev; + dsp->cs_dsp.regmap = cs35l41->regmap; + dsp->cs_dsp.base = CS35L41_DSP1_CTRL_BASE; + dsp->cs_dsp.base_sysinfo = CS35L41_DSP1_SYS_ID; + dsp->cs_dsp.mem = cs35l41_dsp1_regions; + dsp->cs_dsp.num_mems = ARRAY_SIZE(cs35l41_dsp1_regions); + dsp->cs_dsp.lock_regions = 0xFFFFFFFF; + + ret = regmap_multi_reg_write(cs35l41->regmap, cs35l41_fs_errata_patch, + ARRAY_SIZE(cs35l41_fs_errata_patch)); + if (ret < 0) { + dev_err(cs35l41->dev, "Failed to write fs errata: %d\n", ret); + return ret; + } + + ret = wm_halo_init(dsp); + if (ret) { + dev_err(cs35l41->dev, "wm_halo_init failed: %d\n", ret); + return ret; + } + + ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_RX5_SRC, + CS35L41_INPUT_SRC_VPMON); + if (ret < 0) { + dev_err(cs35l41->dev, "Write INPUT_SRC_VPMON failed: %d\n", ret); + goto err_dsp; + } + ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_RX6_SRC, + CS35L41_INPUT_SRC_CLASSH); + if (ret < 0) { + dev_err(cs35l41->dev, "Write INPUT_SRC_CLASSH failed: %d\n", ret); + goto err_dsp; + } + ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_RX7_SRC, + CS35L41_INPUT_SRC_TEMPMON); + if (ret < 0) { + dev_err(cs35l41->dev, "Write INPUT_SRC_TEMPMON failed: %d\n", ret); + goto err_dsp; + } + ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_RX8_SRC, + CS35L41_INPUT_SRC_RSVD); + if (ret < 0) { + dev_err(cs35l41->dev, "Write INPUT_SRC_RSVD failed: %d\n", ret); + goto err_dsp; + } + + return 0; + +err_dsp: + wm_adsp2_remove(dsp); + + return ret; +} + int cs35l41_probe(struct cs35l41_private *cs35l41, struct cs35l41_platform_data *pdata) { @@ -1413,12 +1706,16 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, goto err; } + ret = cs35l41_dsp_init(cs35l41); + if (ret < 0) + goto err; + ret = devm_snd_soc_register_component(cs35l41->dev, &soc_component_dev_cs35l41, cs35l41_dai, ARRAY_SIZE(cs35l41_dai)); if (ret < 0) { dev_err(cs35l41->dev, "Register codec failed: %d\n", ret); - goto err; + goto err_dsp; } dev_info(cs35l41->dev, "Cirrus Logic CS35L41 (%x), Revision: %02X\n", @@ -1426,6 +1723,8 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, return 0; +err_dsp: + wm_adsp2_remove(&cs35l41->dsp); err: regulator_bulk_disable(CS35L41_NUM_SUPPLIES, cs35l41->supplies); gpiod_set_value_cansleep(cs35l41->reset_gpio, 0); @@ -1436,6 +1735,7 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, void cs35l41_remove(struct cs35l41_private *cs35l41) { regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1, 0xFFFFFFFF); + wm_adsp2_remove(&cs35l41->dsp); regulator_bulk_disable(CS35L41_NUM_SUPPLIES, cs35l41->supplies); gpiod_set_value_cansleep(cs35l41->reset_gpio, 0); } diff --git a/sound/soc/codecs/cs35l41.h b/sound/soc/codecs/cs35l41.h index 6cffe8a55beb1..eea3b14acb0b4 100644 --- a/sound/soc/codecs/cs35l41.h +++ b/sound/soc/codecs/cs35l41.h @@ -13,9 +13,12 @@ #include #include #include +#include #include #include +#include "wm_adsp.h" + #define CS35L41_FIRSTREG 0x00000000 #define CS35L41_LASTREG 0x03804FE8 #define CS35L41_DEVID 0x00000000 @@ -755,7 +758,24 @@ extern const struct cs35l41_otp_map_element_t #define CS35L41_REGSTRIDE 4 +enum cs35l41_cspl_mbox_status { + CSPL_MBOX_STS_RUNNING = 0, + CSPL_MBOX_STS_PAUSED = 1, + CSPL_MBOX_STS_RDY_FOR_REINIT = 2, +}; + +enum cs35l41_cspl_mbox_cmd { + CSPL_MBOX_CMD_NONE = 0, + CSPL_MBOX_CMD_PAUSE = 1, + CSPL_MBOX_CMD_RESUME = 2, + CSPL_MBOX_CMD_REINIT = 3, + CSPL_MBOX_CMD_STOP_PRE_REINIT = 4, + CSPL_MBOX_CMD_UNKNOWN_CMD = -1, + CSPL_MBOX_CMD_INVALID_SEQUENCE = -2, +}; + struct cs35l41_private { + struct wm_adsp dsp; /* needs to be first member */ struct snd_soc_codec *codec; struct cs35l41_platform_data pdata; struct device *dev; From 95cead06866a95baf0f8355bba81a8142d5908cf Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 3 Nov 2021 20:19:27 +0100 Subject: [PATCH 018/327] ASoC: codecs: Axe some dead code in 'wcd_mbhc_adc_hs_rem_irq()' 'hphpa_on' is know to be false, so this is just dead code that should be removed. Suggested-by: Srinivas Kandagatla Signed-off-by: Christophe JAILLET Reviewed-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/57a89cc31eb2312addd3c77896d7df8206aef138.1635967035.git.christophe.jaillet@wanadoo.fr Signed-off-by: Mark Brown --- sound/soc/codecs/wcd-mbhc-v2.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c index 405128ccb4b0e..b905eb8f3c67e 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.c +++ b/sound/soc/codecs/wcd-mbhc-v2.c @@ -1176,7 +1176,6 @@ static irqreturn_t wcd_mbhc_adc_hs_rem_irq(int irq, void *data) struct wcd_mbhc *mbhc = data; unsigned long timeout; int adc_threshold, output_mv, retry = 0; - bool hphpa_on = false; mutex_lock(&mbhc->lock); timeout = jiffies + msecs_to_jiffies(WCD_FAKE_REMOVAL_MIN_PERIOD_MS); @@ -1210,10 +1209,6 @@ static irqreturn_t wcd_mbhc_adc_hs_rem_irq(int irq, void *data) wcd_mbhc_elec_hs_report_unplug(mbhc); wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0); - if (hphpa_on) { - hphpa_on = false; - wcd_mbhc_write_field(mbhc, WCD_MBHC_HPH_PA_EN, 3); - } exit: mutex_unlock(&mbhc->lock); return IRQ_HANDLED; From 8d0872f6239f9d067d538d8368bdec643bb0d255 Mon Sep 17 00:00:00 2001 From: Mac Chiang Date: Tue, 9 Nov 2021 08:38:08 -0500 Subject: [PATCH 019/327] ASoC: Intel: add sof-nau8825 machine driver The machine driver is a generic machine driver for SOF with nau8825 codec w or w/o speaker additionally. Depending on the SOC HDMI, DMIC, Bluetooth offload support are added dynamically. Only add information related to SOF since the machine driver was only tested with SOF. There are currently 4 i2s machine variants of ADL. This supports the headphone NUA8825(SSP0) alone or with smart or dumb speakers. Board 2,3,4 use SSP2 for Bluetooth offload support except board 1. Board 1 : NAU8825 + RT1019P(SSP2) Board 2 : NAU8825 + MAX98373(SSP1) Board 3 : NAU8825 + MAX98360A(SSP1) Board 4 : NAU8825 Signed-off-by: David Lin Co-developed-by: Mac Chiang Signed-off-by: Mac Chiang Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20211109133808.8729-1-mac.chiang@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 19 + sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/sof_nau8825.c | 651 ++++++++++++++++++ .../intel/common/soc-acpi-intel-adl-match.c | 35 + 4 files changed, 707 insertions(+) create mode 100644 sound/soc/intel/boards/sof_nau8825.c diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 2dd5ff7e35cee..849445fcc05dc 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -527,6 +527,25 @@ config SND_SOC_INTEL_SOF_ES8336_MACH Say Y if you have such a device. If unsure select "N". +config SND_SOC_INTEL_SOF_NAU8825_MACH + tristate "SOF with nau8825 codec in I2S Mode" + depends on I2C && ACPI && GPIOLIB + depends on ((SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC) &&\ + (MFD_INTEL_LPSS || COMPILE_TEST)) + select SND_SOC_NAU8825 + select SND_SOC_RT1015P + select SND_SOC_MAX98373_I2C + select SND_SOC_MAX98357A + select SND_SOC_DMIC + select SND_SOC_HDAC_HDMI + select SND_SOC_INTEL_HDA_DSP_COMMON + select SND_SOC_INTEL_SOF_MAXIM_COMMON + help + This adds support for ASoC machine driver for SOF platforms + with nau8825 codec. + Say Y if you have such a device. + If unsure select "N". + endif ## SND_SOC_SOF_HDA_LINK || SND_SOC_SOF_BAYTRAIL if (SND_SOC_SOF_COMETLAKE && SND_SOC_SOF_HDA_LINK) diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 9ee8ed864f5d1..3ea273d271688 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -22,6 +22,7 @@ snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o snd-soc-sof_rt5682-objs := sof_rt5682.o sof_realtek_common.o snd-soc-sof_cs42l42-objs := sof_cs42l42.o snd-soc-sof_es8336-objs := sof_es8336.o +snd-soc-sof_nau8825-objs := sof_nau8825.o sof_realtek_common.o snd-soc-cml_rt1011_rt5682-objs := cml_rt1011_rt5682.o snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o snd-soc-kbl_da7219_max98927-objs := kbl_da7219_max98927.o @@ -44,6 +45,7 @@ snd-soc-sof-sdw-objs += sof_sdw.o \ obj-$(CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH) += snd-soc-sof_rt5682.o obj-$(CONFIG_SND_SOC_INTEL_SOF_CS42L42_MACH) += snd-soc-sof_cs42l42.o obj-$(CONFIG_SND_SOC_INTEL_SOF_ES8336_MACH) += snd-soc-sof_es8336.o +obj-$(CONFIG_SND_SOC_INTEL_SOF_NAU8825_MACH) += snd-soc-sof_nau8825.o obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o obj-$(CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON) += snd-soc-sst-bxt-da7219_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c new file mode 100644 index 0000000000000..33de043b66c6e --- /dev/null +++ b/sound/soc/intel/boards/sof_nau8825.c @@ -0,0 +1,651 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright(c) 2021 Intel Corporation. +// Copyright(c) 2021 Nuvoton Corporation. + +/* + * Intel SOF Machine Driver with Nuvoton headphone codec NAU8825 + * and speaker codec RT1019P MAX98360a or MAX98373 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../codecs/nau8825.h" +#include "../common/soc-intel-quirks.h" +#include "hda_dsp_common.h" +#include "sof_realtek_common.h" +#include "sof_maxim_common.h" + +#define NAME_SIZE 32 + +#define SOF_NAU8825_SSP_CODEC(quirk) ((quirk) & GENMASK(2, 0)) +#define SOF_NAU8825_SSP_CODEC_MASK (GENMASK(2, 0)) +#define SOF_SPEAKER_AMP_PRESENT BIT(3) +#define SOF_NAU8825_SSP_AMP_SHIFT 4 +#define SOF_NAU8825_SSP_AMP_MASK (GENMASK(6, 4)) +#define SOF_NAU8825_SSP_AMP(quirk) \ + (((quirk) << SOF_NAU8825_SSP_AMP_SHIFT) & SOF_NAU8825_SSP_AMP_MASK) +#define SOF_NAU8825_NUM_HDMIDEV_SHIFT 7 +#define SOF_NAU8825_NUM_HDMIDEV_MASK (GENMASK(9, 7)) +#define SOF_NAU8825_NUM_HDMIDEV(quirk) \ + (((quirk) << SOF_NAU8825_NUM_HDMIDEV_SHIFT) & SOF_NAU8825_NUM_HDMIDEV_MASK) + +/* BT audio offload: reserve 3 bits for future */ +#define SOF_BT_OFFLOAD_SSP_SHIFT 10 +#define SOF_BT_OFFLOAD_SSP_MASK (GENMASK(12, 10)) +#define SOF_BT_OFFLOAD_SSP(quirk) \ + (((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK) +#define SOF_SSP_BT_OFFLOAD_PRESENT BIT(13) +#define SOF_RT1019P_SPEAKER_AMP_PRESENT BIT(14) +#define SOF_MAX98373_SPEAKER_AMP_PRESENT BIT(15) +#define SOF_MAX98360A_SPEAKER_AMP_PRESENT BIT(16) + +static unsigned long sof_nau8825_quirk = SOF_NAU8825_SSP_CODEC(0); + +struct sof_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +struct sof_card_private { + struct clk *mclk; + struct snd_soc_jack sof_headset; + struct list_head hdmi_pcm_list; +}; + +static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd) +{ + struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); + struct sof_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + /* dai_link id is 1:1 mapped to the PCM device */ + pcm->device = rtd->dai_link->id; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +static int sof_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; + + struct snd_soc_jack *jack; + int ret; + + /* + * Headset buttons map to the google Reference headset. + * These can be configured by userspace. + */ + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + &ctx->sof_headset, NULL, 0); + if (ret) { + dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); + return ret; + } + + jack = &ctx->sof_headset; + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + ret = snd_soc_component_set_jack(component, jack, NULL); + + if (ret) { + dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); + return ret; + } + + return ret; +}; + +static void sof_nau8825_codec_exit(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; + + snd_soc_component_set_jack(component, NULL, NULL); +} + +static int sof_nau8825_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + int clk_freq, ret; + + clk_freq = sof_dai_get_bclk(rtd); /* BCLK freq */ + + if (clk_freq <= 0) { + dev_err(rtd->dev, "get bclk freq failed: %d\n", clk_freq); + return -EINVAL; + } + + /* Configure clock for codec */ + ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_BLK, 0, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(codec_dai->dev, "can't set BCLK clock %d\n", ret); + return ret; + } + + /* Configure pll for codec */ + ret = snd_soc_dai_set_pll(codec_dai, 0, 0, clk_freq, + params_rate(params) * 256); + if (ret < 0) { + dev_err(codec_dai->dev, "can't set BCLK: %d\n", ret); + return ret; + } + + return ret; +} + +static struct snd_soc_ops sof_nau8825_ops = { + .hw_params = sof_nau8825_hw_params, +}; + +static struct snd_soc_dai_link_component platform_component[] = { + { + /* name might be overridden during probe */ + .name = "0000:00:1f.3" + } +}; + +static int sof_card_late_probe(struct snd_soc_card *card) +{ + struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_dapm_context *dapm = &card->dapm; + struct sof_hdmi_pcm *pcm; + int err; + + if (list_empty(&ctx->hdmi_pcm_list)) + return -EINVAL; + + pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm, head); + + if (sof_nau8825_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) { + /* Disable Left and Right Spk pin after boot */ + snd_soc_dapm_disable_pin(dapm, "Left Spk"); + snd_soc_dapm_disable_pin(dapm, "Right Spk"); + err = snd_soc_dapm_sync(dapm); + if (err < 0) + return err; + } + + return hda_dsp_hdmi_build_controls(card, pcm->codec_dai->component); +} + +static const struct snd_kcontrol_new sof_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Left Spk"), + SOC_DAPM_PIN_SWITCH("Right Spk"), +}; + +static const struct snd_kcontrol_new speaker_controls[] = { + SOC_DAPM_PIN_SWITCH("Spk"), +}; + +static const struct snd_soc_dapm_widget sof_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_SPK("Left Spk", NULL), + SND_SOC_DAPM_SPK("Right Spk", NULL), +}; + +static const struct snd_soc_dapm_widget speaker_widgets[] = { + SND_SOC_DAPM_SPK("Spk", NULL), +}; + +static const struct snd_soc_dapm_widget dmic_widgets[] = { + SND_SOC_DAPM_MIC("SoC DMIC", NULL), +}; + +static const struct snd_soc_dapm_route sof_map[] = { + /* HP jack connectors - unknown if we have jack detection */ + { "Headphone Jack", NULL, "HPOL" }, + { "Headphone Jack", NULL, "HPOR" }, + + /* other jacks */ + { "MIC", NULL, "Headset Mic" }, +}; + +static const struct snd_soc_dapm_route speaker_map[] = { + /* speaker */ + { "Spk", NULL, "Speaker" }, +}; + +static const struct snd_soc_dapm_route dmic_map[] = { + /* digital mics */ + {"DMic", NULL, "SoC DMIC"}, +}; + +static int speaker_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + ret = snd_soc_dapm_new_controls(&card->dapm, speaker_widgets, + ARRAY_SIZE(speaker_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add dapm controls, ret %d\n", ret); + /* Don't need to add routes if widget addition failed */ + return ret; + } + + ret = snd_soc_add_card_controls(card, speaker_controls, + ARRAY_SIZE(speaker_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, speaker_map, + ARRAY_SIZE(speaker_map)); + + if (ret) + dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret); + return ret; +} + +static int dmic_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets, + ARRAY_SIZE(dmic_widgets)); + if (ret) { + dev_err(card->dev, "DMic widget addition failed: %d\n", ret); + /* Don't need to add routes if widget addition failed */ + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map, + ARRAY_SIZE(dmic_map)); + + if (ret) + dev_err(card->dev, "DMic map addition failed: %d\n", ret); + + return ret; +} + +/* sof audio machine driver for nau8825 codec */ +static struct snd_soc_card sof_audio_card_nau8825 = { + .name = "nau8825", /* the sof- prefix is added by the core */ + .owner = THIS_MODULE, + .controls = sof_controls, + .num_controls = ARRAY_SIZE(sof_controls), + .dapm_widgets = sof_widgets, + .num_dapm_widgets = ARRAY_SIZE(sof_widgets), + .dapm_routes = sof_map, + .num_dapm_routes = ARRAY_SIZE(sof_map), + .fully_routed = true, + .late_probe = sof_card_late_probe, +}; + +static struct snd_soc_dai_link_component nau8825_component[] = { + { + .name = "i2c-10508825:00", + .dai_name = "nau8825-hifi", + } +}; + +static struct snd_soc_dai_link_component dmic_component[] = { + { + .name = "dmic-codec", + .dai_name = "dmic-hifi", + } +}; + +static struct snd_soc_dai_link_component rt1019p_component[] = { + { + .name = "RTL1019:00", + .dai_name = "HiFi", + } +}; + +static struct snd_soc_dai_link_component dummy_component[] = { + { + .name = "snd-soc-dummy", + .dai_name = "snd-soc-dummy-dai", + } +}; + +static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, + int ssp_codec, + int ssp_amp, + int dmic_be_num, + int hdmi_num) +{ + struct snd_soc_dai_link_component *idisp_components; + struct snd_soc_dai_link_component *cpus; + struct snd_soc_dai_link *links; + int i, id = 0; + + links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * + sof_audio_card_nau8825.num_links, GFP_KERNEL); + cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) * + sof_audio_card_nau8825.num_links, GFP_KERNEL); + if (!links || !cpus) + goto devm_err; + + /* codec SSP */ + links[id].name = devm_kasprintf(dev, GFP_KERNEL, + "SSP%d-Codec", ssp_codec); + if (!links[id].name) + goto devm_err; + + links[id].id = id; + links[id].codecs = nau8825_component; + links[id].num_codecs = ARRAY_SIZE(nau8825_component); + links[id].platforms = platform_component; + links[id].num_platforms = ARRAY_SIZE(platform_component); + links[id].init = sof_nau8825_codec_init; + links[id].exit = sof_nau8825_codec_exit; + links[id].ops = &sof_nau8825_ops; + links[id].dpcm_playback = 1; + links[id].dpcm_capture = 1; + links[id].no_pcm = 1; + links[id].cpus = &cpus[id]; + links[id].num_cpus = 1; + + links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + "SSP%d Pin", + ssp_codec); + if (!links[id].cpus->dai_name) + goto devm_err; + + id++; + + /* dmic */ + if (dmic_be_num > 0) { + /* at least we have dmic01 */ + links[id].name = "dmic01"; + links[id].cpus = &cpus[id]; + links[id].cpus->dai_name = "DMIC01 Pin"; + links[id].init = dmic_init; + if (dmic_be_num > 1) { + /* set up 2 BE links at most */ + links[id + 1].name = "dmic16k"; + links[id + 1].cpus = &cpus[id + 1]; + links[id + 1].cpus->dai_name = "DMIC16k Pin"; + dmic_be_num = 2; + } + } + + for (i = 0; i < dmic_be_num; i++) { + links[id].id = id; + links[id].num_cpus = 1; + links[id].codecs = dmic_component; + links[id].num_codecs = ARRAY_SIZE(dmic_component); + links[id].platforms = platform_component; + links[id].num_platforms = ARRAY_SIZE(platform_component); + links[id].ignore_suspend = 1; + links[id].dpcm_capture = 1; + links[id].no_pcm = 1; + id++; + } + + /* HDMI */ + if (hdmi_num > 0) { + idisp_components = devm_kzalloc(dev, + sizeof(struct snd_soc_dai_link_component) * + hdmi_num, GFP_KERNEL); + if (!idisp_components) + goto devm_err; + } + for (i = 1; i <= hdmi_num; i++) { + links[id].name = devm_kasprintf(dev, GFP_KERNEL, + "iDisp%d", i); + if (!links[id].name) + goto devm_err; + + links[id].id = id; + links[id].cpus = &cpus[id]; + links[id].num_cpus = 1; + links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + "iDisp%d Pin", i); + if (!links[id].cpus->dai_name) + goto devm_err; + + idisp_components[i - 1].name = "ehdaudio0D2"; + idisp_components[i - 1].dai_name = devm_kasprintf(dev, + GFP_KERNEL, + "intel-hdmi-hifi%d", + i); + if (!idisp_components[i - 1].dai_name) + goto devm_err; + + links[id].codecs = &idisp_components[i - 1]; + links[id].num_codecs = 1; + links[id].platforms = platform_component; + links[id].num_platforms = ARRAY_SIZE(platform_component); + links[id].init = sof_hdmi_init; + links[id].dpcm_playback = 1; + links[id].no_pcm = 1; + id++; + } + + /* speaker amp */ + if (sof_nau8825_quirk & SOF_SPEAKER_AMP_PRESENT) { + links[id].name = devm_kasprintf(dev, GFP_KERNEL, + "SSP%d-Codec", ssp_amp); + if (!links[id].name) + goto devm_err; + + links[id].id = id; + if (sof_nau8825_quirk & SOF_RT1019P_SPEAKER_AMP_PRESENT) { + links[id].codecs = rt1019p_component; + links[id].num_codecs = ARRAY_SIZE(rt1019p_component); + links[id].init = speaker_codec_init; + } else if (sof_nau8825_quirk & + SOF_MAX98373_SPEAKER_AMP_PRESENT) { + links[id].codecs = max_98373_components; + links[id].num_codecs = ARRAY_SIZE(max_98373_components); + links[id].init = max_98373_spk_codec_init; + links[id].ops = &max_98373_ops; + /* feedback stream */ + links[id].dpcm_capture = 1; + } else if (sof_nau8825_quirk & + SOF_MAX98360A_SPEAKER_AMP_PRESENT) { + max_98360a_dai_link(&links[id]); + } else { + goto devm_err; + } + + links[id].platforms = platform_component; + links[id].num_platforms = ARRAY_SIZE(platform_component); + links[id].dpcm_playback = 1; + links[id].no_pcm = 1; + links[id].cpus = &cpus[id]; + links[id].num_cpus = 1; + links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + "SSP%d Pin", + ssp_amp); + if (!links[id].cpus->dai_name) + goto devm_err; + id++; + } + + /* BT audio offload */ + if (sof_nau8825_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { + int port = (sof_nau8825_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> + SOF_BT_OFFLOAD_SSP_SHIFT; + + links[id].id = id; + links[id].cpus = &cpus[id]; + links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + "SSP%d Pin", port); + if (!links[id].cpus->dai_name) + goto devm_err; + links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); + if (!links[id].name) + goto devm_err; + links[id].codecs = dummy_component; + links[id].num_codecs = ARRAY_SIZE(dummy_component); + links[id].platforms = platform_component; + links[id].num_platforms = ARRAY_SIZE(platform_component); + links[id].dpcm_playback = 1; + links[id].dpcm_capture = 1; + links[id].no_pcm = 1; + links[id].num_cpus = 1; + } + + return links; +devm_err: + return NULL; +} + +static int sof_audio_probe(struct platform_device *pdev) +{ + struct snd_soc_dai_link *dai_links; + struct snd_soc_acpi_mach *mach; + struct sof_card_private *ctx; + int dmic_be_num, hdmi_num; + int ret, ssp_amp, ssp_codec; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + if (pdev->id_entry && pdev->id_entry->driver_data) + sof_nau8825_quirk = (unsigned long)pdev->id_entry->driver_data; + + mach = pdev->dev.platform_data; + + /* A speaker amp might not be present when the quirk claims one is. + * Detect this via whether the machine driver match includes quirk_data. + */ + if ((sof_nau8825_quirk & SOF_SPEAKER_AMP_PRESENT) && !mach->quirk_data) + sof_nau8825_quirk &= ~SOF_SPEAKER_AMP_PRESENT; + + dev_dbg(&pdev->dev, "sof_nau8825_quirk = %lx\n", sof_nau8825_quirk); + + /* default number of DMIC DAI's */ + dmic_be_num = 2; + hdmi_num = (sof_nau8825_quirk & SOF_NAU8825_NUM_HDMIDEV_MASK) >> + SOF_NAU8825_NUM_HDMIDEV_SHIFT; + /* default number of HDMI DAI's */ + if (!hdmi_num) + hdmi_num = 3; + + ssp_amp = (sof_nau8825_quirk & SOF_NAU8825_SSP_AMP_MASK) >> + SOF_NAU8825_SSP_AMP_SHIFT; + + ssp_codec = sof_nau8825_quirk & SOF_NAU8825_SSP_CODEC_MASK; + + /* compute number of dai links */ + sof_audio_card_nau8825.num_links = 1 + dmic_be_num + hdmi_num; + + if (sof_nau8825_quirk & SOF_SPEAKER_AMP_PRESENT) + sof_audio_card_nau8825.num_links++; + + if (sof_nau8825_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) + max_98373_set_codec_conf(&sof_audio_card_nau8825); + + if (sof_nau8825_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) + sof_audio_card_nau8825.num_links++; + + dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp, + dmic_be_num, hdmi_num); + if (!dai_links) + return -ENOMEM; + + sof_audio_card_nau8825.dai_link = dai_links; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + + sof_audio_card_nau8825.dev = &pdev->dev; + + /* set platform name for each dailink */ + ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_nau8825, + mach->mach_params.platform); + if (ret) + return ret; + + snd_soc_card_set_drvdata(&sof_audio_card_nau8825, ctx); + + return devm_snd_soc_register_card(&pdev->dev, + &sof_audio_card_nau8825); +} + +static const struct platform_device_id board_ids[] = { + { + .name = "sof_nau8825", + .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) | + SOF_NAU8825_NUM_HDMIDEV(4) | + SOF_BT_OFFLOAD_SSP(2) | + SOF_SSP_BT_OFFLOAD_PRESENT), + + }, + { + .name = "adl_rt1019p_nau8825", + .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) | + SOF_SPEAKER_AMP_PRESENT | + SOF_RT1019P_SPEAKER_AMP_PRESENT | + SOF_NAU8825_SSP_AMP(2) | + SOF_NAU8825_NUM_HDMIDEV(4)), + }, + { + .name = "adl_max98373_nau8825", + .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) | + SOF_SPEAKER_AMP_PRESENT | + SOF_MAX98373_SPEAKER_AMP_PRESENT | + SOF_NAU8825_SSP_AMP(1) | + SOF_NAU8825_NUM_HDMIDEV(4) | + SOF_BT_OFFLOAD_SSP(2) | + SOF_SSP_BT_OFFLOAD_PRESENT), + }, + { + /* The limitation of length of char array, shorten the name */ + .name = "adl_mx98360a_nau8825", + .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) | + SOF_SPEAKER_AMP_PRESENT | + SOF_MAX98360A_SPEAKER_AMP_PRESENT | + SOF_NAU8825_SSP_AMP(1) | + SOF_NAU8825_NUM_HDMIDEV(4) | + SOF_BT_OFFLOAD_SSP(2) | + SOF_SSP_BT_OFFLOAD_PRESENT), + + }, + { } +}; +MODULE_DEVICE_TABLE(platform, board_ids); + +static struct platform_driver sof_audio = { + .probe = sof_audio_probe, + .driver = { + .name = "sof_nau8825", + .pm = &snd_soc_pm_ops, + }, + .id_table = board_ids, +}; +module_platform_driver(sof_audio) + +/* Module information */ +MODULE_DESCRIPTION("SOF Audio Machine driver for NAU8825"); +MODULE_AUTHOR("David Lin "); +MODULE_AUTHOR("Mac Chiang "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); +MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON); diff --git a/sound/soc/intel/common/soc-acpi-intel-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c index b61a778a9d26b..fde310e5724ba 100644 --- a/sound/soc/intel/common/soc-acpi-intel-adl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c @@ -374,6 +374,11 @@ static const struct snd_soc_acpi_codecs adl_rt5682_rt5682s_hp = { .codecs = {"10EC5682", "RTL5682"}, }; +static const struct snd_soc_acpi_codecs adl_rt1019p_amp = { + .num_codecs = 1, + .codecs = {"RTL1019"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { { .comp_ids = &adl_rt5682_rt5682s_hp, @@ -399,6 +404,36 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { .sof_fw_filename = "sof-adl.ri", .sof_tplg_filename = "sof-adl-max98360a-rt5682.tplg", }, + { + .id = "10508825", + .drv_name = "adl_rt1019p_nau8825", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &adl_rt1019p_amp, + .sof_fw_filename = "sof-adl.ri", + .sof_tplg_filename = "sof-adl-rt1019-nau8825.tplg", + }, + { + .id = "10508825", + .drv_name = "adl_max98373_nau8825", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &adl_max98373_amp, + .sof_fw_filename = "sof-adl.ri", + .sof_tplg_filename = "sof-adl-max98373-nau8825.tplg", + }, + { + .id = "10508825", + .drv_name = "adl_mx98360a_nau8825", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &adl_max98360a_amp, + .sof_fw_filename = "sof-adl.ri", + .sof_tplg_filename = "sof-adl-mx98360a-nau8825.tplg", + }, + { + .id = "10508825", + .drv_name = "sof_nau8825", + .sof_fw_filename = "sof-adl.ri", + .sof_tplg_filename = "sof-adl-nau8825.tplg", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_adl_machines); From 7ec4a058c16f3da9c2c0c66506f45c083198ed30 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 1 Nov 2021 10:10:06 +0000 Subject: [PATCH 020/327] ASoC: cs42l42: Add control for audio slow-start switch This adds an ALSA control so that the slow-start audio ramp feature can be disabled. This is useful for high-definition audio applications. The register field is unusual in that it is a 3-bit field with only two valid values, 000=off and 111=on. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20211101101006.13092-1-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 30 +++++++++++++++++++++++++++++- sound/soc/codecs/cs42l42.h | 3 +++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 27a1c4c73074f..56804a3f285e6 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -42,6 +42,7 @@ static const struct reg_default cs42l42_reg_defaults[] = { { CS42L42_SRC_CTL, 0x10 }, { CS42L42_MCLK_CTL, 0x02 }, { CS42L42_SFTRAMP_RATE, 0xA4 }, + { CS42L42_SLOW_START_ENABLE, 0x70 }, { CS42L42_I2C_DEBOUNCE, 0x88 }, { CS42L42_I2C_STRETCH, 0x03 }, { CS42L42_I2C_TIMEOUT, 0xB7 }, @@ -177,6 +178,7 @@ static bool cs42l42_readable_register(struct device *dev, unsigned int reg) case CS42L42_MCLK_STATUS: case CS42L42_MCLK_CTL: case CS42L42_SFTRAMP_RATE: + case CS42L42_SLOW_START_ENABLE: case CS42L42_I2C_DEBOUNCE: case CS42L42_I2C_STRETCH: case CS42L42_I2C_TIMEOUT: @@ -387,6 +389,28 @@ static const struct regmap_config cs42l42_regmap = { static DECLARE_TLV_DB_SCALE(adc_tlv, -9700, 100, true); static DECLARE_TLV_DB_SCALE(mixer_tlv, -6300, 100, true); +static int cs42l42_slow_start_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + u8 val; + + /* all bits of SLOW_START_EN much change together */ + switch (ucontrol->value.integer.value[0]) { + case 0: + val = 0; + break; + case 1: + val = CS42L42_SLOW_START_EN_MASK; + break; + default: + return -EINVAL; + } + + return snd_soc_component_update_bits(component, CS42L42_SLOW_START_ENABLE, + CS42L42_SLOW_START_EN_MASK, val); +} + static const char * const cs42l42_hpf_freq_text[] = { "1.86Hz", "120Hz", "235Hz", "466Hz" }; @@ -431,7 +455,11 @@ static const struct snd_kcontrol_new cs42l42_snd_controls[] = { CS42L42_DAC_HPF_EN_SHIFT, true, false), SOC_DOUBLE_R_TLV("Mixer Volume", CS42L42_MIXER_CHA_VOL, CS42L42_MIXER_CHB_VOL, CS42L42_MIXER_CH_VOL_SHIFT, - 0x3f, 1, mixer_tlv) + 0x3f, 1, mixer_tlv), + + SOC_SINGLE_EXT("Slow Start Switch", CS42L42_SLOW_START_ENABLE, + CS42L42_SLOW_START_EN_SHIFT, true, false, + snd_soc_get_volsw, cs42l42_slow_start_put), }; static int cs42l42_hp_adc_ev(struct snd_soc_dapm_widget *w, diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index f45bcc9a3a62f..c8b3267a318b5 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -62,6 +62,9 @@ #define CS42L42_INTERNAL_FS_MASK (1 << CS42L42_INTERNAL_FS_SHIFT) #define CS42L42_SFTRAMP_RATE (CS42L42_PAGE_10 + 0x0A) +#define CS42L42_SLOW_START_ENABLE (CS42L42_PAGE_10 + 0x0B) +#define CS42L42_SLOW_START_EN_MASK GENMASK(6, 4) +#define CS42L42_SLOW_START_EN_SHIFT 4 #define CS42L42_I2C_DEBOUNCE (CS42L42_PAGE_10 + 0x0E) #define CS42L42_I2C_STRETCH (CS42L42_PAGE_10 + 0x0F) #define CS42L42_I2C_TIMEOUT (CS42L42_PAGE_10 + 0x10) From 749303055b78bc38ec0790ccc596cae235446367 Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Mon, 15 Nov 2021 12:02:15 +0000 Subject: [PATCH 021/327] firmware: cs_dsp: tidy includes in cs_dsp.c and cs_dsp.h This patch removes unused included header files and moves others into cs_dsp.h to ensure that types referenced in the header file are properly described to prevent compiler warnings. Signed-off-by: Simon Trimmer Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20211115120215.56824-1-simont@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/firmware/cirrus/cs_dsp.c | 6 ------ include/linux/firmware/cirrus/cs_dsp.h | 5 +++++ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c index 948dd8382686b..1a0c6c793f6a7 100644 --- a/drivers/firmware/cirrus/cs_dsp.c +++ b/drivers/firmware/cirrus/cs_dsp.c @@ -12,16 +12,10 @@ #include #include #include -#include -#include -#include -#include #include #include -#include #include #include -#include #include #include diff --git a/include/linux/firmware/cirrus/cs_dsp.h b/include/linux/firmware/cirrus/cs_dsp.h index 9ad9eaaaa5527..3a54b1afc48fc 100644 --- a/include/linux/firmware/cirrus/cs_dsp.h +++ b/include/linux/firmware/cirrus/cs_dsp.h @@ -11,6 +11,11 @@ #ifndef __CS_DSP_H #define __CS_DSP_H +#include +#include +#include +#include + #define CS_ADSP2_REGION_0 BIT(0) #define CS_ADSP2_REGION_1 BIT(1) #define CS_ADSP2_REGION_2 BIT(2) From 5dbec393cd23ecfdeddced217f8a1c11228139c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ADra=20Canal?= Date: Sun, 24 Oct 2021 15:42:07 -0300 Subject: [PATCH 022/327] ASoC: adau1701: Replace legacy gpio interface for gpiod MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Considering the current transition of the GPIO subsystem, remove all dependencies of the legacy GPIO interface (linux/gpio.h and linux /of_gpio.h) and replace it with the descriptor-based GPIO approach. Signed-off-by: Maíra Canal Link: https://lore.kernel.org/r/YXWo/9o7ye9a11aR@fedora Signed-off-by: Mark Brown --- sound/soc/codecs/adau1701.c | 94 ++++++++++++------------------------- 1 file changed, 31 insertions(+), 63 deletions(-) diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index c5bf461c0b7e4..dba9af7531880 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c @@ -13,8 +13,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -106,8 +106,8 @@ static const char * const supply_names[] = { }; struct adau1701 { - int gpio_nreset; - int gpio_pll_mode[2]; + struct gpio_desc *gpio_nreset; + struct gpio_descs *gpio_pll_mode; unsigned int dai_fmt; unsigned int pll_clkdiv; unsigned int sysclk; @@ -303,39 +303,41 @@ static int adau1701_reset(struct snd_soc_component *component, unsigned int clkd struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component); int ret; + DECLARE_BITMAP(values, 2); sigmadsp_reset(adau1701->sigmadsp); - if (clkdiv != ADAU1707_CLKDIV_UNSET && - gpio_is_valid(adau1701->gpio_pll_mode[0]) && - gpio_is_valid(adau1701->gpio_pll_mode[1])) { + if (clkdiv != ADAU1707_CLKDIV_UNSET && adau1701->gpio_pll_mode) { switch (clkdiv) { case 64: - gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 0); - gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 0); + __assign_bit(0, values, 0); + __assign_bit(1, values, 0); break; case 256: - gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 0); - gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 1); + __assign_bit(0, values, 0); + __assign_bit(1, values, 1); break; case 384: - gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 1); - gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 0); + __assign_bit(0, values, 1); + __assign_bit(1, values, 0); break; - case 0: /* fallback */ + case 0: /* fallback */ case 512: - gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 1); - gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 1); + __assign_bit(0, values, 1); + __assign_bit(1, values, 1); break; } + gpiod_set_array_value_cansleep(adau1701->gpio_pll_mode->ndescs, + adau1701->gpio_pll_mode->desc, adau1701->gpio_pll_mode->info, + values); } adau1701->pll_clkdiv = clkdiv; - if (gpio_is_valid(adau1701->gpio_nreset)) { - gpio_set_value_cansleep(adau1701->gpio_nreset, 0); + if (adau1701->gpio_nreset) { + gpiod_set_value_cansleep(adau1701->gpio_nreset, 0); /* minimum reset time is 20ns */ udelay(1); - gpio_set_value_cansleep(adau1701->gpio_nreset, 1); + gpiod_set_value_cansleep(adau1701->gpio_nreset, 1); /* power-up time may be as long as 85ms */ mdelay(85); } @@ -719,8 +721,8 @@ static void adau1701_remove(struct snd_soc_component *component) { struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component); - if (gpio_is_valid(adau1701->gpio_nreset)) - gpio_set_value_cansleep(adau1701->gpio_nreset, 0); + if (adau1701->gpio_nreset) + gpiod_set_value_cansleep(adau1701->gpio_nreset, 0); regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies), adau1701->supplies); } @@ -788,8 +790,6 @@ static int adau1701_i2c_probe(struct i2c_client *client, { struct adau1701 *adau1701; struct device *dev = &client->dev; - int gpio_nreset = -EINVAL; - int gpio_pll_mode[2] = { -EINVAL, -EINVAL }; int ret, i; adau1701 = devm_kzalloc(dev, sizeof(*adau1701), GFP_KERNEL); @@ -823,26 +823,6 @@ static int adau1701_i2c_probe(struct i2c_client *client, if (dev->of_node) { - gpio_nreset = of_get_named_gpio(dev->of_node, "reset-gpio", 0); - if (gpio_nreset < 0 && gpio_nreset != -ENOENT) { - ret = gpio_nreset; - goto exit_regulators_disable; - } - - gpio_pll_mode[0] = of_get_named_gpio(dev->of_node, - "adi,pll-mode-gpios", 0); - if (gpio_pll_mode[0] < 0 && gpio_pll_mode[0] != -ENOENT) { - ret = gpio_pll_mode[0]; - goto exit_regulators_disable; - } - - gpio_pll_mode[1] = of_get_named_gpio(dev->of_node, - "adi,pll-mode-gpios", 1); - if (gpio_pll_mode[1] < 0 && gpio_pll_mode[1] != -ENOENT) { - ret = gpio_pll_mode[1]; - goto exit_regulators_disable; - } - of_property_read_u32(dev->of_node, "adi,pll-clkdiv", &adau1701->pll_clkdiv); @@ -851,32 +831,20 @@ static int adau1701_i2c_probe(struct i2c_client *client, ARRAY_SIZE(adau1701->pin_config)); } - if (gpio_is_valid(gpio_nreset)) { - ret = devm_gpio_request_one(dev, gpio_nreset, GPIOF_OUT_INIT_LOW, - "ADAU1701 Reset"); - if (ret < 0) - goto exit_regulators_disable; + adau1701->gpio_nreset = devm_gpiod_get_optional(dev, "reset", GPIOD_IN); + + if (IS_ERR(adau1701->gpio_nreset)) { + ret = PTR_ERR(adau1701->gpio_nreset); + goto exit_regulators_disable; } - if (gpio_is_valid(gpio_pll_mode[0]) && - gpio_is_valid(gpio_pll_mode[1])) { - ret = devm_gpio_request_one(dev, gpio_pll_mode[0], - GPIOF_OUT_INIT_LOW, - "ADAU1701 PLL mode 0"); - if (ret < 0) - goto exit_regulators_disable; + adau1701->gpio_pll_mode = devm_gpiod_get_array_optional(dev, "adi,pll-mode", GPIOD_OUT_LOW); - ret = devm_gpio_request_one(dev, gpio_pll_mode[1], - GPIOF_OUT_INIT_LOW, - "ADAU1701 PLL mode 1"); - if (ret < 0) - goto exit_regulators_disable; + if (IS_ERR(adau1701->gpio_pll_mode)) { + ret = PTR_ERR(adau1701->gpio_pll_mode); + goto exit_regulators_disable; } - adau1701->gpio_nreset = gpio_nreset; - adau1701->gpio_pll_mode[0] = gpio_pll_mode[0]; - adau1701->gpio_pll_mode[1] = gpio_pll_mode[1]; - i2c_set_clientdata(client, adau1701); adau1701->sigmadsp = devm_sigmadsp_init_i2c(client, From 5b59289bfdbe287d0756e5ccadf039329147de67 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 2 Nov 2021 11:47:56 +0200 Subject: [PATCH 023/327] ASoC: SOF: core: Unregister machine driver before IPC and debugfs To ensure clean unload of the machine driver, components and topology, do the unregister before we free IPC and debugfs. It is a possibility that part of the unregister we would have IPC communication with the firmware. Suggested-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20211102094756.9317-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/core.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 9ec9ef8ed525f..40549cdd6d588 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -362,6 +362,13 @@ int snd_sof_device_remove(struct device *dev) if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) cancel_work_sync(&sdev->probe_work); + /* + * Unregister machine driver. This will unbind the snd_card which + * will remove the component driver and unload the topology + * before freeing the snd_card. + */ + snd_sof_machine_unregister(sdev, pdata); + if (sdev->fw_state > SOF_FW_BOOT_NOT_STARTED) { snd_sof_free_trace(sdev); ret = snd_sof_dsp_power_down_notify(sdev); @@ -373,13 +380,6 @@ int snd_sof_device_remove(struct device *dev) snd_sof_free_debug(sdev); } - /* - * Unregister machine driver. This will unbind the snd_card which - * will remove the component driver and unload the topology - * before freeing the snd_card. - */ - snd_sof_machine_unregister(sdev, pdata); - /* * Unregistering the machine driver results in unloading the topology. * Some widgets, ex: scheduler, attempt to power down the core they are From 3c8a3ad4019126f06016ab0128dde11817502f52 Mon Sep 17 00:00:00 2001 From: Srinivasa Rao Mandadapu Date: Mon, 15 Nov 2021 12:41:28 +0530 Subject: [PATCH 024/327] ASoC: codecs: MBHC: Add support for special headset Update MBHC driver to support special headset such as apple and huwawei headsets. Signed-off-by: Srinivasa Rao Mandadapu Co-developed-by: Venkata Prasad Potturu Signed-off-by: Venkata Prasad Potturu Reviewed-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/1636960288-27537-1-git-send-email-srivasam@codeaurora.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd-mbhc-v2.c | 75 ++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c index b905eb8f3c67e..934194b155d58 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.c +++ b/sound/soc/codecs/wcd-mbhc-v2.c @@ -1022,6 +1022,56 @@ static int wcd_mbhc_get_plug_from_adc(struct wcd_mbhc *mbhc, int adc_result) return plug_type; } +static int wcd_mbhc_get_spl_hs_thres(struct wcd_mbhc *mbhc) +{ + int hs_threshold, micbias_mv; + + micbias_mv = wcd_mbhc_get_micbias(mbhc); + if (mbhc->cfg->hs_thr && mbhc->cfg->micb_mv != WCD_MBHC_ADC_MICBIAS_MV) { + if (mbhc->cfg->micb_mv == micbias_mv) + hs_threshold = mbhc->cfg->hs_thr; + else + hs_threshold = (mbhc->cfg->hs_thr * micbias_mv) / mbhc->cfg->micb_mv; + } else { + hs_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV * micbias_mv) / + WCD_MBHC_ADC_MICBIAS_MV); + } + return hs_threshold; +} + +static bool wcd_mbhc_check_for_spl_headset(struct wcd_mbhc *mbhc) +{ + bool is_spl_hs = false; + int output_mv, hs_threshold, hph_threshold; + + if (!mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) + return false; + + /* Bump up MIC_BIAS2 to 2.7V */ + mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component, MIC_BIAS_2, true); + usleep_range(10000, 10100); + + output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P); + hs_threshold = wcd_mbhc_get_spl_hs_thres(mbhc); + hph_threshold = wcd_mbhc_adc_get_hph_thres(mbhc); + + if (output_mv > hs_threshold || output_mv < hph_threshold) { + if (mbhc->force_linein == true) + is_spl_hs = false; + } else { + is_spl_hs = true; + } + + /* Back MIC_BIAS2 to 1.8v if the type is not special headset */ + if (!is_spl_hs) { + mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component, MIC_BIAS_2, false); + /* Add 10ms delay for micbias to settle */ + usleep_range(10000, 10100); + } + + return is_spl_hs; +} + static void wcd_correct_swch_plug(struct work_struct *work) { struct wcd_mbhc *mbhc; @@ -1029,12 +1079,14 @@ static void wcd_correct_swch_plug(struct work_struct *work) enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_INVALID; unsigned long timeout; int pt_gnd_mic_swap_cnt = 0; - int output_mv, cross_conn, hs_threshold, try = 0; + int output_mv, cross_conn, hs_threshold, try = 0, micbias_mv; + bool is_spl_hs = false; bool is_pa_on; mbhc = container_of(work, struct wcd_mbhc, correct_plug_swch); component = mbhc->component; + micbias_mv = wcd_mbhc_get_micbias(mbhc); hs_threshold = wcd_mbhc_adc_get_hs_thres(mbhc); /* Mask ADC COMPLETE interrupt */ @@ -1097,6 +1149,16 @@ static void wcd_correct_swch_plug(struct work_struct *work) plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv); is_pa_on = wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN); + if ((output_mv > hs_threshold) && (!is_spl_hs)) { + is_spl_hs = wcd_mbhc_check_for_spl_headset(mbhc); + output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P); + + if (is_spl_hs) { + hs_threshold = (hs_threshold * wcd_mbhc_get_micbias(mbhc)) / + micbias_mv; + } + } + if ((output_mv <= hs_threshold) && !is_pa_on) { /* Check for cross connection*/ cross_conn = wcd_check_cross_conn(mbhc); @@ -1122,14 +1184,19 @@ static void wcd_correct_swch_plug(struct work_struct *work) } } - if (output_mv > hs_threshold) /* cable is extension cable */ + /* cable is extension cable */ + if (output_mv > hs_threshold || mbhc->force_linein == true) plug_type = MBHC_PLUG_TYPE_HIGH_HPH; } wcd_mbhc_bcs_enable(mbhc, plug_type, true); - if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH) - wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_ISRC_EN, 1); + if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH) { + if (is_spl_hs) + plug_type = MBHC_PLUG_TYPE_HEADSET; + else + wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_ISRC_EN, 1); + } wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0); wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0); From 5ecc573d0c542c0f95497ba4586a6226814e4e18 Mon Sep 17 00:00:00 2001 From: David Heidelberg Date: Thu, 28 Oct 2021 14:46:38 +0200 Subject: [PATCH 025/327] ASoC: wm8903: Convert txt bindings to yaml Convert the Wolfson WM8903 Ultra-Low Power Stereo CODEC Device Tree binding documentation to json-schema. Signed-off-by: David Heidelberg Acked-by: Charles Keepax Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20211028124639.38420-1-david@ixit.cz Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/wlf,wm8903.yaml | 116 ++++++++++++++++++ .../devicetree/bindings/sound/wm8903.txt | 82 ------------- 2 files changed, 116 insertions(+), 82 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/wlf,wm8903.yaml delete mode 100644 Documentation/devicetree/bindings/sound/wm8903.txt diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8903.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8903.yaml new file mode 100644 index 0000000000000..7105ed5fd6c7a --- /dev/null +++ b/Documentation/devicetree/bindings/sound/wlf,wm8903.yaml @@ -0,0 +1,116 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/sound/wlf,wm8903.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: WM8903 audio codec + +description: | + This device supports I2C only. + Pins on the device (for linking into audio routes): + * IN1L + * IN1R + * IN2L + * IN2R + * IN3L + * IN3R + * DMICDAT + * HPOUTL + * HPOUTR + * LINEOUTL + * LINEOUTR + * LOP + * LON + * ROP + * RON + * MICBIAS + +maintainers: + - patches@opensource.cirrus.com + +properties: + compatible: + const: wlf,wm8903 + + reg: + maxItems: 1 + + gpio-controller: true + '#gpio-cells': + const: 2 + + interrupts: + maxItems: 1 + + micdet-cfg: + $ref: /schemas/types.yaml#/definitions/uint32 + default: 0 + description: Default register value for R6 (Mic Bias). + + micdet-delay: + $ref: /schemas/types.yaml#/definitions/uint32 + default: 100 + description: The debounce delay for microphone detection in mS. + + gpio-cfg: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: | + minItems: 5 + maxItems: 5 + A list of GPIO configuration register values. + If absent, no configuration of these registers is performed. + If any entry has the value 0xffffffff, that GPIO's + configuration will not be modified. + + AVDD-supply: + description: Analog power supply regulator on the AVDD pin. + + CPVDD-supply: + description: Charge pump supply regulator on the CPVDD pin. + + DBVDD-supply: + description: Digital buffer supply regulator for the DBVDD pin. + + DCVDD-supply: + description: Digital core supply regulator for the DCVDD pin. + + +required: + - compatible + - reg + - gpio-controller + - '#gpio-cells' + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + wm8903: codec@1a { + compatible = "wlf,wm8903"; + reg = <0x1a>; + interrupts = <347>; + + AVDD-supply = <&fooreg_a>; + CPVDD-supply = <&fooreg_b>; + DBVDD-supply = <&fooreg_c>; + DCVDD-supply = <&fooreg_d>; + + gpio-controller; + #gpio-cells = <2>; + + micdet-cfg = <0>; + micdet-delay = <100>; + gpio-cfg = < + 0x0600 /* DMIC_LR, output */ + 0x0680 /* DMIC_DAT, input */ + 0x0000 /* GPIO, output, low */ + 0x0200 /* Interrupt, output */ + 0x01a0 /* BCLK, input, active high */ + >; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/wm8903.txt b/Documentation/devicetree/bindings/sound/wm8903.txt deleted file mode 100644 index 6371c2434afe7..0000000000000 --- a/Documentation/devicetree/bindings/sound/wm8903.txt +++ /dev/null @@ -1,82 +0,0 @@ -WM8903 audio CODEC - -This device supports I2C only. - -Required properties: - - - compatible : "wlf,wm8903" - - - reg : the I2C address of the device. - - - gpio-controller : Indicates this device is a GPIO controller. - - - #gpio-cells : Should be two. The first cell is the pin number and the - second cell is used to specify optional parameters (currently unused). - -Optional properties: - - - interrupts : The interrupt line the codec is connected to. - - - micdet-cfg : Default register value for R6 (Mic Bias). If absent, the - default is 0. - - - micdet-delay : The debounce delay for microphone detection in mS. If - absent, the default is 100. - - - gpio-cfg : A list of GPIO configuration register values. The list must - be 5 entries long. If absent, no configuration of these registers is - performed. If any entry has the value 0xffffffff, that GPIO's - configuration will not be modified. - - - AVDD-supply : Analog power supply regulator on the AVDD pin. - - - CPVDD-supply : Charge pump supply regulator on the CPVDD pin. - - - DBVDD-supply : Digital buffer supply regulator for the DBVDD pin. - - - DCVDD-supply : Digital core supply regulator for the DCVDD pin. - -Pins on the device (for linking into audio routes): - - * IN1L - * IN1R - * IN2L - * IN2R - * IN3L - * IN3R - * DMICDAT - * HPOUTL - * HPOUTR - * LINEOUTL - * LINEOUTR - * LOP - * LON - * ROP - * RON - * MICBIAS - -Example: - -wm8903: codec@1a { - compatible = "wlf,wm8903"; - reg = <0x1a>; - interrupts = < 347 >; - - AVDD-supply = <&fooreg_a>; - CPVDD-supply = <&fooreg_b>; - DBVDD-supply = <&fooreg_c>; - DCVDC-supply = <&fooreg_d>; - - gpio-controller; - #gpio-cells = <2>; - - micdet-cfg = <0>; - micdet-delay = <100>; - gpio-cfg = < - 0x0600 /* DMIC_LR, output */ - 0x0680 /* DMIC_DAT, input */ - 0x0000 /* GPIO, output, low */ - 0x0200 /* Interrupt, output */ - 0x01a0 /* BCLK, input, active high */ - >; -}; From 5f55c9693a222ee1b8ec62a57fbcff59af0c4837 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 16 Nov 2021 11:50:21 +0000 Subject: [PATCH 026/327] ASoC: qcom: sdm845: only setup slim ports once Currently same slim channel map setup for every dai link, which is redundant. Fix this by adding a flag and conditionally setting these channel maps. Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20211116115021.14213-1-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/sdm845.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c index 0adfc57089492..10d724bd1d67c 100644 --- a/sound/soc/qcom/sdm845.c +++ b/sound/soc/qcom/sdm845.c @@ -33,6 +33,7 @@ struct sdm845_snd_data { struct snd_soc_jack jack; bool jack_setup; + bool slim_port_setup; bool stream_prepared[AFE_PORT_MAX]; struct snd_soc_card *card; uint32_t pri_mi2s_clk_count; @@ -224,6 +225,7 @@ static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); struct sdm845_snd_data *pdata = snd_soc_card_get_drvdata(card); + struct snd_soc_dai_link *link = rtd->dai_link; struct snd_jack *jack; /* * Codec SLIMBUS configuration @@ -276,6 +278,10 @@ static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd) } break; case SLIMBUS_0_RX...SLIMBUS_6_TX: + /* setting up wcd multiple times for slim port is redundant */ + if (pdata->slim_port_setup || !link->no_pcm) + return 0; + for_each_rtd_codec_dais(rtd, i, codec_dai) { rval = snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch), @@ -295,8 +301,10 @@ static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd) dev_warn(card->dev, "Failed to set jack: %d\n", rval); return rval; } - } + + pdata->slim_port_setup = true; + break; default: break; From 7548a391c53cab2af0954d252cc5a9a793fd4c0e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 16 Nov 2021 14:41:31 +0200 Subject: [PATCH 027/327] ASoC: SOF: i.MX: simplify Kconfig Follow the Intel example and simplify the Kconfig a) start from the end-product for 'select' chains b) use 'depends on' to filter out configurations. c) use snd-sof-of as a common module without any 'select' Signed-off-by: Pierre-Louis Bossart Reviewed-by: Daniel Baluta Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211116124131.46414-1-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/Kconfig | 4 +++- sound/soc/sof/Makefile | 2 +- sound/soc/sof/imx/Kconfig | 46 +++++++++++---------------------------- 3 files changed, 17 insertions(+), 35 deletions(-) diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 041c54639c4d9..b6fa659179b60 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -40,12 +40,14 @@ config SND_SOC_SOF_ACPI_DEV config SND_SOC_SOF_OF tristate "SOF OF enumeration support" depends on OF || COMPILE_TEST - select SND_SOC_SOF help This adds support for Device Tree enumeration. This option is required to enable i.MX8 devices. Say Y if you need this option. If unsure select "N". +config SND_SOC_SOF_OF_DEV + tristate + config SND_SOC_SOF_COMPRESS bool select SND_SOC_COMPRESS diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 06e5f49f7ee86..1dac5cb4dfd64 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -17,7 +17,7 @@ obj-$(CONFIG_SND_SOC_SOF_NOCODEC) += snd-sof-nocodec.o obj-$(CONFIG_SND_SOC_SOF_ACPI_DEV) += snd-sof-acpi.o -obj-$(CONFIG_SND_SOC_SOF_OF) += snd-sof-of.o +obj-$(CONFIG_SND_SOC_SOF_OF_DEV) += snd-sof-of.o obj-$(CONFIG_SND_SOC_SOF_PCI_DEV) += snd-sof-pci.o obj-$(CONFIG_SND_SOC_SOF_INTEL_TOPLEVEL) += intel/ diff --git a/sound/soc/sof/imx/Kconfig b/sound/soc/sof/imx/Kconfig index 34cf228c188f9..9b8d5bb1e4491 100644 --- a/sound/soc/sof/imx/Kconfig +++ b/sound/soc/sof/imx/Kconfig @@ -11,53 +11,33 @@ config SND_SOC_SOF_IMX_TOPLEVEL if SND_SOC_SOF_IMX_TOPLEVEL -config SND_SOC_SOF_IMX_OF - def_tristate SND_SOC_SOF_OF - select SND_SOC_SOF_IMX8 if SND_SOC_SOF_IMX8_SUPPORT - select SND_SOC_SOF_IMX8M if SND_SOC_SOF_IMX8M_SUPPORT - help - This option is not user-selectable but automagically handled by - 'select' statements at a higher level. - config SND_SOC_SOF_IMX_COMMON tristate + select SND_SOC_SOF_OF_DEV + select SND_SOC_SOF + select SND_SOC_SOF_XTENSA + select SND_SOC_SOF_COMPRESS help This option is not user-selectable but automagically handled by 'select' statements at a higher level. -config SND_SOC_SOF_IMX8_SUPPORT - bool "SOF support for i.MX8" - depends on IMX_SCU=y || IMX_SCU=SND_SOC_SOF_IMX_OF - depends on IMX_DSP=y || IMX_DSP=SND_SOC_SOF_IMX_OF +config SND_SOC_SOF_IMX8 + tristate "SOF support for i.MX8" + depends on IMX_SCU + depends on IMX_DSP + select SND_SOC_SOF_IMX_COMMON help This adds support for Sound Open Firmware for NXP i.MX8 platforms. Say Y if you have such a device. If unsure select "N". -config SND_SOC_SOF_IMX8 - tristate +config SND_SOC_SOF_IMX8M + tristate "SOF support for i.MX8M" + depends on IMX_DSP select SND_SOC_SOF_IMX_COMMON - select SND_SOC_SOF_XTENSA - select SND_SOC_SOF_COMPRESS - help - This option is not user-selectable but automagically handled by - 'select' statements at a higher level. - -config SND_SOC_SOF_IMX8M_SUPPORT - bool "SOF support for i.MX8M" - depends on IMX_DSP=y || IMX_DSP=SND_SOC_SOF_OF help This adds support for Sound Open Firmware for NXP i.MX8M platforms. Say Y if you have such a device. If unsure select "N". -config SND_SOC_SOF_IMX8M - tristate - select SND_SOC_SOF_IMX_COMMON - select SND_SOC_SOF_XTENSA - select SND_SOC_SOF_COMPRESS - help - This option is not user-selectable but automagically handled by - 'select' statements at a higher level. - -endif ## SND_SOC_SOF_IMX_IMX_TOPLEVEL +endif ## SND_SOC_SOF_IMX_TOPLEVEL From 976001b10fa4441917f216452e70fd8c5aeccd94 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 16 Nov 2021 16:38:58 +0000 Subject: [PATCH 028/327] ASoC: cs42l42: Remove redundant writes to DETECT_MODE There are multiple places where DETECT_MODE is included in a register write, but in every case it is written as 0. Removing these redundant writes makes the code less cluttered and also makes it obvious that DETECT_MODE is never changed. A single initialization to 0 is added to cs42l42_setup_hs_type_detect(). Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20211116163901.45390-2-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 56804a3f285e6..92bdc3a355ffb 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -1270,10 +1270,8 @@ static void cs42l42_process_hs_type_detect(struct cs42l42_private *cs42l42) /* Turn on level detect circuitry */ regmap_update_bits(cs42l42->regmap, CS42L42_MISC_DET_CTL, - CS42L42_DETECT_MODE_MASK | CS42L42_HSBIAS_CTL_MASK | CS42L42_PDN_MIC_LVL_DET_MASK, - (0 << CS42L42_DETECT_MODE_SHIFT) | (3 << CS42L42_HSBIAS_CTL_SHIFT) | (0 << CS42L42_PDN_MIC_LVL_DET_SHIFT)); @@ -1300,10 +1298,8 @@ static void cs42l42_process_hs_type_detect(struct cs42l42_private *cs42l42) /* Make sure button detect and HS bias circuits are off */ regmap_update_bits(cs42l42->regmap, CS42L42_MISC_DET_CTL, - CS42L42_DETECT_MODE_MASK | CS42L42_HSBIAS_CTL_MASK | CS42L42_PDN_MIC_LVL_DET_MASK, - (0 << CS42L42_DETECT_MODE_SHIFT) | (1 << CS42L42_HSBIAS_CTL_SHIFT) | (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT)); } @@ -1351,10 +1347,8 @@ static void cs42l42_init_hs_type_detect(struct cs42l42_private *cs42l42) /* Make sure button detect and HS bias circuits are off */ regmap_update_bits(cs42l42->regmap, CS42L42_MISC_DET_CTL, - CS42L42_DETECT_MODE_MASK | CS42L42_HSBIAS_CTL_MASK | CS42L42_PDN_MIC_LVL_DET_MASK, - (0 << CS42L42_DETECT_MODE_SHIFT) | (1 << CS42L42_HSBIAS_CTL_SHIFT) | (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT)); @@ -1398,10 +1392,8 @@ static void cs42l42_init_hs_type_detect(struct cs42l42_private *cs42l42) /* Power up HS bias to 2.7V */ regmap_update_bits(cs42l42->regmap, CS42L42_MISC_DET_CTL, - CS42L42_DETECT_MODE_MASK | CS42L42_HSBIAS_CTL_MASK | CS42L42_PDN_MIC_LVL_DET_MASK, - (0 << CS42L42_DETECT_MODE_SHIFT) | (3 << CS42L42_HSBIAS_CTL_SHIFT) | (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT)); @@ -1448,10 +1440,8 @@ static void cs42l42_cancel_hs_type_detect(struct cs42l42_private *cs42l42) /* Ground HS bias */ regmap_update_bits(cs42l42->regmap, CS42L42_MISC_DET_CTL, - CS42L42_DETECT_MODE_MASK | CS42L42_HSBIAS_CTL_MASK | CS42L42_PDN_MIC_LVL_DET_MASK, - (0 << CS42L42_DETECT_MODE_SHIFT) | (1 << CS42L42_HSBIAS_CTL_SHIFT) | (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT)); @@ -1829,6 +1819,9 @@ static void cs42l42_setup_hs_type_detect(struct cs42l42_private *cs42l42) cs42l42->hs_type = CS42L42_PLUG_INVALID; + regmap_update_bits(cs42l42->regmap, CS42L42_MISC_DET_CTL, + CS42L42_DETECT_MODE_MASK, 0); + /* Latch analog controls to VP power domain */ regmap_update_bits(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_LATCH_TO_VP_MASK | From f2dfbaaa5404cadf70213146a5b4b89b647d9092 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 16 Nov 2021 16:38:59 +0000 Subject: [PATCH 029/327] ASoC: cs42l42: Remove redundant writes to RS_PLUG/RS_UNPLUG masks The RS_PLUG and RS_UNPLUG interrupt masks are always written as 1 so those writes are redundant and can be deleted. This makes it completely clear in the code that only the TS_PLUG and TS_UNPLUG masks are being changed. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20211116163901.45390-3-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 92bdc3a355ffb..3674f73301dc7 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -1320,12 +1320,8 @@ static void cs42l42_process_hs_type_detect(struct cs42l42_private *cs42l42) /* Unmask tip sense interrupts */ regmap_update_bits(cs42l42->regmap, CS42L42_TSRS_PLUG_INT_MASK, - CS42L42_RS_PLUG_MASK | - CS42L42_RS_UNPLUG_MASK | CS42L42_TS_PLUG_MASK | CS42L42_TS_UNPLUG_MASK, - (1 << CS42L42_RS_PLUG_SHIFT) | - (1 << CS42L42_RS_UNPLUG_SHIFT) | (0 << CS42L42_TS_PLUG_SHIFT) | (0 << CS42L42_TS_UNPLUG_SHIFT)); } @@ -1335,12 +1331,8 @@ static void cs42l42_init_hs_type_detect(struct cs42l42_private *cs42l42) /* Mask tip sense interrupts */ regmap_update_bits(cs42l42->regmap, CS42L42_TSRS_PLUG_INT_MASK, - CS42L42_RS_PLUG_MASK | - CS42L42_RS_UNPLUG_MASK | CS42L42_TS_PLUG_MASK | CS42L42_TS_UNPLUG_MASK, - (1 << CS42L42_RS_PLUG_SHIFT) | - (1 << CS42L42_RS_UNPLUG_SHIFT) | (1 << CS42L42_TS_PLUG_SHIFT) | (1 << CS42L42_TS_UNPLUG_SHIFT)); From 3edde6de090617adea18f2068489086c0d8087e3 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 16 Nov 2021 16:39:00 +0000 Subject: [PATCH 030/327] ASoC: cs42l42: Simplify reporting of jack unplug When reporting a jack unplug there's no need to make the reported flags conditional on which flags were reported during the plug event. It's perfectly safe to report all flags and buttons as not-present and let the higher code filter for changes. There's also no need to make two separate snd_soc_jack_report() calls for presence flags and button flags. It can all be done in one report. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20211116163901.45390-4-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 3674f73301dc7..8efcee3e60d37 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -1657,18 +1657,8 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data) cs42l42->plug_state = CS42L42_TS_UNPLUG; cs42l42_cancel_hs_type_detect(cs42l42); - switch (cs42l42->hs_type) { - case CS42L42_PLUG_CTIA: - case CS42L42_PLUG_OMTP: - snd_soc_jack_report(cs42l42->jack, 0, SND_JACK_HEADSET); - break; - case CS42L42_PLUG_HEADPHONE: - snd_soc_jack_report(cs42l42->jack, 0, SND_JACK_HEADPHONE); - break; - default: - break; - } snd_soc_jack_report(cs42l42->jack, 0, + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3); From bbf0e1d36519a5cd2c08dc1348f997cd5240eb2e Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 16 Nov 2021 16:39:01 +0000 Subject: [PATCH 031/327] ASoC: cs42l42: Remove redundant pll_divout member Now that struct cs42l42_private has pll_config, the current PLL configuration can be looked up directly in pll_ratio_table. This makes the pll_divout member of cs42l42_private redundant since it was only a copy of the value from pll_ratio_table. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20211116163901.45390-5-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 9 +++------ sound/soc/codecs/cs42l42.h | 1 - 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 8efcee3e60d37..0c4303547fd81 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -734,10 +734,6 @@ static int cs42l42_pll_config(struct snd_soc_component *component) CS42L42_PLL_DIVOUT_MASK, (pll_ratio_table[i].pll_divout * pll_ratio_table[i].n) << CS42L42_PLL_DIVOUT_SHIFT); - if (pll_ratio_table[i].n != 1) - cs42l42->pll_divout = pll_ratio_table[i].pll_divout; - else - cs42l42->pll_divout = 0; snd_soc_component_update_bits(component, CS42L42_PLL_CAL_RATIO, CS42L42_PLL_CAL_RATIO_MASK, @@ -1004,12 +1000,13 @@ static int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream) snd_soc_component_update_bits(component, CS42L42_PLL_CTL1, CS42L42_PLL_START_MASK, 1); - if (cs42l42->pll_divout) { + if (pll_ratio_table[cs42l42->pll_config].n > 1) { usleep_range(CS42L42_PLL_DIVOUT_TIME_US, CS42L42_PLL_DIVOUT_TIME_US * 2); + regval = pll_ratio_table[cs42l42->pll_config].pll_divout; snd_soc_component_update_bits(component, CS42L42_PLL_CTL3, CS42L42_PLL_DIVOUT_MASK, - cs42l42->pll_divout << + regval << CS42L42_PLL_DIVOUT_SHIFT); } diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index c8b3267a318b5..75ade987d0db3 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -845,7 +845,6 @@ struct cs42l42_private { int bclk; u32 sclk; u32 srate; - u8 pll_divout; u8 plug_state; u8 hs_type; u8 ts_inv; From 8ae77801c81d16a09f6b67a6f8d91255d34f5f2c Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 16 Nov 2021 17:21:34 +0200 Subject: [PATCH 032/327] ASoC: SOF: utils: Add generic function to get the reply for a tx message The code to get the reply for a tx is identical in all but one place: imx8_get_reply(), imx8m_get_reply(), atom_get_reply(), bdw_get_reply(). hda_dsp_ipc_get_reply() have additional check in place for PROBES and special handling of PM messages. Add a generic implementation to the core which can be used as drop in replacement. The reply size check is changed to be able to handle cases when the reply size is not know beforehand (this is the case for PROBES and DEBUG_MEM_USAGE for example). Signed-off-by: Peter Ujfalusi Reviewed-by: Rander Wang Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Reviewed-by: Guennadi Liakhovetski Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211116152137.52129-2-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc.c | 61 ++++++++++++++++++++++++++++++++++++++++ sound/soc/sof/sof-priv.h | 6 ++++ 2 files changed, 67 insertions(+) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index a4036d0b3d3ab..6771b444065de 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -394,6 +394,67 @@ int sof_ipc_tx_message_no_pm(struct snd_sof_ipc *ipc, u32 header, } EXPORT_SYMBOL(sof_ipc_tx_message_no_pm); +/* Generic helper function to retrieve the reply */ +void snd_sof_ipc_get_reply(struct snd_sof_dev *sdev) +{ + struct snd_sof_ipc_msg *msg = sdev->msg; + struct sof_ipc_reply reply; + int ret = 0; + + /* + * Sometimes, there is unexpected reply ipc arriving. The reply + * ipc belongs to none of the ipcs sent from driver. + * In this case, the driver must ignore the ipc. + */ + if (!msg) { + dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); + return; + } + + /* get the generic reply */ + snd_sof_dsp_mailbox_read(sdev, sdev->host_box.offset, &reply, + sizeof(reply)); + + if (reply.error < 0) { + memcpy(msg->reply_data, &reply, sizeof(reply)); + ret = reply.error; + } else if (!reply.hdr.size) { + /* Reply should always be >= sizeof(struct sof_ipc_reply) */ + if (msg->reply_size) + dev_err(sdev->dev, + "empty reply received, expected %zu bytes\n", + msg->reply_size); + else + dev_err(sdev->dev, "empty reply received\n"); + + ret = -EINVAL; + } else if (msg->reply_size > 0) { + if (reply.hdr.size == msg->reply_size) { + ret = 0; + } else if (reply.hdr.size < msg->reply_size) { + dev_dbg(sdev->dev, + "reply size (%u) is less than expected (%zu)\n", + reply.hdr.size, msg->reply_size); + + msg->reply_size = reply.hdr.size; + ret = 0; + } else { + dev_err(sdev->dev, + "reply size (%u) exceeds the buffer size (%zu)\n", + reply.hdr.size, msg->reply_size); + ret = -EINVAL; + } + + /* get the full message if reply.hdr.size <= msg->reply_size */ + if (!ret) + snd_sof_dsp_mailbox_read(sdev, sdev->host_box.offset, + msg->reply_data, msg->reply_size); + } + + msg->reply_error = ret; +} +EXPORT_SYMBOL(snd_sof_ipc_get_reply); + /* handle reply message from DSP */ void snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) { diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index ba341b1bda0cb..2c97ffa98e3eb 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -515,6 +515,7 @@ void snd_sof_fw_unload(struct snd_sof_dev *sdev); */ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev); void snd_sof_ipc_free(struct snd_sof_dev *sdev); +void snd_sof_ipc_get_reply(struct snd_sof_dev *sdev); void snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id); void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev); int snd_sof_ipc_stream_pcm_params(struct snd_sof_dev *sdev, @@ -527,6 +528,11 @@ int sof_ipc_tx_message_no_pm(struct snd_sof_ipc *ipc, u32 header, void *msg_data, size_t msg_bytes, void *reply_data, size_t reply_bytes); int sof_ipc_init_msg_memory(struct snd_sof_dev *sdev); +static inline void snd_sof_ipc_process_reply(struct snd_sof_dev *sdev, u32 msg_id) +{ + snd_sof_ipc_get_reply(sdev); + snd_sof_ipc_reply(sdev, msg_id); +} /* * Trace/debug From 18c45f270352fb76c8b5b133b3ae3971769f8a22 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 16 Nov 2021 17:21:35 +0200 Subject: [PATCH 033/327] ASoC: SOF: imx: Use the generic helper to get the reply Make use of the generic snd_sof_ipc_process_reply() from the core instead the local implementation. snd_sof_ipc_process_reply() handles the reply retrieving and the ipc reply Signed-off-by: Peter Ujfalusi Reviewed-by: Rander Wang Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Reviewed-by: Guennadi Liakhovetski Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211116152137.52129-3-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/imx/imx8.c | 37 +------------------------------------ sound/soc/sof/imx/imx8m.c | 37 +------------------------------------ 2 files changed, 2 insertions(+), 72 deletions(-) diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c index dd59a74480d6a..0aeb44d0acc7e 100644 --- a/sound/soc/sof/imx/imx8.c +++ b/sound/soc/sof/imx/imx8.c @@ -59,40 +59,6 @@ struct imx8_priv { }; -static void imx8_get_reply(struct snd_sof_dev *sdev) -{ - struct snd_sof_ipc_msg *msg = sdev->msg; - struct sof_ipc_reply reply; - int ret = 0; - - if (!msg) { - dev_warn(sdev->dev, "unexpected ipc interrupt\n"); - return; - } - - /* get reply */ - sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); - - if (reply.error < 0) { - memcpy(msg->reply_data, &reply, sizeof(reply)); - ret = reply.error; - } else { - /* reply has correct size? */ - if (reply.hdr.size != msg->reply_size) { - dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", - msg->reply_size, reply.hdr.size); - ret = -EINVAL; - } - - /* read the message */ - if (msg->reply_size > 0) - sof_mailbox_read(sdev, sdev->host_box.offset, - msg->reply_data, msg->reply_size); - } - - msg->reply_error = ret; -} - static int imx8_get_mailbox_offset(struct snd_sof_dev *sdev) { return MBOX_OFFSET; @@ -109,8 +75,7 @@ static void imx8_dsp_handle_reply(struct imx_dsp_ipc *ipc) unsigned long flags; spin_lock_irqsave(&priv->sdev->ipc_lock, flags); - imx8_get_reply(priv->sdev); - snd_sof_ipc_reply(priv->sdev, 0); + snd_sof_ipc_process_reply(priv->sdev, 0); spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags); } diff --git a/sound/soc/sof/imx/imx8m.c b/sound/soc/sof/imx/imx8m.c index e4618980cf8bc..f454a5d0a87e9 100644 --- a/sound/soc/sof/imx/imx8m.c +++ b/sound/soc/sof/imx/imx8m.c @@ -32,40 +32,6 @@ struct imx8m_priv { struct platform_device *ipc_dev; }; -static void imx8m_get_reply(struct snd_sof_dev *sdev) -{ - struct snd_sof_ipc_msg *msg = sdev->msg; - struct sof_ipc_reply reply; - int ret = 0; - - if (!msg) { - dev_warn(sdev->dev, "unexpected ipc interrupt\n"); - return; - } - - /* get reply */ - sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); - - if (reply.error < 0) { - memcpy(msg->reply_data, &reply, sizeof(reply)); - ret = reply.error; - } else { - /* reply has correct size? */ - if (reply.hdr.size != msg->reply_size) { - dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", - msg->reply_size, reply.hdr.size); - ret = -EINVAL; - } - - /* read the message */ - if (msg->reply_size > 0) - sof_mailbox_read(sdev, sdev->host_box.offset, - msg->reply_data, msg->reply_size); - } - - msg->reply_error = ret; -} - static int imx8m_get_mailbox_offset(struct snd_sof_dev *sdev) { return MBOX_OFFSET; @@ -82,8 +48,7 @@ static void imx8m_dsp_handle_reply(struct imx_dsp_ipc *ipc) unsigned long flags; spin_lock_irqsave(&priv->sdev->ipc_lock, flags); - imx8m_get_reply(priv->sdev); - snd_sof_ipc_reply(priv->sdev, 0); + snd_sof_ipc_process_reply(priv->sdev, 0); spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags); } From 0bd2891bda4550774946abbfac88443a16c15d5a Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 16 Nov 2021 17:21:36 +0200 Subject: [PATCH 034/327] ASoC: SOF: intel: Use the generic helper to get the reply Make use of the generic snd_sof_ipc_process_reply() from the core instead the local implementation. snd_sof_ipc_process_reply() handles the reply retrieving and the ipc reply Signed-off-by: Peter Ujfalusi Reviewed-by: Rander Wang Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Reviewed-by: Guennadi Liakhovetski Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211116152137.52129-4-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/atom.c | 43 +---------------------------------- sound/soc/sof/intel/bdw.c | 43 +---------------------------------- sound/soc/sof/intel/hda-ipc.c | 29 ++--------------------- 3 files changed, 4 insertions(+), 111 deletions(-) diff --git a/sound/soc/sof/intel/atom.c b/sound/soc/sof/intel/atom.c index 74c630bb98471..cdc96a7df4937 100644 --- a/sound/soc/sof/intel/atom.c +++ b/sound/soc/sof/intel/atom.c @@ -27,7 +27,6 @@ static void atom_host_done(struct snd_sof_dev *sdev); static void atom_dsp_done(struct snd_sof_dev *sdev); -static void atom_get_reply(struct snd_sof_dev *sdev); /* * Debug @@ -154,8 +153,7 @@ irqreturn_t atom_irq_thread(int irq, void *context) * because the done bit can't be set in cmd_done function * which is triggered by msg */ - atom_get_reply(sdev); - snd_sof_ipc_reply(sdev, ipcx); + snd_sof_ipc_process_reply(sdev, ipcx); atom_dsp_done(sdev); @@ -195,45 +193,6 @@ int atom_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) } EXPORT_SYMBOL_NS(atom_send_msg, SND_SOC_SOF_INTEL_ATOM_HIFI_EP); -static void atom_get_reply(struct snd_sof_dev *sdev) -{ - struct snd_sof_ipc_msg *msg = sdev->msg; - struct sof_ipc_reply reply; - int ret = 0; - - /* - * Sometimes, there is unexpected reply ipc arriving. The reply - * ipc belongs to none of the ipcs sent from driver. - * In this case, the driver must ignore the ipc. - */ - if (!msg) { - dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); - return; - } - - /* get reply */ - sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); - - if (reply.error < 0) { - memcpy(msg->reply_data, &reply, sizeof(reply)); - ret = reply.error; - } else { - /* reply correct size ? */ - if (reply.hdr.size != msg->reply_size) { - dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", - msg->reply_size, reply.hdr.size); - ret = -EINVAL; - } - - /* read the message */ - if (msg->reply_size > 0) - sof_mailbox_read(sdev, sdev->host_box.offset, - msg->reply_data, msg->reply_size); - } - - msg->reply_error = ret; -} - int atom_get_mailbox_offset(struct snd_sof_dev *sdev) { return MBOX_OFFSET; diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 2c09a523288e5..156006bed0174 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -75,7 +75,6 @@ static const struct snd_sof_debugfs_map bdw_debugfs[] = { static void bdw_host_done(struct snd_sof_dev *sdev); static void bdw_dsp_done(struct snd_sof_dev *sdev); -static void bdw_get_reply(struct snd_sof_dev *sdev); /* * DSP Control. @@ -326,8 +325,7 @@ static irqreturn_t bdw_irq_thread(int irq, void *context) * because the done bit can't be set in cmd_done function * which is triggered by msg */ - bdw_get_reply(sdev); - snd_sof_ipc_reply(sdev, ipcx); + snd_sof_ipc_process_reply(sdev, ipcx); bdw_dsp_done(sdev); @@ -372,45 +370,6 @@ static int bdw_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) return 0; } -static void bdw_get_reply(struct snd_sof_dev *sdev) -{ - struct snd_sof_ipc_msg *msg = sdev->msg; - struct sof_ipc_reply reply; - int ret = 0; - - /* - * Sometimes, there is unexpected reply ipc arriving. The reply - * ipc belongs to none of the ipcs sent from driver. - * In this case, the driver must ignore the ipc. - */ - if (!msg) { - dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); - return; - } - - /* get reply */ - sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); - - if (reply.error < 0) { - memcpy(msg->reply_data, &reply, sizeof(reply)); - ret = reply.error; - } else { - /* reply correct size ? */ - if (reply.hdr.size != msg->reply_size) { - dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", - msg->reply_size, reply.hdr.size); - ret = -EINVAL; - } - - /* read the message */ - if (msg->reply_size > 0) - sof_mailbox_read(sdev, sdev->host_box.offset, - msg->reply_data, msg->reply_size); - } - - msg->reply_error = ret; -} - static int bdw_get_mailbox_offset(struct snd_sof_dev *sdev) { return MBOX_OFFSET; diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 11f20a5a62dfa..2019087a84cec 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -70,7 +70,6 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) struct snd_sof_ipc_msg *msg = sdev->msg; struct sof_ipc_reply reply; struct sof_ipc_cmd_hdr *hdr; - int ret = 0; /* * Sometimes, there is unexpected reply ipc arriving. The reply @@ -94,35 +93,11 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) reply.hdr.cmd = SOF_IPC_GLB_REPLY; reply.hdr.size = sizeof(reply); memcpy(msg->reply_data, &reply, sizeof(reply)); - goto out; - } - - /* get IPC reply from DSP in the mailbox */ - sof_mailbox_read(sdev, sdev->host_box.offset, &reply, - sizeof(reply)); - if (reply.error < 0) { - memcpy(msg->reply_data, &reply, sizeof(reply)); - ret = reply.error; + msg->reply_error = 0; } else { - /* reply correct size ? */ - if (reply.hdr.size != msg->reply_size && - /* getter payload is never known upfront */ - ((reply.hdr.cmd & SOF_GLB_TYPE_MASK) != SOF_IPC_GLB_PROBE)) { - dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", - msg->reply_size, reply.hdr.size); - ret = -EINVAL; - } - - /* read the message */ - if (msg->reply_size > 0) - sof_mailbox_read(sdev, sdev->host_box.offset, - msg->reply_data, msg->reply_size); + snd_sof_ipc_get_reply(sdev); } - -out: - msg->reply_error = ret; - } /* IPC handler thread */ From 2f0b1b013bbc5d6f4c7c386e12f423d6b4ef3245 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 16 Nov 2021 17:21:37 +0200 Subject: [PATCH 035/327] ASoC: SOF: debug: Add support for IPC message injection In order to stress test the firmware's ability to handle (mis)crafted IPC messages this patch adds a debugfs interface where a binary file (message) can be written and the message is sent to the firmware as it is. Read on the same file will return the reply from the firmware if it is available as a binary. Signed-off-by: Peter Ujfalusi Reviewed-by: Rander Wang Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Reviewed-by: Guennadi Liakhovetski Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211116152137.52129-5-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/Kconfig | 8 +++ sound/soc/sof/debug.c | 107 +++++++++++++++++++++++++++++++++++++++ sound/soc/sof/sof-priv.h | 4 ++ 3 files changed, 119 insertions(+) diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index b6fa659179b60..89eea55581906 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -194,6 +194,14 @@ config SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST Say Y if you want to enable IPC flood test. If unsure, select "N". +config SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR + bool "SOF enable IPC message injector" + help + This option enables the IPC message injector which can be used to send + crafted IPC messages to the DSP to test its robustness. + Say Y if you want to enable the IPC message injector. + If unsure, select "N". + config SND_SOC_SOF_DEBUG_RETAIN_DSP_CONTEXT bool "SOF retain DSP context on any FW exceptions" help diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index dc1df5fb7b4ca..2f8b5ac9b78a2 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -336,6 +336,104 @@ static int sof_debug_ipc_flood_test(struct snd_sof_dev *sdev, } #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR) +static ssize_t msg_inject_read(struct file *file, char __user *buffer, + size_t count, loff_t *ppos) +{ + struct snd_sof_dfsentry *dfse = file->private_data; + struct sof_ipc_reply *rhdr = dfse->msg_inject_rx; + + if (!rhdr->hdr.size || !count || *ppos) + return 0; + + if (count > rhdr->hdr.size) + count = rhdr->hdr.size; + + if (copy_to_user(buffer, dfse->msg_inject_rx, count)) + return -EFAULT; + + *ppos += count; + return count; +} + +static ssize_t msg_inject_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + struct snd_sof_dfsentry *dfse = file->private_data; + struct snd_sof_dev *sdev = dfse->sdev; + struct sof_ipc_cmd_hdr *hdr = dfse->msg_inject_tx; + size_t size; + int ret, err; + + if (*ppos) + return 0; + + size = simple_write_to_buffer(dfse->msg_inject_tx, SOF_IPC_MSG_MAX_SIZE, + ppos, buffer, count); + if (size != count) + return size > 0 ? -EFAULT : size; + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0 && ret != -EACCES) { + dev_err_ratelimited(sdev->dev, "%s: DSP resume failed: %d\n", + __func__, ret); + pm_runtime_put_noidle(sdev->dev); + goto out; + } + + /* send the message */ + memset(dfse->msg_inject_rx, 0, SOF_IPC_MSG_MAX_SIZE); + ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd, dfse->msg_inject_tx, count, + dfse->msg_inject_rx, SOF_IPC_MSG_MAX_SIZE); + + pm_runtime_mark_last_busy(sdev->dev); + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err_ratelimited(sdev->dev, "%s: DSP idle failed: %d\n", + __func__, err); + + /* return size if test is successful */ + if (ret >= 0) + ret = size; + +out: + return ret; +} + +static const struct file_operations msg_inject_fops = { + .open = simple_open, + .read = msg_inject_read, + .write = msg_inject_write, + .llseek = default_llseek, +}; + +static int snd_sof_debugfs_msg_inject_item(struct snd_sof_dev *sdev, + const char *name, mode_t mode, + const struct file_operations *fops) +{ + struct snd_sof_dfsentry *dfse; + + dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL); + if (!dfse) + return -ENOMEM; + + /* pre allocate the tx and rx buffers */ + dfse->msg_inject_tx = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL); + dfse->msg_inject_rx = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL); + if (!dfse->msg_inject_tx || !dfse->msg_inject_rx) + return -ENOMEM; + + dfse->type = SOF_DFSENTRY_TYPE_BUF; + dfse->sdev = sdev; + + debugfs_create_file(name, mode, sdev->debugfs_root, dfse, fops); + /* add to dfsentry list */ + list_add(&dfse->list, &sdev->dfsentry_list); + + return 0; +} +#endif + static ssize_t sof_dfsentry_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { @@ -812,6 +910,15 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev) return err; #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR) + err = snd_sof_debugfs_msg_inject_item(sdev, "ipc_msg_inject", 0644, + &msg_inject_fops); + + /* errors are only due to memory allocation, not debugfs */ + if (err < 0) + return err; +#endif + return 0; } EXPORT_SYMBOL_GPL(snd_sof_dbg_init); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 2c97ffa98e3eb..9a8af76b2f8b9 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -325,6 +325,10 @@ struct snd_sof_dfsentry { enum sof_debugfs_access_type access_type; #if ENABLE_DEBUGFS_CACHEBUF char *cache_buf; /* buffer to cache the contents of debugfs memory */ +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR) + void *msg_inject_tx; + void *msg_inject_rx; #endif struct snd_sof_dev *sdev; struct list_head list; /* list in sdev dfsentry list */ From 7fabe7fed182498cac568100d8e28d4b95f8a80e Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Wed, 17 Nov 2021 12:00:31 +0100 Subject: [PATCH 036/327] ASoC: stm32: sai: increase channels_max limit The SAI peripheral supports up to 16 channels in TDM mode (8L+8R). The driver currently supports TDM over two channels. Increase SAI DAI playback/record channels_max, to also allow up to 16 channels in TDM mode. Signed-off-by: Olivier Moysan Link: https://lore.kernel.org/r/20211117110031.19345-1-olivier.moysan@foss.st.com Signed-off-by: Mark Brown --- sound/soc/stm/stm32_sai_sub.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 9c3b8e2096565..95cd38a502bb4 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -1294,7 +1294,7 @@ static struct snd_soc_dai_driver stm32_sai_playback_dai = { .id = 1, /* avoid call to fmt_single_name() */ .playback = { .channels_min = 1, - .channels_max = 2, + .channels_max = 16, .rate_min = 8000, .rate_max = 192000, .rates = SNDRV_PCM_RATE_CONTINUOUS, @@ -1312,7 +1312,7 @@ static struct snd_soc_dai_driver stm32_sai_capture_dai = { .id = 1, /* avoid call to fmt_single_name() */ .capture = { .channels_min = 1, - .channels_max = 2, + .channels_max = 16, .rate_min = 8000, .rate_max = 192000, .rates = SNDRV_PCM_RATE_CONTINUOUS, From 846aef1d7cc05651e27c17c3b4e2b5ce5cdec97b Mon Sep 17 00:00:00 2001 From: Ajit Kumar Pandey Date: Wed, 17 Nov 2021 11:37:14 +0200 Subject: [PATCH 037/327] ASoC: SOF: amd: Add Renoir ACP HW support This patch initializes ACP HW block to support SOF on AMD Renoir platform. Signed-off-by: Ajit Kumar Pandey Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211117093734.17407-2-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/Kconfig | 1 + sound/soc/sof/Makefile | 1 + sound/soc/sof/amd/Kconfig | 30 ++++++++ sound/soc/sof/amd/Makefile | 11 +++ sound/soc/sof/amd/acp-dsp-offset.h | 20 +++++ sound/soc/sof/amd/acp.c | 118 +++++++++++++++++++++++++++++ sound/soc/sof/amd/acp.h | 36 +++++++++ sound/soc/sof/amd/renoir.c | 34 +++++++++ 8 files changed, 251 insertions(+) create mode 100644 sound/soc/sof/amd/Kconfig create mode 100644 sound/soc/sof/amd/Makefile create mode 100644 sound/soc/sof/amd/acp-dsp-offset.h create mode 100644 sound/soc/sof/amd/acp.c create mode 100644 sound/soc/sof/amd/acp.h create mode 100644 sound/soc/sof/amd/renoir.c diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index b6fa659179b60..35c68192d2cee 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -225,6 +225,7 @@ config SND_SOC_SOF_PROBE_WORK_QUEUE When selected, the probe is handled in two steps, for example to avoid lockdeps if request_module is used in the probe. +source "sound/soc/sof/amd/Kconfig" source "sound/soc/sof/imx/Kconfig" source "sound/soc/sof/intel/Kconfig" source "sound/soc/sof/xtensa/Kconfig" diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 1dac5cb4dfd64..81ad8cb666e33 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -22,4 +22,5 @@ obj-$(CONFIG_SND_SOC_SOF_PCI_DEV) += snd-sof-pci.o obj-$(CONFIG_SND_SOC_SOF_INTEL_TOPLEVEL) += intel/ obj-$(CONFIG_SND_SOC_SOF_IMX_TOPLEVEL) += imx/ +obj-$(CONFIG_SND_SOC_SOF_AMD_TOPLEVEL) += amd/ obj-$(CONFIG_SND_SOC_SOF_XTENSA) += xtensa/ diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig new file mode 100644 index 0000000000000..400dd5a24ae6a --- /dev/null +++ b/sound/soc/sof/amd/Kconfig @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +# This file is provided under a dual BSD/GPLv2 license. When using or +# redistributing this file, you may do so under either license. +# +# Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. + +config SND_SOC_SOF_AMD_TOPLEVEL + tristate "SOF support for AMD audio DSPs" + depends on X86 || COMPILE_TEST + help + This adds support for Sound Open Firmware for AMD platforms. + Say Y if you have such a device. + If unsure select "N". + +if SND_SOC_SOF_AMD_TOPLEVEL + +config SND_SOC_SOF_AMD_COMMON + tristate + select SND_SOC_SOF + help + This option is not user-selectable but automatically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_AMD_RENOIR + tristate "SOF support for RENOIR" + select SND_SOC_SOF_AMD_COMMON + help + Select this option for SOF support on AMD Renoir platform + +endif diff --git a/sound/soc/sof/amd/Makefile b/sound/soc/sof/amd/Makefile new file mode 100644 index 0000000000000..ac2ecd21be5fe --- /dev/null +++ b/sound/soc/sof/amd/Makefile @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +# This file is provided under a dual BSD/GPLv2 license. When using or +# redistributing this file, you may do so under either license. +# +# Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. + +snd-sof-amd-acp-objs := acp.o +snd-sof-amd-renoir-objs := renoir.o + +obj-$(CONFIG_SND_SOC_SOF_AMD_COMMON) += snd-sof-amd-acp.o +obj-$(CONFIG_SND_SOC_SOF_AMD_RENOIR) +=snd-sof-amd-renoir.o diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h new file mode 100644 index 0000000000000..2cc2a9a842c5d --- /dev/null +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. + * + * Author: Ajit Kumar Pandey + */ + +#ifndef _ACP_DSP_IP_OFFSET_H +#define _ACP_DSP_IP_OFFSET_H + +#define ACP_SOFT_RESET 0x1000 + +/* Registers from ACP_PGFSM block */ +#define ACP_PGFSM_CONTROL 0x141C +#define ACP_PGFSM_STATUS 0x1420 + +#endif diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c new file mode 100644 index 0000000000000..687a67419335d --- /dev/null +++ b/sound/soc/sof/amd/acp.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. +// +// Authors: Vijendar Mukunda +// Ajit Kumar Pandey + +/* + * Hardware interface for generic AMD ACP processor + */ + +#include +#include +#include + +#include "../ops.h" +#include "acp.h" +#include "acp-dsp-offset.h" + +static int acp_power_on(struct snd_sof_dev *sdev) +{ + unsigned int val; + int ret; + + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_PGFSM_STATUS); + + if (val == ACP_POWERED_ON) + return 0; + + if (val & ACP_PGFSM_STATUS_MASK) + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_PGFSM_CONTROL, + ACP_PGFSM_CNTL_POWER_ON_MASK); + + ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_PGFSM_STATUS, val, !val, + ACP_REG_POLL_INTERVAL, ACP_REG_POLL_TIMEOUT_US); + if (ret < 0) + dev_err(sdev->dev, "timeout in ACP_PGFSM_STATUS read\n"); + + return ret; +} + +static int acp_reset(struct snd_sof_dev *sdev) +{ + unsigned int val; + int ret; + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SOFT_RESET, ACP_ASSERT_RESET); + + ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_SOFT_RESET, val, + val & ACP_SOFT_RESET_DONE_MASK, + ACP_REG_POLL_INTERVAL, ACP_REG_POLL_TIMEOUT_US); + if (ret < 0) { + dev_err(sdev->dev, "timeout asserting reset\n"); + return ret; + } + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SOFT_RESET, ACP_RELEASE_RESET); + + ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_SOFT_RESET, val, !val, + ACP_REG_POLL_INTERVAL, ACP_REG_POLL_TIMEOUT_US); + if (ret < 0) + dev_err(sdev->dev, "timeout in releasing reset\n"); + + return ret; +} + +static int acp_init(struct snd_sof_dev *sdev) +{ + int ret; + + /* power on */ + ret = acp_power_on(sdev); + if (ret) { + dev_err(sdev->dev, "ACP power on failed\n"); + return ret; + } + /* Reset */ + return acp_reset(sdev); +} + +int amd_sof_acp_probe(struct snd_sof_dev *sdev) +{ + struct pci_dev *pci = to_pci_dev(sdev->dev); + struct acp_dev_data *adata; + unsigned int addr; + + adata = devm_kzalloc(sdev->dev, sizeof(struct acp_dev_data), + GFP_KERNEL); + if (!adata) + return -ENOMEM; + + adata->dev = sdev; + addr = pci_resource_start(pci, ACP_DSP_BAR); + sdev->bar[ACP_DSP_BAR] = devm_ioremap(sdev->dev, addr, pci_resource_len(pci, ACP_DSP_BAR)); + if (!sdev->bar[ACP_DSP_BAR]) { + dev_err(sdev->dev, "ioremap error\n"); + return -ENXIO; + } + + pci_set_master(pci); + + sdev->pdata->hw_pdata = adata; + + return acp_init(sdev); +} +EXPORT_SYMBOL_NS(amd_sof_acp_probe, SND_SOC_SOF_AMD_COMMON); + +int amd_sof_acp_remove(struct snd_sof_dev *sdev) +{ + return acp_reset(sdev); +} +EXPORT_SYMBOL_NS(amd_sof_acp_remove, SND_SOC_SOF_AMD_COMMON); + +MODULE_DESCRIPTION("AMD ACP sof driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h new file mode 100644 index 0000000000000..c7ac8f9941d57 --- /dev/null +++ b/sound/soc/sof/amd/acp.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. + * + * Author: Ajit Kumar Pandey + */ + +#ifndef __SOF_AMD_ACP_H +#define __SOF_AMD_ACP_H + +#define ACP_DSP_BAR 0 + +#define ACP_REG_POLL_INTERVAL 500 +#define ACP_REG_POLL_TIMEOUT_US 2000 + +#define ACP_PGFSM_CNTL_POWER_ON_MASK 0x01 +#define ACP_PGFSM_STATUS_MASK 0x03 +#define ACP_POWERED_ON 0x00 +#define ACP_ASSERT_RESET 0x01 +#define ACP_RELEASE_RESET 0x00 +#define ACP_SOFT_RESET_DONE_MASK 0x00010001 + +/* Common device data struct for ACP devices */ +struct acp_dev_data { + struct snd_sof_dev *dev; +}; + +/* ACP device probe/remove */ +int amd_sof_acp_probe(struct snd_sof_dev *sdev); +int amd_sof_acp_remove(struct snd_sof_dev *sdev); + +extern const struct snd_sof_dsp_ops sof_renoir_ops; +#endif diff --git a/sound/soc/sof/amd/renoir.c b/sound/soc/sof/amd/renoir.c new file mode 100644 index 0000000000000..3d1dc6c2fa9be --- /dev/null +++ b/sound/soc/sof/amd/renoir.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2021 Advanced Micro Devices, Inc. +// +// Authors: Ajit Kumar Pandey + +/* + * Hardware interface for Audio DSP on Renoir platform + */ + +#include +#include + +#include "../ops.h" +#include "acp.h" + +/* AMD Renoir DSP ops */ +const struct snd_sof_dsp_ops sof_renoir_ops = { + /* probe and remove */ + .probe = amd_sof_acp_probe, + .remove = amd_sof_acp_remove, + + /* Register IO */ + .write = sof_io_write, + .read = sof_io_read, +}; +EXPORT_SYMBOL(sof_renoir_ops); + +MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON); +MODULE_DESCRIPTION("RENOIR SOF Driver"); +MODULE_LICENSE("Dual BSD/GPL"); From 0e44572a28a49109eae23af1545c658b86c4bf00 Mon Sep 17 00:00:00 2001 From: Ajit Kumar Pandey Date: Wed, 17 Nov 2021 11:37:15 +0200 Subject: [PATCH 038/327] ASoC: SOF: amd: Add helper callbacks for ACP's DMA configuration ACP DMA is used for loading SOF firmware into DSP memory and data transfer from system memory to DSP memory. Add helper callbacks to initialize and configure ACP DMA block for fw loading. Signed-off-by: Vijendar Mukunda Signed-off-by: Ajit Kumar Pandey Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211117093734.17407-3-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp-dsp-offset.h | 47 ++++++ sound/soc/sof/amd/acp.c | 222 ++++++++++++++++++++++++++++- sound/soc/sof/amd/acp.h | 91 ++++++++++++ 3 files changed, 359 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h index 2cc2a9a842c5d..bfb02390b4141 100644 --- a/sound/soc/sof/amd/acp-dsp-offset.h +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -11,10 +11,57 @@ #ifndef _ACP_DSP_IP_OFFSET_H #define _ACP_DSP_IP_OFFSET_H +/* Registers from ACP_DMA_0 block */ +#define ACP_DMA_CNTL_0 0x00 +#define ACP_DMA_DSCR_STRT_IDX_0 0x20 +#define ACP_DMA_DSCR_CNT_0 0x40 +#define ACP_DMA_PRIO_0 0x60 +#define ACP_DMA_CUR_DSCR_0 0x80 +#define ACP_DMA_ERR_STS_0 0xC0 +#define ACP_DMA_DESC_BASE_ADDR 0xE0 +#define ACP_DMA_DESC_MAX_NUM_DSCR 0xE4 +#define ACP_DMA_CH_STS 0xE8 +#define ACP_DMA_CH_GROUP 0xEC +#define ACP_DMA_CH_RST_STS 0xF0 + +/* Registers from ACP_AXI2AXIATU block */ +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1 0xC00 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_1 0xC04 +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_2 0xC08 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_2 0xC0C +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_3 0xC10 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_3 0xC14 +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_4 0xC18 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_4 0xC1C +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5 0xC20 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_5 0xC24 +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_6 0xC28 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_6 0xC2C +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_7 0xC30 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_7 0xC34 +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_8 0xC38 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_8 0xC3C +#define ACPAXI2AXI_ATU_CTRL 0xC40 #define ACP_SOFT_RESET 0x1000 /* Registers from ACP_PGFSM block */ #define ACP_PGFSM_CONTROL 0x141C #define ACP_PGFSM_STATUS 0x1420 +/* Registers from ACP_INTR block */ +#define ACP_DSP_SW_INTR_CNTL 0x1814 +#define ACP_ERROR_STATUS 0x18C4 + +/* Registers from ACP_SHA block */ +#define ACP_SHA_DSP_FW_QUALIFIER 0x1C70 +#define ACP_SHA_DMA_CMD 0x1CB0 +#define ACP_SHA_MSG_LENGTH 0x1CB4 +#define ACP_SHA_DMA_STRT_ADDR 0x1CB8 +#define ACP_SHA_DMA_DESTINATION_ADDR 0x1CBC +#define ACP_SHA_DMA_CMD_STS 0x1CC0 +#define ACP_SHA_DMA_ERR_STATUS 0x1CC4 +#define ACP_SHA_TRANSFER_BYTE_CNT 0x1CC8 + +#define ACP_SCRATCH_REG_0 0x10000 + #endif diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 687a67419335d..3778f781f16a4 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -20,6 +20,219 @@ #include "acp.h" #include "acp-dsp-offset.h" +static void configure_acp_groupregisters(struct acp_dev_data *adata) +{ + struct snd_sof_dev *sdev = adata->dev; + + /* Group Enable */ + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACPAXI2AXI_ATU_BASE_ADDR_GRP_1, + ACP_SRAM_PTE_OFFSET | BIT(31)); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1, + PAGE_SIZE_4K_ENABLE); + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACPAXI2AXI_ATU_CTRL, ACP_ATU_CACHE_INVALID); +} + +static void init_dma_descriptor(struct acp_dev_data *adata) +{ + struct snd_sof_dev *sdev = adata->dev; + unsigned int addr; + + addr = ACP_SRAM_PTE_OFFSET + offsetof(struct scratch_reg_conf, dma_desc); + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_DESC_BASE_ADDR, addr); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_DESC_MAX_NUM_DSCR, ACP_MAX_DESC_CNT); +} + +static void configure_dma_descriptor(struct acp_dev_data *adata, unsigned short idx, + struct dma_descriptor *dscr_info) +{ + struct snd_sof_dev *sdev = adata->dev; + unsigned int offset; + + offset = ACP_SCRATCH_REG_0 + offsetof(struct scratch_reg_conf, dma_desc) + + idx * sizeof(struct dma_descriptor); + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, offset, dscr_info->src_addr); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, offset + 0x4, dscr_info->dest_addr); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, offset + 0x8, dscr_info->tx_cnt.u32_all); +} + +static int config_dma_channel(struct acp_dev_data *adata, unsigned int ch, + unsigned int idx, unsigned int dscr_count) +{ + struct snd_sof_dev *sdev = adata->dev; + unsigned int val, status; + int ret; + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_CNTL_0 + ch * sizeof(u32), + ACP_DMA_CH_RST | ACP_DMA_CH_GRACEFUL_RST_EN); + + ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_DMA_CH_RST_STS, val, + val & (1 << ch), ACP_REG_POLL_INTERVAL, + ACP_REG_POLL_TIMEOUT_US); + if (ret < 0) { + status = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_ERROR_STATUS); + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_DMA_ERR_STS_0 + ch * sizeof(u32)); + + dev_err(sdev->dev, "ACP_DMA_ERR_STS :0x%x ACP_ERROR_STATUS :0x%x\n", val, status); + return ret; + } + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, (ACP_DMA_CNTL_0 + ch * sizeof(u32)), 0); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_DSCR_CNT_0 + ch * sizeof(u32), dscr_count); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_DSCR_STRT_IDX_0 + ch * sizeof(u32), idx); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_PRIO_0 + ch * sizeof(u32), 0); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_CNTL_0 + ch * sizeof(u32), ACP_DMA_CH_RUN); + + return ret; +} + +static int acpbus_dma_start(struct acp_dev_data *adata, unsigned int ch, + unsigned int dscr_count, struct dma_descriptor *dscr_info) +{ + struct snd_sof_dev *sdev = adata->dev; + int ret; + u16 dscr; + + if (!dscr_info || !dscr_count) + return -EINVAL; + + for (dscr = 0; dscr < dscr_count; dscr++) + configure_dma_descriptor(adata, dscr, dscr_info++); + + ret = config_dma_channel(adata, ch, 0, dscr_count); + if (ret < 0) + dev_err(sdev->dev, "config dma ch failed:%d\n", ret); + + return ret; +} + +int configure_and_run_dma(struct acp_dev_data *adata, unsigned int src_addr, + unsigned int dest_addr, int dsp_data_size) +{ + struct snd_sof_dev *sdev = adata->dev; + unsigned int desc_count, index; + int ret; + + for (desc_count = 0; desc_count < ACP_MAX_DESC && dsp_data_size >= 0; + desc_count++, dsp_data_size -= ACP_PAGE_SIZE) { + adata->dscr_info[desc_count].src_addr = src_addr + desc_count * ACP_PAGE_SIZE; + adata->dscr_info[desc_count].dest_addr = dest_addr + desc_count * ACP_PAGE_SIZE; + adata->dscr_info[desc_count].tx_cnt.bits.count = ACP_PAGE_SIZE; + if (dsp_data_size < ACP_PAGE_SIZE) + adata->dscr_info[desc_count].tx_cnt.bits.count = dsp_data_size; + } + + ret = acpbus_dma_start(adata, 0, desc_count, adata->dscr_info); + if (ret) + dev_err(sdev->dev, "acpbus_dma_start failed\n"); + + /* Clear descriptor array */ + for (index = 0; index < desc_count; index++) + memset(&adata->dscr_info[index], 0x00, sizeof(struct dma_descriptor)); + + return ret; +} + +int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, + unsigned int start_addr, unsigned int dest_addr, + unsigned int image_length) +{ + struct snd_sof_dev *sdev = adata->dev; + unsigned int tx_count, fw_qualifier, val; + int ret; + + if (!image_addr) { + dev_err(sdev->dev, "SHA DMA image address is NULL\n"); + return -EINVAL; + } + + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SHA_DMA_CMD); + if (val & ACP_SHA_RUN) { + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_CMD, ACP_SHA_RESET); + ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_SHA_DMA_CMD_STS, + val, val & ACP_SHA_RESET, + ACP_REG_POLL_INTERVAL, + ACP_REG_POLL_TIMEOUT_US); + if (ret < 0) { + dev_err(sdev->dev, "SHA DMA Failed to Reset\n"); + return ret; + } + } + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_STRT_ADDR, start_addr); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_DESTINATION_ADDR, dest_addr); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_MSG_LENGTH, image_length); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_CMD, ACP_SHA_RUN); + + ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_SHA_TRANSFER_BYTE_CNT, + tx_count, tx_count == image_length, + ACP_REG_POLL_INTERVAL, ACP_DMA_COMPLETE_TIMEOUT_US); + if (ret < 0) { + dev_err(sdev->dev, "SHA DMA Failed to Transfer Length %x\n", tx_count); + return ret; + } + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DSP_FW_QUALIFIER, DSP_FW_RUN_ENABLE); + + fw_qualifier = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SHA_DSP_FW_QUALIFIER); + if (!(fw_qualifier & DSP_FW_RUN_ENABLE)) { + dev_err(sdev->dev, "PSP validation failed\n"); + return -EINVAL; + } + + return ret; +} + +int acp_dma_status(struct acp_dev_data *adata, unsigned char ch) +{ + struct snd_sof_dev *sdev = adata->dev; + unsigned int val; + int ret = 0; + + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_DMA_CNTL_0 + ch * sizeof(u32)); + if (val & ACP_DMA_CH_RUN) { + ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_DMA_CH_STS, val, !val, + ACP_REG_POLL_INTERVAL, + ACP_DMA_COMPLETE_TIMEOUT_US); + if (ret < 0) + dev_err(sdev->dev, "DMA_CHANNEL %d status timeout\n", ch); + } + + return ret; +} + +void memcpy_from_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *dst, size_t bytes) +{ + unsigned int reg_offset = offset + ACP_SCRATCH_REG_0; + int i, j; + + for (i = 0, j = 0; i < bytes; i = i + 4, j++) + dst[j] = snd_sof_dsp_read(sdev, ACP_DSP_BAR, reg_offset + i); +} + +void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes) +{ + unsigned int reg_offset = offset + ACP_SCRATCH_REG_0; + int i, j; + + for (i = 0, j = 0; i < bytes; i = i + 4, j++) + snd_sof_dsp_write(sdev, ACP_DSP_BAR, reg_offset + i, src[j]); +} + +static int acp_memory_init(struct snd_sof_dev *sdev) +{ + struct acp_dev_data *adata = sdev->pdata->hw_pdata; + + snd_sof_dsp_update_bits(sdev, ACP_DSP_BAR, ACP_DSP_SW_INTR_CNTL, + ACP_DSP_INTR_EN_MASK, ACP_DSP_INTR_EN_MASK); + configure_acp_groupregisters(adata); + init_dma_descriptor(adata); + + return 0; +} + static int acp_power_on(struct snd_sof_dev *sdev) { unsigned int val; @@ -86,6 +299,7 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) struct pci_dev *pci = to_pci_dev(sdev->dev); struct acp_dev_data *adata; unsigned int addr; + int ret; adata = devm_kzalloc(sdev->dev, sizeof(struct acp_dev_data), GFP_KERNEL); @@ -104,7 +318,13 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) sdev->pdata->hw_pdata = adata; - return acp_init(sdev); + ret = acp_init(sdev); + if (ret < 0) + return ret; + + acp_memory_init(sdev); + + return 0; } EXPORT_SYMBOL_NS(amd_sof_acp_probe, SND_SOC_SOF_AMD_COMMON); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index c7ac8f9941d57..ff01d0ef67efd 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -15,6 +15,7 @@ #define ACP_REG_POLL_INTERVAL 500 #define ACP_REG_POLL_TIMEOUT_US 2000 +#define ACP_DMA_COMPLETE_TIMEOUT_US 5000 #define ACP_PGFSM_CNTL_POWER_ON_MASK 0x01 #define ACP_PGFSM_STATUS_MASK 0x03 @@ -23,11 +24,101 @@ #define ACP_RELEASE_RESET 0x00 #define ACP_SOFT_RESET_DONE_MASK 0x00010001 +#define ACP_DSP_INTR_EN_MASK 0x00000001 +#define ACP_SRAM_PTE_OFFSET 0x02050000 +#define PAGE_SIZE_4K_ENABLE 0x2 +#define ACP_PAGE_SIZE 0x1000 +#define ACP_DMA_CH_RUN 0x02 +#define ACP_MAX_DESC_CNT 0x02 +#define DSP_FW_RUN_ENABLE 0x01 +#define ACP_SHA_RUN 0x01 +#define ACP_SHA_RESET 0x02 +#define ACP_DMA_CH_RST 0x01 +#define ACP_DMA_CH_GRACEFUL_RST_EN 0x10 +#define ACP_ATU_CACHE_INVALID 0x01 +#define ACP_MAX_DESC 128 +#define ACPBUS_REG_BASE_OFFSET ACP_DMA_CNTL_0 + +struct acp_atu_grp_pte { + u32 low; + u32 high; +}; + +union dma_tx_cnt { + struct { + unsigned int count : 19; + unsigned int reserved : 12; + unsigned ioc : 1; + } bitfields, bits; + unsigned int u32_all; + signed int i32_all; +}; + +struct dma_descriptor { + unsigned int src_addr; + unsigned int dest_addr; + union dma_tx_cnt tx_cnt; + unsigned int reserved; +}; + +/* Scratch memory structure for communication b/w host and dsp */ +struct scratch_ipc_conf { + /* DSP mailbox */ + u8 sof_out_box[512]; + /* Host mailbox */ + u8 sof_in_box[512]; + /* Debug memory */ + u8 sof_debug_box[1024]; + /* Exception memory*/ + u8 sof_except_box[1024]; + /* Stream buffer */ + u8 sof_stream_box[1024]; + /* Trace buffer */ + u8 sof_trace_box[1024]; + /* Host msg flag */ + u32 sof_host_msg_write; + /* Host ack flag*/ + u32 sof_host_ack_write; + /* DSP msg flag */ + u32 sof_dsp_msg_write; + /* Dsp ack flag */ + u32 sof_dsp_ack_write; +}; + +struct scratch_reg_conf { + struct scratch_ipc_conf info; + struct acp_atu_grp_pte grp1_pte[16]; + struct acp_atu_grp_pte grp2_pte[16]; + struct acp_atu_grp_pte grp3_pte[16]; + struct acp_atu_grp_pte grp4_pte[16]; + struct acp_atu_grp_pte grp5_pte[16]; + struct acp_atu_grp_pte grp6_pte[16]; + struct acp_atu_grp_pte grp7_pte[16]; + struct acp_atu_grp_pte grp8_pte[16]; + struct dma_descriptor dma_desc[64]; + unsigned int reg_offset[8]; + unsigned int buf_size[8]; + u8 acp_tx_fifo_buf[256]; + u8 acp_rx_fifo_buf[256]; + unsigned int reserve[]; +}; + /* Common device data struct for ACP devices */ struct acp_dev_data { struct snd_sof_dev *dev; + struct dma_descriptor dscr_info[ACP_MAX_DESC]; }; +void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes); +void memcpy_from_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *dst, size_t bytes); + +int acp_dma_status(struct acp_dev_data *adata, unsigned char ch); +int configure_and_run_dma(struct acp_dev_data *adata, unsigned int src_addr, + unsigned int dest_addr, int dsp_data_size); +int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, + unsigned int start_addr, unsigned int dest_addr, + unsigned int image_length); + /* ACP device probe/remove */ int amd_sof_acp_probe(struct snd_sof_dev *sdev); int amd_sof_acp_remove(struct snd_sof_dev *sdev); From 7e51a9e38ab204eba2844b8773486392d7444435 Mon Sep 17 00:00:00 2001 From: Ajit Kumar Pandey Date: Wed, 17 Nov 2021 11:37:16 +0200 Subject: [PATCH 039/327] ASoC: SOF: amd: Add fw loader and renoir dsp ops to load firmware Add acp-loader module with ops callback to load and run firmware on ACP DSP block on Renoir platform. Signed-off-by: Ajit Kumar Pandey Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211117093734.17407-4-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/Makefile | 2 +- sound/soc/sof/amd/acp-dsp-offset.h | 3 + sound/soc/sof/amd/acp-loader.c | 199 +++++++++++++++++++++++++++++ sound/soc/sof/amd/acp.h | 27 ++++ sound/soc/sof/amd/renoir.c | 15 +++ 5 files changed, 245 insertions(+), 1 deletion(-) create mode 100644 sound/soc/sof/amd/acp-loader.c diff --git a/sound/soc/sof/amd/Makefile b/sound/soc/sof/amd/Makefile index ac2ecd21be5fe..031fb9493876f 100644 --- a/sound/soc/sof/amd/Makefile +++ b/sound/soc/sof/amd/Makefile @@ -4,7 +4,7 @@ # # Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. -snd-sof-amd-acp-objs := acp.o +snd-sof-amd-acp-objs := acp.o acp-loader.o snd-sof-amd-renoir-objs := renoir.o obj-$(CONFIG_SND_SOC_SOF_AMD_COMMON) += snd-sof-amd-acp.o diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h index bfb02390b4141..f4bc7e9abafb1 100644 --- a/sound/soc/sof/amd/acp-dsp-offset.h +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -24,6 +24,9 @@ #define ACP_DMA_CH_GROUP 0xEC #define ACP_DMA_CH_RST_STS 0xF0 +/* Registers from ACP_DSP_0 block */ +#define ACP_DSP0_RUNSTALL 0x414 + /* Registers from ACP_AXI2AXIATU block */ #define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1 0xC00 #define ACPAXI2AXI_ATU_BASE_ADDR_GRP_1 0xC04 diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c new file mode 100644 index 0000000000000..2dc15ae381552 --- /dev/null +++ b/sound/soc/sof/amd/acp-loader.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2021 Advanced Micro Devices, Inc. +// +// Authors: Ajit Kumar Pandey + +/* + * Hardware interface for ACP DSP Firmware binaries loader + */ + +#include +#include +#include + +#include "../ops.h" +#include "acp-dsp-offset.h" +#include "acp.h" + +#define FW_BIN 0 +#define FW_DATA_BIN 1 + +#define FW_BIN_PTE_OFFSET 0x00 +#define FW_DATA_BIN_PTE_OFFSET 0x08 + +#define ACP_DSP_RUN 0x00 + +int acp_dsp_block_read(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type, + u32 offset, void *dest, size_t size) +{ + switch (blk_type) { + case SOF_FW_BLK_TYPE_SRAM: + offset = offset - ACP_SCRATCH_MEMORY_ADDRESS; + memcpy_from_scratch(sdev, offset, dest, size); + break; + default: + dev_err(sdev->dev, "bad blk type 0x%x\n", blk_type); + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_NS(acp_dsp_block_read, SND_SOC_SOF_AMD_COMMON); + +int acp_dsp_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type, + u32 offset, void *src, size_t size) +{ + struct snd_sof_pdata *plat_data = sdev->pdata; + struct pci_dev *pci = to_pci_dev(sdev->dev); + struct acp_dev_data *adata; + void *dest; + u32 dma_size, page_count; + unsigned int size_fw; + + adata = sdev->pdata->hw_pdata; + + switch (blk_type) { + case SOF_FW_BLK_TYPE_IRAM: + if (!adata->bin_buf) { + size_fw = plat_data->fw->size; + page_count = PAGE_ALIGN(size_fw) >> PAGE_SHIFT; + dma_size = page_count * ACP_PAGE_SIZE; + adata->bin_buf = dma_alloc_coherent(&pci->dev, dma_size, + &adata->sha_dma_addr, + GFP_ATOMIC); + if (!adata->bin_buf) + return -ENOMEM; + } + adata->fw_bin_size = size + offset; + dest = adata->bin_buf + offset; + break; + case SOF_FW_BLK_TYPE_DRAM: + if (!adata->data_buf) { + adata->data_buf = dma_alloc_coherent(&pci->dev, + ACP_DEFAULT_DRAM_LENGTH, + &adata->dma_addr, + GFP_ATOMIC); + if (!adata->data_buf) + return -ENOMEM; + } + dest = adata->data_buf + offset; + adata->fw_data_bin_size = size + offset; + break; + case SOF_FW_BLK_TYPE_SRAM: + offset = offset - ACP_SCRATCH_MEMORY_ADDRESS; + memcpy_to_scratch(sdev, offset, src, size); + return 0; + default: + dev_err(sdev->dev, "bad blk type 0x%x\n", blk_type); + return -EINVAL; + } + + memcpy(dest, src, size); + return 0; +} +EXPORT_SYMBOL_NS(acp_dsp_block_write, SND_SOC_SOF_AMD_COMMON); + +int acp_get_bar_index(struct snd_sof_dev *sdev, u32 type) +{ + return type; +} +EXPORT_SYMBOL_NS(acp_get_bar_index, SND_SOC_SOF_AMD_COMMON); + +static void configure_pte_for_fw_loading(int type, int num_pages, struct acp_dev_data *adata) +{ + struct snd_sof_dev *sdev; + unsigned int low, high; + dma_addr_t addr; + u16 page_idx; + u32 offset; + + sdev = adata->dev; + + switch (type) { + case FW_BIN: + offset = FW_BIN_PTE_OFFSET; + addr = adata->sha_dma_addr; + break; + case FW_DATA_BIN: + offset = adata->fw_bin_page_count * 8; + addr = adata->dma_addr; + break; + default: + dev_err(sdev->dev, "Invalid data type %x\n", type); + return; + } + + for (page_idx = 0; page_idx < num_pages; page_idx++) { + low = lower_32_bits(addr); + high = upper_32_bits(addr); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + offset, low); + high |= BIT(31); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + offset + 4, high); + offset += 8; + addr += PAGE_SIZE; + } +} + +/* pre fw run operations */ +int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev) +{ + struct pci_dev *pci = to_pci_dev(sdev->dev); + struct snd_sof_pdata *plat_data = sdev->pdata; + struct acp_dev_data *adata; + unsigned int src_addr, size_fw; + u32 page_count, dma_size; + int ret; + + adata = sdev->pdata->hw_pdata; + size_fw = adata->fw_bin_size; + + page_count = PAGE_ALIGN(size_fw) >> PAGE_SHIFT; + adata->fw_bin_page_count = page_count; + + configure_pte_for_fw_loading(FW_BIN, page_count, adata); + ret = configure_and_run_sha_dma(adata, adata->bin_buf, ACP_SYSTEM_MEMORY_WINDOW, + ACP_IRAM_BASE_ADDRESS, size_fw); + if (ret < 0) { + dev_err(sdev->dev, "SHA DMA transfer failed status: %d\n", ret); + return ret; + } + configure_pte_for_fw_loading(FW_DATA_BIN, ACP_DRAM_PAGE_COUNT, adata); + + src_addr = ACP_SYSTEM_MEMORY_WINDOW + page_count * ACP_PAGE_SIZE; + ret = configure_and_run_dma(adata, src_addr, ACP_DATA_RAM_BASE_ADDRESS, + adata->fw_data_bin_size); + if (ret < 0) { + dev_err(sdev->dev, "acp dma configuration failed: %d\n", ret); + return ret; + } + + ret = acp_dma_status(adata, 0); + if (ret < 0) + dev_err(sdev->dev, "acp dma transfer status: %d\n", ret); + + /* Free memory once DMA is complete */ + dma_size = (PAGE_ALIGN(plat_data->fw->size) >> PAGE_SHIFT) * ACP_PAGE_SIZE; + dma_free_coherent(&pci->dev, dma_size, adata->bin_buf, adata->sha_dma_addr); + dma_free_coherent(&pci->dev, ACP_DEFAULT_DRAM_LENGTH, adata->data_buf, adata->dma_addr); + adata->bin_buf = NULL; + adata->data_buf = NULL; + + return ret; +} +EXPORT_SYMBOL_NS(acp_dsp_pre_fw_run, SND_SOC_SOF_AMD_COMMON); + +int acp_sof_dsp_run(struct snd_sof_dev *sdev) +{ + int val; + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DSP0_RUNSTALL, ACP_DSP_RUN); + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_DSP0_RUNSTALL); + dev_dbg(sdev->dev, "ACP_DSP0_RUNSTALL : 0x%0x\n", val); + + return 0; +} +EXPORT_SYMBOL_NS(acp_sof_dsp_run, SND_SOC_SOF_AMD_COMMON); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index ff01d0ef67efd..e755a31374c65 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -11,6 +11,8 @@ #ifndef __SOF_AMD_ACP_H #define __SOF_AMD_ACP_H +#include "../sof-priv.h" + #define ACP_DSP_BAR 0 #define ACP_REG_POLL_INTERVAL 500 @@ -39,6 +41,13 @@ #define ACP_MAX_DESC 128 #define ACPBUS_REG_BASE_OFFSET ACP_DMA_CNTL_0 +#define ACP_DEFAULT_DRAM_LENGTH 0x00080000 +#define ACP_SCRATCH_MEMORY_ADDRESS 0x02050000 +#define ACP_SYSTEM_MEMORY_WINDOW 0x4000000 +#define ACP_IRAM_BASE_ADDRESS 0x000000 +#define ACP_DATA_RAM_BASE_ADDRESS 0x01000000 +#define ACP_DRAM_PAGE_COUNT 128 + struct acp_atu_grp_pte { u32 low; u32 high; @@ -106,6 +115,13 @@ struct scratch_reg_conf { /* Common device data struct for ACP devices */ struct acp_dev_data { struct snd_sof_dev *dev; + unsigned int fw_bin_size; + unsigned int fw_data_bin_size; + u32 fw_bin_page_count; + dma_addr_t sha_dma_addr; + u8 *bin_buf; + dma_addr_t dma_addr; + u8 *data_buf; struct dma_descriptor dscr_info[ACP_MAX_DESC]; }; @@ -123,5 +139,16 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, int amd_sof_acp_probe(struct snd_sof_dev *sdev); int amd_sof_acp_remove(struct snd_sof_dev *sdev); +/* DSP Loader callbacks */ +int acp_sof_dsp_run(struct snd_sof_dev *sdev); +int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev); +int acp_get_bar_index(struct snd_sof_dev *sdev, u32 type); + +/* Block IO callbacks */ +int acp_dsp_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type, + u32 offset, void *src, size_t size); +int acp_dsp_block_read(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type, + u32 offset, void *dest, size_t size); + extern const struct snd_sof_dsp_ops sof_renoir_ops; #endif diff --git a/sound/soc/sof/amd/renoir.c b/sound/soc/sof/amd/renoir.c index 3d1dc6c2fa9be..bca80784b3223 100644 --- a/sound/soc/sof/amd/renoir.c +++ b/sound/soc/sof/amd/renoir.c @@ -26,6 +26,21 @@ const struct snd_sof_dsp_ops sof_renoir_ops = { /* Register IO */ .write = sof_io_write, .read = sof_io_read, + + /* Block IO */ + .block_read = acp_dsp_block_read, + .block_write = acp_dsp_block_write, + + /* Module loading */ + .load_module = snd_sof_parse_module_memcpy, + + /*Firmware loading */ + .load_firmware = snd_sof_load_firmware_memcpy, + .pre_fw_run = acp_dsp_pre_fw_run, + .get_bar_index = acp_get_bar_index, + + /* DSP core boot */ + .run = acp_sof_dsp_run, }; EXPORT_SYMBOL(sof_renoir_ops); From 738a2b5e2cc9fd63d48faac11c8d60a5a2313a9d Mon Sep 17 00:00:00 2001 From: Ajit Kumar Pandey Date: Wed, 17 Nov 2021 11:37:17 +0200 Subject: [PATCH 040/327] ASoC: SOF: amd: Add IPC support for ACP IP block Add IPC module for generic ACP block and exposed ops callback for to synchronize SOF IPC message between host and DSP Signed-off-by: Balakishore Pati Signed-off-by: Ajit Kumar Pandey Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211117093734.17407-5-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/Makefile | 2 +- sound/soc/sof/amd/acp-dsp-offset.h | 2 + sound/soc/sof/amd/acp-ipc.c | 187 +++++++++++++++++++++++++++++ sound/soc/sof/amd/acp.c | 44 ++++++- sound/soc/sof/amd/acp.h | 15 +++ sound/soc/sof/amd/renoir.c | 8 ++ 6 files changed, 256 insertions(+), 2 deletions(-) create mode 100644 sound/soc/sof/amd/acp-ipc.c diff --git a/sound/soc/sof/amd/Makefile b/sound/soc/sof/amd/Makefile index 031fb9493876f..29928b16002f6 100644 --- a/sound/soc/sof/amd/Makefile +++ b/sound/soc/sof/amd/Makefile @@ -4,7 +4,7 @@ # # Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. -snd-sof-amd-acp-objs := acp.o acp-loader.o +snd-sof-amd-acp-objs := acp.o acp-loader.o acp-ipc.o snd-sof-amd-renoir-objs := renoir.o obj-$(CONFIG_SND_SOC_SOF_AMD_COMMON) += snd-sof-amd-acp.o diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h index f4bc7e9abafb1..3a1c848020cae 100644 --- a/sound/soc/sof/amd/acp-dsp-offset.h +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -53,6 +53,8 @@ /* Registers from ACP_INTR block */ #define ACP_DSP_SW_INTR_CNTL 0x1814 +#define ACP_DSP_SW_INTR_STAT 0x1818 +#define ACP_SW_INTR_TRIG 0x181C #define ACP_ERROR_STATUS 0x18C4 /* Registers from ACP_SHA block */ diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c new file mode 100644 index 0000000000000..e132223b4c669 --- /dev/null +++ b/sound/soc/sof/amd/acp-ipc.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2021 Advanced Micro Devices, Inc. +// +// Authors: Balakishore Pati +// Ajit Kumar Pandey + +/* ACP-specific SOF IPC code */ + +#include +#include "../ops.h" +#include "acp.h" +#include "acp-dsp-offset.h" + +void acp_mailbox_write(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes) +{ + memcpy_to_scratch(sdev, offset, message, bytes); +} +EXPORT_SYMBOL_NS(acp_mailbox_write, SND_SOC_SOF_AMD_COMMON); + +void acp_mailbox_read(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes) +{ + memcpy_from_scratch(sdev, offset, message, bytes); +} +EXPORT_SYMBOL_NS(acp_mailbox_read, SND_SOC_SOF_AMD_COMMON); + +static void acpbus_trigger_host_to_dsp_swintr(struct acp_dev_data *adata) +{ + struct snd_sof_dev *sdev = adata->dev; + u32 swintr_trigger; + + swintr_trigger = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SW_INTR_TRIG); + swintr_trigger |= 0x01; + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SW_INTR_TRIG, swintr_trigger); +} + +static void acp_ipc_host_msg_set(struct snd_sof_dev *sdev) +{ + unsigned int host_msg = offsetof(struct scratch_ipc_conf, sof_host_msg_write); + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + host_msg, 1); +} + +static void acp_dsp_ipc_host_done(struct snd_sof_dev *sdev) +{ + unsigned int dsp_msg = offsetof(struct scratch_ipc_conf, sof_dsp_msg_write); + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_msg, 0); +} + +static void acp_dsp_ipc_dsp_done(struct snd_sof_dev *sdev) +{ + unsigned int dsp_ack = offsetof(struct scratch_ipc_conf, sof_dsp_ack_write); + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_ack, 0); +} + +int acp_sof_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +{ + struct acp_dev_data *adata = sdev->pdata->hw_pdata; + unsigned int offset = offsetof(struct scratch_ipc_conf, sof_in_box); + + acp_mailbox_write(sdev, offset, msg->msg_data, msg->msg_size); + acp_ipc_host_msg_set(sdev); + + /* Trigger host to dsp interrupt for the msg */ + acpbus_trigger_host_to_dsp_swintr(adata); + return 0; +} +EXPORT_SYMBOL_NS(acp_sof_ipc_send_msg, SND_SOC_SOF_AMD_COMMON); + +static void acp_dsp_ipc_get_reply(struct snd_sof_dev *sdev) +{ + struct snd_sof_ipc_msg *msg = sdev->msg; + struct sof_ipc_reply reply; + struct sof_ipc_cmd_hdr *hdr; + unsigned int offset = offsetof(struct scratch_ipc_conf, sof_in_box); + int ret = 0; + + /* + * Sometimes, there is unexpected reply ipc arriving. The reply + * ipc belongs to none of the ipcs sent from driver. + * In this case, the driver must ignore the ipc. + */ + if (!msg) { + dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); + return; + } + hdr = msg->msg_data; + if (hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE) || + hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_GATE)) { + /* + * memory windows are powered off before sending IPC reply, + * so we can't read the mailbox for CTX_SAVE and PM_GATE + * replies. + */ + reply.error = 0; + reply.hdr.cmd = SOF_IPC_GLB_REPLY; + reply.hdr.size = sizeof(reply); + memcpy(msg->reply_data, &reply, sizeof(reply)); + goto out; + } + /* get IPC reply from DSP in the mailbox */ + acp_mailbox_read(sdev, offset, &reply, sizeof(reply)); + if (reply.error < 0) { + memcpy(msg->reply_data, &reply, sizeof(reply)); + ret = reply.error; + } else { + /* reply correct size ? */ + if (reply.hdr.size != msg->reply_size && + !(reply.hdr.cmd & SOF_IPC_GLB_PROBE)) { + dev_err(sdev->dev, "reply expected %zu got %u bytes\n", + msg->reply_size, reply.hdr.size); + ret = -EINVAL; + } + /* read the message */ + if (msg->reply_size > 0) + acp_mailbox_read(sdev, offset, msg->reply_data, msg->reply_size); + } +out: + msg->reply_error = ret; +} + +irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context) +{ + struct snd_sof_dev *sdev = context; + unsigned int dsp_msg_write = offsetof(struct scratch_ipc_conf, sof_dsp_msg_write); + unsigned int dsp_ack_write = offsetof(struct scratch_ipc_conf, sof_dsp_ack_write); + bool ipc_irq = false; + int dsp_msg, dsp_ack; + + dsp_msg = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_msg_write); + if (dsp_msg) { + snd_sof_ipc_msgs_rx(sdev); + acp_dsp_ipc_host_done(sdev); + ipc_irq = true; + } + + dsp_ack = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_ack_write); + if (dsp_ack) { + spin_lock_irq(&sdev->ipc_lock); + /* handle immediate reply from DSP core */ + acp_dsp_ipc_get_reply(sdev); + snd_sof_ipc_reply(sdev, 0); + /* set the done bit */ + acp_dsp_ipc_dsp_done(sdev); + spin_unlock_irq(&sdev->ipc_lock); + ipc_irq = true; + } + + if (!ipc_irq) + dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n"); + + return IRQ_HANDLED; +} +EXPORT_SYMBOL_NS(acp_sof_ipc_irq_thread, SND_SOC_SOF_AMD_COMMON); + +int acp_sof_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, + void *p, size_t sz) +{ + unsigned int offset = offsetof(struct scratch_ipc_conf, sof_out_box); + + if (!substream || !sdev->stream_box.size) + acp_mailbox_read(sdev, offset, p, sz); + + return 0; +} +EXPORT_SYMBOL_NS(acp_sof_ipc_msg_data, SND_SOC_SOF_AMD_COMMON); + +int acp_sof_ipc_pcm_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, + const struct sof_ipc_pcm_params_reply *reply) +{ + /* TODO: Implement stream hw params to validate stream offset */ + return 0; +} +EXPORT_SYMBOL_NS(acp_sof_ipc_pcm_params, SND_SOC_SOF_AMD_COMMON); + +int acp_sof_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) +{ + return ACP_SCRATCH_MEMORY_ADDRESS; +} +EXPORT_SYMBOL_NS(acp_sof_ipc_get_mailbox_offset, SND_SOC_SOF_AMD_COMMON); + +MODULE_DESCRIPTION("AMD ACP sof-ipc driver"); diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 3778f781f16a4..43a57d15e3caf 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -233,6 +233,34 @@ static int acp_memory_init(struct snd_sof_dev *sdev) return 0; } +static irqreturn_t acp_irq_thread(int irq, void *context) +{ + struct snd_sof_dev *sdev = context; + unsigned int val; + + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_DSP_SW_INTR_STAT); + if (val & ACP_DSP_TO_HOST_IRQ) { + sof_ops(sdev)->irq_thread(irq, sdev); + val |= ACP_DSP_TO_HOST_IRQ; + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DSP_SW_INTR_STAT, val); + return IRQ_HANDLED; + } + + return IRQ_NONE; +}; + +static irqreturn_t acp_irq_handler(int irq, void *dev_id) +{ + struct snd_sof_dev *sdev = dev_id; + unsigned int val; + + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_DSP_SW_INTR_STAT); + if (val) + return IRQ_WAKE_THREAD; + + return IRQ_NONE; +} + static int acp_power_on(struct snd_sof_dev *sdev) { unsigned int val; @@ -318,9 +346,20 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) sdev->pdata->hw_pdata = adata; + sdev->ipc_irq = pci->irq; + ret = request_threaded_irq(sdev->ipc_irq, acp_irq_handler, acp_irq_thread, + IRQF_SHARED, "AudioDSP", sdev); + if (ret < 0) { + dev_err(sdev->dev, "failed to register IRQ %d\n", + sdev->ipc_irq); + return ret; + } + ret = acp_init(sdev); - if (ret < 0) + if (ret < 0) { + free_irq(sdev->ipc_irq, sdev); return ret; + } acp_memory_init(sdev); @@ -330,6 +369,9 @@ EXPORT_SYMBOL_NS(amd_sof_acp_probe, SND_SOC_SOF_AMD_COMMON); int amd_sof_acp_remove(struct snd_sof_dev *sdev) { + if (sdev->ipc_irq) + free_irq(sdev->ipc_irq, sdev); + return acp_reset(sdev); } EXPORT_SYMBOL_NS(amd_sof_acp_remove, SND_SOC_SOF_AMD_COMMON); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index e755a31374c65..ac8340119125c 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -48,6 +48,8 @@ #define ACP_DATA_RAM_BASE_ADDRESS 0x01000000 #define ACP_DRAM_PAGE_COUNT 128 +#define ACP_DSP_TO_HOST_IRQ 0x04 + struct acp_atu_grp_pte { u32 low; u32 high; @@ -150,5 +152,18 @@ int acp_dsp_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_t int acp_dsp_block_read(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type, u32 offset, void *dest, size_t size); +/* IPC callbacks */ +irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context); +int acp_sof_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, + void *p, size_t sz); +int acp_sof_ipc_send_msg(struct snd_sof_dev *sdev, + struct snd_sof_ipc_msg *msg); +int acp_sof_ipc_get_mailbox_offset(struct snd_sof_dev *sdev); +int acp_sof_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id); +int acp_sof_ipc_pcm_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, + const struct sof_ipc_pcm_params_reply *reply); +void acp_mailbox_write(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes); +void acp_mailbox_read(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes); + extern const struct snd_sof_dsp_ops sof_renoir_ops; #endif diff --git a/sound/soc/sof/amd/renoir.c b/sound/soc/sof/amd/renoir.c index bca80784b3223..9d95ea66f867d 100644 --- a/sound/soc/sof/amd/renoir.c +++ b/sound/soc/sof/amd/renoir.c @@ -41,6 +41,14 @@ const struct snd_sof_dsp_ops sof_renoir_ops = { /* DSP core boot */ .run = acp_sof_dsp_run, + + /*IPC */ + .send_msg = acp_sof_ipc_send_msg, + .ipc_msg_data = acp_sof_ipc_msg_data, + .ipc_pcm_params = acp_sof_ipc_pcm_params, + .get_mailbox_offset = acp_sof_ipc_get_mailbox_offset, + .irq_thread = acp_sof_ipc_irq_thread, + .fw_ready = sof_fw_ready, }; EXPORT_SYMBOL(sof_renoir_ops); From bda93076d184ad80a8cab09bf29ace7692de18f7 Mon Sep 17 00:00:00 2001 From: Ajit Kumar Pandey Date: Wed, 17 Nov 2021 11:37:18 +0200 Subject: [PATCH 041/327] ASoC: SOF: amd: Add dai driver dsp ops callback for Renoir Add dsp ops callback to register I2S and DMIC sof dai's with ALSA Signed-off-by: Ajit Kumar Pandey Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211117093734.17407-6-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp-dsp-offset.h | 2 + sound/soc/sof/amd/renoir.c | 91 ++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h index 3a1c848020cae..1d11e9d69dce8 100644 --- a/sound/soc/sof/amd/acp-dsp-offset.h +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -47,6 +47,8 @@ #define ACPAXI2AXI_ATU_CTRL 0xC40 #define ACP_SOFT_RESET 0x1000 +#define ACP_I2S_PIN_CONFIG 0x1400 + /* Registers from ACP_PGFSM block */ #define ACP_PGFSM_CONTROL 0x141C #define ACP_PGFSM_STATUS 0x1420 diff --git a/sound/soc/sof/amd/renoir.c b/sound/soc/sof/amd/renoir.c index 9d95ea66f867d..ca5582b3f82d4 100644 --- a/sound/soc/sof/amd/renoir.c +++ b/sound/soc/sof/amd/renoir.c @@ -15,7 +15,94 @@ #include #include "../ops.h" +#include "../sof-audio.h" #include "acp.h" +#include "acp-dsp-offset.h" + +#define I2S_BT_INSTANCE 0 +#define I2S_SP_INSTANCE 1 +#define PDM_DMIC_INSTANCE 2 + +#define I2S_MODE 0x04 + +static int renoir_dai_probe(struct snd_soc_dai *dai) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); + unsigned int val; + + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_I2S_PIN_CONFIG); + if (val != I2S_MODE) { + dev_err(sdev->dev, "I2S Mode is not supported (I2S_PIN_CONFIG: %#x)\n", val); + return -EINVAL; + } + + return 0; +} + +static struct snd_soc_dai_driver renoir_sof_dai[] = { + [I2S_BT_INSTANCE] = { + .id = I2S_BT_INSTANCE, + .name = "acp-sof-bt", + .playback = { + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 96000, + }, + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + /* Supporting only stereo for I2S BT controller capture */ + .channels_min = 2, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 48000, + }, + .probe = &renoir_dai_probe, + }, + + [I2S_SP_INSTANCE] = { + .id = I2S_SP_INSTANCE, + .name = "acp-sof-sp", + .playback = { + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 96000, + }, + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + /* Supporting only stereo for I2S SP controller capture */ + .channels_min = 2, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 48000, + }, + .probe = &renoir_dai_probe, + }, + + [PDM_DMIC_INSTANCE] = { + .id = PDM_DMIC_INSTANCE, + .name = "acp-sof-dmic", + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 4, + .rate_min = 8000, + .rate_max = 48000, + }, + }, +}; /* AMD Renoir DSP ops */ const struct snd_sof_dsp_ops sof_renoir_ops = { @@ -49,6 +136,10 @@ const struct snd_sof_dsp_ops sof_renoir_ops = { .get_mailbox_offset = acp_sof_ipc_get_mailbox_offset, .irq_thread = acp_sof_ipc_irq_thread, .fw_ready = sof_fw_ready, + + /* DAI drivers */ + .drv = renoir_sof_dai, + .num_drv = ARRAY_SIZE(renoir_sof_dai), }; EXPORT_SYMBOL(sof_renoir_ops); From e8afccf8fb75bae9c3292a0e51593af92839415e Mon Sep 17 00:00:00 2001 From: Ajit Kumar Pandey Date: Wed, 17 Nov 2021 11:37:19 +0200 Subject: [PATCH 042/327] ASoC: SOF: amd: Add PCM stream callback for Renoir dai's Add module to support ALSA pcm stream configurations for ACP I2S and DMIC endpoints Signed-off-by: Ajit Kumar Pandey Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211117093734.17407-7-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/Makefile | 2 +- sound/soc/sof/amd/acp-pcm.c | 82 +++++++++++++++ sound/soc/sof/amd/acp-stream.c | 181 +++++++++++++++++++++++++++++++++ sound/soc/sof/amd/acp.c | 2 + sound/soc/sof/amd/acp.h | 28 +++++ sound/soc/sof/amd/renoir.c | 11 ++ 6 files changed, 305 insertions(+), 1 deletion(-) create mode 100644 sound/soc/sof/amd/acp-pcm.c create mode 100644 sound/soc/sof/amd/acp-stream.c diff --git a/sound/soc/sof/amd/Makefile b/sound/soc/sof/amd/Makefile index 29928b16002f6..7b88db9c5fb7f 100644 --- a/sound/soc/sof/amd/Makefile +++ b/sound/soc/sof/amd/Makefile @@ -4,7 +4,7 @@ # # Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. -snd-sof-amd-acp-objs := acp.o acp-loader.o acp-ipc.o +snd-sof-amd-acp-objs := acp.o acp-loader.o acp-ipc.o acp-pcm.o acp-stream.o snd-sof-amd-renoir-objs := renoir.o obj-$(CONFIG_SND_SOC_SOF_AMD_COMMON) += snd-sof-amd-acp.o diff --git a/sound/soc/sof/amd/acp-pcm.c b/sound/soc/sof/amd/acp-pcm.c new file mode 100644 index 0000000000000..5b23830cb1f36 --- /dev/null +++ b/sound/soc/sof/amd/acp-pcm.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2021 Advanced Micro Devices, Inc. +// +// Authors: Ajit Kumar Pandey + +/* + * PCM interface for generic AMD audio ACP DSP block + */ +#include + +#include "../ops.h" +#include "acp.h" +#include "acp-dsp-offset.h" + +int acp_pcm_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct sof_ipc_stream_params *ipc_params) +{ + struct acp_dsp_stream *stream = substream->runtime->private_data; + unsigned int buf_offset, index; + u32 size; + int ret; + + size = ipc_params->buffer.size; + stream->num_pages = ipc_params->buffer.pages; + stream->dmab = substream->runtime->dma_buffer_p; + + ret = acp_dsp_stream_config(sdev, stream); + if (ret < 0) { + dev_err(sdev->dev, "stream configuration failed\n"); + return ret; + } + + ipc_params->buffer.phy_addr = stream->reg_offset; + ipc_params->stream_tag = stream->stream_tag; + + /* write buffer size of stream in scratch memory */ + + buf_offset = offsetof(struct scratch_reg_conf, buf_size); + index = stream->stream_tag - 1; + buf_offset = buf_offset + index * 4; + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + buf_offset, size); + + return 0; +} +EXPORT_SYMBOL_NS(acp_pcm_hw_params, SND_SOC_SOF_AMD_COMMON); + +int acp_pcm_open(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) +{ + struct acp_dsp_stream *stream; + + stream = acp_dsp_stream_get(sdev, 0); + if (!stream) + return -ENODEV; + + substream->runtime->private_data = stream; + stream->substream = substream; + + return 0; +} +EXPORT_SYMBOL_NS(acp_pcm_open, SND_SOC_SOF_AMD_COMMON); + +int acp_pcm_close(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) +{ + struct acp_dsp_stream *stream; + + stream = substream->runtime->private_data; + if (!stream) { + dev_err(sdev->dev, "No open stream\n"); + return -EINVAL; + } + + stream->substream = NULL; + substream->runtime->private_data = NULL; + + return acp_dsp_stream_put(sdev, stream); +} +EXPORT_SYMBOL_NS(acp_pcm_close, SND_SOC_SOF_AMD_COMMON); diff --git a/sound/soc/sof/amd/acp-stream.c b/sound/soc/sof/amd/acp-stream.c new file mode 100644 index 0000000000000..f2837bfbdb207 --- /dev/null +++ b/sound/soc/sof/amd/acp-stream.c @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2021 Advanced Micro Devices, Inc. +// +// Authors: Ajit Kumar Pandey + +/* + * Hardware interface for generic AMD audio DSP ACP IP + */ + +#include "../ops.h" +#include "acp-dsp-offset.h" +#include "acp.h" + +#define PTE_GRP1_OFFSET 0x00000000 +#define PTE_GRP2_OFFSET 0x00800000 +#define PTE_GRP3_OFFSET 0x01000000 +#define PTE_GRP4_OFFSET 0x01800000 +#define PTE_GRP5_OFFSET 0x02000000 +#define PTE_GRP6_OFFSET 0x02800000 +#define PTE_GRP7_OFFSET 0x03000000 +#define PTE_GRP8_OFFSET 0x03800000 + +int acp_dsp_stream_config(struct snd_sof_dev *sdev, struct acp_dsp_stream *stream) +{ + unsigned int pte_reg, pte_size, phy_addr_offset, index; + int stream_tag = stream->stream_tag; + u32 low, high, offset, reg_val; + dma_addr_t addr; + int page_idx; + + switch (stream_tag) { + case 1: + pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_1; + pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1; + offset = offsetof(struct scratch_reg_conf, grp1_pte); + stream->reg_offset = PTE_GRP1_OFFSET; + break; + case 2: + pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_2; + pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_2; + offset = offsetof(struct scratch_reg_conf, grp2_pte); + stream->reg_offset = PTE_GRP2_OFFSET; + break; + case 3: + pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_3; + pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_3; + offset = offsetof(struct scratch_reg_conf, grp3_pte); + stream->reg_offset = PTE_GRP3_OFFSET; + break; + case 4: + pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_4; + pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_4; + offset = offsetof(struct scratch_reg_conf, grp4_pte); + stream->reg_offset = PTE_GRP4_OFFSET; + break; + case 5: + pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_5; + pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5; + offset = offsetof(struct scratch_reg_conf, grp5_pte); + stream->reg_offset = PTE_GRP5_OFFSET; + break; + case 6: + pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_6; + pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_6; + offset = offsetof(struct scratch_reg_conf, grp6_pte); + stream->reg_offset = PTE_GRP6_OFFSET; + break; + case 7: + pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_7; + pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_7; + offset = offsetof(struct scratch_reg_conf, grp7_pte); + stream->reg_offset = PTE_GRP7_OFFSET; + break; + case 8: + pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_8; + pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_8; + offset = offsetof(struct scratch_reg_conf, grp8_pte); + stream->reg_offset = PTE_GRP8_OFFSET; + break; + default: + dev_err(sdev->dev, "Invalid stream tag %d\n", stream_tag); + return -EINVAL; + } + + /* write phy_addr in scratch memory */ + + phy_addr_offset = offsetof(struct scratch_reg_conf, reg_offset); + index = stream_tag - 1; + phy_addr_offset = phy_addr_offset + index * 4; + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + + phy_addr_offset, stream->reg_offset); + + /* Group Enable */ + reg_val = ACP_SRAM_PTE_OFFSET + offset; + snd_sof_dsp_write(sdev, ACP_DSP_BAR, pte_reg, reg_val | BIT(31)); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, pte_size, PAGE_SIZE_4K_ENABLE); + + for (page_idx = 0; page_idx < stream->num_pages; page_idx++) { + addr = snd_sgbuf_get_addr(stream->dmab, page_idx * PAGE_SIZE); + + /* Load the low address of page int ACP SRAM through SRBM */ + low = lower_32_bits(addr); + high = upper_32_bits(addr); + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + offset, low); + + high |= BIT(31); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + offset + 4, high); + /* Move to next physically contiguous page */ + offset += 8; + } + + return 0; +} + +struct acp_dsp_stream *acp_dsp_stream_get(struct snd_sof_dev *sdev, int tag) +{ + struct acp_dev_data *adata = sdev->pdata->hw_pdata; + struct acp_dsp_stream *stream = adata->stream_buf; + int i; + + for (i = 0; i < ACP_MAX_STREAM; i++, stream++) { + if (stream->active) + continue; + + /* return stream if tag not specified*/ + if (!tag) { + stream->active = 1; + return stream; + } + + /* check if this is the requested stream tag */ + if (stream->stream_tag == tag) { + stream->active = 1; + return stream; + } + } + + dev_err(sdev->dev, "stream %d active or no inactive stream\n", tag); + return NULL; +} +EXPORT_SYMBOL_NS(acp_dsp_stream_get, SND_SOC_SOF_AMD_COMMON); + +int acp_dsp_stream_put(struct snd_sof_dev *sdev, + struct acp_dsp_stream *acp_stream) +{ + struct acp_dev_data *adata = sdev->pdata->hw_pdata; + struct acp_dsp_stream *stream = adata->stream_buf; + int i; + + /* Free an active stream */ + for (i = 0; i < ACP_MAX_STREAM; i++, stream++) { + if (stream == acp_stream) { + stream->active = 0; + return 0; + } + } + + dev_err(sdev->dev, "Cannot find active stream tag %d\n", acp_stream->stream_tag); + return -EINVAL; +} +EXPORT_SYMBOL_NS(acp_dsp_stream_put, SND_SOC_SOF_AMD_COMMON); + +int acp_dsp_stream_init(struct snd_sof_dev *sdev) +{ + struct acp_dev_data *adata = sdev->pdata->hw_pdata; + int i; + + for (i = 0; i < ACP_MAX_STREAM; i++) { + adata->stream_buf[i].sdev = sdev; + adata->stream_buf[i].active = 0; + adata->stream_buf[i].stream_tag = i + 1; + } + return 0; +} +EXPORT_SYMBOL_NS(acp_dsp_stream_init, SND_SOC_SOF_AMD_COMMON); diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 43a57d15e3caf..74ede28aa8d84 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -363,6 +363,8 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) acp_memory_init(sdev); + acp_dsp_stream_init(sdev); + return 0; } EXPORT_SYMBOL_NS(amd_sof_acp_probe, SND_SOC_SOF_AMD_COMMON); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index ac8340119125c..36d000c3f7929 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -13,6 +13,8 @@ #include "../sof-priv.h" +#define ACP_MAX_STREAM 8 + #define ACP_DSP_BAR 0 #define ACP_REG_POLL_INTERVAL 500 @@ -114,6 +116,17 @@ struct scratch_reg_conf { unsigned int reserve[]; }; +struct acp_dsp_stream { + struct list_head list; + struct snd_sof_dev *sdev; + struct snd_pcm_substream *substream; + struct snd_dma_buffer *dmab; + int num_pages; + int stream_tag; + int active; + unsigned int reg_offset; +}; + /* Common device data struct for ACP devices */ struct acp_dev_data { struct snd_sof_dev *dev; @@ -125,6 +138,7 @@ struct acp_dev_data { dma_addr_t dma_addr; u8 *data_buf; struct dma_descriptor dscr_info[ACP_MAX_DESC]; + struct acp_dsp_stream stream_buf[ACP_MAX_STREAM]; }; void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes); @@ -165,5 +179,19 @@ int acp_sof_ipc_pcm_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *s void acp_mailbox_write(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes); void acp_mailbox_read(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes); +/* ACP - DSP stream callbacks */ +int acp_dsp_stream_config(struct snd_sof_dev *sdev, struct acp_dsp_stream *stream); +int acp_dsp_stream_init(struct snd_sof_dev *sdev); +struct acp_dsp_stream *acp_dsp_stream_get(struct snd_sof_dev *sdev, int tag); +int acp_dsp_stream_put(struct snd_sof_dev *sdev, struct acp_dsp_stream *acp_stream); + +/* + * DSP PCM Operations. + */ +int acp_pcm_open(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream); +int acp_pcm_close(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream); +int acp_pcm_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct sof_ipc_stream_params *ipc_params); + extern const struct snd_sof_dsp_ops sof_renoir_ops; #endif diff --git a/sound/soc/sof/amd/renoir.c b/sound/soc/sof/amd/renoir.c index ca5582b3f82d4..0241c5dce156a 100644 --- a/sound/soc/sof/amd/renoir.c +++ b/sound/soc/sof/amd/renoir.c @@ -140,6 +140,17 @@ const struct snd_sof_dsp_ops sof_renoir_ops = { /* DAI drivers */ .drv = renoir_sof_dai, .num_drv = ARRAY_SIZE(renoir_sof_dai), + + /* stream callbacks */ + .pcm_open = acp_pcm_open, + .pcm_close = acp_pcm_close, + .pcm_hw_params = acp_pcm_hw_params, + + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, }; EXPORT_SYMBOL(sof_renoir_ops); From f1bdd8d385a803565024c8feeedc17bf86aac4f5 Mon Sep 17 00:00:00 2001 From: Ajit Kumar Pandey Date: Wed, 17 Nov 2021 11:37:20 +0200 Subject: [PATCH 043/327] ASoC: amd: Add module to determine ACP configuration ACP hw block configuration differs across various distributions and hence it's required to register different drivers module for distributions. For now we support three ACP drivers: * ACP without SOF use case * ACP with SOF use case * ACP with SOF use case for DMIC and non SOF for I2S endpoints As all above driver registers with common PCI ID for ACP hw block we need code to determine ACP configuration and auto select driver module. This patch expose function that return configuration flag based on dmi checks for a system. ACP driver module probe register platform device based on such configuration flag to avoid conflict with other ACP drivers probed for same PCI ID. Signed-off-by: Ajit Kumar Pandey Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211117093734.17407-8-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/amd/Kconfig | 6 +++ sound/soc/amd/Makefile | 2 + sound/soc/amd/acp-config.c | 81 +++++++++++++++++++++++++++++++++++++ sound/soc/amd/mach-config.h | 29 +++++++++++++ 4 files changed, 118 insertions(+) create mode 100644 sound/soc/amd/acp-config.c create mode 100644 sound/soc/amd/mach-config.h diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig index 2c6af3f8f2961..092966ff5ea7d 100644 --- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -96,4 +96,10 @@ config SND_SOC_AMD_YC_MACH Say m if you have such a device. If unsure select "N". +config SND_AMD_ACP_CONFIG + tristate "AMD ACP configuration selection" + help + This option adds an auto detection to determine which ACP + driver modules to use + source "sound/soc/amd/acp/Kconfig" diff --git a/sound/soc/amd/Makefile b/sound/soc/amd/Makefile index f1d42bbda7095..4b1f77930a4a8 100644 --- a/sound/soc/amd/Makefile +++ b/sound/soc/amd/Makefile @@ -3,6 +3,7 @@ acp_audio_dma-objs := acp-pcm-dma.o snd-soc-acp-da7219mx98357-mach-objs := acp-da7219-max98357a.o snd-soc-acp-rt5645-mach-objs := acp-rt5645.o snd-soc-acp-rt5682-mach-objs := acp3x-rt5682-max9836.o +snd-acp-config-objs := acp-config.o obj-$(CONFIG_SND_SOC_AMD_ACP) += acp_audio_dma.o obj-$(CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH) += snd-soc-acp-da7219mx98357-mach.o @@ -13,3 +14,4 @@ obj-$(CONFIG_SND_SOC_AMD_RENOIR) += renoir/ obj-$(CONFIG_SND_SOC_AMD_ACP5x) += vangogh/ obj-$(CONFIG_SND_SOC_AMD_ACP6x) += yc/ obj-$(CONFIG_SND_SOC_AMD_ACP_COMMON) += acp/ +obj-$(CONFIG_SND_AMD_ACP_CONFIG) += snd-acp-config.o diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c new file mode 100644 index 0000000000000..c9abbb46b6f51 --- /dev/null +++ b/sound/soc/amd/acp-config.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2021 Advanced Micro Devices, Inc. +// +// Authors: Ajit Kumar Pandey +// + +/* ACP machine configuration module */ + +#include +#include +#include +#include +#include + +#include "../sof/amd/acp.h" +#include "mach-config.h" + +static int acp_quirk_data; + +static const struct config_entry config_table[] = { + { + .flags = FLAG_AMD_SOF, + .device = ACP_PCI_DEV_ID, + .dmi_table = (const struct dmi_system_id []) { + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "AMD"), + DMI_MATCH(DMI_PRODUCT_NAME, "Majolica-CZN"), + }, + }, + {} + }, + }, +}; + +int snd_amd_acp_find_config(struct pci_dev *pci) +{ + const struct config_entry *table = config_table; + u16 device = pci->device; + int i; + + for (i = 0; i < ARRAY_SIZE(config_table); i++, table++) { + if (table->device != device) + continue; + if (table->dmi_table && !dmi_check_system(table->dmi_table)) + continue; + acp_quirk_data = table->flags; + return table->flags; + } + + return 0; +} +EXPORT_SYMBOL(snd_amd_acp_find_config); + +struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[] = { + { + .id = "AMDI1019", + .drv_name = "renoir-dsp", + .pdata = (void *)&acp_quirk_data, + .fw_filename = "sof-rn.ri", + .sof_tplg_filename = "sof-acp.tplg", + }, + {}, +}; +EXPORT_SYMBOL(snd_soc_acpi_amd_sof_machines); + +struct snd_soc_acpi_mach snd_soc_acpi_amd_acp_machines[] = { + { + .id = "AMDI1019", + .drv_name = "renoir-acp", + .pdata = (void *)&acp_quirk_data, + }, + {}, +}; +EXPORT_SYMBOL(snd_soc_acpi_amd_acp_machines); + +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/amd/mach-config.h b/sound/soc/amd/mach-config.h new file mode 100644 index 0000000000000..608f1e1997754 --- /dev/null +++ b/sound/soc/amd/mach-config.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. + * + * Author: Ajit Kumar Pandey + */ +#ifndef __AMD_MACH_CONFIG_H +#define __AMD_MACH_CONFIG_H + +#include + +#define FLAG_AMD_SOF BIT(1) +#define FLAG_AMD_SOF_ONLY_DMIC BIT(2) + +#define ACP_PCI_DEV_ID 0x15E2 + +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp_machines[]; + +struct config_entry { + u32 flags; + u16 device; + const struct dmi_system_id *dmi_table; +}; + +#endif From 11ddd4e371810017faf7ff7cb2349f321e50d1d3 Mon Sep 17 00:00:00 2001 From: Ajit Kumar Pandey Date: Wed, 17 Nov 2021 11:37:21 +0200 Subject: [PATCH 044/327] ASoC: SOF: amd: Add machine driver dsp ops for Renoir platform Add dsp ops callback to select and register machine driver. Signed-off-by: Ajit Kumar Pandey Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211117093734.17407-9-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/renoir.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/sound/soc/sof/amd/renoir.c b/sound/soc/sof/amd/renoir.c index 0241c5dce156a..3cd269bfe75dd 100644 --- a/sound/soc/sof/amd/renoir.c +++ b/sound/soc/sof/amd/renoir.c @@ -104,6 +104,23 @@ static struct snd_soc_dai_driver renoir_sof_dai[] = { }, }; +static void amd_sof_machine_select(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *sof_pdata = sdev->pdata; + const struct sof_dev_desc *desc = sof_pdata->desc; + struct snd_soc_acpi_mach *mach; + + mach = snd_soc_acpi_find_machine(desc->machines); + if (!mach) { + dev_warn(sdev->dev, "No matching ASoC machine driver found\n"); + return; + } + + sof_pdata->tplg_filename = mach->sof_tplg_filename; + sof_pdata->fw_filename = mach->fw_filename; + sof_pdata->machine = mach; +} + /* AMD Renoir DSP ops */ const struct snd_sof_dsp_ops sof_renoir_ops = { /* probe and remove */ @@ -151,6 +168,11 @@ const struct snd_sof_dsp_ops sof_renoir_ops = { SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, + + /* Machine driver callbacks */ + .machine_select = amd_sof_machine_select, + .machine_register = sof_machine_register, + .machine_unregister = sof_machine_unregister, }; EXPORT_SYMBOL(sof_renoir_ops); From ec25a3b14261fcb05568a1fec15ca68152e9d208 Mon Sep 17 00:00:00 2001 From: Ajit Kumar Pandey Date: Wed, 17 Nov 2021 11:37:22 +0200 Subject: [PATCH 045/327] ASoC: SOF: amd: Add Renoir PCI driver interface Add PCI driver module to enable sof pci device support for Renoir. If machine flag set to FLAG_SOF_ONLY_DMIC this pci driver register platform device for non dsp based I2S platform device. If machine flag is not enabled for SOF pci probe will return without invoking sof device probe and registration Signed-off-by: Ajit Kumar Pandey Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211117093734.17407-10-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/Kconfig | 5 +- sound/soc/sof/amd/Makefile | 2 +- sound/soc/sof/amd/acp.h | 3 + sound/soc/sof/amd/pci-rn.c | 160 +++++++++++++++++++++++++++++++++++++ 4 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 sound/soc/sof/amd/pci-rn.c diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig index 400dd5a24ae6a..085232e04582e 100644 --- a/sound/soc/sof/amd/Kconfig +++ b/sound/soc/sof/amd/Kconfig @@ -17,14 +17,17 @@ if SND_SOC_SOF_AMD_TOPLEVEL config SND_SOC_SOF_AMD_COMMON tristate select SND_SOC_SOF + select SND_SOC_SOF_PCI_DEV + select SND_AMD_ACP_CONFIG + select SND_SOC_ACPI if ACPI help This option is not user-selectable but automatically handled by 'select' statements at a higher level config SND_SOC_SOF_AMD_RENOIR tristate "SOF support for RENOIR" + depends on SND_SOC_SOF_PCI select SND_SOC_SOF_AMD_COMMON help Select this option for SOF support on AMD Renoir platform - endif diff --git a/sound/soc/sof/amd/Makefile b/sound/soc/sof/amd/Makefile index 7b88db9c5fb7f..b27ce50014b8f 100644 --- a/sound/soc/sof/amd/Makefile +++ b/sound/soc/sof/amd/Makefile @@ -5,7 +5,7 @@ # Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. snd-sof-amd-acp-objs := acp.o acp-loader.o acp-ipc.o acp-pcm.o acp-stream.o -snd-sof-amd-renoir-objs := renoir.o +snd-sof-amd-renoir-objs := pci-rn.o renoir.o obj-$(CONFIG_SND_SOC_SOF_AMD_COMMON) += snd-sof-amd-acp.o obj-$(CONFIG_SND_SOC_SOF_AMD_RENOIR) +=snd-sof-amd-renoir.o diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 36d000c3f7929..5f6e9eff116a3 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -194,4 +194,7 @@ int acp_pcm_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substr struct snd_pcm_hw_params *params, struct sof_ipc_stream_params *ipc_params); extern const struct snd_sof_dsp_ops sof_renoir_ops; + +/* Machine configuration */ +int snd_amd_acp_find_config(struct pci_dev *pci); #endif diff --git a/sound/soc/sof/amd/pci-rn.c b/sound/soc/sof/amd/pci-rn.c new file mode 100644 index 0000000000000..3c379a5ef2315 --- /dev/null +++ b/sound/soc/sof/amd/pci-rn.c @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. +// +// Authors: Ajit Kumar Pandey + +/* + * PCI interface for Renoir ACP device + */ + +#include +#include +#include +#include +#include + +#include "../ops.h" +#include "../sof-pci-dev.h" +#include "../../amd/mach-config.h" +#include "acp.h" + +#define ACP3x_REG_START 0x1240000 +#define ACP3x_REG_END 0x125C000 + +static struct platform_device *dmic_dev; +static struct platform_device *pdev; + +static const struct resource renoir_res[] = { + { + .start = 0, + .end = ACP3x_REG_END - ACP3x_REG_START, + .name = "acp_mem", + .flags = IORESOURCE_MEM, + }, + { + .start = 0, + .end = 0, + .name = "acp_dai_irq", + .flags = IORESOURCE_IRQ, + }, +}; + +static const struct sof_dev_desc renoir_desc = { + .machines = snd_soc_acpi_amd_sof_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .default_fw_path = "amd/sof", + .default_tplg_path = "amd/sof-tplg", + .default_fw_filename = "sof-rn.ri", + .nocodec_tplg_filename = "sof-acp.tplg", + .ops = &sof_renoir_ops, +}; + +static int acp_pci_rn_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) +{ + struct platform_device_info pdevinfo; + struct device *dev = &pci->dev; + const struct resource *res_i2s; + struct resource *res; + unsigned int flag, i, addr; + int ret; + + flag = snd_amd_acp_find_config(pci); + if (flag != FLAG_AMD_SOF && flag != FLAG_AMD_SOF_ONLY_DMIC) + return -ENODEV; + + ret = sof_pci_probe(pci, pci_id); + if (ret != 0) + return ret; + + dmic_dev = platform_device_register_data(dev, "dmic-codec", PLATFORM_DEVID_NONE, NULL, 0); + if (IS_ERR(dmic_dev)) { + dev_err(dev, "failed to create DMIC device\n"); + sof_pci_remove(pci); + return PTR_ERR(dmic_dev); + } + + /* Register platform device only if flag set to FLAG_AMD_SOF_ONLY_DMIC */ + if (flag != FLAG_AMD_SOF_ONLY_DMIC) + return 0; + + addr = pci_resource_start(pci, 0); + res = devm_kzalloc(&pci->dev, sizeof(struct resource) * ARRAY_SIZE(renoir_res), GFP_KERNEL); + if (!res) { + sof_pci_remove(pci); + return -ENOMEM; + } + + res_i2s = renoir_res; + for (i = 0; i < ARRAY_SIZE(renoir_res); i++, res_i2s++) { + res[i].name = res_i2s->name; + res[i].flags = res_i2s->flags; + res[i].start = addr + res_i2s->start; + res[i].end = addr + res_i2s->end; + if (res_i2s->flags == IORESOURCE_IRQ) { + res[i].start = pci->irq; + res[i].end = res[i].start; + } + } + + memset(&pdevinfo, 0, sizeof(pdevinfo)); + + /* + * We have common PCI driver probe for ACP device but we have to support I2S without SOF + * for some distributions. Register platform device that will be used to support non dsp + * ACP's audio ends points on some machines. + */ + + pdevinfo.name = "acp_asoc_renoir"; + pdevinfo.id = 0; + pdevinfo.parent = &pci->dev; + pdevinfo.num_res = ARRAY_SIZE(renoir_res); + pdevinfo.res = &res[0]; + + pdev = platform_device_register_full(&pdevinfo); + if (IS_ERR(pdev)) { + dev_err(&pci->dev, "cannot register %s device\n", pdevinfo.name); + sof_pci_remove(pci); + platform_device_unregister(dmic_dev); + ret = PTR_ERR(pdev); + } + + return ret; +}; + +static void acp_pci_rn_remove(struct pci_dev *pci) +{ + if (dmic_dev) + platform_device_unregister(dmic_dev); + if (pdev) + platform_device_unregister(pdev); + + return sof_pci_remove(pci); +} + +/* PCI IDs */ +static const struct pci_device_id rn_pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_PCI_DEV_ID), + .driver_data = (unsigned long)&renoir_desc}, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, rn_pci_ids); + +/* pci_driver definition */ +static struct pci_driver snd_sof_pci_amd_rn_driver = { + .name = KBUILD_MODNAME, + .id_table = rn_pci_ids, + .probe = acp_pci_rn_probe, + .remove = acp_pci_rn_remove, +}; +module_pci_driver(snd_sof_pci_amd_rn_driver); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON); +MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); From 63fba90fc88b6cee9f8bead761a419169ecda6cc Mon Sep 17 00:00:00 2001 From: Ajit Kumar Pandey Date: Wed, 17 Nov 2021 11:37:23 +0200 Subject: [PATCH 046/327] ASoC: amd: acp-config: Remove legacy acpi based machine struct We have moved legacy based machine struct into platform driver to resolve module dependency with non-SOF ALSA build, hence removed it from acp-config driver module. Signed-off-by: Ajit Kumar Pandey Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211117093734.17407-11-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/amd/acp-config.c | 10 ---------- sound/soc/amd/mach-config.h | 1 - 2 files changed, 11 deletions(-) diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c index c9abbb46b6f51..1493d52c92907 100644 --- a/sound/soc/amd/acp-config.c +++ b/sound/soc/amd/acp-config.c @@ -68,14 +68,4 @@ struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[] = { }; EXPORT_SYMBOL(snd_soc_acpi_amd_sof_machines); -struct snd_soc_acpi_mach snd_soc_acpi_amd_acp_machines[] = { - { - .id = "AMDI1019", - .drv_name = "renoir-acp", - .pdata = (void *)&acp_quirk_data, - }, - {}, -}; -EXPORT_SYMBOL(snd_soc_acpi_amd_acp_machines); - MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/amd/mach-config.h b/sound/soc/amd/mach-config.h index 608f1e1997754..feb3756d9ac4e 100644 --- a/sound/soc/amd/mach-config.h +++ b/sound/soc/amd/mach-config.h @@ -18,7 +18,6 @@ #define ACP_PCI_DEV_ID 0x15E2 extern struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[]; -extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp_machines[]; struct config_entry { u32 flags; From efb931cdc4b94a0f7ed17a76844f08cef1bdffe5 Mon Sep 17 00:00:00 2001 From: Ajit Kumar Pandey Date: Wed, 17 Nov 2021 11:37:24 +0200 Subject: [PATCH 047/327] ASoC: SOF: topology: Add support for AMD ACP DAIs Add new sof dais and config to pass topology file configuration to SOF firmware running on ACP's DSP core. ACP firmware support I2S_BT, I2S_SP and DMIC controller hence add three new dais to the list of supported sof_dais Signed-off-by: Ajit Kumar Pandey Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211117093734.17407-12-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- include/sound/sof/dai-amd.h | 21 +++++++ include/sound/sof/dai.h | 7 +++ sound/soc/sof/pcm.c | 36 ++++++++++++ sound/soc/sof/topology.c | 109 ++++++++++++++++++++++++++++++++++++ 4 files changed, 173 insertions(+) create mode 100644 include/sound/sof/dai-amd.h diff --git a/include/sound/sof/dai-amd.h b/include/sound/sof/dai-amd.h new file mode 100644 index 0000000000000..90d09dbdd709b --- /dev/null +++ b/include/sound/sof/dai-amd.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2021 Advanced Micro Devices, Inc.. All rights reserved. + */ + +#ifndef __INCLUDE_SOUND_SOF_DAI_AMD_H__ +#define __INCLUDE_SOUND_SOF_DAI_AMD_H__ + +#include + +/* ACP Configuration Request - SOF_IPC_DAI_AMD_CONFIG */ +struct sof_ipc_dai_acp_params { + struct sof_ipc_hdr hdr; + + uint32_t fsync_rate; /* FSYNC frequency in Hz */ + uint32_t tdm_slots; +} __packed; +#endif diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h index 9625f47557b8e..3782127a70956 100644 --- a/include/sound/sof/dai.h +++ b/include/sound/sof/dai.h @@ -12,6 +12,7 @@ #include #include #include +#include /* * DAI Configuration. @@ -66,6 +67,9 @@ enum sof_ipc_dai_type { SOF_DAI_INTEL_ALH, /**< Intel ALH */ SOF_DAI_IMX_SAI, /**< i.MX SAI */ SOF_DAI_IMX_ESAI, /**< i.MX ESAI */ + SOF_DAI_AMD_BT, /**< AMD ACP BT*/ + SOF_DAI_AMD_SP, /**< AMD ACP SP */ + SOF_DAI_AMD_DMIC, /**< AMD ACP DMIC */ }; /* general purpose DAI configuration */ @@ -90,6 +94,9 @@ struct sof_ipc_dai_config { struct sof_ipc_dai_alh_params alh; struct sof_ipc_dai_esai_params esai; struct sof_ipc_dai_sai_params sai; + struct sof_ipc_dai_acp_params acpbt; + struct sof_ipc_dai_acp_params acpsp; + struct sof_ipc_dai_acp_params acpdmic; }; } __packed; diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index fa0bfcd2474e0..8d313c9862cb5 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -826,6 +826,42 @@ int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_pa "channels_min: %d channels_max: %d\n", channels->min, channels->max); break; + case SOF_DAI_AMD_BT: + rate->min = dai->dai_config->acpbt.fsync_rate; + rate->max = dai->dai_config->acpbt.fsync_rate; + channels->min = dai->dai_config->acpbt.tdm_slots; + channels->max = dai->dai_config->acpbt.tdm_slots; + + dev_dbg(component->dev, + "AMD_BT rate_min: %d rate_max: %d\n", rate->min, rate->max); + dev_dbg(component->dev, + "AMD_BT channels_min: %d channels_max: %d\n", + channels->min, channels->max); + break; + case SOF_DAI_AMD_SP: + rate->min = dai->dai_config->acpsp.fsync_rate; + rate->max = dai->dai_config->acpsp.fsync_rate; + channels->min = dai->dai_config->acpsp.tdm_slots; + channels->max = dai->dai_config->acpsp.tdm_slots; + + dev_dbg(component->dev, + "AMD_SP rate_min: %d rate_max: %d\n", rate->min, rate->max); + dev_dbg(component->dev, + "AMD_SP channels_min: %d channels_max: %d\n", + channels->min, channels->max); + break; + case SOF_DAI_AMD_DMIC: + rate->min = dai->dai_config->acpdmic.fsync_rate; + rate->max = dai->dai_config->acpdmic.fsync_rate; + channels->min = dai->dai_config->acpdmic.tdm_slots; + channels->max = dai->dai_config->acpdmic.tdm_slots; + + dev_dbg(component->dev, + "AMD_DMIC rate_min: %d rate_max: %d\n", rate->min, rate->max); + dev_dbg(component->dev, + "AMD_DMIC channels_min: %d channels_max: %d\n", + channels->min, channels->max); + break; default: dev_err(component->dev, "error: invalid DAI type %d\n", dai->dai_config->type); diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index bb9e62bbe5db9..72e671c15a347 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -376,6 +376,9 @@ static const struct sof_dai_types sof_dais[] = { {"ALH", SOF_DAI_INTEL_ALH}, {"SAI", SOF_DAI_IMX_SAI}, {"ESAI", SOF_DAI_IMX_ESAI}, + {"ACP", SOF_DAI_AMD_BT}, + {"ACPSP", SOF_DAI_AMD_SP}, + {"ACPDMIC", SOF_DAI_AMD_DMIC}, }; static enum sof_ipc_dai_type find_dai(const char *name) @@ -2992,6 +2995,102 @@ static int sof_link_esai_load(struct snd_soc_component *scomp, int index, return ret; } +static int sof_link_acp_dmic_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg, + struct snd_soc_tplg_hw_config *hw_config, + struct sof_ipc_dai_config *config) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + u32 size = sizeof(*config); + int ret; + + /* handle master/slave and inverted clocks */ + sof_dai_set_format(hw_config, config); + + /* init IPC */ + memset(&config->acpdmic, 0, sizeof(struct sof_ipc_dai_acp_params)); + config->hdr.size = size; + + config->acpdmic.fsync_rate = le32_to_cpu(hw_config->fsync_rate); + config->acpdmic.tdm_slots = le32_to_cpu(hw_config->tdm_slots); + + dev_info(scomp->dev, "ACP_DMIC config ACP%d channel %d rate %d\n", + config->dai_index, config->acpdmic.tdm_slots, + config->acpdmic.fsync_rate); + + /* set config for all DAI's with name matching the link name */ + ret = sof_set_dai_config(sdev, size, link, config); + if (ret < 0) + dev_err(scomp->dev, "ACP_DMIC failed to save DAI config for ACP%d\n", + config->dai_index); + return ret; +} + +static int sof_link_acp_bt_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg, + struct snd_soc_tplg_hw_config *hw_config, + struct sof_ipc_dai_config *config) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + u32 size = sizeof(*config); + int ret; + + /* handle master/slave and inverted clocks */ + sof_dai_set_format(hw_config, config); + + /* init IPC */ + memset(&config->acpbt, 0, sizeof(struct sof_ipc_dai_acp_params)); + config->hdr.size = size; + + config->acpbt.fsync_rate = le32_to_cpu(hw_config->fsync_rate); + config->acpbt.tdm_slots = le32_to_cpu(hw_config->tdm_slots); + + dev_info(scomp->dev, "ACP_BT config ACP%d channel %d rate %d\n", + config->dai_index, config->acpbt.tdm_slots, + config->acpbt.fsync_rate); + + /* set config for all DAI's with name matching the link name */ + ret = sof_set_dai_config(sdev, size, link, config); + if (ret < 0) + dev_err(scomp->dev, "ACP_BT failed to save DAI config for ACP%d\n", + config->dai_index); + return ret; +} + +static int sof_link_acp_sp_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg, + struct snd_soc_tplg_hw_config *hw_config, + struct sof_ipc_dai_config *config) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + u32 size = sizeof(*config); + int ret; + + /* handle master/slave and inverted clocks */ + sof_dai_set_format(hw_config, config); + + /* init IPC */ + memset(&config->acpsp, 0, sizeof(struct sof_ipc_dai_acp_params)); + config->hdr.size = size; + + config->acpsp.fsync_rate = le32_to_cpu(hw_config->fsync_rate); + config->acpsp.tdm_slots = le32_to_cpu(hw_config->tdm_slots); + + dev_info(scomp->dev, "ACP_SP config ACP%d channel %d rate %d\n", + config->dai_index, config->acpsp.tdm_slots, + config->acpsp.fsync_rate); + + /* set config for all DAI's with name matching the link name */ + ret = sof_set_dai_config(sdev, size, link, config); + if (ret < 0) + dev_err(scomp->dev, "ACP_SP failed to save DAI config for ACP%d\n", + config->dai_index); + return ret; +} + static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, struct snd_soc_dai_link *link, struct snd_soc_tplg_link_config *cfg, @@ -3277,6 +3376,16 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, case SOF_DAI_IMX_ESAI: ret = sof_link_esai_load(scomp, index, link, cfg, hw_config + curr_conf, config); break; + case SOF_DAI_AMD_BT: + ret = sof_link_acp_bt_load(scomp, index, link, cfg, hw_config + curr_conf, config); + break; + case SOF_DAI_AMD_SP: + ret = sof_link_acp_sp_load(scomp, index, link, cfg, hw_config + curr_conf, config); + break; + case SOF_DAI_AMD_DMIC: + ret = sof_link_acp_dmic_load(scomp, index, link, cfg, hw_config + curr_conf, + config); + break; default: dev_err(scomp->dev, "error: invalid DAI type %d\n", common_config.type); ret = -EINVAL; From 4627421fb883928af5220c66a304bed1f9b77e8d Mon Sep 17 00:00:00 2001 From: V sujith kumar Reddy Date: Wed, 17 Nov 2021 11:37:25 +0200 Subject: [PATCH 048/327] ASoC: SOF: amd: Add trace logger support Add trace support and configure trace stream for ACP firmware. Signed-off-by: Vishnuvardhanrao Ravuapati Signed-off-by: V sujith kumar Reddy Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211117093734.17407-13-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/Makefile | 2 +- sound/soc/sof/amd/acp-trace.c | 84 +++++++++++++++++++++++++++++++++++ sound/soc/sof/amd/acp.h | 5 +++ sound/soc/sof/amd/renoir.c | 4 ++ 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 sound/soc/sof/amd/acp-trace.c diff --git a/sound/soc/sof/amd/Makefile b/sound/soc/sof/amd/Makefile index b27ce50014b8f..7b9f1a0af3c87 100644 --- a/sound/soc/sof/amd/Makefile +++ b/sound/soc/sof/amd/Makefile @@ -4,7 +4,7 @@ # # Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. -snd-sof-amd-acp-objs := acp.o acp-loader.o acp-ipc.o acp-pcm.o acp-stream.o +snd-sof-amd-acp-objs := acp.o acp-loader.o acp-ipc.o acp-pcm.o acp-stream.o acp-trace.o snd-sof-amd-renoir-objs := pci-rn.o renoir.o obj-$(CONFIG_SND_SOC_SOF_AMD_COMMON) += snd-sof-amd-acp.o diff --git a/sound/soc/sof/amd/acp-trace.c b/sound/soc/sof/amd/acp-trace.c new file mode 100644 index 0000000000000..fa4da89471860 --- /dev/null +++ b/sound/soc/sof/amd/acp-trace.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. +// +// Authors: Vishnuvardhanrao Ravuapati +// V Sujith Kumar Reddy + +/*This file support Host TRACE Logger driver callback for SOF FW */ + +#include "acp.h" + +#define ACP_LOGGER_STREAM 8 +#define NUM_PAGES 16 + +int acp_sof_trace_release(struct snd_sof_dev *sdev) +{ + struct acp_dsp_stream *stream; + struct acp_dev_data *adata; + int ret; + + adata = sdev->pdata->hw_pdata; + stream = adata->dtrace_stream; + ret = acp_dsp_stream_put(sdev, stream); + if (ret < 0) { + dev_err(sdev->dev, "Failed to release trace stream\n"); + return ret; + } + + adata->dtrace_stream = NULL; + return 0; +} +EXPORT_SYMBOL_NS(acp_sof_trace_release, SND_SOC_SOF_AMD_COMMON); + +static int acp_sof_trace_prepare(struct snd_sof_dev *sdev, + struct sof_ipc_dma_trace_params_ext *params) +{ + struct acp_dsp_stream *stream; + struct acp_dev_data *adata; + int ret; + + adata = sdev->pdata->hw_pdata; + stream = adata->dtrace_stream; + stream->dmab = &sdev->dmatb; + stream->num_pages = NUM_PAGES; + + ret = acp_dsp_stream_config(sdev, stream); + if (ret < 0) { + dev_err(sdev->dev, "Failed to configure trace stream\n"); + return ret; + } + + params->buffer.phy_addr = stream->reg_offset; + params->stream_tag = stream->stream_tag; + + return 0; +} + +int acp_sof_trace_init(struct snd_sof_dev *sdev, u32 *stream_tag) +{ + struct sof_ipc_dma_trace_params_ext *params; + struct acp_dsp_stream *stream; + struct acp_dev_data *adata; + int ret; + + adata = sdev->pdata->hw_pdata; + stream = acp_dsp_stream_get(sdev, ACP_LOGGER_STREAM); + if (!stream) + return -ENODEV; + + adata->dtrace_stream = stream; + params = container_of(stream_tag, struct sof_ipc_dma_trace_params_ext, stream_tag); + ret = acp_sof_trace_prepare(sdev, params); + if (ret < 0) { + acp_dsp_stream_put(sdev, stream); + return ret; + } + + *stream_tag = stream->stream_tag; + return 0; +} +EXPORT_SYMBOL_NS(acp_sof_trace_init, SND_SOC_SOF_AMD_COMMON); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 5f6e9eff116a3..fd923f72a01ad 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -139,6 +139,7 @@ struct acp_dev_data { u8 *data_buf; struct dma_descriptor dscr_info[ACP_MAX_DESC]; struct acp_dsp_stream stream_buf[ACP_MAX_STREAM]; + struct acp_dsp_stream *dtrace_stream; }; void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes); @@ -197,4 +198,8 @@ extern const struct snd_sof_dsp_ops sof_renoir_ops; /* Machine configuration */ int snd_amd_acp_find_config(struct pci_dev *pci); + +/* Trace */ +int acp_sof_trace_init(struct snd_sof_dev *sdev, u32 *stream_tag); +int acp_sof_trace_release(struct snd_sof_dev *sdev); #endif diff --git a/sound/soc/sof/amd/renoir.c b/sound/soc/sof/amd/renoir.c index 3cd269bfe75dd..43037109e130c 100644 --- a/sound/soc/sof/amd/renoir.c +++ b/sound/soc/sof/amd/renoir.c @@ -173,6 +173,10 @@ const struct snd_sof_dsp_ops sof_renoir_ops = { .machine_select = amd_sof_machine_select, .machine_register = sof_machine_register, .machine_unregister = sof_machine_unregister, + + /* Trace Logger */ + .trace_init = acp_sof_trace_init, + .trace_release = acp_sof_trace_release, }; EXPORT_SYMBOL(sof_renoir_ops); From f063eba3e7a6aeec8e2abb00469e70c51432453b Mon Sep 17 00:00:00 2001 From: Ajit Kumar Pandey Date: Wed, 17 Nov 2021 11:37:26 +0200 Subject: [PATCH 049/327] ASoC: SOF: amd: Add support for SOF firmware authentication Add callback to notify PSP after loading firmware on DSP. PSP will validate the loaded firmware and set qualifier bit to run firmware on secured AMD systems. Signed-off-by: Julian Schroeder Signed-off-by: Ajit Kumar Pandey Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Curtis Malainey Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211117093734.17407-14-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp-dsp-offset.h | 4 ++ sound/soc/sof/amd/acp.c | 66 +++++++++++++++++++++++++++++- sound/soc/sof/amd/acp.h | 21 ++++++++++ sound/soc/sof/amd/pci-rn.c | 5 +++ 4 files changed, 95 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h index 1d11e9d69dce8..63f13c111b241 100644 --- a/sound/soc/sof/amd/acp-dsp-offset.h +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -54,6 +54,9 @@ #define ACP_PGFSM_STATUS 0x1420 /* Registers from ACP_INTR block */ +#define ACP_EXTERNAL_INTR_ENB 0x1800 +#define ACP_EXTERNAL_INTR_CNTL 0x1804 +#define ACP_EXTERNAL_INTR_STAT 0x1808 #define ACP_DSP_SW_INTR_CNTL 0x1814 #define ACP_DSP_SW_INTR_STAT 0x1818 #define ACP_SW_INTR_TRIG 0x181C @@ -68,6 +71,7 @@ #define ACP_SHA_DMA_CMD_STS 0x1CC0 #define ACP_SHA_DMA_ERR_STATUS 0x1CC4 #define ACP_SHA_TRANSFER_BYTE_CNT 0x1CC8 +#define ACP_SHA_PSP_ACK 0x1C74 #define ACP_SCRATCH_REG_0 0x10000 diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 74ede28aa8d84..4c5550e8d3649 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -20,6 +20,22 @@ #include "acp.h" #include "acp-dsp-offset.h" +static int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data) +{ + pci_write_config_dword(dev, 0x60, smn_addr); + pci_write_config_dword(dev, 0x64, data); + + return 0; +} + +static int smn_read(struct pci_dev *dev, u32 smn_addr, u32 *data) +{ + pci_write_config_dword(dev, 0x60, smn_addr); + pci_read_config_dword(dev, 0x64, data); + + return 0; +} + static void configure_acp_groupregisters(struct acp_dev_data *adata) { struct snd_sof_dev *sdev = adata->dev; @@ -135,6 +151,25 @@ int configure_and_run_dma(struct acp_dev_data *adata, unsigned int src_addr, return ret; } +static int psp_fw_validate(struct acp_dev_data *adata) +{ + struct snd_sof_dev *sdev = adata->dev; + int timeout; + u32 data; + + smn_write(adata->smn_dev, MP0_C2PMSG_26_REG, MBOX_ACP_SHA_DMA_COMMAND); + + for (timeout = ACP_PSP_TIMEOUT_COUNTER; timeout > 0; timeout--) { + msleep(20); + smn_read(adata->smn_dev, MP0_C2PMSG_26_REG, &data); + if (data & MBOX_READY_MASK) + return 0; + } + + dev_err(sdev->dev, "FW validation timedout: status %x\n", data & MBOX_STATUS_MASK); + return -ETIMEDOUT; +} + int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, unsigned int start_addr, unsigned int dest_addr, unsigned int image_length) @@ -174,7 +209,9 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, return ret; } - snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DSP_FW_QUALIFIER, DSP_FW_RUN_ENABLE); + ret = psp_fw_validate(adata); + if (ret) + return ret; fw_qualifier = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SHA_DSP_FW_QUALIFIER); if (!(fw_qualifier & DSP_FW_RUN_ENABLE)) { @@ -238,6 +275,13 @@ static irqreturn_t acp_irq_thread(int irq, void *context) struct snd_sof_dev *sdev = context; unsigned int val; + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_EXTERNAL_INTR_STAT); + if (val & ACP_SHA_STAT) { + /* Clear SHA interrupt raised by PSP */ + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_EXTERNAL_INTR_STAT, val); + return IRQ_HANDLED; + } + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_DSP_SW_INTR_STAT); if (val & ACP_DSP_TO_HOST_IRQ) { sof_ops(sdev)->irq_thread(irq, sdev); @@ -326,6 +370,7 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) { struct pci_dev *pci = to_pci_dev(sdev->dev); struct acp_dev_data *adata; + const struct sof_amd_acp_desc *chip; unsigned int addr; int ret; @@ -346,18 +391,32 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) sdev->pdata->hw_pdata = adata; + chip = get_chip_info(sdev->pdata); + if (!chip) { + dev_err(sdev->dev, "no such device supported, chip id:%x\n", pci->device); + return -EIO; + } + + adata->smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, chip->host_bridge_id, NULL); + if (!adata->smn_dev) { + dev_err(sdev->dev, "Failed to get host bridge device\n"); + return -ENODEV; + } + sdev->ipc_irq = pci->irq; ret = request_threaded_irq(sdev->ipc_irq, acp_irq_handler, acp_irq_thread, IRQF_SHARED, "AudioDSP", sdev); if (ret < 0) { dev_err(sdev->dev, "failed to register IRQ %d\n", sdev->ipc_irq); + pci_dev_put(adata->smn_dev); return ret; } ret = acp_init(sdev); if (ret < 0) { free_irq(sdev->ipc_irq, sdev); + pci_dev_put(adata->smn_dev); return ret; } @@ -371,6 +430,11 @@ EXPORT_SYMBOL_NS(amd_sof_acp_probe, SND_SOC_SOF_AMD_COMMON); int amd_sof_acp_remove(struct snd_sof_dev *sdev) { + struct acp_dev_data *adata = sdev->pdata->hw_pdata; + + if (adata->smn_dev) + pci_dev_put(adata->smn_dev); + if (sdev->ipc_irq) free_irq(sdev->ipc_irq, sdev); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index fd923f72a01ad..a2f8e42190663 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -52,6 +52,15 @@ #define ACP_DSP_TO_HOST_IRQ 0x04 +#define HOST_BRIDGE_CZN 0x1630 +#define ACP_SHA_STAT 0x8000 +#define ACP_PSP_TIMEOUT_COUNTER 5 +#define ACP_EXT_INTR_ERROR_STAT 0x20000000 +#define MP0_C2PMSG_26_REG 0x03810570 +#define MBOX_ACP_SHA_DMA_COMMAND 0x330000 +#define MBOX_READY_MASK 0x80000000 +#define MBOX_STATUS_MASK 0xFFFF + struct acp_atu_grp_pte { u32 low; u32 high; @@ -140,6 +149,7 @@ struct acp_dev_data { struct dma_descriptor dscr_info[ACP_MAX_DESC]; struct acp_dsp_stream stream_buf[ACP_MAX_STREAM]; struct acp_dsp_stream *dtrace_stream; + struct pci_dev *smn_dev; }; void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes); @@ -202,4 +212,15 @@ int snd_amd_acp_find_config(struct pci_dev *pci); /* Trace */ int acp_sof_trace_init(struct snd_sof_dev *sdev, u32 *stream_tag); int acp_sof_trace_release(struct snd_sof_dev *sdev); + +struct sof_amd_acp_desc { + unsigned int host_bridge_id; +}; + +static inline const struct sof_amd_acp_desc *get_chip_info(struct snd_sof_pdata *pdata) +{ + const struct sof_dev_desc *desc = pdata->desc; + + return desc->chip_info; +} #endif diff --git a/sound/soc/sof/amd/pci-rn.c b/sound/soc/sof/amd/pci-rn.c index 3c379a5ef2315..392ffbdf64179 100644 --- a/sound/soc/sof/amd/pci-rn.c +++ b/sound/soc/sof/amd/pci-rn.c @@ -43,12 +43,17 @@ static const struct resource renoir_res[] = { }, }; +static const struct sof_amd_acp_desc renoir_chip_info = { + .host_bridge_id = HOST_BRIDGE_CZN, +}; + static const struct sof_dev_desc renoir_desc = { .machines = snd_soc_acpi_amd_sof_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, .resindex_imr_base = -1, .irqindex_host_ipc = -1, + .chip_info = &renoir_chip_info, .default_fw_path = "amd/sof", .default_tplg_path = "amd/sof-tplg", .default_fw_filename = "sof-rn.ri", From 56717d72f7a811799e8d138ff3d49325272c5cf6 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 17 Nov 2021 13:22:51 +0000 Subject: [PATCH 050/327] ASoC: wm_adsp: Remove the wmfw_add_ctl helper function The helper function wmfw_add_ctl is only called from one place and that place is a function with only 2 lines of code. Merge the helper function into the work function to simplify the code. Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20211117132300.1290-1-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 33 +++++++++------------------------ 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index d4f0d72cbcc80..404717e30f44d 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -537,15 +537,20 @@ static unsigned int wmfw_convert_flags(unsigned int in, unsigned int len) return out; } -static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) +static void wm_adsp_ctl_work(struct work_struct *work) { + struct wm_coeff_ctl *ctl = container_of(work, + struct wm_coeff_ctl, + work); struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl; + struct wm_adsp *dsp = container_of(cs_ctl->dsp, + struct wm_adsp, + cs_dsp); struct snd_kcontrol_new *kcontrol; - int ret; kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL); if (!kcontrol) - return -ENOMEM; + return; kcontrol->name = ctl->name; kcontrol->info = wm_coeff_info; @@ -571,29 +576,9 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) break; } - ret = snd_soc_add_component_controls(dsp->component, kcontrol, 1); - if (ret < 0) - goto err_kcontrol; + snd_soc_add_component_controls(dsp->component, kcontrol, 1); kfree(kcontrol); - - return 0; - -err_kcontrol: - kfree(kcontrol); - return ret; -} - -static void wm_adsp_ctl_work(struct work_struct *work) -{ - struct wm_coeff_ctl *ctl = container_of(work, - struct wm_coeff_ctl, - work); - struct wm_adsp *dsp = container_of(ctl->cs_ctl->dsp, - struct wm_adsp, - cs_dsp); - - wmfw_add_ctl(dsp, ctl); } static int wm_adsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl) From 5065cfabec21a4acf562932f1d0a814c119e0a69 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 17 Nov 2021 13:22:52 +0000 Subject: [PATCH 051/327] firmware: cs_dsp: Add lockdep asserts to interface functions Some of the control functions exposed by the cs_dsp code require the pwr_lock to be held by the caller. Add lockdep_assert_held calls to ensure this is done correctly. Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20211117132300.1290-2-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/firmware/cirrus/cs_dsp.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c index 1a0c6c793f6a7..0d1ba7d8efa47 100644 --- a/drivers/firmware/cirrus/cs_dsp.c +++ b/drivers/firmware/cirrus/cs_dsp.c @@ -653,6 +653,8 @@ int cs_dsp_coeff_write_acked_control(struct cs_dsp_coeff_ctl *ctl, unsigned int unsigned int reg; int i, ret; + lockdep_assert_held(&dsp->pwr_lock); + if (!dsp->running) return -EPERM; @@ -754,6 +756,8 @@ int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl, const void *buf, size_ { int ret = 0; + lockdep_assert_held(&ctl->dsp->pwr_lock); + if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) ret = -EPERM; else if (buf != ctl->cache) @@ -811,6 +815,8 @@ int cs_dsp_coeff_read_ctrl(struct cs_dsp_coeff_ctl *ctl, void *buf, size_t len) { int ret = 0; + lockdep_assert_held(&ctl->dsp->pwr_lock); + if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) { if (ctl->enabled && ctl->dsp->running) return cs_dsp_coeff_read_ctrl_raw(ctl, buf, len); @@ -1453,6 +1459,8 @@ struct cs_dsp_coeff_ctl *cs_dsp_get_ctl(struct cs_dsp *dsp, const char *name, in { struct cs_dsp_coeff_ctl *pos, *rslt = NULL; + lockdep_assert_held(&dsp->pwr_lock); + list_for_each_entry(pos, &dsp->ctl_list, list) { if (!pos->subname) continue; @@ -1548,6 +1556,8 @@ struct cs_dsp_alg_region *cs_dsp_find_alg_region(struct cs_dsp *dsp, { struct cs_dsp_alg_region *alg_region; + lockdep_assert_held(&dsp->pwr_lock); + list_for_each_entry(alg_region, &dsp->alg_regions, list) { if (id == alg_region->alg && type == alg_region->type) return alg_region; @@ -2783,6 +2793,8 @@ int cs_dsp_read_raw_data_block(struct cs_dsp *dsp, int mem_type, unsigned int me unsigned int reg; int ret; + lockdep_assert_held(&dsp->pwr_lock); + if (!mem) return -EINVAL; @@ -2836,6 +2848,8 @@ int cs_dsp_write_data_word(struct cs_dsp *dsp, int mem_type, unsigned int mem_ad __be32 val = cpu_to_be32(data & 0x00ffffffu); unsigned int reg; + lockdep_assert_held(&dsp->pwr_lock); + if (!mem) return -EINVAL; From 2925748eadc33cba3bded7b69475a1b002b124ac Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 17 Nov 2021 13:22:53 +0000 Subject: [PATCH 052/327] firmware: cs_dsp: Add version checks on coefficient loading The firmware coefficient files contain version information that is currently ignored by the cs_dsp code. This information specifies which version of the firmware the coefficient were generated for. Add a check into the code which prints a warning in the case the coefficient and firmware differ in version, in many cases this will be ok but it is not always, so best to let the user know there is a potential issue. Co-authored-by: Simon Trimmer Signed-off-by: Simon Trimmer Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20211117132300.1290-3-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/firmware/cirrus/cs_dsp.c | 49 +++++++++++++++++++------- include/linux/firmware/cirrus/cs_dsp.h | 2 ++ 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c index 0d1ba7d8efa47..0da454a8498d0 100644 --- a/drivers/firmware/cirrus/cs_dsp.c +++ b/drivers/firmware/cirrus/cs_dsp.c @@ -1569,7 +1569,7 @@ EXPORT_SYMBOL_GPL(cs_dsp_find_alg_region); static struct cs_dsp_alg_region *cs_dsp_create_region(struct cs_dsp *dsp, int type, __be32 id, - __be32 base) + __be32 ver, __be32 base) { struct cs_dsp_alg_region *alg_region; @@ -1579,6 +1579,7 @@ static struct cs_dsp_alg_region *cs_dsp_create_region(struct cs_dsp *dsp, alg_region->type = type; alg_region->alg = be32_to_cpu(id); + alg_region->ver = be32_to_cpu(ver); alg_region->base = be32_to_cpu(base); list_add_tail(&alg_region->list, &dsp->alg_regions); @@ -1628,14 +1629,14 @@ static void cs_dsp_parse_wmfw_v3_id_header(struct cs_dsp *dsp, nalgs); } -static int cs_dsp_create_regions(struct cs_dsp *dsp, __be32 id, int nregions, - const int *type, __be32 *base) +static int cs_dsp_create_regions(struct cs_dsp *dsp, __be32 id, __be32 ver, + int nregions, const int *type, __be32 *base) { struct cs_dsp_alg_region *alg_region; int i; for (i = 0; i < nregions; i++) { - alg_region = cs_dsp_create_region(dsp, type[i], id, base[i]); + alg_region = cs_dsp_create_region(dsp, type[i], id, ver, base[i]); if (IS_ERR(alg_region)) return PTR_ERR(alg_region); } @@ -1670,12 +1671,14 @@ static int cs_dsp_adsp1_setup_algs(struct cs_dsp *dsp) cs_dsp_parse_wmfw_id_header(dsp, &adsp1_id.fw, n_algs); alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_ZM, - adsp1_id.fw.id, adsp1_id.zm); + adsp1_id.fw.id, adsp1_id.fw.ver, + adsp1_id.zm); if (IS_ERR(alg_region)) return PTR_ERR(alg_region); alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_DM, - adsp1_id.fw.id, adsp1_id.dm); + adsp1_id.fw.id, adsp1_id.fw.ver, + adsp1_id.dm); if (IS_ERR(alg_region)) return PTR_ERR(alg_region); @@ -1698,6 +1701,7 @@ static int cs_dsp_adsp1_setup_algs(struct cs_dsp *dsp) alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_DM, adsp1_alg[i].alg.id, + adsp1_alg[i].alg.ver, adsp1_alg[i].dm); if (IS_ERR(alg_region)) { ret = PTR_ERR(alg_region); @@ -1719,6 +1723,7 @@ static int cs_dsp_adsp1_setup_algs(struct cs_dsp *dsp) alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_ZM, adsp1_alg[i].alg.id, + adsp1_alg[i].alg.ver, adsp1_alg[i].zm); if (IS_ERR(alg_region)) { ret = PTR_ERR(alg_region); @@ -1771,17 +1776,20 @@ static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp) cs_dsp_parse_wmfw_id_header(dsp, &adsp2_id.fw, n_algs); alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_XM, - adsp2_id.fw.id, adsp2_id.xm); + adsp2_id.fw.id, adsp2_id.fw.ver, + adsp2_id.xm); if (IS_ERR(alg_region)) return PTR_ERR(alg_region); alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_YM, - adsp2_id.fw.id, adsp2_id.ym); + adsp2_id.fw.id, adsp2_id.fw.ver, + adsp2_id.ym); if (IS_ERR(alg_region)) return PTR_ERR(alg_region); alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_ZM, - adsp2_id.fw.id, adsp2_id.zm); + adsp2_id.fw.id, adsp2_id.fw.ver, + adsp2_id.zm); if (IS_ERR(alg_region)) return PTR_ERR(alg_region); @@ -1806,6 +1814,7 @@ static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp) alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_XM, adsp2_alg[i].alg.id, + adsp2_alg[i].alg.ver, adsp2_alg[i].xm); if (IS_ERR(alg_region)) { ret = PTR_ERR(alg_region); @@ -1827,6 +1836,7 @@ static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp) alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_YM, adsp2_alg[i].alg.id, + adsp2_alg[i].alg.ver, adsp2_alg[i].ym); if (IS_ERR(alg_region)) { ret = PTR_ERR(alg_region); @@ -1848,6 +1858,7 @@ static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp) alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_ZM, adsp2_alg[i].alg.id, + adsp2_alg[i].alg.ver, adsp2_alg[i].zm); if (IS_ERR(alg_region)) { ret = PTR_ERR(alg_region); @@ -1873,7 +1884,7 @@ static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp) return ret; } -static int cs_dsp_halo_create_regions(struct cs_dsp *dsp, __be32 id, +static int cs_dsp_halo_create_regions(struct cs_dsp *dsp, __be32 id, __be32 ver, __be32 xm_base, __be32 ym_base) { static const int types[] = { @@ -1882,7 +1893,7 @@ static int cs_dsp_halo_create_regions(struct cs_dsp *dsp, __be32 id, }; __be32 bases[] = { xm_base, xm_base, ym_base, ym_base }; - return cs_dsp_create_regions(dsp, id, ARRAY_SIZE(types), types, bases); + return cs_dsp_create_regions(dsp, id, ver, ARRAY_SIZE(types), types, bases); } static int cs_dsp_halo_setup_algs(struct cs_dsp *dsp) @@ -1910,7 +1921,7 @@ static int cs_dsp_halo_setup_algs(struct cs_dsp *dsp) cs_dsp_parse_wmfw_v3_id_header(dsp, &halo_id.fw, n_algs); - ret = cs_dsp_halo_create_regions(dsp, halo_id.fw.id, + ret = cs_dsp_halo_create_regions(dsp, halo_id.fw.id, halo_id.fw.ver, halo_id.xm_base, halo_id.ym_base); if (ret) return ret; @@ -1934,6 +1945,7 @@ static int cs_dsp_halo_setup_algs(struct cs_dsp *dsp) be32_to_cpu(halo_alg[i].ym_base)); ret = cs_dsp_halo_create_regions(dsp, halo_alg[i].alg.id, + halo_alg[i].alg.ver, halo_alg[i].xm_base, halo_alg[i].ym_base); if (ret) @@ -1955,7 +1967,7 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware const struct cs_dsp_region *mem; struct cs_dsp_alg_region *alg_region; const char *region_name; - int ret, pos, blocks, type, offset, reg; + int ret, pos, blocks, type, offset, reg, version; struct cs_dsp_buf *buf; if (!firmware) @@ -1999,6 +2011,7 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware type = le16_to_cpu(blk->type); offset = le16_to_cpu(blk->offset); + version = le32_to_cpu(blk->ver) >> 8; cs_dsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n", file, blocks, le32_to_cpu(blk->id), @@ -2056,6 +2069,16 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware alg_region = cs_dsp_find_alg_region(dsp, type, le32_to_cpu(blk->id)); if (alg_region) { + if (version != alg_region->ver) + cs_dsp_warn(dsp, + "Algorithm coefficient version %d.%d.%d but expected %d.%d.%d\n", + (version >> 16) & 0xFF, + (version >> 8) & 0xFF, + version & 0xFF, + (alg_region->ver >> 16) & 0xFF, + (alg_region->ver >> 8) & 0xFF, + alg_region->ver & 0xFF); + reg = alg_region->base; reg = dsp->ops->region_to_reg(mem, reg); reg += offset; diff --git a/include/linux/firmware/cirrus/cs_dsp.h b/include/linux/firmware/cirrus/cs_dsp.h index 3a54b1afc48fc..ce54705e2becf 100644 --- a/include/linux/firmware/cirrus/cs_dsp.h +++ b/include/linux/firmware/cirrus/cs_dsp.h @@ -54,12 +54,14 @@ struct cs_dsp_region { * struct cs_dsp_alg_region - Describes a logical algorithm region in DSP address space * @list: List node for internal use * @alg: Algorithm id + * @ver: Expected algorithm version * @type: Memory region type * @base: Address of region */ struct cs_dsp_alg_region { struct list_head list; unsigned int alg; + unsigned int ver; int type; unsigned int base; }; From 14055b5a3a23204c4702ae5d3f2a819ee081ce33 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 17 Nov 2021 13:22:54 +0000 Subject: [PATCH 053/327] firmware: cs_dsp: Add pre_run callback The code already has a post_run callback, add a matching pre_run callback to the client_ops that is called before execution is started. This callback provides a convenient place for the client code to set DSP controls or hardware that requires configuration before the DSP core actually starts execution. Note that placing this callback before cs_dsp_coeff_sync_controls is important to ensure that any control values are then correctly synced out to the chip. Co-authored-by: Simon Trimmer Signed-off-by: Simon Trimmer Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20211117132300.1290-4-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/firmware/cirrus/cs_dsp.c | 6 ++++++ include/linux/firmware/cirrus/cs_dsp.h | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c index 0da454a8498d0..ef7afadea42d1 100644 --- a/drivers/firmware/cirrus/cs_dsp.c +++ b/drivers/firmware/cirrus/cs_dsp.c @@ -2627,6 +2627,12 @@ int cs_dsp_run(struct cs_dsp *dsp) goto err; } + if (dsp->client_ops->pre_run) { + ret = dsp->client_ops->pre_run(dsp); + if (ret) + goto err; + } + /* Sync set controls */ ret = cs_dsp_coeff_sync_controls(dsp); if (ret != 0) diff --git a/include/linux/firmware/cirrus/cs_dsp.h b/include/linux/firmware/cirrus/cs_dsp.h index ce54705e2becf..0bf849baeaa5a 100644 --- a/include/linux/firmware/cirrus/cs_dsp.h +++ b/include/linux/firmware/cirrus/cs_dsp.h @@ -187,7 +187,8 @@ struct cs_dsp { * struct cs_dsp_client_ops - client callbacks * @control_add: Called under the pwr_lock when a control is created * @control_remove: Called under the pwr_lock when a control is destroyed - * @post_run: Called under the pwr_lock by cs_dsp_run() + * @pre_run: Called under the pwr_lock by cs_dsp_run() before the core is started + * @post_run: Called under the pwr_lock by cs_dsp_run() after the core is started * @post_stop: Called under the pwr_lock by cs_dsp_stop() * @watchdog_expired: Called when a watchdog expiry is detected * @@ -197,6 +198,7 @@ struct cs_dsp { struct cs_dsp_client_ops { int (*control_add)(struct cs_dsp_coeff_ctl *ctl); void (*control_remove)(struct cs_dsp_coeff_ctl *ctl); + int (*pre_run)(struct cs_dsp *dsp); int (*post_run)(struct cs_dsp *dsp); void (*post_stop)(struct cs_dsp *dsp); void (*watchdog_expired)(struct cs_dsp *dsp); From 40a34ae7308682bbbf5827145afa23dcdfb1f090 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 17 Nov 2021 13:22:55 +0000 Subject: [PATCH 054/327] firmware: cs_dsp: Print messages from bin files The coefficient file contains various info strings, and the equivalent strings are printed from the WMFW file as it is loaded. Add support for printing these from the coefficient file as well. Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20211117132300.1290-5-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/firmware/cirrus/cs_dsp.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c index ef7afadea42d1..3d21574f3a443 100644 --- a/drivers/firmware/cirrus/cs_dsp.c +++ b/drivers/firmware/cirrus/cs_dsp.c @@ -1968,6 +1968,7 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware struct cs_dsp_alg_region *alg_region; const char *region_name; int ret, pos, blocks, type, offset, reg, version; + char *text = NULL; struct cs_dsp_buf *buf; if (!firmware) @@ -2025,6 +2026,8 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware region_name = "Unknown"; switch (type) { case (WMFW_NAME_TEXT << 8): + text = kzalloc(le32_to_cpu(blk->len) + 1, GFP_KERNEL); + break; case (WMFW_INFO_TEXT << 8): case (WMFW_METADATA << 8): break; @@ -2094,6 +2097,13 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware break; } + if (text) { + memcpy(text, blk->data, le32_to_cpu(blk->len)); + cs_dsp_info(dsp, "%s: %s\n", dsp->fw_name, text); + kfree(text); + text = NULL; + } + if (reg) { if (le32_to_cpu(blk->len) > firmware->size - pos - sizeof(*blk)) { @@ -2144,6 +2154,7 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware out_fw: regmap_async_complete(regmap); cs_dsp_buf_free(&buf_list); + kfree(text); return ret; } From dcee767667f44ed0d40a3debf507a3ba027a1994 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 17 Nov 2021 13:22:56 +0000 Subject: [PATCH 055/327] firmware: cs_dsp: Add support for rev 2 coefficient files Add support for the revision 2 coefficient file, this format is identical to revision 1 and was simply added by accident to some firmware. However unfortunately many firmwares have leaked into production using this and as such driver support really needs to be added for it. Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20211117132300.1290-6-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/firmware/cirrus/cs_dsp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c index 3d21574f3a443..62ba4ebbf11f5 100644 --- a/drivers/firmware/cirrus/cs_dsp.c +++ b/drivers/firmware/cirrus/cs_dsp.c @@ -1990,6 +1990,7 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware switch (be32_to_cpu(hdr->rev) & 0xff) { case 1: + case 2: break; default: cs_dsp_err(dsp, "%s: Unsupported coefficient file format %d\n", From 86c6080407740937ed2ba0ccd181e947f77e2154 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 17 Nov 2021 13:22:57 +0000 Subject: [PATCH 056/327] firmware: cs_dsp: Perform NULL check in cs_dsp_coeff_write/read_ctrl Add a NULL check to the cs_dsp_coeff_write/read_ctrl functions. This is a major convenience for users of the cs_dsp library as it allows the call to cs_dsp_get_ctl to be inlined with the call to read/write the control itself. Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20211117132300.1290-7-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/firmware/cirrus/cs_dsp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c index 62ba4ebbf11f5..9eecd16265375 100644 --- a/drivers/firmware/cirrus/cs_dsp.c +++ b/drivers/firmware/cirrus/cs_dsp.c @@ -758,6 +758,9 @@ int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl, const void *buf, size_ lockdep_assert_held(&ctl->dsp->pwr_lock); + if (!ctl) + return -ENOENT; + if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) ret = -EPERM; else if (buf != ctl->cache) @@ -817,6 +820,9 @@ int cs_dsp_coeff_read_ctrl(struct cs_dsp_coeff_ctl *ctl, void *buf, size_t len) lockdep_assert_held(&ctl->dsp->pwr_lock); + if (!ctl) + return -ENOENT; + if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) { if (ctl->enabled && ctl->dsp->running) return cs_dsp_coeff_read_ctrl_raw(ctl, buf, len); From b329b3d39497a9fdb175d7e4fd77ae7170d5d26c Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 17 Nov 2021 13:22:58 +0000 Subject: [PATCH 057/327] firmware: cs_dsp: Clarify some kernel doc comments Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20211117132300.1290-8-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/firmware/cirrus/cs_dsp.c | 4 ++-- include/linux/firmware/cirrus/cs_dsp.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c index 9eecd16265375..d1bcade2efe23 100644 --- a/drivers/firmware/cirrus/cs_dsp.c +++ b/drivers/firmware/cirrus/cs_dsp.c @@ -746,7 +746,7 @@ static int cs_dsp_coeff_write_ctrl_raw(struct cs_dsp_coeff_ctl *ctl, * cs_dsp_coeff_write_ctrl() - Writes the given buffer to the given coefficient control * @ctl: pointer to coefficient control * @buf: the buffer to write to the given control - * @len: the length of the buffer + * @len: the length of the buffer in bytes * * Must be called with pwr_lock held. * @@ -808,7 +808,7 @@ static int cs_dsp_coeff_read_ctrl_raw(struct cs_dsp_coeff_ctl *ctl, void *buf, s * cs_dsp_coeff_read_ctrl() - Reads the given coefficient control into the given buffer * @ctl: pointer to coefficient control * @buf: the buffer to store to the given control - * @len: the length of the buffer + * @len: the length of the buffer in bytes * * Must be called with pwr_lock held. * diff --git a/include/linux/firmware/cirrus/cs_dsp.h b/include/linux/firmware/cirrus/cs_dsp.h index 0bf849baeaa5a..1ad1b173417a0 100644 --- a/include/linux/firmware/cirrus/cs_dsp.h +++ b/include/linux/firmware/cirrus/cs_dsp.h @@ -76,8 +76,8 @@ struct cs_dsp_alg_region { * @enabled: Flag indicating whether control is enabled * @list: List node for internal use * @cache: Cached value of the control - * @offset: Offset of control within alg_region - * @len: Length of the cached value + * @offset: Offset of control within alg_region in words + * @len: Length of the cached value in bytes * @set: Flag indicating the value has been written by the user * @flags: Bitfield of WMFW_CTL_FLAG_ control flags defined in wmfw.h * @type: One of the WMFW_CTL_TYPE_ control types defined in wmfw.h From f444da38ac924748de696c393327a44c4b8d727e Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 17 Nov 2021 13:22:59 +0000 Subject: [PATCH 058/327] firmware: cs_dsp: Add offset to cs_dsp read/write Provide a mechanism to access only part of a control through the cs_dsp interface. Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20211117132300.1290-9-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/firmware/cirrus/cs_dsp.c | 44 ++++++++++++++++---------- include/linux/firmware/cirrus/cs_dsp.h | 6 ++-- sound/soc/codecs/wm_adsp.c | 14 ++++---- 3 files changed, 39 insertions(+), 25 deletions(-) diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c index d1bcade2efe23..5fe08de91ecd3 100644 --- a/drivers/firmware/cirrus/cs_dsp.c +++ b/drivers/firmware/cirrus/cs_dsp.c @@ -616,7 +616,8 @@ static void cs_dsp_halo_show_fw_status(struct cs_dsp *dsp) offs[0], offs[1], offs[2], offs[3]); } -static int cs_dsp_coeff_base_reg(struct cs_dsp_coeff_ctl *ctl, unsigned int *reg) +static int cs_dsp_coeff_base_reg(struct cs_dsp_coeff_ctl *ctl, unsigned int *reg, + unsigned int off) { const struct cs_dsp_alg_region *alg_region = &ctl->alg_region; struct cs_dsp *dsp = ctl->dsp; @@ -629,7 +630,7 @@ static int cs_dsp_coeff_base_reg(struct cs_dsp_coeff_ctl *ctl, unsigned int *reg return -EINVAL; } - *reg = dsp->ops->region_to_reg(mem, ctl->alg_region.base + ctl->offset); + *reg = dsp->ops->region_to_reg(mem, ctl->alg_region.base + ctl->offset + off); return 0; } @@ -658,7 +659,7 @@ int cs_dsp_coeff_write_acked_control(struct cs_dsp_coeff_ctl *ctl, unsigned int if (!dsp->running) return -EPERM; - ret = cs_dsp_coeff_base_reg(ctl, ®); + ret = cs_dsp_coeff_base_reg(ctl, ®, 0); if (ret) return ret; @@ -712,14 +713,14 @@ int cs_dsp_coeff_write_acked_control(struct cs_dsp_coeff_ctl *ctl, unsigned int EXPORT_SYMBOL_GPL(cs_dsp_coeff_write_acked_control); static int cs_dsp_coeff_write_ctrl_raw(struct cs_dsp_coeff_ctl *ctl, - const void *buf, size_t len) + unsigned int off, const void *buf, size_t len) { struct cs_dsp *dsp = ctl->dsp; void *scratch; int ret; unsigned int reg; - ret = cs_dsp_coeff_base_reg(ctl, ®); + ret = cs_dsp_coeff_base_reg(ctl, ®, off); if (ret) return ret; @@ -745,6 +746,7 @@ static int cs_dsp_coeff_write_ctrl_raw(struct cs_dsp_coeff_ctl *ctl, /** * cs_dsp_coeff_write_ctrl() - Writes the given buffer to the given coefficient control * @ctl: pointer to coefficient control + * @off: word offset at which data should be written * @buf: the buffer to write to the given control * @len: the length of the buffer in bytes * @@ -752,7 +754,8 @@ static int cs_dsp_coeff_write_ctrl_raw(struct cs_dsp_coeff_ctl *ctl, * * Return: Zero for success, a negative number on error. */ -int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl, const void *buf, size_t len) +int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl, + unsigned int off, const void *buf, size_t len) { int ret = 0; @@ -761,27 +764,31 @@ int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl, const void *buf, size_ if (!ctl) return -ENOENT; + if (len + off * sizeof(u32) > ctl->len) + return -EINVAL; + if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) ret = -EPERM; else if (buf != ctl->cache) - memcpy(ctl->cache, buf, len); + memcpy(ctl->cache + off * sizeof(u32), buf, len); ctl->set = 1; if (ctl->enabled && ctl->dsp->running) - ret = cs_dsp_coeff_write_ctrl_raw(ctl, buf, len); + ret = cs_dsp_coeff_write_ctrl_raw(ctl, off, buf, len); return ret; } EXPORT_SYMBOL_GPL(cs_dsp_coeff_write_ctrl); -static int cs_dsp_coeff_read_ctrl_raw(struct cs_dsp_coeff_ctl *ctl, void *buf, size_t len) +static int cs_dsp_coeff_read_ctrl_raw(struct cs_dsp_coeff_ctl *ctl, + unsigned int off, void *buf, size_t len) { struct cs_dsp *dsp = ctl->dsp; void *scratch; int ret; unsigned int reg; - ret = cs_dsp_coeff_base_reg(ctl, ®); + ret = cs_dsp_coeff_base_reg(ctl, ®, off); if (ret) return ret; @@ -807,6 +814,7 @@ static int cs_dsp_coeff_read_ctrl_raw(struct cs_dsp_coeff_ctl *ctl, void *buf, s /** * cs_dsp_coeff_read_ctrl() - Reads the given coefficient control into the given buffer * @ctl: pointer to coefficient control + * @off: word offset at which data should be read * @buf: the buffer to store to the given control * @len: the length of the buffer in bytes * @@ -814,7 +822,8 @@ static int cs_dsp_coeff_read_ctrl_raw(struct cs_dsp_coeff_ctl *ctl, void *buf, s * * Return: Zero for success, a negative number on error. */ -int cs_dsp_coeff_read_ctrl(struct cs_dsp_coeff_ctl *ctl, void *buf, size_t len) +int cs_dsp_coeff_read_ctrl(struct cs_dsp_coeff_ctl *ctl, + unsigned int off, void *buf, size_t len) { int ret = 0; @@ -823,17 +832,20 @@ int cs_dsp_coeff_read_ctrl(struct cs_dsp_coeff_ctl *ctl, void *buf, size_t len) if (!ctl) return -ENOENT; + if (len + off * sizeof(u32) > ctl->len) + return -EINVAL; + if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) { if (ctl->enabled && ctl->dsp->running) - return cs_dsp_coeff_read_ctrl_raw(ctl, buf, len); + return cs_dsp_coeff_read_ctrl_raw(ctl, off, buf, len); else return -EPERM; } else { if (!ctl->flags && ctl->enabled && ctl->dsp->running) - ret = cs_dsp_coeff_read_ctrl_raw(ctl, ctl->cache, ctl->len); + ret = cs_dsp_coeff_read_ctrl_raw(ctl, 0, ctl->cache, ctl->len); if (buf != ctl->cache) - memcpy(buf, ctl->cache, len); + memcpy(buf, ctl->cache + off * sizeof(u32), len); } return ret; @@ -857,7 +869,7 @@ static int cs_dsp_coeff_init_control_caches(struct cs_dsp *dsp) * created so we don't need to do anything. */ if (!ctl->flags || (ctl->flags & WMFW_CTL_FLAG_READABLE)) { - ret = cs_dsp_coeff_read_ctrl_raw(ctl, ctl->cache, ctl->len); + ret = cs_dsp_coeff_read_ctrl_raw(ctl, 0, ctl->cache, ctl->len); if (ret < 0) return ret; } @@ -875,7 +887,7 @@ static int cs_dsp_coeff_sync_controls(struct cs_dsp *dsp) if (!ctl->enabled) continue; if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) { - ret = cs_dsp_coeff_write_ctrl_raw(ctl, ctl->cache, + ret = cs_dsp_coeff_write_ctrl_raw(ctl, 0, ctl->cache, ctl->len); if (ret < 0) return ret; diff --git a/include/linux/firmware/cirrus/cs_dsp.h b/include/linux/firmware/cirrus/cs_dsp.h index 1ad1b173417a0..38b4da3ddfe4f 100644 --- a/include/linux/firmware/cirrus/cs_dsp.h +++ b/include/linux/firmware/cirrus/cs_dsp.h @@ -232,8 +232,10 @@ void cs_dsp_init_debugfs(struct cs_dsp *dsp, struct dentry *debugfs_root); void cs_dsp_cleanup_debugfs(struct cs_dsp *dsp); int cs_dsp_coeff_write_acked_control(struct cs_dsp_coeff_ctl *ctl, unsigned int event_id); -int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl, const void *buf, size_t len); -int cs_dsp_coeff_read_ctrl(struct cs_dsp_coeff_ctl *ctl, void *buf, size_t len); +int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl, unsigned int off, + const void *buf, size_t len); +int cs_dsp_coeff_read_ctrl(struct cs_dsp_coeff_ctl *ctl, unsigned int off, + void *buf, size_t len); struct cs_dsp_coeff_ctl *cs_dsp_get_ctl(struct cs_dsp *dsp, const char *name, int type, unsigned int alg); diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 404717e30f44d..f084b093cff64 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -401,7 +401,7 @@ static int wm_coeff_put(struct snd_kcontrol *kctl, int ret = 0; mutex_lock(&cs_ctl->dsp->pwr_lock); - ret = cs_dsp_coeff_write_ctrl(cs_ctl, p, cs_ctl->len); + ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, p, cs_ctl->len); mutex_unlock(&cs_ctl->dsp->pwr_lock); return ret; @@ -421,7 +421,7 @@ static int wm_coeff_tlv_put(struct snd_kcontrol *kctl, if (copy_from_user(cs_ctl->cache, bytes, size)) ret = -EFAULT; else - ret = cs_dsp_coeff_write_ctrl(cs_ctl, cs_ctl->cache, size); + ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, cs_ctl->cache, size); mutex_unlock(&cs_ctl->dsp->pwr_lock); @@ -464,7 +464,7 @@ static int wm_coeff_get(struct snd_kcontrol *kctl, int ret; mutex_lock(&cs_ctl->dsp->pwr_lock); - ret = cs_dsp_coeff_read_ctrl(cs_ctl, p, cs_ctl->len); + ret = cs_dsp_coeff_read_ctrl(cs_ctl, 0, p, cs_ctl->len); mutex_unlock(&cs_ctl->dsp->pwr_lock); return ret; @@ -481,7 +481,7 @@ static int wm_coeff_tlv_get(struct snd_kcontrol *kctl, mutex_lock(&cs_ctl->dsp->pwr_lock); - ret = cs_dsp_coeff_read_ctrl(cs_ctl, cs_ctl->cache, size); + ret = cs_dsp_coeff_read_ctrl(cs_ctl, 0, cs_ctl->cache, size); if (!ret && copy_to_user(bytes, cs_ctl->cache, size)) ret = -EFAULT; @@ -684,7 +684,7 @@ int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type, if (len > cs_ctl->len) return -EINVAL; - ret = cs_dsp_coeff_write_ctrl(cs_ctl, buf, len); + ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, buf, len); if (ret) return ret; @@ -723,7 +723,7 @@ int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type, if (len > cs_ctl->len) return -EINVAL; - return cs_dsp_coeff_read_ctrl(cs_ctl, buf, len); + return cs_dsp_coeff_read_ctrl(cs_ctl, 0, buf, len); } EXPORT_SYMBOL_GPL(wm_adsp_read_ctl); @@ -1432,7 +1432,7 @@ static int wm_adsp_buffer_parse_coeff(struct cs_dsp_coeff_ctl *cs_ctl) int ret, i; for (i = 0; i < 5; ++i) { - ret = cs_dsp_coeff_read_ctrl(cs_ctl, &coeff_v1, sizeof(coeff_v1)); + ret = cs_dsp_coeff_read_ctrl(cs_ctl, 0, &coeff_v1, sizeof(coeff_v1)); if (ret < 0) return ret; From 5c903f64ce97172d63f7591cfa9e37cba58867b2 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 17 Nov 2021 13:23:00 +0000 Subject: [PATCH 059/327] firmware: cs_dsp: Allow creation of event controls Some firmwares contain controls intended to convey firmware state back to the host. Whilst more infrastructure will probably be needed for these in time, as a first step allow creation of the controls, so said firmwares arn't completely rejected. Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20211117132300.1290-10-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/firmware/cirrus/cs_dsp.c | 1 + include/linux/firmware/cirrus/wmfw.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c index 5fe08de91ecd3..3814cbba0a544 100644 --- a/drivers/firmware/cirrus/cs_dsp.c +++ b/drivers/firmware/cirrus/cs_dsp.c @@ -1177,6 +1177,7 @@ static int cs_dsp_parse_coeff(struct cs_dsp *dsp, return -EINVAL; break; case WMFW_CTL_TYPE_HOSTEVENT: + case WMFW_CTL_TYPE_FWEVENT: ret = cs_dsp_check_coeff_flags(dsp, &coeff_blk, WMFW_CTL_FLAG_SYS | WMFW_CTL_FLAG_VOLATILE | diff --git a/include/linux/firmware/cirrus/wmfw.h b/include/linux/firmware/cirrus/wmfw.h index a19bf7c6fc8b0..74e5a4f6c13a0 100644 --- a/include/linux/firmware/cirrus/wmfw.h +++ b/include/linux/firmware/cirrus/wmfw.h @@ -29,6 +29,7 @@ #define WMFW_CTL_TYPE_ACKED 0x1000 /* acked control */ #define WMFW_CTL_TYPE_HOSTEVENT 0x1001 /* event control */ #define WMFW_CTL_TYPE_HOST_BUFFER 0x1002 /* host buffer pointer */ +#define WMFW_CTL_TYPE_FWEVENT 0x1004 /* firmware event control */ struct wmfw_header { char magic[4]; From 32d7e03d26fd93187c87ed0fbf59ec7023a61404 Mon Sep 17 00:00:00 2001 From: YC Hung Date: Thu, 18 Nov 2021 12:07:42 +0200 Subject: [PATCH 060/327] ASoC: SOF: mediatek: Add mt8195 hardware support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch initialize to support SOF on Mediatek mt8195 platform. MT8195 has four Cortex A78 cores paired with four Cortex A55 cores. It also has Cadence HiFi-4 DSP single core. There are shared DRAM and mailbox interrupt between AP and DSP to use for IPC communication. Signed-off-by: YC Hung Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Kai Vehmanen Reviewed-by: Guennadi Liakhovetski Reviewed-by: Daniel Baluta Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211118100749.54628-2-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/Kconfig | 1 + sound/soc/sof/Makefile | 1 + sound/soc/sof/mediatek/Kconfig | 33 +++ sound/soc/sof/mediatek/Makefile | 2 + sound/soc/sof/mediatek/adsp_helper.h | 49 ++++ sound/soc/sof/mediatek/mediatek-ops.h | 8 + sound/soc/sof/mediatek/mt8195/Makefile | 3 + sound/soc/sof/mediatek/mt8195/mt8195.c | 323 +++++++++++++++++++++++++ sound/soc/sof/mediatek/mt8195/mt8195.h | 155 ++++++++++++ 9 files changed, 575 insertions(+) create mode 100644 sound/soc/sof/mediatek/Kconfig create mode 100644 sound/soc/sof/mediatek/Makefile create mode 100644 sound/soc/sof/mediatek/adsp_helper.h create mode 100644 sound/soc/sof/mediatek/mediatek-ops.h create mode 100644 sound/soc/sof/mediatek/mt8195/Makefile create mode 100644 sound/soc/sof/mediatek/mt8195/mt8195.c create mode 100644 sound/soc/sof/mediatek/mt8195/mt8195.h diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 0e5473e899cd7..b0cdabcfdde75 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -236,6 +236,7 @@ config SND_SOC_SOF_PROBE_WORK_QUEUE source "sound/soc/sof/amd/Kconfig" source "sound/soc/sof/imx/Kconfig" source "sound/soc/sof/intel/Kconfig" +source "sound/soc/sof/mediatek/Kconfig" source "sound/soc/sof/xtensa/Kconfig" endif diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 81ad8cb666e33..964b429146be0 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -24,3 +24,4 @@ obj-$(CONFIG_SND_SOC_SOF_INTEL_TOPLEVEL) += intel/ obj-$(CONFIG_SND_SOC_SOF_IMX_TOPLEVEL) += imx/ obj-$(CONFIG_SND_SOC_SOF_AMD_TOPLEVEL) += amd/ obj-$(CONFIG_SND_SOC_SOF_XTENSA) += xtensa/ +obj-$(CONFIG_SND_SOC_SOF_MTK_TOPLEVEL) += mediatek/ diff --git a/sound/soc/sof/mediatek/Kconfig b/sound/soc/sof/mediatek/Kconfig new file mode 100644 index 0000000000000..aeacf0e5bfbb1 --- /dev/null +++ b/sound/soc/sof/mediatek/Kconfig @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) + +config SND_SOC_SOF_MTK_TOPLEVEL + bool "SOF support for MTK audio DSPs" + depends on ARM64 || COMPILE_TEST + depends on SND_SOC_SOF_OF + help + This adds support for Sound Open Firmware for Mediatek platforms. + It is top level for all mediatek platforms. + Say Y if you have such a device. + If unsure select "N". + +if SND_SOC_SOF_MTK_TOPLEVEL +config SND_SOC_SOF_MTK_COMMON + tristate + select SND_SOC_SOF_OF_DEV + select SND_SOC_SOF + select SND_SOC_SOF_XTENSA + select SND_SOC_SOF_COMPRESS + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_MT8195 + tristate "SOF support for MT8195 audio DSP" + select SND_SOC_SOF_MTK_COMMON + help + This adds support for Sound Open Firmware for Mediatek platforms + using the mt8195 processors. + Say Y if you have such a device. + If unsure select "N". + +endif ## SND_SOC_SOF_MTK_TOPLEVEL diff --git a/sound/soc/sof/mediatek/Makefile b/sound/soc/sof/mediatek/Makefile new file mode 100644 index 0000000000000..e8ec6da981de4 --- /dev/null +++ b/sound/soc/sof/mediatek/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +obj-$(CONFIG_SND_SOC_SOF_MT8195) += mt8195/ diff --git a/sound/soc/sof/mediatek/adsp_helper.h b/sound/soc/sof/mediatek/adsp_helper.h new file mode 100644 index 0000000000000..346953dd22db9 --- /dev/null +++ b/sound/soc/sof/mediatek/adsp_helper.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * Copyright (c) 2021 MediaTek Corporation. All rights reserved. + */ + +#ifndef __MTK_ADSP_HELPER_H__ +#define __MTK_ADSP_HELPER_H__ + +/* + * Global important adsp data structure. + */ +#define DSP_MBOX_NUM 3 + +struct mtk_adsp_chip_info { + phys_addr_t pa_sram; + phys_addr_t pa_dram; /* adsp dram physical base */ + phys_addr_t pa_shared_dram; /* adsp dram physical base */ + phys_addr_t pa_cfgreg; + phys_addr_t pa_mboxreg[DSP_MBOX_NUM]; + u32 sramsize; + u32 dramsize; + u32 cfgregsize; + void __iomem *va_sram; /* corresponding to pa_sram */ + void __iomem *va_dram; /* corresponding to pa_dram */ + void __iomem *va_cfgreg; + void __iomem *va_mboxreg[DSP_MBOX_NUM]; + void __iomem *shared_sram; /* part of va_sram */ + void __iomem *shared_dram; /* part of va_dram */ + phys_addr_t adsp_bootup_addr; + int dram_offset; /*dram offset between system and dsp view*/ +}; + +struct adsp_priv { + struct device *dev; + struct snd_sof_dev *sdev; + + /* DSP IPC handler */ + struct mbox_controller *adsp_mbox; + + struct mtk_adsp_chip_info *adsp; + + u32 (*ap2adsp_addr)(u32 addr, void *data); + u32 (*adsp2ap_addr)(u32 addr, void *data); + + void *private_data; +}; + +#endif diff --git a/sound/soc/sof/mediatek/mediatek-ops.h b/sound/soc/sof/mediatek/mediatek-ops.h new file mode 100644 index 0000000000000..e0ffa69ecb0c6 --- /dev/null +++ b/sound/soc/sof/mediatek/mediatek-ops.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ + +#ifndef __MEDIATEK_OPS_H__ +#define __MEDIATEK_OPS_H__ + +extern const struct snd_sof_dsp_ops sof_mt8195_ops; + +#endif diff --git a/sound/soc/sof/mediatek/mt8195/Makefile b/sound/soc/sof/mediatek/mt8195/Makefile new file mode 100644 index 0000000000000..dd2b6e4affc9f --- /dev/null +++ b/sound/soc/sof/mediatek/mt8195/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +snd-sof-mt8195-objs := mt8195.o +obj-$(CONFIG_SND_SOC_SOF_MT8195) += snd-sof-mt8195.o diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c new file mode 100644 index 0000000000000..966b8660e21c6 --- /dev/null +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -0,0 +1,323 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// Copyright(c) 2021 Mediatek Inc. All rights reserved. +// +// Author: YC Hung +// + +/* + * Hardware interface for audio DSP on mt8195 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "../../ops.h" +#include "../../sof-audio.h" +#include "../adsp_helper.h" +#include "../mediatek-ops.h" +#include "mt8195.h" + +static int platform_parse_resource(struct platform_device *pdev, void *data) +{ + struct resource *mmio; + struct resource res; + struct device_node *mem_region; + struct device *dev = &pdev->dev; + struct mtk_adsp_chip_info *adsp = data; + int ret; + + mem_region = of_parse_phandle(dev->of_node, "memory-region", 0); + if (!mem_region) { + dev_err(dev, "no dma memory-region phandle\n"); + return -ENODEV; + } + + ret = of_address_to_resource(mem_region, 0, &res); + if (ret) { + dev_err(dev, "of_address_to_resource dma failed\n"); + return ret; + } + + dev_dbg(dev, "DMA pbase=0x%llx, size=0x%llx\n", + (phys_addr_t)res.start, resource_size(&res)); + + ret = of_reserved_mem_device_init(dev); + if (ret) { + dev_err(dev, "of_reserved_mem_device_init failed\n"); + return ret; + } + + mem_region = of_parse_phandle(dev->of_node, "memory-region", 1); + if (!mem_region) { + dev_err(dev, "no memory-region sysmem phandle\n"); + return -ENODEV; + } + + ret = of_address_to_resource(mem_region, 0, &res); + if (ret) { + dev_err(dev, "of_address_to_resource sysmem failed\n"); + return ret; + } + + adsp->pa_dram = (phys_addr_t)res.start; + adsp->dramsize = resource_size(&res); + if (adsp->pa_dram & DRAM_REMAP_MASK) { + dev_err(dev, "adsp memory(%#x) is not 4K-aligned\n", + (u32)adsp->pa_dram); + return -EINVAL; + } + + if (adsp->dramsize < TOTAL_SIZE_SHARED_DRAM_FROM_TAIL) { + dev_err(dev, "adsp memory(%#x) is not enough for share\n", + adsp->dramsize); + return -EINVAL; + } + + dev_dbg(dev, "dram pbase=%pa, dramsize=%#x\n", + &adsp->pa_dram, adsp->dramsize); + + /* Parse CFG base */ + mmio = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg"); + if (!mmio) { + dev_err(dev, "no ADSP-CFG register resource\n"); + return -ENXIO; + } + /* remap for DSP register accessing */ + adsp->va_cfgreg = devm_ioremap_resource(dev, mmio); + if (IS_ERR(adsp->va_cfgreg)) + return PTR_ERR(adsp->va_cfgreg); + + adsp->pa_cfgreg = (phys_addr_t)mmio->start; + adsp->cfgregsize = resource_size(mmio); + + dev_dbg(dev, "cfgreg-vbase=%p, cfgregsize=%#x\n", + adsp->va_cfgreg, adsp->cfgregsize); + + /* Parse SRAM */ + mmio = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram"); + if (!mmio) { + dev_err(dev, "no SRAM resource\n"); + return -ENXIO; + } + + adsp->pa_sram = (phys_addr_t)mmio->start; + adsp->sramsize = resource_size(mmio); + if (adsp->sramsize < TOTAL_SIZE_SHARED_SRAM_FROM_TAIL) { + dev_err(dev, "adsp SRAM(%#x) is not enough for share\n", + adsp->sramsize); + return -EINVAL; + } + + dev_dbg(dev, "sram pbase=%pa,%#x\n", &adsp->pa_sram, adsp->sramsize); + + return ret; +} + +static int adsp_sram_power_on(struct device *dev, bool on) +{ + void __iomem *va_dspsysreg; + u32 srampool_con; + + va_dspsysreg = ioremap(ADSP_SRAM_POOL_CON, 0x4); + if (!va_dspsysreg) { + dev_err(dev, "failed to ioremap sram pool base %#x\n", + ADSP_SRAM_POOL_CON); + return -ENOMEM; + } + + srampool_con = readl(va_dspsysreg); + if (on) + writel(srampool_con & ~DSP_SRAM_POOL_PD_MASK, va_dspsysreg); + else + writel(srampool_con | DSP_SRAM_POOL_PD_MASK, va_dspsysreg); + + iounmap(va_dspsysreg); + return 0; +} + +/* Init the basic DSP DRAM address */ +static int adsp_memory_remap_init(struct device *dev, struct mtk_adsp_chip_info *adsp) +{ + void __iomem *vaddr_emi_map; + int offset; + + if (!adsp) + return -ENXIO; + + vaddr_emi_map = devm_ioremap(dev, DSP_EMI_MAP_ADDR, 0x4); + if (!vaddr_emi_map) { + dev_err(dev, "failed to ioremap emi map base %#x\n", + DSP_EMI_MAP_ADDR); + return -ENOMEM; + } + + offset = adsp->pa_dram - DRAM_PHYS_BASE_FROM_DSP_VIEW; + adsp->dram_offset = offset; + offset >>= DRAM_REMAP_SHIFT; + dev_dbg(dev, "adsp->pa_dram %llx, offset %#x\n", adsp->pa_dram, offset); + writel(offset, vaddr_emi_map); + if (offset != readl(vaddr_emi_map)) { + dev_err(dev, "write emi map fail : %#x\n", readl(vaddr_emi_map)); + return -EIO; + } + + return 0; +} + +static int adsp_shared_base_ioremap(struct platform_device *pdev, void *data) +{ + struct device *dev = &pdev->dev; + struct mtk_adsp_chip_info *adsp = data; + u32 shared_size; + + /* remap shared-dram base to be non-cachable */ + shared_size = TOTAL_SIZE_SHARED_DRAM_FROM_TAIL; + adsp->pa_shared_dram = adsp->pa_dram + adsp->dramsize - shared_size; + if (adsp->va_dram) { + adsp->shared_dram = adsp->va_dram + DSP_DRAM_SIZE - shared_size; + } else { + adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram, + shared_size); + if (!adsp->shared_dram) { + dev_err(dev, "ioremap failed for shared DRAM\n"); + return -ENOMEM; + } + } + dev_dbg(dev, "shared-dram vbase=%p, phy addr :%llx, size=%#x\n", + adsp->shared_dram, adsp->pa_shared_dram, shared_size); + + return 0; +} + +static int mt8195_dsp_probe(struct snd_sof_dev *sdev) +{ + struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev); + struct adsp_priv *priv; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + sdev->pdata->hw_pdata = priv; + priv->dev = sdev->dev; + priv->sdev = sdev; + + priv->adsp = devm_kzalloc(&pdev->dev, sizeof(struct mtk_adsp_chip_info), GFP_KERNEL); + if (!priv->adsp) + return -ENOMEM; + + ret = platform_parse_resource(pdev, priv->adsp); + if (ret) + return ret; + + ret = adsp_sram_power_on(sdev->dev, true); + if (ret) { + dev_err(sdev->dev, "adsp_sram_power_on fail!\n"); + return ret; + } + + ret = adsp_memory_remap_init(&pdev->dev, priv->adsp); + if (ret) { + dev_err(sdev->dev, "adsp_memory_remap_init fail!\n"); + goto err_adsp_sram_power_off; + } + + sdev->bar[SOF_FW_BLK_TYPE_IRAM] = devm_ioremap(sdev->dev, + priv->adsp->pa_sram, + priv->adsp->sramsize); + if (!sdev->bar[SOF_FW_BLK_TYPE_IRAM]) { + dev_err(sdev->dev, "failed to ioremap base %pa size %#x\n", + &priv->adsp->pa_sram, priv->adsp->sramsize); + ret = -EINVAL; + goto err_adsp_sram_power_off; + } + + sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, + priv->adsp->pa_dram, + priv->adsp->dramsize); + if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) { + dev_err(sdev->dev, "failed to ioremap base %pa size %#x\n", + &priv->adsp->pa_dram, priv->adsp->dramsize); + ret = -EINVAL; + goto err_adsp_sram_power_off; + } + priv->adsp->va_dram = sdev->bar[SOF_FW_BLK_TYPE_SRAM]; + + ret = adsp_shared_base_ioremap(pdev, priv->adsp); + if (ret) { + dev_err(sdev->dev, "adsp_shared_base_ioremap fail!\n"); + goto err_adsp_sram_power_off; + } + + sdev->bar[DSP_REG_BAR] = priv->adsp->va_cfgreg; + sdev->bar[DSP_MBOX0_BAR] = priv->adsp->va_mboxreg[0]; + sdev->bar[DSP_MBOX1_BAR] = priv->adsp->va_mboxreg[1]; + sdev->bar[DSP_MBOX2_BAR] = priv->adsp->va_mboxreg[2]; + + sdev->mmio_bar = SOF_FW_BLK_TYPE_SRAM; + sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM; + + return 0; + +err_adsp_sram_power_off: + adsp_sram_power_on(&pdev->dev, false); + + return ret; +} + +static int mt8195_dsp_remove(struct snd_sof_dev *sdev) +{ + struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev); + + return adsp_sram_power_on(&pdev->dev, false); +} + +/* on mt8195 there is 1 to 1 match between type and BAR idx */ +static int mt8195_get_bar_index(struct snd_sof_dev *sdev, u32 type) +{ + return type; +} + +/* mt8195 ops */ +const struct snd_sof_dsp_ops sof_mt8195_ops = { + /* probe and remove */ + .probe = mt8195_dsp_probe, + .remove = mt8195_dsp_remove, + + /* Block IO */ + .block_read = sof_block_read, + .block_write = sof_block_write, + + /* Register IO */ + .write = sof_io_write, + .read = sof_io_read, + .write64 = sof_io_write64, + .read64 = sof_io_read64, + + /* misc */ + .get_bar_index = mt8195_get_bar_index, + + /* Firmware ops */ + .dsp_arch_ops = &sof_xtensa_arch_ops, + + /* ALSA HW info flags */ + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, +}; +EXPORT_SYMBOL(sof_mt8195_ops); + +MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.h b/sound/soc/sof/mediatek/mt8195/mt8195.h new file mode 100644 index 0000000000000..48cbbb5aacb51 --- /dev/null +++ b/sound/soc/sof/mediatek/mt8195/mt8195.h @@ -0,0 +1,155 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * Copyright (c) 2021 MediaTek Corporation. All rights reserved. + * + * Header file for the mt8195 DSP register definition + */ + +#ifndef __MT8195_H +#define __MT8195_H + +struct mtk_adsp_chip_info; + +#define DSP_REG_BASE 0x10803000 +#define SCP_CFGREG_BASE 0x10724000 +#define DSP_SYSAO_BASE 0x1080C000 + +/***************************************************************************** + * R E G I S T E R TABLE + *****************************************************************************/ +#define DSP_JTAGMUX 0x0000 +#define DSP_ALTRESETVEC 0x0004 +#define DSP_PDEBUGDATA 0x0008 +#define DSP_PDEBUGBUS0 0x000c +#define PDEBUG_ENABLE BIT(0) +#define DSP_PDEBUGBUS1 0x0010 +#define DSP_PDEBUGINST 0x0014 +#define DSP_PDEBUGLS0STAT 0x0018 +#define DSP_PDEBUGLS1STAT 0x001c +#define DSP_PDEBUGPC 0x0020 +#define DSP_RESET_SW 0x0024 /*reset sw*/ +#define ADSP_BRESET_SW BIT(0) +#define ADSP_DRESET_SW BIT(1) +#define ADSP_RUNSTALL BIT(3) +#define STATVECTOR_SEL BIT(4) +#define DSP_PFAULTBUS 0x0028 +#define DSP_PFAULTINFO 0x002c +#define DSP_GPR00 0x0030 +#define DSP_GPR01 0x0034 +#define DSP_GPR02 0x0038 +#define DSP_GPR03 0x003c +#define DSP_GPR04 0x0040 +#define DSP_GPR05 0x0044 +#define DSP_GPR06 0x0048 +#define DSP_GPR07 0x004c +#define DSP_GPR08 0x0050 +#define DSP_GPR09 0x0054 +#define DSP_GPR0A 0x0058 +#define DSP_GPR0B 0x005c +#define DSP_GPR0C 0x0060 +#define DSP_GPR0D 0x0064 +#define DSP_GPR0E 0x0068 +#define DSP_GPR0F 0x006c +#define DSP_GPR10 0x0070 +#define DSP_GPR11 0x0074 +#define DSP_GPR12 0x0078 +#define DSP_GPR13 0x007c +#define DSP_GPR14 0x0080 +#define DSP_GPR15 0x0084 +#define DSP_GPR16 0x0088 +#define DSP_GPR17 0x008c +#define DSP_GPR18 0x0090 +#define DSP_GPR19 0x0094 +#define DSP_GPR1A 0x0098 +#define DSP_GPR1B 0x009c +#define DSP_GPR1C 0x00a0 +#define DSP_GPR1D 0x00a4 +#define DSP_GPR1E 0x00a8 +#define DSP_GPR1F 0x00ac +#define DSP_TCM_OFFSET 0x00b0 /* not used */ +#define DSP_DDR_OFFSET 0x00b4 /* not used */ +#define DSP_INTFDSP 0x00d0 +#define DSP_INTFDSP_CLR 0x00d4 +#define DSP_SRAM_PD_SW1 0x00d8 +#define DSP_SRAM_PD_SW2 0x00dc +#define DSP_OCD 0x00e0 +#define DSP_RG_DSP_IRQ_POL 0x00f0 /* not used */ +#define DSP_DSP_IRQ_EN 0x00f4 /* not used */ +#define DSP_DSP_IRQ_LEVEL 0x00f8 /* not used */ +#define DSP_DSP_IRQ_STATUS 0x00fc /* not used */ +#define DSP_RG_INT2CIRQ 0x0114 +#define DSP_RG_INT_POL_CTL0 0x0120 +#define DSP_RG_INT_EN_CTL0 0x0130 +#define DSP_RG_INT_LV_CTL0 0x0140 +#define DSP_RG_INT_STATUS0 0x0150 +#define DSP_PDEBUGSTATUS0 0x0200 +#define DSP_PDEBUGSTATUS1 0x0204 +#define DSP_PDEBUGSTATUS2 0x0208 +#define DSP_PDEBUGSTATUS3 0x020c +#define DSP_PDEBUGSTATUS4 0x0210 +#define DSP_PDEBUGSTATUS5 0x0214 +#define DSP_PDEBUGSTATUS6 0x0218 +#define DSP_PDEBUGSTATUS7 0x021c +#define DSP_DSP2PSRAM_PRIORITY 0x0220 /* not used */ +#define DSP_AUDIO_DSP2SPM_INT 0x0224 +#define DSP_AUDIO_DSP2SPM_INT_ACK 0x0228 +#define DSP_AUDIO_DSP_DEBUG_SEL 0x022C +#define DSP_AUDIO_DSP_EMI_BASE_ADDR 0x02E0 /* not used */ +#define DSP_AUDIO_DSP_SHARED_IRAM 0x02E4 +#define DSP_AUDIO_DSP_CKCTRL_P2P_CK_CON 0x02F0 +#define DSP_RG_SEMAPHORE00 0x0300 +#define DSP_RG_SEMAPHORE01 0x0304 +#define DSP_RG_SEMAPHORE02 0x0308 +#define DSP_RG_SEMAPHORE03 0x030C +#define DSP_RG_SEMAPHORE04 0x0310 +#define DSP_RG_SEMAPHORE05 0x0314 +#define DSP_RG_SEMAPHORE06 0x0318 +#define DSP_RG_SEMAPHORE07 0x031C +#define DSP_RESERVED_0 0x03F0 +#define DSP_RESERVED_1 0x03F4 + +/* dsp wdt */ +#define DSP_WDT_MODE 0x0400 + +/* dsp mbox */ +#define DSP_MBOX_IN_CMD 0x00 +#define DSP_MBOX_IN_CMD_CLR 0x04 +#define DSP_MBOX_OUT_CMD 0x1c +#define DSP_MBOX_OUT_CMD_CLR 0x20 +#define DSP_MBOX_IN_MSG0 0x08 +#define DSP_MBOX_IN_MSG1 0x0C +#define DSP_MBOX_OUT_MSG0 0x24 +#define DSP_MBOX_OUT_MSG1 0x28 + +/*dsp sys ao*/ +#define ADSP_SRAM_POOL_CON (DSP_SYSAO_BASE + 0x30) +#define DSP_SRAM_POOL_PD_MASK 0xf +#define DSP_EMI_MAP_ADDR (DSP_SYSAO_BASE + 0x81c) + +/* DSP memories */ +#define MBOX_OFFSET 0x800000 /* DRAM */ +#define MBOX_SIZE 0x1000 /* consistent with which in memory.h of sof fw */ +#define DSP_DRAM_SIZE 0x1000000 /* 16M */ + +#define DSP_REG_BAR 4 +#define DSP_MBOX0_BAR 5 +#define DSP_MBOX1_BAR 6 +#define DSP_MBOX2_BAR 7 + +#define TOTAL_SIZE_SHARED_SRAM_FROM_TAIL 0x0 + +#define SIZE_SHARED_DRAM_DL 0x40000 /*Shared buffer for Downlink*/ +#define SIZE_SHARED_DRAM_UL 0x40000 /*Shared buffer for Uplink*/ + +#define TOTAL_SIZE_SHARED_DRAM_FROM_TAIL \ + (SIZE_SHARED_DRAM_DL + SIZE_SHARED_DRAM_UL) + +#define SRAM_PHYS_BASE_FROM_DSP_VIEW 0x40000000 /* MT8195 DSP view */ +#define DRAM_PHYS_BASE_FROM_DSP_VIEW 0x60000000 /* MT8195 DSP view */ + +/*remap dram between AP and DSP view, 4KB aligned*/ +#define DRAM_REMAP_SHIFT 12 +#define DRAM_REMAP_MASK (BIT(DRAM_REMAP_SHIFT) - 1) + +#endif From e6feefa541f309afed8aa54431681261bc57bcde Mon Sep 17 00:00:00 2001 From: YC Hung Date: Thu, 18 Nov 2021 12:07:43 +0200 Subject: [PATCH 061/327] ASoC: SOF: tokens: add token for Mediatek AFE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the definition for Mediatek audio front end(AFE) tokens,include AFE sampling rate, channels, and format. Signed-off-by: YC Hung Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Kai Vehmanen Reviewed-by: Guennadi Liakhovetski Reviewed-by: Daniel Baluta Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211118100749.54628-3-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- include/uapi/sound/sof/tokens.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index 02b71a8deea45..b72fa385bebf5 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -140,4 +140,9 @@ #define SOF_TKN_INTEL_HDA_RATE 1500 #define SOF_TKN_INTEL_HDA_CH 1501 +/* AFE */ +#define SOF_TKN_MEDIATEK_AFE_RATE 1600 +#define SOF_TKN_MEDIATEK_AFE_CH 1601 +#define SOF_TKN_MEDIATEK_AFE_FORMAT 1602 + #endif From b72bfcffcfc11858a8fc92998733372606db485e Mon Sep 17 00:00:00 2001 From: YC Hung Date: Thu, 18 Nov 2021 12:07:44 +0200 Subject: [PATCH 062/327] ASoC: SOF: topology: Add support for Mediatek AFE DAI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add new sof dai and config to pass topology file configuration to SOF firmware running on Mediatek platform DSP core. Add mediatek audio front end(AFE) to the list of supported sof_dais Signed-off-by: YC Hung Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Kai Vehmanen Reviewed-by: Guennadi Liakhovetski Reviewed-by: Daniel Baluta Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211118100749.54628-4-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- include/sound/sof/dai-mediatek.h | 23 +++++++++++++ include/sound/sof/dai.h | 3 ++ sound/soc/sof/pcm.c | 12 +++++++ sound/soc/sof/topology.c | 59 ++++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+) create mode 100644 include/sound/sof/dai-mediatek.h diff --git a/include/sound/sof/dai-mediatek.h b/include/sound/sof/dai-mediatek.h new file mode 100644 index 0000000000000..62dd4720558d5 --- /dev/null +++ b/include/sound/sof/dai-mediatek.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ +/* + * Copyright(c) 2021 Mediatek Corporation. All rights reserved. + * + * Author: Bo Pan + */ + +#ifndef __INCLUDE_SOUND_SOF_DAI_MEDIATEK_H__ +#define __INCLUDE_SOUND_SOF_DAI_MEDIATEK_H__ + +#include + +struct sof_ipc_dai_mtk_afe_params { + struct sof_ipc_hdr hdr; + u32 channels; + u32 rate; + u32 format; + u32 stream_id; + u32 reserved[4]; /* reserve for future */ +} __packed; + +#endif + diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h index 3782127a70956..5132bc60f54bf 100644 --- a/include/sound/sof/dai.h +++ b/include/sound/sof/dai.h @@ -13,6 +13,7 @@ #include #include #include +#include /* * DAI Configuration. @@ -70,6 +71,7 @@ enum sof_ipc_dai_type { SOF_DAI_AMD_BT, /**< AMD ACP BT*/ SOF_DAI_AMD_SP, /**< AMD ACP SP */ SOF_DAI_AMD_DMIC, /**< AMD ACP DMIC */ + SOF_DAI_MEDIATEK_AFE, /**< Mediatek AFE */ }; /* general purpose DAI configuration */ @@ -97,6 +99,7 @@ struct sof_ipc_dai_config { struct sof_ipc_dai_acp_params acpbt; struct sof_ipc_dai_acp_params acpsp; struct sof_ipc_dai_acp_params acpdmic; + struct sof_ipc_dai_mtk_afe_params afe; }; } __packed; diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 8d313c9862cb5..31dd79b794f15 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -808,6 +808,18 @@ int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_pa channels->min = dai->dai_config->esai.tdm_slots; channels->max = dai->dai_config->esai.tdm_slots; + dev_dbg(component->dev, + "rate_min: %d rate_max: %d\n", rate->min, rate->max); + dev_dbg(component->dev, + "channels_min: %d channels_max: %d\n", + channels->min, channels->max); + break; + case SOF_DAI_MEDIATEK_AFE: + rate->min = dai->dai_config->afe.rate; + rate->max = dai->dai_config->afe.rate; + channels->min = dai->dai_config->afe.channels; + channels->max = dai->dai_config->afe.channels; + dev_dbg(component->dev, "rate_min: %d rate_max: %d\n", rate->min, rate->max); dev_dbg(component->dev, diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 72e671c15a347..10caf2b1a33ce 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -379,6 +379,7 @@ static const struct sof_dai_types sof_dais[] = { {"ACP", SOF_DAI_AMD_BT}, {"ACPSP", SOF_DAI_AMD_SP}, {"ACPDMIC", SOF_DAI_AMD_DMIC}, + {"AFE", SOF_DAI_MEDIATEK_AFE}, }; static enum sof_ipc_dai_type find_dai(const char *name) @@ -806,6 +807,19 @@ static const struct sof_topology_token led_tokens[] = { get_token_u32, offsetof(struct snd_sof_led_control, direction), 0}, }; +/* AFE */ +static const struct sof_topology_token afe_tokens[] = { + {SOF_TKN_MEDIATEK_AFE_RATE, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_mtk_afe_params, rate), 0}, + {SOF_TKN_MEDIATEK_AFE_CH, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_mtk_afe_params, channels), 0}, + {SOF_TKN_MEDIATEK_AFE_FORMAT, + SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_format, + offsetof(struct sof_ipc_dai_mtk_afe_params, format), 0}, +}; + static int sof_parse_uuid_tokens(struct snd_soc_component *scomp, void *object, const struct sof_topology_token *tokens, @@ -3091,6 +3105,48 @@ static int sof_link_acp_sp_load(struct snd_soc_component *scomp, int index, return ret; } +static int sof_link_afe_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg, + struct snd_soc_tplg_hw_config *hw_config, + struct sof_ipc_dai_config *config) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &cfg->priv; + struct snd_soc_dai *dai; + u32 size = sizeof(*config); + int ret; + + config->hdr.size = size; + + /* get any bespoke DAI tokens */ + ret = sof_parse_tokens(scomp, &config->afe, afe_tokens, + ARRAY_SIZE(afe_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(scomp->dev, "parse afe tokens failed %d\n", + le32_to_cpu(private->size)); + return ret; + } + + dev_dbg(scomp->dev, "AFE config rate %d channels %d format:%d\n", + config->afe.rate, config->afe.channels, config->afe.format); + + dai = snd_soc_find_dai(link->cpus); + if (!dai) { + dev_err(scomp->dev, "%s: failed to find dai %s", __func__, link->cpus->dai_name); + return -EINVAL; + } + + config->afe.stream_id = DMA_CHAN_INVALID; + + ret = sof_set_dai_config(sdev, size, link, config); + if (ret < 0) + dev_err(scomp->dev, "failed to process afe dai link %s", link->name); + + return ret; +} + static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, struct snd_soc_dai_link *link, struct snd_soc_tplg_link_config *cfg, @@ -3386,6 +3442,9 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, ret = sof_link_acp_dmic_load(scomp, index, link, cfg, hw_config + curr_conf, config); break; + case SOF_DAI_MEDIATEK_AFE: + ret = sof_link_afe_load(scomp, index, link, cfg, hw_config + curr_conf, config); + break; default: dev_err(scomp->dev, "error: invalid DAI type %d\n", common_config.type); ret = -EINVAL; From b7f6503830cd8f3f7076635409460861b5ff6310 Mon Sep 17 00:00:00 2001 From: YC Hung Date: Thu, 18 Nov 2021 12:07:45 +0200 Subject: [PATCH 063/327] ASoC: SOF: mediatek: Add fw loader and mt8195 dsp ops to load firmware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add mt8195-loader module with ops callback to load and run firmware on mt8195 platform. Signed-off-by: YC Hung Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Kai Vehmanen Reviewed-by: Guennadi Liakhovetski Reviewed-by: Daniel Baluta Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211118100749.54628-5-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/mediatek/mt8195/Makefile | 2 +- sound/soc/sof/mediatek/mt8195/mt8195-loader.c | 56 +++++++++++++++++++ sound/soc/sof/mediatek/mt8195/mt8195.c | 19 +++++++ sound/soc/sof/mediatek/mt8195/mt8195.h | 3 + 4 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 sound/soc/sof/mediatek/mt8195/mt8195-loader.c diff --git a/sound/soc/sof/mediatek/mt8195/Makefile b/sound/soc/sof/mediatek/mt8195/Makefile index dd2b6e4affc9f..66cdc0e7bf3cb 100644 --- a/sound/soc/sof/mediatek/mt8195/Makefile +++ b/sound/soc/sof/mediatek/mt8195/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) -snd-sof-mt8195-objs := mt8195.o +snd-sof-mt8195-objs := mt8195.o mt8195-loader.o obj-$(CONFIG_SND_SOC_SOF_MT8195) += snd-sof-mt8195.o diff --git a/sound/soc/sof/mediatek/mt8195/mt8195-loader.c b/sound/soc/sof/mediatek/mt8195/mt8195-loader.c new file mode 100644 index 0000000000000..ed18d6379e922 --- /dev/null +++ b/sound/soc/sof/mediatek/mt8195/mt8195-loader.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// Copyright (c) 2021 Mediatek Corporation. All rights reserved. +// +// Author: YC Hung +// +// Hardware interface for mt8195 DSP code loader + +#include +#include "mt8195.h" +#include "../../ops.h" + +void sof_hifixdsp_boot_sequence(struct snd_sof_dev *sdev, u32 boot_addr) +{ + /* ADSP bootup base */ + snd_sof_dsp_write(sdev, DSP_REG_BAR, DSP_ALTRESETVEC, boot_addr); + + /* pull high RunStall (set bit3 to 1) */ + snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW, + ADSP_RUNSTALL, ADSP_RUNSTALL); + + /* pull high StatVectorSel to use AltResetVec (set bit4 to 1) */ + snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW, + DSP_RESET_SW, DSP_RESET_SW); + + /* toggle DReset & BReset */ + /* pull high DReset & BReset */ + snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW, + ADSP_BRESET_SW | ADSP_DRESET_SW, + ADSP_BRESET_SW | ADSP_DRESET_SW); + + /* pull low DReset & BReset */ + snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW, + ADSP_BRESET_SW | ADSP_DRESET_SW, + 0); + + /* Enable PDebug */ + snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_PDEBUGBUS0, + PDEBUG_ENABLE, + PDEBUG_ENABLE); + + /* release RunStall (set bit3 to 0) */ + snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW, + ADSP_RUNSTALL, 0); +} + +void sof_hifixdsp_shutdown(struct snd_sof_dev *sdev) +{ + /* Clear to 0 firstly */ + snd_sof_dsp_write(sdev, DSP_REG_BAR, DSP_RESET_SW, 0x0); + + /* RUN_STALL pull high again to reset */ + snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW, + ADSP_RUNSTALL, ADSP_RUNSTALL); +} + diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index 966b8660e21c6..88da6c2de070b 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -198,6 +198,17 @@ static int adsp_shared_base_ioremap(struct platform_device *pdev, void *data) return 0; } +static int mt8195_run(struct snd_sof_dev *sdev) +{ + u32 adsp_bootup_addr; + + adsp_bootup_addr = SRAM_PHYS_BASE_FROM_DSP_VIEW; + dev_dbg(sdev->dev, "HIFIxDSP boot from base : 0x%08X\n", adsp_bootup_addr); + sof_hifixdsp_boot_sequence(sdev, adsp_bootup_addr); + + return 0; +} + static int mt8195_dsp_probe(struct snd_sof_dev *sdev) { struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev); @@ -294,6 +305,9 @@ const struct snd_sof_dsp_ops sof_mt8195_ops = { .probe = mt8195_dsp_probe, .remove = mt8195_dsp_remove, + /* DSP core boot */ + .run = mt8195_run, + /* Block IO */ .block_read = sof_block_read, .block_write = sof_block_write, @@ -307,6 +321,11 @@ const struct snd_sof_dsp_ops sof_mt8195_ops = { /* misc */ .get_bar_index = mt8195_get_bar_index, + /* module loading */ + .load_module = snd_sof_parse_module_memcpy, + /* firmware loading */ + .load_firmware = snd_sof_load_firmware_memcpy, + /* Firmware ops */ .dsp_arch_ops = &sof_xtensa_arch_ops, diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.h b/sound/soc/sof/mediatek/mt8195/mt8195.h index 48cbbb5aacb51..9294241823572 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.h +++ b/sound/soc/sof/mediatek/mt8195/mt8195.h @@ -10,6 +10,7 @@ #define __MT8195_H struct mtk_adsp_chip_info; +struct snd_sof_dev; #define DSP_REG_BASE 0x10803000 #define SCP_CFGREG_BASE 0x10724000 @@ -152,4 +153,6 @@ struct mtk_adsp_chip_info; #define DRAM_REMAP_SHIFT 12 #define DRAM_REMAP_MASK (BIT(DRAM_REMAP_SHIFT) - 1) +void sof_hifixdsp_boot_sequence(struct snd_sof_dev *sdev, u32 boot_addr); +void sof_hifixdsp_shutdown(struct snd_sof_dev *sdev); #endif From 24281bc2bf1884e665dfbcd17aaaabbc5872e501 Mon Sep 17 00:00:00 2001 From: YC Hung Date: Thu, 18 Nov 2021 12:07:46 +0200 Subject: [PATCH 064/327] ASoC: SOF: Add mt8195 device descriptor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add SOF device and DT descriptor for Mediatek mt8195 platform. Signed-off-by: YC Hung Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Kai Vehmanen Reviewed-by: Guennadi Liakhovetski Reviewed-by: Daniel Baluta Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211118100749.54628-6-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/Kconfig | 2 +- sound/soc/sof/sof-of-dev.c | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index b0cdabcfdde75..ac34c330cf0c0 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -42,7 +42,7 @@ config SND_SOC_SOF_OF depends on OF || COMPILE_TEST help This adds support for Device Tree enumeration. This option is - required to enable i.MX8 devices. + required to enable i.MX8 or Mediatek devices. Say Y if you need this option. If unsure select "N". config SND_SOC_SOF_OF_DEV diff --git a/sound/soc/sof/sof-of-dev.c b/sound/soc/sof/sof-of-dev.c index 885430a42226e..412cbb824b844 100644 --- a/sound/soc/sof/sof-of-dev.c +++ b/sound/soc/sof/sof-of-dev.c @@ -13,6 +13,7 @@ #include "ops.h" #include "imx/imx-ops.h" +#include "mediatek/mediatek-ops.h" static char *fw_path; module_param(fw_path, charp, 0444); @@ -50,6 +51,15 @@ static struct sof_dev_desc sof_of_imx8mp_desc = { .ops = &sof_imx8m_ops, }; #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_MT8195) +static const struct sof_dev_desc sof_of_mt8195_desc = { + .default_fw_path = "mediatek/sof", + .default_tplg_path = "mediatek/sof-tplg", + .default_fw_filename = "sof-mt8195.ri", + .nocodec_tplg_filename = "sof-mt8195-nocodec.tplg", + .ops = &sof_mt8195_ops, +}; +#endif static const struct dev_pm_ops sof_of_pm = { .prepare = snd_sof_prepare, @@ -130,6 +140,9 @@ static const struct of_device_id sof_of_ids[] = { #endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8M) { .compatible = "fsl,imx8mp-dsp", .data = &sof_of_imx8mp_desc}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_MT8195) + { .compatible = "mediatek,mt8195-dsp", .data = &sof_of_mt8195_desc}, #endif { } }; From 24d75049c5ed5193bd12ce0d43c355c4ef74a7fa Mon Sep 17 00:00:00 2001 From: YC Hung Date: Thu, 18 Nov 2021 12:07:47 +0200 Subject: [PATCH 065/327] ASoC: SOF: mediatek: Add dai driver dsp ops callback for mt8195 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add dsp ops callback to register AFE DL2/DL3/UL4/UL5 sof dai's with ALSA Signed-off-by: YC Hung Reviewed-by: Péter Ujfalusi Reviewed-by: Kai Vehmanen Reviewed-by: Daniel Baluta Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Reviewed-by: Guennadi Liakhovetski Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211118100749.54628-7-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/mediatek/mt8195/mt8195.c | 35 ++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index 88da6c2de070b..99075598a35ae 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -299,6 +299,37 @@ static int mt8195_get_bar_index(struct snd_sof_dev *sdev, u32 type) return type; } +static struct snd_soc_dai_driver mt8195_dai[] = { +{ + .name = "SOF_DL2", + .playback = { + .channels_min = 1, + .channels_max = 2, + }, +}, +{ + .name = "SOF_DL3", + .playback = { + .channels_min = 1, + .channels_max = 2, + }, +}, +{ + .name = "SOF_UL4", + .capture = { + .channels_min = 1, + .channels_max = 2, + }, +}, +{ + .name = "SOF_UL5", + .capture = { + .channels_min = 1, + .channels_max = 2, + }, +}, +}; + /* mt8195 ops */ const struct snd_sof_dsp_ops sof_mt8195_ops = { /* probe and remove */ @@ -329,6 +360,10 @@ const struct snd_sof_dsp_ops sof_mt8195_ops = { /* Firmware ops */ .dsp_arch_ops = &sof_xtensa_arch_ops, + /* DAI drivers */ + .drv = mt8195_dai, + .num_drv = ARRAY_SIZE(mt8195_dai), + /* ALSA HW info flags */ .hw_info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | From 424d6d1a9a51b7e6ab397132700a237082d64cf4 Mon Sep 17 00:00:00 2001 From: YC Hung Date: Thu, 18 Nov 2021 12:07:48 +0200 Subject: [PATCH 066/327] ASoC: SOF: mediatek: Add mt8195 dsp clock support Add adsp clock on/off support on mt8195 platform. Signed-off-by: YC Hung Reviewed-by: Pierre-Louis Bossart Reviewed-by: Daniel Baluta Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211118100749.54628-8-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/mediatek/adsp_helper.h | 2 +- sound/soc/sof/mediatek/mt8195/Makefile | 2 +- sound/soc/sof/mediatek/mt8195/mt8195-clk.c | 158 +++++++++++++++++++++ sound/soc/sof/mediatek/mt8195/mt8195-clk.h | 28 ++++ sound/soc/sof/mediatek/mt8195/mt8195.c | 22 ++- 5 files changed, 208 insertions(+), 4 deletions(-) create mode 100644 sound/soc/sof/mediatek/mt8195/mt8195-clk.c create mode 100644 sound/soc/sof/mediatek/mt8195/mt8195-clk.h diff --git a/sound/soc/sof/mediatek/adsp_helper.h b/sound/soc/sof/mediatek/adsp_helper.h index 346953dd22db9..6734e2c0c6b1c 100644 --- a/sound/soc/sof/mediatek/adsp_helper.h +++ b/sound/soc/sof/mediatek/adsp_helper.h @@ -39,7 +39,7 @@ struct adsp_priv { struct mbox_controller *adsp_mbox; struct mtk_adsp_chip_info *adsp; - + struct clk **clk; u32 (*ap2adsp_addr)(u32 addr, void *data); u32 (*adsp2ap_addr)(u32 addr, void *data); diff --git a/sound/soc/sof/mediatek/mt8195/Makefile b/sound/soc/sof/mediatek/mt8195/Makefile index 66cdc0e7bf3cb..afc4f21fccc50 100644 --- a/sound/soc/sof/mediatek/mt8195/Makefile +++ b/sound/soc/sof/mediatek/mt8195/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) -snd-sof-mt8195-objs := mt8195.o mt8195-loader.o +snd-sof-mt8195-objs := mt8195.o mt8195-clk.o mt8195-loader.o obj-$(CONFIG_SND_SOC_SOF_MT8195) += snd-sof-mt8195.o diff --git a/sound/soc/sof/mediatek/mt8195/mt8195-clk.c b/sound/soc/sof/mediatek/mt8195/mt8195-clk.c new file mode 100644 index 0000000000000..6bcb4b9b00fb9 --- /dev/null +++ b/sound/soc/sof/mediatek/mt8195/mt8195-clk.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// Copyright(c) 2021 Mediatek Corporation. All rights reserved. +// +// Author: YC Hung +// +// Hardware interface for mt8195 DSP clock + +#include +#include +#include +#include "mt8195.h" +#include "mt8195-clk.h" +#include "../adsp_helper.h" +#include "../../sof-audio.h" + +static const char *adsp_clks[ADSP_CLK_MAX] = { + [CLK_TOP_ADSP] = "adsp_sel", + [CLK_TOP_CLK26M] = "clk26m_ck", + [CLK_TOP_AUDIO_LOCAL_BUS] = "audio_local_bus", + [CLK_TOP_MAINPLL_D7_D2] = "mainpll_d7_d2", + [CLK_SCP_ADSP_AUDIODSP] = "scp_adsp_audiodsp", + [CLK_TOP_AUDIO_H] = "audio_h", +}; + +int mt8195_adsp_init_clock(struct snd_sof_dev *sdev) +{ + struct device *dev = sdev->dev; + struct adsp_priv *priv = sdev->pdata->hw_pdata; + int i; + + priv->clk = devm_kcalloc(dev, ADSP_CLK_MAX, sizeof(*priv->clk), GFP_KERNEL); + + if (!priv->clk) + return -ENOMEM; + + for (i = 0; i < ADSP_CLK_MAX; i++) { + priv->clk[i] = devm_clk_get(dev, adsp_clks[i]); + if (IS_ERR(priv->clk[i])) + return PTR_ERR(priv->clk[i]); + } + + return 0; +} + +static int adsp_enable_all_clock(struct snd_sof_dev *sdev) +{ + struct device *dev = sdev->dev; + struct adsp_priv *priv = sdev->pdata->hw_pdata; + int ret; + + ret = clk_prepare_enable(priv->clk[CLK_TOP_MAINPLL_D7_D2]); + if (ret) { + dev_err(dev, "%s clk_prepare_enable(mainpll_d7_d2) fail %d\n", + __func__, ret); + return ret; + } + + ret = clk_prepare_enable(priv->clk[CLK_TOP_ADSP]); + if (ret) { + dev_err(dev, "%s clk_prepare_enable(adsp_sel) fail %d\n", + __func__, ret); + goto disable_mainpll_d7_d2_clk; + } + + ret = clk_prepare_enable(priv->clk[CLK_TOP_AUDIO_LOCAL_BUS]); + if (ret) { + dev_err(dev, "%s clk_prepare_enable(audio_local_bus) fail %d\n", + __func__, ret); + goto disable_dsp_sel_clk; + } + + ret = clk_prepare_enable(priv->clk[CLK_SCP_ADSP_AUDIODSP]); + if (ret) { + dev_err(dev, "%s clk_prepare_enable(scp_adsp_audiodsp) fail %d\n", + __func__, ret); + goto disable_audio_local_bus_clk; + } + + ret = clk_prepare_enable(priv->clk[CLK_TOP_AUDIO_H]); + if (ret) { + dev_err(dev, "%s clk_prepare_enable(audio_h) fail %d\n", + __func__, ret); + goto disable_scp_adsp_audiodsp_clk; + } + + return 0; + +disable_scp_adsp_audiodsp_clk: + clk_disable_unprepare(priv->clk[CLK_SCP_ADSP_AUDIODSP]); +disable_audio_local_bus_clk: + clk_disable_unprepare(priv->clk[CLK_TOP_AUDIO_LOCAL_BUS]); +disable_dsp_sel_clk: + clk_disable_unprepare(priv->clk[CLK_TOP_ADSP]); +disable_mainpll_d7_d2_clk: + clk_disable_unprepare(priv->clk[CLK_TOP_MAINPLL_D7_D2]); + + return ret; +} + +static void adsp_disable_all_clock(struct snd_sof_dev *sdev) +{ + struct adsp_priv *priv = sdev->pdata->hw_pdata; + + clk_disable_unprepare(priv->clk[CLK_TOP_AUDIO_H]); + clk_disable_unprepare(priv->clk[CLK_SCP_ADSP_AUDIODSP]); + clk_disable_unprepare(priv->clk[CLK_TOP_AUDIO_LOCAL_BUS]); + clk_disable_unprepare(priv->clk[CLK_TOP_ADSP]); + clk_disable_unprepare(priv->clk[CLK_TOP_MAINPLL_D7_D2]); +} + +static int adsp_default_clk_init(struct snd_sof_dev *sdev, bool enable) +{ + struct device *dev = sdev->dev; + struct adsp_priv *priv = sdev->pdata->hw_pdata; + int ret; + + dev_dbg(dev, "%s: %s\n", __func__, enable ? "on" : "off"); + + if (enable) { + ret = clk_set_parent(priv->clk[CLK_TOP_ADSP], + priv->clk[CLK_TOP_CLK26M]); + if (ret) { + dev_err(dev, "failed to set dsp_sel to clk26m: %d\n", ret); + return ret; + } + + ret = clk_set_parent(priv->clk[CLK_TOP_AUDIO_LOCAL_BUS], + priv->clk[CLK_TOP_MAINPLL_D7_D2]); + if (ret) { + dev_err(dev, "set audio_local_bus failed %d\n", ret); + return ret; + } + + ret = adsp_enable_all_clock(sdev); + if (ret) { + dev_err(dev, "failed to adsp_enable_clock: %d\n", ret); + return ret; + } + } else { + adsp_disable_all_clock(sdev); + } + + return 0; +} + +int adsp_clock_on(struct snd_sof_dev *sdev) +{ + /* Open ADSP clock */ + return adsp_default_clk_init(sdev, 1); +} + +int adsp_clock_off(struct snd_sof_dev *sdev) +{ + /* Close ADSP clock */ + return adsp_default_clk_init(sdev, 0); +} + diff --git a/sound/soc/sof/mediatek/mt8195/mt8195-clk.h b/sound/soc/sof/mediatek/mt8195/mt8195-clk.h new file mode 100644 index 0000000000000..9cc0573d5cd2f --- /dev/null +++ b/sound/soc/sof/mediatek/mt8195/mt8195-clk.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * Copyright (c) 2021 MediaTek Corporation. All rights reserved. + * + * Header file for the mt8195 DSP clock definition + */ + +#ifndef __MT8195_CLK_H +#define __MT8195_CLK_H + +struct snd_sof_dev; + +/*DSP clock*/ +enum adsp_clk_id { + CLK_TOP_ADSP, + CLK_TOP_CLK26M, + CLK_TOP_AUDIO_LOCAL_BUS, + CLK_TOP_MAINPLL_D7_D2, + CLK_SCP_ADSP_AUDIODSP, + CLK_TOP_AUDIO_H, + ADSP_CLK_MAX +}; + +int mt8195_adsp_init_clock(struct snd_sof_dev *sdev); +int adsp_clock_on(struct snd_sof_dev *sdev); +int adsp_clock_off(struct snd_sof_dev *sdev); +#endif diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index 99075598a35ae..5bfae9379ac8d 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -25,6 +25,7 @@ #include "../adsp_helper.h" #include "../mediatek-ops.h" #include "mt8195.h" +#include "mt8195-clk.h" static int platform_parse_resource(struct platform_device *pdev, void *data) { @@ -231,10 +232,22 @@ static int mt8195_dsp_probe(struct snd_sof_dev *sdev) if (ret) return ret; + ret = mt8195_adsp_init_clock(sdev); + if (ret) { + dev_err(sdev->dev, "mt8195_adsp_init_clock failed\n"); + return -EINVAL; + } + + ret = adsp_clock_on(sdev); + if (ret) { + dev_err(sdev->dev, "adsp_clock_on fail!\n"); + return -EINVAL; + } + ret = adsp_sram_power_on(sdev->dev, true); if (ret) { dev_err(sdev->dev, "adsp_sram_power_on fail!\n"); - return ret; + goto exit_clk_disable; } ret = adsp_memory_remap_init(&pdev->dev, priv->adsp); @@ -282,6 +295,8 @@ static int mt8195_dsp_probe(struct snd_sof_dev *sdev) err_adsp_sram_power_off: adsp_sram_power_on(&pdev->dev, false); +exit_clk_disable: + adsp_clock_off(sdev); return ret; } @@ -290,7 +305,10 @@ static int mt8195_dsp_remove(struct snd_sof_dev *sdev) { struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev); - return adsp_sram_power_on(&pdev->dev, false); + adsp_sram_power_on(&pdev->dev, false); + adsp_clock_off(sdev); + + return 0; } /* on mt8195 there is 1 to 1 match between type and BAR idx */ From 163fa3a5927e1d8f948ea1fc16c897944933a06a Mon Sep 17 00:00:00 2001 From: YC Hung Date: Thu, 18 Nov 2021 12:07:49 +0200 Subject: [PATCH 067/327] ASoC: SOF: mediatek: Add DSP system PM callback for mt8195 Add DSP system PM callback for suspend and resume Signed-off-by: YC Hung Reviewed-by: Pierre-Louis Bossart Reviewed-by: Daniel Baluta Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211118100749.54628-9-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/mediatek/mt8195/mt8195.c | 42 ++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index 5bfae9379ac8d..40e5a25875a6a 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -311,6 +311,44 @@ static int mt8195_dsp_remove(struct snd_sof_dev *sdev) return 0; } +static int mt8195_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state) +{ + struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev); + int ret; + + /* stall and reset dsp */ + sof_hifixdsp_shutdown(sdev); + + /* power down adsp sram */ + ret = adsp_sram_power_on(&pdev->dev, false); + if (ret) { + dev_err(sdev->dev, "adsp_sram_power_off fail!\n"); + return ret; + } + + /* turn off adsp clock */ + return adsp_clock_off(sdev); +} + +static int mt8195_dsp_resume(struct snd_sof_dev *sdev) +{ + int ret; + + /* turn on adsp clock */ + ret = adsp_clock_on(sdev); + if (ret) { + dev_err(sdev->dev, "adsp_clock_on fail!\n"); + return ret; + } + + /* power on adsp sram */ + ret = adsp_sram_power_on(sdev->dev, true); + if (ret) + dev_err(sdev->dev, "adsp_sram_power_on fail!\n"); + + return ret; +} + /* on mt8195 there is 1 to 1 match between type and BAR idx */ static int mt8195_get_bar_index(struct snd_sof_dev *sdev, u32 type) { @@ -382,6 +420,10 @@ const struct snd_sof_dsp_ops sof_mt8195_ops = { .drv = mt8195_dai, .num_drv = ARRAY_SIZE(mt8195_dai), + /* PM */ + .suspend = mt8195_dsp_suspend, + .resume = mt8195_dsp_resume, + /* ALSA HW info flags */ .hw_info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | From b38892b5b85ae54b7b867313996f967122ede42e Mon Sep 17 00:00:00 2001 From: Srinivasa Rao Mandadapu Date: Thu, 18 Nov 2021 16:50:11 +0530 Subject: [PATCH 068/327] ASoC: codecs: MBHC: Remove useless condition check Remove redundant conditional check and clean code in special headset support functions. Signed-off-by: Srinivasa Rao Mandadapu Co-developed-by: Venkata Prasad Potturu Signed-off-by: Venkata Prasad Potturu Link: https://lore.kernel.org/r/1637234411-554-1-git-send-email-srivasam@codeaurora.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd-mbhc-v2.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c index 934194b155d58..7488a150a1389 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.c +++ b/sound/soc/codecs/wcd-mbhc-v2.c @@ -1055,12 +1055,8 @@ static bool wcd_mbhc_check_for_spl_headset(struct wcd_mbhc *mbhc) hs_threshold = wcd_mbhc_get_spl_hs_thres(mbhc); hph_threshold = wcd_mbhc_adc_get_hph_thres(mbhc); - if (output_mv > hs_threshold || output_mv < hph_threshold) { - if (mbhc->force_linein == true) - is_spl_hs = false; - } else { + if (!(output_mv > hs_threshold || output_mv < hph_threshold)) is_spl_hs = true; - } /* Back MIC_BIAS2 to 1.8v if the type is not special headset */ if (!is_spl_hs) { @@ -1149,13 +1145,13 @@ static void wcd_correct_swch_plug(struct work_struct *work) plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv); is_pa_on = wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN); - if ((output_mv > hs_threshold) && (!is_spl_hs)) { + if (output_mv > hs_threshold && !is_spl_hs) { is_spl_hs = wcd_mbhc_check_for_spl_headset(mbhc); output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P); if (is_spl_hs) { - hs_threshold = (hs_threshold * wcd_mbhc_get_micbias(mbhc)) / - micbias_mv; + hs_threshold *= wcd_mbhc_get_micbias(mbhc); + hs_threshold /= micbias_mv; } } @@ -1185,7 +1181,7 @@ static void wcd_correct_swch_plug(struct work_struct *work) } /* cable is extension cable */ - if (output_mv > hs_threshold || mbhc->force_linein == true) + if (output_mv > hs_threshold || mbhc->force_linein) plug_type = MBHC_PLUG_TYPE_HIGH_HPH; } From 8253aa4700b37cef1ca3bbda0d986349357608d3 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Fri, 19 Nov 2021 11:43:15 +0200 Subject: [PATCH 069/327] ASoC: SOF: imx: Add code to manage DSP related clocks We need at least 3 clocks in order to power up and access DSP core registers found on i.MX8QM, i.MX8QXP and i.MX8MP platforms. Add code to request these clocks and enable them at probe. Next patches will add PM support which will only activate clocks when DSP is used. DSP clocks are already documented in Documentation/devicetree/bindings/dsp/fsl,dsp.yaml We choose to add: * imx8_parse_clocks * imx8_enable_clocks * imx8_disable_clocks wrappers because in the future DSP will need to take care about the clocks of other related Audio IPs (e.g SAI, ESAI). Signed-off-by: Daniel Baluta Reviewed-by: Paul Olaru Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20211119094319.81674-2-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/imx/imx-common.c | 24 ++++++++++++++++++++++++ sound/soc/sof/imx/imx-common.h | 11 +++++++++++ sound/soc/sof/imx/imx8.c | 23 +++++++++++++++++++++++ sound/soc/sof/imx/imx8m.c | 23 +++++++++++++++++++++++ 4 files changed, 81 insertions(+) diff --git a/sound/soc/sof/imx/imx-common.c b/sound/soc/sof/imx/imx-common.c index 8826ef94f04a3..9371e9062cb14 100644 --- a/sound/soc/sof/imx/imx-common.c +++ b/sound/soc/sof/imx/imx-common.c @@ -74,4 +74,28 @@ void imx8_dump(struct snd_sof_dev *sdev, u32 flags) } EXPORT_SYMBOL(imx8_dump); +int imx8_parse_clocks(struct snd_sof_dev *sdev, struct imx_clocks *clks) +{ + int ret; + + ret = devm_clk_bulk_get(sdev->dev, clks->num_dsp_clks, clks->dsp_clks); + if (ret) + dev_err(sdev->dev, "Failed to request DSP clocks\n"); + + return ret; +} +EXPORT_SYMBOL(imx8_parse_clocks); + +int imx8_enable_clocks(struct snd_sof_dev *sdev, struct imx_clocks *clks) +{ + return clk_bulk_prepare_enable(clks->num_dsp_clks, clks->dsp_clks); +} +EXPORT_SYMBOL(imx8_enable_clocks); + +void imx8_disable_clocks(struct snd_sof_dev *sdev, struct imx_clocks *clks) +{ + clk_bulk_disable_unprepare(clks->num_dsp_clks, clks->dsp_clks); +} +EXPORT_SYMBOL(imx8_disable_clocks); + MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/imx/imx-common.h b/sound/soc/sof/imx/imx-common.h index 1cc7d67041825..ec4b3a5c7496a 100644 --- a/sound/soc/sof/imx/imx-common.h +++ b/sound/soc/sof/imx/imx-common.h @@ -3,6 +3,8 @@ #ifndef __IMX_COMMON_H__ #define __IMX_COMMON_H__ +#include + #define EXCEPT_MAX_HDR_SIZE 0x400 #define IMX8_STACK_DUMP_SIZE 32 @@ -13,4 +15,13 @@ void imx8_get_registers(struct snd_sof_dev *sdev, void imx8_dump(struct snd_sof_dev *sdev, u32 flags); +struct imx_clocks { + struct clk_bulk_data *dsp_clks; + int num_dsp_clks; +}; + +int imx8_parse_clocks(struct snd_sof_dev *sdev, struct imx_clocks *clks); +int imx8_enable_clocks(struct snd_sof_dev *sdev, struct imx_clocks *clks); +void imx8_disable_clocks(struct snd_sof_dev *sdev, struct imx_clocks *clks); + #endif diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c index 0aeb44d0acc7e..32f852cbba30d 100644 --- a/sound/soc/sof/imx/imx8.c +++ b/sound/soc/sof/imx/imx8.c @@ -41,6 +41,13 @@ #define MBOX_OFFSET 0x800000 #define MBOX_SIZE 0x1000 +/* DSP clocks */ +static struct clk_bulk_data imx8_dsp_clks[] = { + { .id = "ipg" }, + { .id = "ocram" }, + { .id = "core" }, +}; + struct imx8_priv { struct device *dev; struct snd_sof_dev *sdev; @@ -57,6 +64,7 @@ struct imx8_priv { struct device **pd_dev; struct device_link **link; + struct imx_clocks *clks; }; static int imx8_get_mailbox_offset(struct snd_sof_dev *sdev) @@ -188,6 +196,10 @@ static int imx8_probe(struct snd_sof_dev *sdev) if (!priv) return -ENOMEM; + priv->clks = devm_kzalloc(&pdev->dev, sizeof(*priv->clks), GFP_KERNEL); + if (!priv->clks) + return -ENOMEM; + sdev->pdata->hw_pdata = priv; priv->dev = sdev->dev; priv->sdev = sdev; @@ -300,6 +312,16 @@ static int imx8_probe(struct snd_sof_dev *sdev) /* set default mailbox offset for FW ready message */ sdev->dsp_box.offset = MBOX_OFFSET; + /* init clocks info */ + priv->clks->dsp_clks = imx8_dsp_clks; + priv->clks->num_dsp_clks = ARRAY_SIZE(imx8_dsp_clks); + + ret = imx8_parse_clocks(sdev, priv->clks); + if (ret < 0) + goto exit_pdev_unregister; + + imx8_enable_clocks(sdev, priv->clks); + return 0; exit_pdev_unregister: @@ -318,6 +340,7 @@ static int imx8_remove(struct snd_sof_dev *sdev) struct imx8_priv *priv = sdev->pdata->hw_pdata; int i; + imx8_disable_clocks(sdev, priv->clks); platform_device_unregister(priv->ipc_dev); for (i = 0; i < priv->num_domains; i++) { diff --git a/sound/soc/sof/imx/imx8m.c b/sound/soc/sof/imx/imx8m.c index f454a5d0a87e9..ab40c0bdf7963 100644 --- a/sound/soc/sof/imx/imx8m.c +++ b/sound/soc/sof/imx/imx8m.c @@ -23,6 +23,12 @@ #define MBOX_OFFSET 0x800000 #define MBOX_SIZE 0x1000 +static struct clk_bulk_data imx8m_dsp_clks[] = { + { .id = "ipg" }, + { .id = "ocram" }, + { .id = "core" }, +}; + struct imx8m_priv { struct device *dev; struct snd_sof_dev *sdev; @@ -30,6 +36,8 @@ struct imx8m_priv { /* DSP IPC handler */ struct imx_dsp_ipc *dsp_ipc; struct platform_device *ipc_dev; + + struct imx_clocks *clks; }; static int imx8m_get_mailbox_offset(struct snd_sof_dev *sdev) @@ -108,6 +116,10 @@ static int imx8m_probe(struct snd_sof_dev *sdev) if (!priv) return -ENOMEM; + priv->clks = devm_kzalloc(&pdev->dev, sizeof(*priv->clks), GFP_KERNEL); + if (!priv->clks) + return -ENOMEM; + sdev->pdata->hw_pdata = priv; priv->dev = sdev->dev; priv->sdev = sdev; @@ -175,6 +187,16 @@ static int imx8m_probe(struct snd_sof_dev *sdev) /* set default mailbox offset for FW ready message */ sdev->dsp_box.offset = MBOX_OFFSET; + /* init clocks info */ + priv->clks->dsp_clks = imx8m_dsp_clks; + priv->clks->num_dsp_clks = ARRAY_SIZE(imx8m_dsp_clks); + + ret = imx8_parse_clocks(sdev, priv->clks); + if (ret < 0) + goto exit_pdev_unregister; + + imx8_enable_clocks(sdev, priv->clks); + return 0; exit_pdev_unregister: @@ -186,6 +208,7 @@ static int imx8m_remove(struct snd_sof_dev *sdev) { struct imx8m_priv *priv = sdev->pdata->hw_pdata; + imx8_disable_clocks(sdev, priv->clks); platform_device_unregister(priv->ipc_dev); return 0; From 6fc8515806dfd5b7d3198c189b51e7624aadafdc Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Fri, 19 Nov 2021 11:43:16 +0200 Subject: [PATCH 070/327] ASoC: SOF: imx8: Add runtime PM / System PM support Handle clocks and mailbox channels at runtime suspend/resume in order to save power. DSP runtime PM uses a timeout of 2s. If device is idle for 2s system will enter runtime suspend. Because SOF state machine assumes that even if the DSP wasn't previously active at a System resume, will re-load the firmware we need to make sure that all needed resources are active. Kernel core will take care of enabling the PD, we need to make sure that we request the MU channels. Signed-off-by: Daniel Baluta Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20211119094319.81674-3-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/imx/imx8.c | 116 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 115 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c index 32f852cbba30d..c4755c88d4923 100644 --- a/sound/soc/sof/imx/imx8.c +++ b/sound/soc/sof/imx/imx8.c @@ -320,7 +320,9 @@ static int imx8_probe(struct snd_sof_dev *sdev) if (ret < 0) goto exit_pdev_unregister; - imx8_enable_clocks(sdev, priv->clks); + ret = imx8_enable_clocks(sdev, priv->clks); + if (ret < 0) + goto exit_pdev_unregister; return 0; @@ -364,6 +366,92 @@ static int imx8_get_bar_index(struct snd_sof_dev *sdev, u32 type) } } +static void imx8_suspend(struct snd_sof_dev *sdev) +{ + int i; + struct imx8_priv *priv = (struct imx8_priv *)sdev->pdata->hw_pdata; + + for (i = 0; i < DSP_MU_CHAN_NUM; i++) + imx_dsp_free_channel(priv->dsp_ipc, i); + + imx8_disable_clocks(sdev, priv->clks); +} + +static int imx8_resume(struct snd_sof_dev *sdev) +{ + struct imx8_priv *priv = (struct imx8_priv *)sdev->pdata->hw_pdata; + int ret; + int i; + + ret = imx8_enable_clocks(sdev, priv->clks); + if (ret < 0) + return ret; + + for (i = 0; i < DSP_MU_CHAN_NUM; i++) + imx_dsp_request_channel(priv->dsp_ipc, i); + + return 0; +} + +static int imx8_dsp_runtime_resume(struct snd_sof_dev *sdev) +{ + int ret; + const struct sof_dsp_power_state target_dsp_state = { + .state = SOF_DSP_PM_D0, + }; + + ret = imx8_resume(sdev); + if (ret < 0) + return ret; + + return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); +} + +static int imx8_dsp_runtime_suspend(struct snd_sof_dev *sdev) +{ + const struct sof_dsp_power_state target_dsp_state = { + .state = SOF_DSP_PM_D3, + }; + + imx8_suspend(sdev); + + return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); +} + +static int imx8_dsp_suspend(struct snd_sof_dev *sdev, unsigned int target_state) +{ + const struct sof_dsp_power_state target_dsp_state = { + .state = target_state, + }; + + if (!pm_runtime_suspended(sdev->dev)) + imx8_suspend(sdev); + + return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); +} + +static int imx8_dsp_resume(struct snd_sof_dev *sdev) +{ + int ret; + const struct sof_dsp_power_state target_dsp_state = { + .state = SOF_DSP_PM_D0, + }; + + ret = imx8_resume(sdev); + if (ret < 0) + return ret; + + if (pm_runtime_suspended(sdev->dev)) { + pm_runtime_disable(sdev->dev); + pm_runtime_set_active(sdev->dev); + pm_runtime_mark_last_busy(sdev->dev); + pm_runtime_enable(sdev->dev); + pm_runtime_idle(sdev->dev); + } + + return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); +} + static struct snd_soc_dai_driver imx8_dai[] = { { .name = "esai0", @@ -389,6 +477,14 @@ static struct snd_soc_dai_driver imx8_dai[] = { }, }; +static int imx8_dsp_set_power_state(struct snd_sof_dev *sdev, + const struct sof_dsp_power_state *target_state) +{ + sdev->dsp_power_state = *target_state; + + return 0; +} + /* i.MX8 ops */ struct snd_sof_dsp_ops sof_imx8_ops = { /* probe and remove */ @@ -441,6 +537,15 @@ struct snd_sof_dsp_ops sof_imx8_ops = { SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, + + /* PM */ + .runtime_suspend = imx8_dsp_runtime_suspend, + .runtime_resume = imx8_dsp_runtime_resume, + + .suspend = imx8_dsp_suspend, + .resume = imx8_dsp_resume, + + .set_power_state = imx8_dsp_set_power_state, }; EXPORT_SYMBOL(sof_imx8_ops); @@ -490,6 +595,15 @@ struct snd_sof_dsp_ops sof_imx8x_ops = { .drv = imx8_dai, .num_drv = ARRAY_SIZE(imx8_dai), + /* PM */ + .runtime_suspend = imx8_dsp_runtime_suspend, + .runtime_resume = imx8_dsp_runtime_resume, + + .suspend = imx8_dsp_suspend, + .resume = imx8_dsp_resume, + + .set_power_state = imx8_dsp_set_power_state, + /* ALSA HW info flags */ .hw_info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | From a73b493d8e1b37acad686c15321d2eaab45567ce Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Fri, 19 Nov 2021 11:43:17 +0200 Subject: [PATCH 071/327] ASoC: SOF: imx8m: Add runtime PM / System PM support We make use of common imx8m_suspend / imx8m_resume functions for both system PM and runtime PM. imx8m_suspend: - frees the MU channels - disables the clocks imx8m_resume - enables the clocks - requests the MU channels On i.MX8MP there is no dedicated functionality to put the DSP in reset. The only way of doing this is to POWER DOWN the Audiomix domain. We are able to do this because turning off the clocks and freeing the channels makes the Audiomix to have no users thus PM kernel core turns it down. SOF core will not call system PM suspend handler if the DSP is already down, but at resume it will call the system PM resume. So, we need to keep track of the state via snd_sof_dsp_set_power_state Few insights on how SOF core handles the PM: - SOF core uses PM runtime autosuspend (with a timeout of 2 secs) - at probe, SOF core boots the DSP and lets the PM runtime suspend to turn it off, if there is no activity - when someone opens the ALSA sound card (aplay/arecord, etc) ALSA core calls PM runtime resume to turn on the DSP - when the ALSA sound card is closed SOF core make use of PM subsystem to call PM runtime suspend and thus turning off the DSP. Signed-off-by: Daniel Baluta Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20211119094319.81674-4-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/imx/imx8m.c | 106 +++++++++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/imx/imx8m.c b/sound/soc/sof/imx/imx8m.c index ab40c0bdf7963..b050d4cf9cd51 100644 --- a/sound/soc/sof/imx/imx8m.c +++ b/sound/soc/sof/imx/imx8m.c @@ -195,7 +195,9 @@ static int imx8m_probe(struct snd_sof_dev *sdev) if (ret < 0) goto exit_pdev_unregister; - imx8_enable_clocks(sdev, priv->clks); + ret = imx8_enable_clocks(sdev, priv->clks); + if (ret < 0) + goto exit_pdev_unregister; return 0; @@ -252,6 +254,100 @@ static struct snd_soc_dai_driver imx8m_dai[] = { }, }; +static int imx8m_dsp_set_power_state(struct snd_sof_dev *sdev, + const struct sof_dsp_power_state *target_state) +{ + sdev->dsp_power_state = *target_state; + + return 0; +} + +static int imx8m_resume(struct snd_sof_dev *sdev) +{ + struct imx8m_priv *priv = (struct imx8m_priv *)sdev->pdata->hw_pdata; + int ret; + int i; + + ret = imx8_enable_clocks(sdev, priv->clks); + if (ret < 0) + return ret; + + for (i = 0; i < DSP_MU_CHAN_NUM; i++) + imx_dsp_request_channel(priv->dsp_ipc, i); + + return 0; +} + +static void imx8m_suspend(struct snd_sof_dev *sdev) +{ + struct imx8m_priv *priv = (struct imx8m_priv *)sdev->pdata->hw_pdata; + int i; + + for (i = 0; i < DSP_MU_CHAN_NUM; i++) + imx_dsp_free_channel(priv->dsp_ipc, i); + + imx8_disable_clocks(sdev, priv->clks); +} + +static int imx8m_dsp_runtime_resume(struct snd_sof_dev *sdev) +{ + int ret; + const struct sof_dsp_power_state target_dsp_state = { + .state = SOF_DSP_PM_D0, + }; + + ret = imx8m_resume(sdev); + if (ret < 0) + return ret; + + return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); +} + +static int imx8m_dsp_runtime_suspend(struct snd_sof_dev *sdev) +{ + const struct sof_dsp_power_state target_dsp_state = { + .state = SOF_DSP_PM_D3, + }; + + imx8m_suspend(sdev); + + return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); +} + +static int imx8m_dsp_resume(struct snd_sof_dev *sdev) +{ + int ret; + const struct sof_dsp_power_state target_dsp_state = { + .state = SOF_DSP_PM_D0, + }; + + ret = imx8m_resume(sdev); + if (ret < 0) + return ret; + + if (pm_runtime_suspended(sdev->dev)) { + pm_runtime_disable(sdev->dev); + pm_runtime_set_active(sdev->dev); + pm_runtime_mark_last_busy(sdev->dev); + pm_runtime_enable(sdev->dev); + pm_runtime_idle(sdev->dev); + } + + return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); +} + +static int imx8m_dsp_suspend(struct snd_sof_dev *sdev, unsigned int target_state) +{ + const struct sof_dsp_power_state target_dsp_state = { + .state = target_state, + }; + + if (!pm_runtime_suspended(sdev->dev)) + imx8m_suspend(sdev); + + return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); +} + /* i.MX8 ops */ struct snd_sof_dsp_ops sof_imx8m_ops = { /* probe and remove */ @@ -297,6 +393,14 @@ struct snd_sof_dsp_ops sof_imx8m_ops = { .drv = imx8m_dai, .num_drv = ARRAY_SIZE(imx8m_dai), + .suspend = imx8m_dsp_suspend, + .resume = imx8m_dsp_resume, + + .runtime_suspend = imx8m_dsp_runtime_suspend, + .runtime_resume = imx8m_dsp_runtime_resume, + + .set_power_state = imx8m_dsp_set_power_state, + .hw_info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | From 9ba23717b2927071ddb49f3d6719244e3fe8f4c9 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Fri, 19 Nov 2021 11:43:18 +0200 Subject: [PATCH 072/327] ASoC: SOF: imx8m: Implement DSP start On i.MX8M DSP is controlled via a set of registers from Audio MIX. This patches gets a reference (via regmap) to Audio Mix registers and implements DSP start. Signed-off-by: Daniel Baluta Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20211119094319.81674-5-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/imx/imx8m.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/imx/imx8m.c b/sound/soc/sof/imx/imx8m.c index b050d4cf9cd51..9972ca8e6ec66 100644 --- a/sound/soc/sof/imx/imx8m.c +++ b/sound/soc/sof/imx/imx8m.c @@ -6,10 +6,13 @@ // // Hardware interface for audio DSP on i.MX8M +#include #include +#include #include #include #include +#include #include #include @@ -29,6 +32,14 @@ static struct clk_bulk_data imx8m_dsp_clks[] = { { .id = "core" }, }; +/* DSP audio mix registers */ +#define AudioDSP_REG0 0x100 +#define AudioDSP_REG1 0x104 +#define AudioDSP_REG2 0x108 +#define AudioDSP_REG3 0x10c + +#define AudioDSP_REG2_RUNSTALL BIT(5) + struct imx8m_priv { struct device *dev; struct snd_sof_dev *sdev; @@ -38,6 +49,8 @@ struct imx8m_priv { struct platform_device *ipc_dev; struct imx_clocks *clks; + + struct regmap *regmap; }; static int imx8m_get_mailbox_offset(struct snd_sof_dev *sdev) @@ -96,7 +109,10 @@ static int imx8m_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) */ static int imx8m_run(struct snd_sof_dev *sdev) { - /* TODO: start DSP using Audio MIX bits */ + struct imx8m_priv *priv = (struct imx8m_priv *)sdev->pdata->hw_pdata; + + regmap_update_bits(priv->regmap, AudioDSP_REG2, AudioDSP_REG2_RUNSTALL, 0); + return 0; } @@ -187,6 +203,13 @@ static int imx8m_probe(struct snd_sof_dev *sdev) /* set default mailbox offset for FW ready message */ sdev->dsp_box.offset = MBOX_OFFSET; + priv->regmap = syscon_regmap_lookup_by_compatible("fsl,dsp-ctrl"); + if (IS_ERR(priv->regmap)) { + dev_err(sdev->dev, "cannot find dsp-ctrl registers"); + ret = PTR_ERR(priv->regmap); + goto exit_pdev_unregister; + } + /* init clocks info */ priv->clks->dsp_clks = imx8m_dsp_clks; priv->clks->num_dsp_clks = ARRAY_SIZE(imx8m_dsp_clks); From 3bf4cd8b747a222f0f454f3220199c99f1c03da6 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Fri, 19 Nov 2021 11:43:19 +0200 Subject: [PATCH 073/327] ASoC: SOF: imx8m: Implement reset callback Resume common flow (System PM / Runtime PM) is like this: sof_resume -> specific device resume -> snd_sof_load_firmware -> snd_sof_dsp_reset (1) -> load_modules() -> snd_sof_run_firmware (2) We need to implement dsp_reset callback (1) that will actually reset the DSP but keep it stalled. In order to implement this we do the following: -> put DSP into reset (assert CoreReset bit from PWRCTL) -> stall the DSP using RunStall bit from AudioDSP_REG2 mix -> take DSP out of reset (de-assert CoreReset bit from PWRCTL) At this moment the DSP is taken out of reset and Stalled! This means that we can load the firmware and then start the DSP (2). Until now we resetted the DSP by turning down the Audiomix PD. This doesn't work for Runtime PM if another IP is keeping Audiomix PD up. By introducing dsp_reset() we no longer rely on turning off the audiomix to reset the DSP. Signed-off-by: Daniel Baluta Reviewed-by: Pierre-Louis Bossart Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211119094319.81674-6-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/imx/imx8m.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/sound/soc/sof/imx/imx8m.c b/sound/soc/sof/imx/imx8m.c index 9972ca8e6ec66..8f24c6db7f5be 100644 --- a/sound/soc/sof/imx/imx8m.c +++ b/sound/soc/sof/imx/imx8m.c @@ -32,6 +32,12 @@ static struct clk_bulk_data imx8m_dsp_clks[] = { { .id = "core" }, }; +/* DAP registers */ +#define IMX8M_DAP_DEBUG 0x28800000 +#define IMX8M_DAP_DEBUG_SIZE (64 * 1024) +#define IMX8M_DAP_PWRCTL (0x4000 + 0x3020) +#define IMX8M_PWRCTL_CORERESET BIT(16) + /* DSP audio mix registers */ #define AudioDSP_REG0 0x100 #define AudioDSP_REG1 0x104 @@ -50,6 +56,7 @@ struct imx8m_priv { struct imx_clocks *clks; + void __iomem *dap; struct regmap *regmap; }; @@ -116,6 +123,30 @@ static int imx8m_run(struct snd_sof_dev *sdev) return 0; } +static int imx8m_reset(struct snd_sof_dev *sdev) +{ + struct imx8m_priv *priv = (struct imx8m_priv *)sdev->pdata->hw_pdata; + u32 pwrctl; + + /* put DSP into reset and stall */ + pwrctl = readl(priv->dap + IMX8M_DAP_PWRCTL); + pwrctl |= IMX8M_PWRCTL_CORERESET; + writel(pwrctl, priv->dap + IMX8M_DAP_PWRCTL); + + /* keep reset asserted for 10 cycles */ + usleep_range(1, 2); + + regmap_update_bits(priv->regmap, AudioDSP_REG2, + AudioDSP_REG2_RUNSTALL, AudioDSP_REG2_RUNSTALL); + + /* take the DSP out of reset and keep stalled for FW loading */ + pwrctl = readl(priv->dap + IMX8M_DAP_PWRCTL); + pwrctl &= ~IMX8M_PWRCTL_CORERESET; + writel(pwrctl, priv->dap + IMX8M_DAP_PWRCTL); + + return 0; +} + static int imx8m_probe(struct snd_sof_dev *sdev) { struct platform_device *pdev = @@ -168,6 +199,13 @@ static int imx8m_probe(struct snd_sof_dev *sdev) goto exit_pdev_unregister; } + priv->dap = devm_ioremap(sdev->dev, IMX8M_DAP_DEBUG, IMX8M_DAP_DEBUG_SIZE); + if (!priv->dap) { + dev_err(sdev->dev, "error: failed to map DAP debug memory area"); + ret = -ENODEV; + goto exit_pdev_unregister; + } + sdev->bar[SOF_FW_BLK_TYPE_IRAM] = devm_ioremap(sdev->dev, base, size); if (!sdev->bar[SOF_FW_BLK_TYPE_IRAM]) { dev_err(sdev->dev, "failed to ioremap base 0x%x size 0x%x\n", @@ -378,6 +416,7 @@ struct snd_sof_dsp_ops sof_imx8m_ops = { .remove = imx8m_remove, /* DSP core boot */ .run = imx8m_run, + .reset = imx8m_reset, /* Block IO */ .block_read = sof_block_read, From 81ed6770ba67358b07e96a277206f6c742737dab Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 19 Nov 2021 21:26:12 +0200 Subject: [PATCH 074/327] ASoC: SOF: Intel: hda: expose get_chip_info() expose get_chip_info(). Signed-off-by: Ranjani Sridharan Reviewed-by: Guennadi Liakhovetski Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211119192621.4096077-2-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.c | 11 ----------- sound/soc/sof/intel/shim.h | 7 +++++++ 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 568d351b7a4e9..1ebf8db488b80 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -127,17 +127,6 @@ int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w) return sof_widget_free(sdev, swidget); } -static const struct sof_intel_dsp_desc - *get_chip_info(struct snd_sof_pdata *pdata) -{ - const struct sof_dev_desc *desc = pdata->desc; - const struct sof_intel_dsp_desc *chip_info; - - chip_info = desc->chip_info; - - return chip_info; -} - #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) /* diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h index e9f7d4d7fcce8..08c53cb41ea7d 100644 --- a/sound/soc/sof/intel/shim.h +++ b/sound/soc/sof/intel/shim.h @@ -177,4 +177,11 @@ struct sof_intel_stream { size_t posn_offset; }; +static inline const struct sof_intel_dsp_desc *get_chip_info(struct snd_sof_pdata *pdata) +{ + const struct sof_dev_desc *desc = pdata->desc; + + return desc->chip_info; +} + #endif From 5974f6843203f0061d9df05c32262a10359740a6 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 19 Nov 2021 21:26:13 +0200 Subject: [PATCH 075/327] ASoC: SOF: Introduce num_cores and ref count per core Add two fields num_cores and dsp_cores_ref_count to struct snd_sof_dev. These will be used to maintain the ref count for each core to determine when it should be powered up or down. Signed-off-by: Ranjani Sridharan Reviewed-by: Guennadi Liakhovetski Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211119192621.4096077-3-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/imx/imx8.c | 1 + sound/soc/sof/imx/imx8m.c | 1 + sound/soc/sof/intel/bdw.c | 9 +++++++++ sound/soc/sof/intel/byt.c | 9 +++++++++ sound/soc/sof/intel/hda.c | 2 ++ sound/soc/sof/intel/pci-tng.c | 9 +++++++++ sound/soc/sof/sof-priv.h | 15 +++++++++++++++ 7 files changed, 46 insertions(+) diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c index 0aeb44d0acc7e..2d0448b3c8c3e 100644 --- a/sound/soc/sof/imx/imx8.c +++ b/sound/soc/sof/imx/imx8.c @@ -188,6 +188,7 @@ static int imx8_probe(struct snd_sof_dev *sdev) if (!priv) return -ENOMEM; + sdev->num_cores = 1; sdev->pdata->hw_pdata = priv; priv->dev = sdev->dev; priv->sdev = sdev; diff --git a/sound/soc/sof/imx/imx8m.c b/sound/soc/sof/imx/imx8m.c index f454a5d0a87e9..c94422323d675 100644 --- a/sound/soc/sof/imx/imx8m.c +++ b/sound/soc/sof/imx/imx8m.c @@ -108,6 +108,7 @@ static int imx8m_probe(struct snd_sof_dev *sdev) if (!priv) return -ENOMEM; + sdev->num_cores = 1; sdev->pdata->hw_pdata = priv; priv->dev = sdev->dev; priv->sdev = sdev; diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 156006bed0174..1a8a39a878fd1 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -412,10 +412,19 @@ static int bdw_probe(struct snd_sof_dev *sdev) const struct sof_dev_desc *desc = pdata->desc; struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev); + const struct sof_intel_dsp_desc *chip; struct resource *mmio; u32 base, size; int ret; + chip = get_chip_info(sdev->pdata); + if (!chip) { + dev_err(sdev->dev, "error: no such device supported\n"); + return -EIO; + } + + sdev->num_cores = chip->cores_num; + /* LPE base */ mmio = platform_get_resource(pdev, IORESOURCE_MEM, desc->resindex_lpe_base); diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index e2fa08f1ae74e..dcfeaedb8fd5f 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -113,10 +113,19 @@ static int byt_acpi_probe(struct snd_sof_dev *sdev) const struct sof_dev_desc *desc = pdata->desc; struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev); + const struct sof_intel_dsp_desc *chip; struct resource *mmio; u32 base, size; int ret; + chip = get_chip_info(sdev->pdata); + if (!chip) { + dev_err(sdev->dev, "error: no such device supported\n"); + return -EIO; + } + + sdev->num_cores = chip->cores_num; + /* DSP DMA can only access low 31 bits of host memory */ ret = dma_coerce_mask_and_coherent(sdev->dev, DMA_BIT_MASK(31)); if (ret < 0) { diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 1ebf8db488b80..3c69e8fcd43b4 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -897,6 +897,8 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) goto err; } + sdev->num_cores = chip->cores_num; + hdev = devm_kzalloc(sdev->dev, sizeof(*hdev), GFP_KERNEL); if (!hdev) return -ENOMEM; diff --git a/sound/soc/sof/intel/pci-tng.c b/sound/soc/sof/intel/pci-tng.c index 18eb41b8a8f4a..f8c841caa3622 100644 --- a/sound/soc/sof/intel/pci-tng.c +++ b/sound/soc/sof/intel/pci-tng.c @@ -55,9 +55,18 @@ static int tangier_pci_probe(struct snd_sof_dev *sdev) struct snd_sof_pdata *pdata = sdev->pdata; const struct sof_dev_desc *desc = pdata->desc; struct pci_dev *pci = to_pci_dev(sdev->dev); + const struct sof_intel_dsp_desc *chip; u32 base, size; int ret; + chip = get_chip_info(sdev->pdata); + if (!chip) { + dev_err(sdev->dev, "error: no such device supported\n"); + return -EIO; + } + + sdev->num_cores = chip->cores_num; + /* DSP DMA can only access low 31 bits of host memory */ ret = dma_coerce_mask_and_coherent(&pci->dev, DMA_BIT_MASK(31)); if (ret < 0) { diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 9a8af76b2f8b9..a56f3c8b483f8 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -71,6 +71,9 @@ extern int sof_core_debug; /* So far the primary core on all DSPs has ID 0 */ #define SOF_DSP_PRIMARY_CORE 0 +/* max number of DSP cores */ +#define SOF_MAX_DSP_NUM_CORES 8 + /* DSP power state */ enum sof_dsp_power_states { SOF_DSP_PM_D0, @@ -477,6 +480,18 @@ struct snd_sof_dev { bool msi_enabled; + /* DSP core context */ + u32 num_cores; + + /* + * ref count per core that will be modified during system suspend/resume and during pcm + * hw_params/hw_free. This doesn't need to be protected with a mutex because pcm + * hw_params/hw_free are already protected by the PCM mutex in the ALSA framework in + * sound/core/ when streams are active and during system suspend/resume, streams are + * already suspended. + */ + int dsp_core_ref_count[SOF_MAX_DSP_NUM_CORES]; + void *private; /* core does not touch this */ }; From c414d5df9d05471aa47f50fca7fa4412daca7ac7 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 19 Nov 2021 21:26:14 +0200 Subject: [PATCH 076/327] ASoC: SOF: Add ops for core_get and core_put Add ops to get/put a core that will be used to power up/down a core along with incrementing/decrementing its ref_count. Signed-off-by: Ranjani Sridharan Reviewed-by: Guennadi Liakhovetski Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211119192621.4096077-4-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ops.h | 63 ++++++++++++++++++++++++++++++++++++++++ sound/soc/sof/sof-priv.h | 2 ++ 2 files changed, 65 insertions(+) diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 09bf38fdfb8a3..61dc2768b0005 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -103,6 +103,69 @@ static inline int snd_sof_dsp_core_power_down(struct snd_sof_dev *sdev, return ret; } +static inline int snd_sof_dsp_core_get(struct snd_sof_dev *sdev, int core) +{ + if (core > sdev->num_cores - 1) { + dev_err(sdev->dev, "invalid core id: %d for num_cores: %d\n", core, + sdev->num_cores); + return -EINVAL; + } + + if (sof_ops(sdev)->core_get) { + int ret; + + /* if current ref_count is > 0, increment it and return */ + if (sdev->dsp_core_ref_count[core] > 0) { + sdev->dsp_core_ref_count[core]++; + return 0; + } + + /* power up the core */ + ret = sof_ops(sdev)->core_get(sdev, core); + if (ret < 0) + return ret; + + /* increment ref_count */ + sdev->dsp_core_ref_count[core]++; + + /* and update enabled_cores_mask */ + sdev->enabled_cores_mask |= BIT(core); + + dev_dbg(sdev->dev, "Core %d powered up\n", core); + } + + return 0; +} + +static inline int snd_sof_dsp_core_put(struct snd_sof_dev *sdev, int core) +{ + if (core > sdev->num_cores - 1) { + dev_err(sdev->dev, "invalid core id: %d for num_cores: %d\n", core, + sdev->num_cores); + return -EINVAL; + } + + if (sof_ops(sdev)->core_put) { + int ret; + + /* decrement ref_count and return if it is > 0 */ + if (--(sdev->dsp_core_ref_count[core]) > 0) + return 0; + + /* power down the core */ + ret = sof_ops(sdev)->core_put(sdev, core); + if (ret < 0) + return ret; + + /* and update enabled_cores_mask */ + sdev->enabled_cores_mask &= ~BIT(core); + + dev_dbg(sdev->dev, "Core %d powered down\n", core); + } + + return 0; +} + /* pre/post fw load */ static inline int snd_sof_dsp_pre_fw_run(struct snd_sof_dev *sdev) { diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index a56f3c8b483f8..f7c86a72ac104 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -134,6 +134,8 @@ struct snd_sof_dsp_ops { unsigned int core_mask); /* optional */ int (*core_power_down)(struct snd_sof_dev *sof_dev, unsigned int core_mask); /* optional */ + int (*core_get)(struct snd_sof_dev *sof_dev, int core); /* optional */ + int (*core_put)(struct snd_sof_dev *sof_dev, int core); /* optional */ /* * Register IO: only used by respective drivers themselves, From 41dd63cccb42ec26f555cbb2495d85828a4b0e96 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 19 Nov 2021 21:26:15 +0200 Subject: [PATCH 077/327] ASoC: SOF: Intel: TGL: set core_get/put ops Set core_get/put() ops for TGL. When core_get() is requested for a core, its ref_count is incremented and the PM_CORE_ENABLE IPC sent to the firmware to power up the core if the current ref_count is 1. Conversely, the ref_count is decremented in core_put() and an IPC is sent to the DSP to power off the core if the ref_count is 0. Signed-off-by: Ranjani Sridharan Reviewed-by: Guennadi Liakhovetski Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211119192621.4096077-5-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/tgl.c | 42 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c index 48da8e7a67bce..51011b0b8c119 100644 --- a/sound/soc/sof/intel/tgl.c +++ b/sound/soc/sof/intel/tgl.c @@ -20,6 +20,46 @@ static const struct snd_sof_debugfs_map tgl_dsp_debugfs[] = { {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS}, }; +static int tgl_dsp_core_get(struct snd_sof_dev *sdev, int core) +{ + struct sof_ipc_pm_core_config pm_core_config = { + .hdr = { + .cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE, + .size = sizeof(pm_core_config), + }, + .enable_mask = sdev->enabled_cores_mask | BIT(core), + }; + + /* power up primary core if not already powered up and return */ + if (core == SOF_DSP_PRIMARY_CORE) + return hda_dsp_enable_core(sdev, BIT(core)); + + /* notify DSP for secondary cores */ + return sof_ipc_tx_message(sdev->ipc, pm_core_config.hdr.cmd, + &pm_core_config, sizeof(pm_core_config), + &pm_core_config, sizeof(pm_core_config)); +} + +static int tgl_dsp_core_put(struct snd_sof_dev *sdev, int core) +{ + struct sof_ipc_pm_core_config pm_core_config = { + .hdr = { + .cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE, + .size = sizeof(pm_core_config), + }, + .enable_mask = sdev->enabled_cores_mask & ~BIT(core), + }; + + /* power down primary core and return */ + if (core == SOF_DSP_PRIMARY_CORE) + return hda_dsp_core_reset_power_down(sdev, BIT(core)); + + /* notify DSP for secondary cores */ + return sof_ipc_tx_message(sdev->ipc, pm_core_config.hdr.cmd, + &pm_core_config, sizeof(pm_core_config), + &pm_core_config, sizeof(pm_core_config)); +} + /* Tigerlake ops */ const struct snd_sof_dsp_ops sof_tgl_ops = { /* probe/remove/shutdown */ @@ -96,6 +136,8 @@ const struct snd_sof_dsp_ops sof_tgl_ops = { /* dsp core power up/down */ .core_power_up = hda_dsp_enable_core, .core_power_down = hda_dsp_core_reset_power_down, + .core_get = tgl_dsp_core_get, + .core_put = tgl_dsp_core_put, /* firmware run */ .run = hda_dsp_cl_boot_firmware_iccmax, From 9cdcbc9f6788661fb02fb2340032a5c8115aaf9b Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 19 Nov 2021 21:26:16 +0200 Subject: [PATCH 078/327] ASoC: SOF: Intel: CNL/ICL/APL: set core_get/core_put ops Set core_get/put ops for CNL/ICL platforms. These platforms do not support enabling/disabling secondary cores dynamically. So skip sending the IPC to power off the cores in the core_put op. Signed-off-by: Ranjani Sridharan Reviewed-by: Guennadi Liakhovetski Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211119192621.4096077-6-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/apl.c | 1 + sound/soc/sof/intel/cnl.c | 1 + sound/soc/sof/intel/hda-dsp.c | 44 +++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/hda.h | 1 + sound/soc/sof/intel/icl.c | 1 + 5 files changed, 48 insertions(+) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 917f78cf6daf1..569668b2186ff 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -104,6 +104,7 @@ const struct snd_sof_dsp_ops sof_apl_ops = { /* dsp core power up/down */ .core_power_up = hda_dsp_enable_core, .core_power_down = hda_dsp_core_reset_power_down, + .core_get = hda_dsp_core_get, /* trace callback */ .trace_init = hda_dsp_trace_init, diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 3957e2b3db320..be6b6500b9072 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -306,6 +306,7 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { /* dsp core power up/down */ .core_power_up = hda_dsp_enable_core, .core_power_down = hda_dsp_core_reset_power_down, + .core_get = hda_dsp_core_get, /* firmware run */ .run = hda_dsp_cl_boot_firmware, diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 287dc0eb6686f..b2f6dcd1c23d0 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -962,3 +962,47 @@ void hda_dsp_d0i3_work(struct work_struct *work) "error: failed to set DSP state %d substate %d\n", target_state.state, target_state.substate); } + +int hda_dsp_core_get(struct snd_sof_dev *sdev, int core) +{ + struct sof_ipc_pm_core_config pm_core_config = { + .hdr = { + .cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE, + .size = sizeof(pm_core_config), + }, + .enable_mask = sdev->enabled_cores_mask | BIT(core), + }; + int ret, ret1; + + /* power up core */ + ret = hda_dsp_enable_core(sdev, BIT(core)); + if (ret < 0) { + dev_err(sdev->dev, "failed to power up core %d with err: %d\n", + core, ret); + return ret; + } + + /* No need to send IPC for primary core or if FW boot is not complete */ + if (sdev->fw_state != SOF_FW_BOOT_COMPLETE || core == SOF_DSP_PRIMARY_CORE) + return 0; + + /* Now notify DSP for secondary cores */ + ret = sof_ipc_tx_message(sdev->ipc, pm_core_config.hdr.cmd, + &pm_core_config, sizeof(pm_core_config), + &pm_core_config, sizeof(pm_core_config)); + if (ret < 0) { + dev_err(sdev->dev, "failed to enable secondary core '%d' failed with %d\n", + core, ret); + goto power_down; + } + + return ret; + +power_down: + /* power down core if it is host managed and return the original error if this fails too */ + ret1 = hda_dsp_core_reset_power_down(sdev, BIT(core)); + if (ret1 < 0) + dev_err(sdev->dev, "failed to power down core: %d with err: %d\n", core, ret1); + + return ret; +} diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 1195018a1f4f5..646f5d4dc8824 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -496,6 +496,7 @@ int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask); int hda_dsp_enable_core(struct snd_sof_dev *sdev, unsigned int core_mask); int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev, unsigned int core_mask); +int hda_dsp_core_get(struct snd_sof_dev *sdev, int core); void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev); void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev); diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c index 0b2cc331d55ba..e3472868f49a4 100644 --- a/sound/soc/sof/intel/icl.c +++ b/sound/soc/sof/intel/icl.c @@ -100,6 +100,7 @@ const struct snd_sof_dsp_ops sof_icl_ops = { /* dsp core power up/down */ .core_power_up = hda_dsp_enable_core, .core_power_down = hda_dsp_core_reset_power_down, + .core_get = hda_dsp_core_get, /* firmware run */ .run = hda_dsp_cl_boot_firmware_iccmax, From 7cc7b9ba21d4978d19f0e3edc2b00d44c9d66ff6 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 19 Nov 2021 21:26:17 +0200 Subject: [PATCH 079/327] ASoC: SOF: topology: remove sof_load_pipeline_ipc() Remove the function sof_load_pipeline_ipc() and directly send the IPC instead. The pipeline core is already enabled with the call to sof_pipeline_core_enable() in sof_widget_setup(). Signed-off-by: Ranjani Sridharan Reviewed-by: Guennadi Liakhovetski Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211119192621.4096077-7-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-audio.c | 3 ++- sound/soc/sof/sof-audio.h | 4 ---- sound/soc/sof/topology.c | 17 ----------------- 3 files changed, 2 insertions(+), 22 deletions(-) diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 7cbe757c1fe29..a019355e0bcf0 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -203,7 +203,8 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) break; case snd_soc_dapm_scheduler: pipeline = swidget->private; - ret = sof_load_pipeline_ipc(sdev, pipeline, &r); + ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline, + sizeof(*pipeline), &r, sizeof(r)); break; default: hdr = swidget->private; diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 05e98e231b85d..6c591b7a531c6 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -184,10 +184,6 @@ void snd_sof_control_notify(struct snd_sof_dev *sdev, int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file); int snd_sof_complete_pipeline(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget); - -int sof_load_pipeline_ipc(struct snd_sof_dev *sdev, - struct sof_ipc_pipe_new *pipeline, - struct sof_ipc_comp_reply *r); int sof_pipeline_core_enable(struct snd_sof_dev *sdev, const struct snd_sof_widget *swidget); diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 10caf2b1a33ce..3a49d7910326f 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1707,23 +1707,6 @@ static int sof_widget_load_pcm(struct snd_soc_component *scomp, int index, /* * Pipeline Topology */ -int sof_load_pipeline_ipc(struct snd_sof_dev *sdev, - struct sof_ipc_pipe_new *pipeline, - struct sof_ipc_comp_reply *r) -{ - int ret = sof_core_enable(sdev, pipeline->core); - - if (ret < 0) - return ret; - - ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline, - sizeof(*pipeline), r, sizeof(*r)); - if (ret < 0) - dev_err(sdev->dev, "error: load pipeline ipc failure\n"); - - return ret; -} - static int sof_widget_load_pipeline(struct snd_soc_component *scomp, int index, struct snd_sof_widget *swidget, struct snd_soc_tplg_dapm_widget *tw) From b2ebcf42a48f4560862bb811f3268767d17ebdcd Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 19 Nov 2021 21:26:18 +0200 Subject: [PATCH 080/327] ASoC: SOF: free widgets in sof_tear_down_pipelines() for static pipelines Free widgets for static pipelines in sof_tear_down_pipelines(). But this feature is unavailable in older firmware with ABI < 3.19. Just reset widget use_count's for this case. This would ensure that the secondary cores enabled required for topology setup are powered down properly before the primary core is powered off during system suspend. Signed-off-by: Ranjani Sridharan Reviewed-by: Guennadi Liakhovetski Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211119192621.4096077-8-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-audio.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index a019355e0bcf0..669d5c924f6bf 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -665,11 +665,12 @@ int sof_set_up_pipelines(struct snd_sof_dev *sdev, bool verify) } /* - * This function doesn't free widgets during suspend. It only resets the set up status for all - * routes and use_count for all widgets. + * For older firmware, this function doesn't free widgets for static pipelines during suspend. + * It only resets use_count for all widgets. */ int sof_tear_down_pipelines(struct snd_sof_dev *sdev, bool verify) { + struct sof_ipc_fw_version *v = &sdev->fw_ready.version; struct snd_sof_widget *swidget; struct snd_sof_route *sroute; int ret; @@ -681,8 +682,14 @@ int sof_tear_down_pipelines(struct snd_sof_dev *sdev, bool verify) * loading the sound card unavailable to open PCMs. */ list_for_each_entry_reverse(swidget, &sdev->widget_list, list) { - if (!verify) { + if (swidget->dynamic_pipeline_widget) + continue; + + /* Do not free widgets for static pipelines with FW ABI older than 3.19 */ + if (!verify && !swidget->dynamic_pipeline_widget && + v->abi_version < SOF_ABI_VER(3, 19, 0)) { swidget->use_count = 0; + swidget->complete = 0; continue; } From d416519982cb1d25358f558a4e68d9d254c9ca53 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 19 Nov 2021 21:26:19 +0200 Subject: [PATCH 081/327] ASoC: SOF: hda: don't use the core op for power up/power down The core_power_up/down() ops will be deprecated. Use the HDA platform-specific functions for powering up/down the cores during probe/suspend/remove. The enabled_cores_mask and the core ref_count's are manually updated in each of these functions. Signed-off-by: Ranjani Sridharan Reviewed-by: Guennadi Liakhovetski Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211119192621.4096077-9-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dsp.c | 8 ++++++-- sound/soc/sof/intel/hda-loader.c | 24 +++++++++++++++++------- sound/soc/sof/intel/hda.c | 4 ++-- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index b2f6dcd1c23d0..916a257ea96b8 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -614,7 +614,7 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) struct hdac_bus *bus = sof_to_bus(sdev); #endif - int ret; + int ret, j; hda_sdw_int_enable(sdev, false); @@ -629,13 +629,17 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) #endif /* power down DSP */ - ret = snd_sof_dsp_core_power_down(sdev, chip->host_managed_cores_mask); + ret = hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask); if (ret < 0) { dev_err(sdev->dev, "error: failed to power down core during suspend\n"); return ret; } + /* reset ref counts for all cores */ + for (j = 0; j < chip->cores_num; j++) + sdev->dsp_core_ref_count[j] = 0; + /* disable ppcap interrupt */ hda_dsp_ctrl_ppcap_enable(sdev, false); hda_dsp_ctrl_ppcap_int_enable(sdev, false); diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index abad6d0ceb837..40201e5ac201e 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -88,12 +88,13 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag) struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; const struct sof_intel_dsp_desc *chip = hda->desc; unsigned int status; - u32 flags; + unsigned long mask; + u32 flags, j; int ret; int i; /* step 1: power up corex */ - ret = snd_sof_dsp_core_power_up(sdev, chip->host_managed_cores_mask); + ret = hda_dsp_enable_core(sdev, chip->host_managed_cores_mask); if (ret < 0) { if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) dev_err(sdev->dev, "error: dsp core 0/1 power up failed\n"); @@ -148,8 +149,8 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag) chip->ipc_ack_mask); /* step 5: power down cores that are no longer needed */ - ret = snd_sof_dsp_core_power_down(sdev, chip->host_managed_cores_mask & - ~(chip->init_core_mask)); + ret = hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask & + ~(chip->init_core_mask)); if (ret < 0) { if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) dev_err(sdev->dev, @@ -168,8 +169,14 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag) HDA_DSP_REG_POLL_INTERVAL_US, chip->rom_init_timeout * USEC_PER_MSEC); - if (!ret) + if (!ret) { + /* set enabled cores mask and increment ref count for cores in init_core_mask */ + sdev->enabled_cores_mask |= chip->init_core_mask; + mask = sdev->enabled_cores_mask; + for_each_set_bit(j, &mask, SOF_MAX_DSP_NUM_CORES) + sdev->dsp_core_ref_count[j]++; return 0; + } if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) dev_err(sdev->dev, @@ -184,7 +191,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag) flags &= ~SOF_DBG_DUMP_OPTIONAL; snd_sof_dsp_dbg_dump(sdev, flags); - snd_sof_dsp_core_power_down(sdev, chip->host_managed_cores_mask); + hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask); return ret; } @@ -501,12 +508,15 @@ int hda_dsp_post_fw_run_icl(struct snd_sof_dev *sdev) * the host whereas on TGL it is handled by the firmware. */ if (!hda->clk_config_lpro) { - ret = snd_sof_dsp_core_power_up(sdev, BIT(3)); + ret = hda_dsp_enable_core(sdev, BIT(3)); if (ret < 0) { dev_err(sdev->dev, "error: dsp core power up failed on core 3\n"); return ret; } + sdev->enabled_cores_mask |= BIT(3); + sdev->dsp_core_ref_count[3]++; + snd_sof_dsp_stall(sdev, BIT(3)); } diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 3c69e8fcd43b4..1e1e9659ea86b 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -1034,9 +1034,9 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) int hda_dsp_remove(struct snd_sof_dev *sdev) { struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; struct hdac_bus *bus = sof_to_bus(sdev); struct pci_dev *pci = to_pci_dev(sdev->dev); - const struct sof_intel_dsp_desc *chip = hda->desc; /* cancel any attempt for DSP D0I3 */ cancel_delayed_work_sync(&hda->d0i3_work); @@ -1061,7 +1061,7 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) /* disable cores */ if (chip) - snd_sof_dsp_core_power_down(sdev, chip->host_managed_cores_mask); + hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask); /* disable DSP */ snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, From 9ea807488cdaef83da702d4a02d54138b88f4377 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 19 Nov 2021 21:26:20 +0200 Subject: [PATCH 082/327] ASoC: SOF: add support for dynamic pipelines with multi-core This patch adds support for dynamic pipelines with multi-core by using the platform-specific core_get/put() ops to power up/down a core when a widget is set up/freed. Along with this, a few redundant functions are removed: 1. sof_pipeline_core_enable() is no longer needed as the pipeline core will be set up when the pipeline widget is set up 2. sof_core_enable() is replaced with snd_sof_core_get() 4. core_power_up/down() DSP ops are deprecated and replaced with core get/put ops. 5. Core power down in sof_widget_unload() during topology removal is also removed as it is not really needed. For dynamic pipelines, the cores will be powered off when they are not used. For static pipelines, the cores will be powered off in the device remove callback. Signed-off-by: Ranjani Sridharan Reviewed-by: Guennadi Liakhovetski Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211119192621.4096077-10-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/apl.c | 4 +- sound/soc/sof/intel/cnl.c | 4 +- sound/soc/sof/intel/icl.c | 4 +- sound/soc/sof/intel/tgl.c | 4 +- sound/soc/sof/ops.h | 32 +-------------- sound/soc/sof/sof-audio.c | 67 +++++++++++++++++++++++++------ sound/soc/sof/sof-audio.h | 2 - sound/soc/sof/sof-priv.h | 4 -- sound/soc/sof/topology.c | 83 --------------------------------------- 9 files changed, 59 insertions(+), 145 deletions(-) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 569668b2186ff..1baf0fddeb3d5 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -101,9 +101,7 @@ const struct snd_sof_dsp_ops sof_apl_ops = { /* parse platform specific extended manifest */ .parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data, - /* dsp core power up/down */ - .core_power_up = hda_dsp_enable_core, - .core_power_down = hda_dsp_core_reset_power_down, + /* dsp core get/put */ .core_get = hda_dsp_core_get, /* trace callback */ diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index be6b6500b9072..d455272bfc8eb 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -303,9 +303,7 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { /* parse platform specific extended manifest */ .parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data, - /* dsp core power up/down */ - .core_power_up = hda_dsp_enable_core, - .core_power_down = hda_dsp_core_reset_power_down, + /* dsp core get/put */ .core_get = hda_dsp_core_get, /* firmware run */ diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c index e3472868f49a4..6c5422157ec89 100644 --- a/sound/soc/sof/intel/icl.c +++ b/sound/soc/sof/intel/icl.c @@ -97,9 +97,7 @@ const struct snd_sof_dsp_ops sof_icl_ops = { /* parse platform specific extended manifest */ .parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data, - /* dsp core power up/down */ - .core_power_up = hda_dsp_enable_core, - .core_power_down = hda_dsp_core_reset_power_down, + /* dsp core get/put */ .core_get = hda_dsp_core_get, /* firmware run */ diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c index 51011b0b8c119..237e92e790b72 100644 --- a/sound/soc/sof/intel/tgl.c +++ b/sound/soc/sof/intel/tgl.c @@ -133,9 +133,7 @@ const struct snd_sof_dsp_ops sof_tgl_ops = { /* parse platform specific extended manifest */ .parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data, - /* dsp core power up/down */ - .core_power_up = hda_dsp_enable_core, - .core_power_down = hda_dsp_core_reset_power_down, + /* dsp core get/put */ .core_get = tgl_dsp_core_get, .core_put = tgl_dsp_core_put, diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 61dc2768b0005..a0648a13e3ebd 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -72,37 +72,7 @@ static inline int snd_sof_dsp_reset(struct snd_sof_dev *sdev) return 0; } -/* dsp core power up/power down */ -static inline int snd_sof_dsp_core_power_up(struct snd_sof_dev *sdev, - unsigned int core_mask) -{ - int ret = 0; - - core_mask &= ~sdev->enabled_cores_mask; - if (sof_ops(sdev)->core_power_up && core_mask) { - ret = sof_ops(sdev)->core_power_up(sdev, core_mask); - if (!ret) - sdev->enabled_cores_mask |= core_mask; - } - - return ret; -} - -static inline int snd_sof_dsp_core_power_down(struct snd_sof_dev *sdev, - unsigned int core_mask) -{ - int ret = 0; - - core_mask &= sdev->enabled_cores_mask; - if (sof_ops(sdev)->core_power_down && core_mask) { - ret = sof_ops(sdev)->core_power_down(sdev, core_mask); - if (!ret) - sdev->enabled_cores_mask &= ~core_mask; - } - - return ret; -} - +/* dsp core get/put */ static inline int snd_sof_dsp_core_get(struct snd_sof_dev *sdev, int core) { if (core > sdev->num_cores - 1) { diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 669d5c924f6bf..0f2566f7c094e 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -106,7 +106,7 @@ int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) .id = swidget->comp_id, }; struct sof_ipc_reply reply; - int ret; + int ret, ret1, core; if (!swidget->private) return 0; @@ -115,10 +115,17 @@ int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) if (--swidget->use_count) return 0; + core = swidget->core; + switch (swidget->id) { case snd_soc_dapm_scheduler: + { + const struct sof_ipc_pipe_new *pipeline = swidget->private; + + core = pipeline->core; ipc_free.hdr.cmd |= SOF_IPC_TPLG_PIPE_FREE; break; + } case snd_soc_dapm_buffer: ipc_free.hdr.cmd |= SOF_IPC_TPLG_BUFFER_FREE; break; @@ -127,20 +134,32 @@ int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) break; } + /* continue to disable core even if IPC fails */ ret = sof_ipc_tx_message(sdev->ipc, ipc_free.hdr.cmd, &ipc_free, sizeof(ipc_free), &reply, sizeof(reply)); - if (ret < 0) { + if (ret < 0) dev_err(sdev->dev, "error: failed to free widget %s\n", swidget->widget->name); - swidget->use_count++; - return ret; + + /* + * disable widget core. continue to route setup status and complete flag + * even if this fails and return the appropriate error + */ + ret1 = snd_sof_dsp_core_put(sdev, core); + if (ret1 < 0) { + dev_err(sdev->dev, "error: failed to disable target core: %d for widget %s\n", + core, swidget->widget->name); + if (!ret) + ret = ret1; } /* reset route setup status for all routes that contain this widget */ sof_reset_route_setup_status(sdev, swidget); swidget->complete = 0; - dev_dbg(sdev->dev, "widget %s freed\n", swidget->widget->name); - return 0; + if (!ret) + dev_dbg(sdev->dev, "widget %s freed\n", swidget->widget->name); + + return ret; } EXPORT_SYMBOL(sof_widget_free); @@ -153,6 +172,7 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) struct snd_sof_dai *dai; size_t ipc_size; int ret; + int core; /* skip if there is no private data */ if (!swidget->private) @@ -162,10 +182,18 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) if (++swidget->use_count > 1) return 0; - ret = sof_pipeline_core_enable(sdev, swidget); + /* set core ID */ + core = swidget->core; + if (swidget->id == snd_soc_dapm_scheduler) { + pipeline = swidget->private; + core = pipeline->core; + } + + /* enable widget core */ + ret = snd_sof_dsp_core_get(sdev, core); if (ret < 0) { - dev_err(sdev->dev, "error: failed to enable target core: %d for widget %s\n", - ret, swidget->widget->name); + dev_err(sdev->dev, "error: failed to enable target core for widget %s\n", + swidget->widget->name); goto use_count_dec; } @@ -174,8 +202,10 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) case snd_soc_dapm_dai_out: ipc_size = sizeof(struct sof_ipc_comp_dai) + sizeof(struct sof_ipc_comp_ext); comp = kzalloc(ipc_size, GFP_KERNEL); - if (!comp) - return -ENOMEM; + if (!comp) { + ret = -ENOMEM; + goto core_put; + } dai = swidget->private; dai->configured = false; @@ -190,13 +220,18 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) if (ret < 0) { dev_err(sdev->dev, "error: failed to load widget %s\n", swidget->widget->name); - goto use_count_dec; + goto core_put; } ret = sof_dai_config_setup(sdev, dai); if (ret < 0) { dev_err(sdev->dev, "error: failed to load dai config for DAI %s\n", swidget->widget->name); + + /* + * widget use_count and core ref_count will both be decremented by + * sof_widget_free() + */ sof_widget_free(sdev, swidget); return ret; } @@ -214,7 +249,7 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) } if (ret < 0) { dev_err(sdev->dev, "error: failed to load widget %s\n", swidget->widget->name); - goto use_count_dec; + goto core_put; } /* restore kcontrols for widget */ @@ -222,6 +257,10 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) if (ret < 0) { dev_err(sdev->dev, "error: failed to restore kcontrols for widget %s\n", swidget->widget->name); + /* + * widget use_count and core ref_count will both be decremented by + * sof_widget_free() + */ sof_widget_free(sdev, swidget); return ret; } @@ -230,6 +269,8 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) return 0; +core_put: + snd_sof_dsp_core_put(sdev, core); use_count_dec: swidget->use_count--; return ret; diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 6c591b7a531c6..389d56ac3aba5 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -184,8 +184,6 @@ void snd_sof_control_notify(struct snd_sof_dev *sdev, int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file); int snd_sof_complete_pipeline(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget); -int sof_pipeline_core_enable(struct snd_sof_dev *sdev, - const struct snd_sof_widget *swidget); /* * Stream IPC diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index f7c86a72ac104..a9c5197617f16 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -130,10 +130,6 @@ struct snd_sof_dsp_ops { int (*run)(struct snd_sof_dev *sof_dev); /* mandatory */ int (*stall)(struct snd_sof_dev *sof_dev, unsigned int core_mask); /* optional */ int (*reset)(struct snd_sof_dev *sof_dev); /* optional */ - int (*core_power_up)(struct snd_sof_dev *sof_dev, - unsigned int core_mask); /* optional */ - int (*core_power_down)(struct snd_sof_dev *sof_dev, - unsigned int core_mask); /* optional */ int (*core_get)(struct snd_sof_dev *sof_dev, int core); /* optional */ int (*core_put)(struct snd_sof_dev *sof_dev, int core); /* optional */ diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 3a49d7910326f..63948bb30710d 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1346,69 +1346,6 @@ static int sof_control_unload(struct snd_soc_component *scomp, * DAI Topology */ -/* Static DSP core power management so far, should be extended in the future */ -static int sof_core_enable(struct snd_sof_dev *sdev, int core) -{ - struct sof_ipc_pm_core_config pm_core_config = { - .hdr = { - .cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE, - .size = sizeof(pm_core_config), - }, - .enable_mask = sdev->enabled_cores_mask | BIT(core), - }; - int ret; - - if (sdev->enabled_cores_mask & BIT(core)) - return 0; - - /* power up the core if it is host managed */ - ret = snd_sof_dsp_core_power_up(sdev, BIT(core)); - if (ret < 0) { - dev_err(sdev->dev, "error: %d powering up core %d\n", - ret, core); - return ret; - } - - /* Now notify DSP */ - ret = sof_ipc_tx_message(sdev->ipc, pm_core_config.hdr.cmd, - &pm_core_config, sizeof(pm_core_config), - &pm_core_config, sizeof(pm_core_config)); - if (ret < 0) { - dev_err(sdev->dev, "error: core %d enable ipc failure %d\n", - core, ret); - goto err; - } - return ret; -err: - /* power down core if it is host managed and return the original error if this fails too */ - if (snd_sof_dsp_core_power_down(sdev, BIT(core)) < 0) - dev_err(sdev->dev, "error: powering down core %d\n", core); - - return ret; -} - -int sof_pipeline_core_enable(struct snd_sof_dev *sdev, - const struct snd_sof_widget *swidget) -{ - const struct sof_ipc_pipe_new *pipeline; - int ret; - - if (swidget->id == snd_soc_dapm_scheduler) { - pipeline = swidget->private; - } else { - pipeline = snd_sof_pipeline_find(sdev, swidget->pipeline_id); - if (!pipeline) - return -ENOENT; - } - - /* First enable the pipeline core */ - ret = sof_core_enable(sdev, pipeline->core); - if (ret < 0) - return ret; - - return sof_core_enable(sdev, swidget->core); -} - static int sof_connect_dai_widget(struct snd_soc_component *scomp, struct snd_soc_dapm_widget *w, struct snd_soc_tplg_dapm_widget *tw, @@ -2485,10 +2422,8 @@ static int sof_route_unload(struct snd_soc_component *scomp, static int sof_widget_unload(struct snd_soc_component *scomp, struct snd_soc_dobj *dobj) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); const struct snd_kcontrol_new *kc; struct snd_soc_dapm_widget *widget; - struct sof_ipc_pipe_new *pipeline; struct snd_sof_control *scontrol; struct snd_sof_widget *swidget; struct soc_mixer_control *sm; @@ -2515,24 +2450,6 @@ static int sof_widget_unload(struct snd_soc_component *scomp, list_del(&dai->list); } break; - case snd_soc_dapm_scheduler: - - /* power down the pipeline schedule core */ - pipeline = swidget->private; - - /* - * Runtime PM should still function normally if topology loading fails and - * it's components are unloaded. Do not power down the primary core so that the - * CTX_SAVE IPC can succeed during runtime suspend. - */ - if (pipeline->core == SOF_DSP_PRIMARY_CORE) - break; - - ret = snd_sof_dsp_core_power_down(sdev, 1 << pipeline->core); - if (ret < 0) - dev_err(scomp->dev, "error: powering down pipeline schedule core %d\n", - pipeline->core); - break; default: break; } From 05827a1537f35221d84b8f5606f2f4c1371c69f3 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 19 Nov 2021 21:26:21 +0200 Subject: [PATCH 083/327] ASoC: SOF: Intel: hda: free DAI widget during stop and suspend To keep the widget use_counts balanced, free the DAI widget during suspend and also during the stop trigger. Signed-off-by: Ranjani Sridharan Reviewed-by: Guennadi Liakhovetski Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211119192621.4096077-11-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dai.c | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 76579383d2904..5c9ee6c494732 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -182,24 +182,6 @@ static struct sof_ipc_dai_config *hda_dai_update_config(struct snd_soc_dapm_widg return config; } -static int hda_link_config_ipc(struct sof_intel_hda_stream *hda_stream, - struct snd_soc_dapm_widget *w, int channel) -{ - struct snd_sof_dev *sdev = hda_stream->sdev; - struct sof_ipc_dai_config *config; - struct sof_ipc_reply reply; - - config = hda_dai_update_config(w, channel); - if (!config) { - dev_err(sdev->dev, "error: no config for DAI %s\n", w->name); - return -ENOENT; - } - - /* send DAI_CONFIG IPC */ - return sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size, - &reply, sizeof(reply)); -} - static int hda_link_dai_widget_update(struct sof_intel_hda_stream *hda_stream, struct snd_soc_dapm_widget *w, int channel, bool widget_setup) @@ -353,10 +335,9 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, w = dai->capture_widget; /* - * clear link DMA channel. It will be assigned when - * hw_params is set up again after resume. + * free DAI widget during stop/suspend to keep widget use_count's balanced. */ - ret = hda_link_config_ipc(hda_stream, w, DMA_CHAN_INVALID); + ret = hda_link_dai_widget_update(hda_stream, w, DMA_CHAN_INVALID, false); if (ret < 0) return ret; From 32a956a1fadfd7d3924ab8ada2b7754054375903 Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Fri, 19 Nov 2021 11:47:50 +0100 Subject: [PATCH 084/327] ASoC: stm32: i2s: add pm_runtime support Enable support of pm_runtime on STM32 I2S driver to allow I2S power state monitoring. Signed-off-by: Olivier Moysan Link: https://lore.kernel.org/r/20211119104752.13564-2-olivier.moysan@foss.st.com Signed-off-by: Mark Brown --- sound/soc/stm/stm32_i2s.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index 6254bacad6eb7..68c5de040df82 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -1113,6 +1114,7 @@ static int stm32_i2s_remove(struct platform_device *pdev) { snd_dmaengine_pcm_unregister(&pdev->dev); snd_soc_unregister_component(&pdev->dev); + pm_runtime_disable(&pdev->dev); return 0; } @@ -1150,6 +1152,8 @@ static int stm32_i2s_probe(struct platform_device *pdev) return PTR_ERR(i2s->regmap); } + pm_runtime_enable(&pdev->dev); + ret = snd_dmaengine_pcm_register(&pdev->dev, &stm32_i2s_pcm_config, 0); if (ret) { if (ret != -EPROBE_DEFER) From 98e500a12f934531b0d44eac6bc53c3d4b66aa74 Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Fri, 19 Nov 2021 11:47:51 +0100 Subject: [PATCH 085/327] ASoC: stm32: dfsdm: add pm_runtime support for audio Enable support of pm_runtime on STM32 DFSDM audio driver to allow power state monitoring. Signed-off-by: Olivier Moysan Link: https://lore.kernel.org/r/20211119104752.13564-3-olivier.moysan@foss.st.com Signed-off-by: Mark Brown --- sound/soc/stm/stm32_adfsdm.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c index e6078f50e508e..6ee714542b84a 100644 --- a/sound/soc/stm/stm32_adfsdm.c +++ b/sound/soc/stm/stm32_adfsdm.c @@ -12,7 +12,7 @@ #include #include #include - +#include #include #include #include @@ -334,6 +334,8 @@ static int stm32_adfsdm_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, priv); + pm_runtime_enable(&pdev->dev); + ret = devm_snd_soc_register_component(&pdev->dev, &stm32_adfsdm_dai_component, &priv->dai_drv, 1); @@ -373,6 +375,7 @@ static int stm32_adfsdm_probe(struct platform_device *pdev) static int stm32_adfsdm_remove(struct platform_device *pdev) { snd_soc_unregister_component(&pdev->dev); + pm_runtime_disable(&pdev->dev); return 0; } From ac5e3efd55868d8c12a178123b24616a22db274d Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Fri, 19 Nov 2021 11:47:52 +0100 Subject: [PATCH 086/327] ASoC: stm32: spdifrx: add pm_runtime support Enable support of pm_runtime on STM32 SPDIFRX driver to allow SPDIFRX power state monitoring. Signed-off-by: Olivier Moysan Link: https://lore.kernel.org/r/20211119104752.13564-4-olivier.moysan@foss.st.com Signed-off-by: Mark Brown --- sound/soc/stm/stm32_spdifrx.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c index 48145f5535880..a9ccdc2c58673 100644 --- a/sound/soc/stm/stm32_spdifrx.c +++ b/sound/soc/stm/stm32_spdifrx.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -955,6 +956,7 @@ static int stm32_spdifrx_remove(struct platform_device *pdev) snd_dmaengine_pcm_unregister(&pdev->dev); snd_soc_unregister_component(&pdev->dev); + pm_runtime_disable(&pdev->dev); return 0; } @@ -1010,6 +1012,8 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) udelay(2); reset_control_deassert(rst); + pm_runtime_enable(&pdev->dev); + pcm_config = &stm32_spdifrx_pcm_config; ret = snd_dmaengine_pcm_register(&pdev->dev, pcm_config, 0); if (ret) { From 405e52f412b85b581899f5e1b82d25a7c8959d89 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 19 Nov 2021 17:13:27 -0600 Subject: [PATCH 087/327] ASoC: SOF: sof-pci-dev: use community key on all Up boards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are already 3 versions of the Up boards with support for the SOF community key (ApolloLake, WhiskyLake, TigerLake). Rather than continue to add quirks for each version, let's add a wildcard. For WHL and TGL, the authentication supports both the SOF community key and the firmware signed with the Intel production key. Given two choices, the community key is the preferred option to allow developers to sign their own firmware. The firmware signed with production key can still be selected if needed with a kernel module option (snd-sof-pci.fw_path="intel/sof") Tested-by: Péter Ujfalusi Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Link: https://lore.kernel.org/r/20211119231327.211946-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-pci-dev.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index bc9e707656789..b4bc4f887b43e 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -64,17 +64,9 @@ static const struct dmi_system_id sof_tplg_table[] = { static const struct dmi_system_id community_key_platforms[] = { { - .ident = "Up Squared", + .ident = "Up boards", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "AAEON"), - DMI_MATCH(DMI_BOARD_NAME, "UP-APL01"), - } - }, - { - .ident = "Up Extreme", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "AAEON"), - DMI_MATCH(DMI_BOARD_NAME, "UP-WHL01"), } }, { From fdd535283779ec9f9c35fda352585c629121214f Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 19 Nov 2021 12:48:54 +0000 Subject: [PATCH 088/327] ASoC: cs42l42: Report initial jack state When a jack handler is registered in cs42l42_set_jack() the initial state should be reported if an attached headphone/headset has already been detected. The jack detect sequence takes around 1 second: typically long enough for the machine driver to probe and register the jack handler in time to receive the first report from the interrupt handler. So it is possible on some systems that the correct initial state was seen simply because of lucky timing. Modular builds were more likely to miss the reporting of the initial state. Signed-off-by: Richard Fitzgerald Fixes: 4ca239f33737 ("ASoC: cs42l42: Always enable TS_PLUG and TS_UNPLUG interrupts") Link: https://lore.kernel.org/r/20211119124854.58939-1-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 22 ++++++++++++++++++++++ sound/soc/codecs/cs42l42.h | 2 ++ 2 files changed, 24 insertions(+) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 0c4303547fd81..43d98bdb5b5b0 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -549,8 +549,25 @@ static int cs42l42_set_jack(struct snd_soc_component *component, struct snd_soc_ { struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component); + /* Prevent race with interrupt handler */ + mutex_lock(&cs42l42->jack_detect_mutex); cs42l42->jack = jk; + if (jk) { + switch (cs42l42->hs_type) { + case CS42L42_PLUG_CTIA: + case CS42L42_PLUG_OMTP: + snd_soc_jack_report(jk, SND_JACK_HEADSET, SND_JACK_HEADSET); + break; + case CS42L42_PLUG_HEADPHONE: + snd_soc_jack_report(jk, SND_JACK_HEADPHONE, SND_JACK_HEADPHONE); + break; + default: + break; + } + } + mutex_unlock(&cs42l42->jack_detect_mutex); + return 0; } @@ -1618,6 +1635,8 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data) CS42L42_M_DETECT_FT_MASK | CS42L42_M_HSBIAS_HIZ_MASK); + mutex_lock(&cs42l42->jack_detect_mutex); + /* Check auto-detect status */ if ((~masks[5]) & irq_params_table[5].mask) { if (stickies[5] & CS42L42_HSDET_AUTO_DONE_MASK) { @@ -1686,6 +1705,8 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data) } } + mutex_unlock(&cs42l42->jack_detect_mutex); + return IRQ_HANDLED; } @@ -2033,6 +2054,7 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client, cs42l42->dev = &i2c_client->dev; i2c_set_clientdata(i2c_client, cs42l42); + mutex_init(&cs42l42->jack_detect_mutex); cs42l42->regmap = devm_regmap_init_i2c(i2c_client, &cs42l42_regmap); if (IS_ERR(cs42l42->regmap)) { diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index 75ade987d0db3..9fff183dce8e5 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -12,6 +12,7 @@ #ifndef __CS42L42_H__ #define __CS42L42_H__ +#include #include #define CS42L42_PAGE_REGISTER 0x00 /* Page Select Register */ @@ -841,6 +842,7 @@ struct cs42l42_private { struct gpio_desc *reset_gpio; struct completion pdn_done; struct snd_soc_jack *jack; + struct mutex jack_detect_mutex; int pll_config; int bclk; u32 sclk; From 7016fd940adf2f4d86032339b546c6ecd737062f Mon Sep 17 00:00:00 2001 From: Ariel D'Alessandro Date: Fri, 19 Nov 2021 12:32:44 -0300 Subject: [PATCH 089/327] ASoC: tlv320aic31xx: Fix typo in BCLK clock name Signed-off-by: Ariel D'Alessandro Link: https://lore.kernel.org/r/20211119153248.419802-2-ariel.dalessandro@collabora.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h index 2513922a02923..80d062578fb5c 100644 --- a/sound/soc/codecs/tlv320aic31xx.h +++ b/sound/soc/codecs/tlv320aic31xx.h @@ -118,7 +118,7 @@ struct aic31xx_pdata { #define AIC31XX_PLL_CLKIN_MASK GENMASK(3, 2) #define AIC31XX_PLL_CLKIN_SHIFT (2) #define AIC31XX_PLL_CLKIN_MCLK 0x00 -#define AIC31XX_PLL_CLKIN_BCKL 0x01 +#define AIC31XX_PLL_CLKIN_BCLK 0x01 #define AIC31XX_PLL_CLKIN_GPIO1 0x02 #define AIC31XX_PLL_CLKIN_DIN 0x03 #define AIC31XX_CODEC_CLKIN_MASK GENMASK(1, 0) From 2664b24a8c51c21b24c2b37b7f10d6485c35b7c1 Mon Sep 17 00:00:00 2001 From: Ariel D'Alessandro Date: Fri, 19 Nov 2021 12:32:45 -0300 Subject: [PATCH 090/327] ASoC: tlv320aic31xx: Add support for pll_r coefficient When the clock used by the codec is BCLK, the operation parameters need to be calculated from input sample rate and format. Low frequency rates required different r multipliers, in order to achieve a higher PLL output frequency. Signed-off-by: Michael Trimarchi Signed-off-by: Ariel D'Alessandro Link: https://lore.kernel.org/r/20211119153248.419802-3-ariel.dalessandro@collabora.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 71 ++++++++++++++++---------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 52d2c968b5c0e..1aec03d834d05 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -180,6 +180,7 @@ struct aic31xx_priv { struct aic31xx_rate_divs { u32 mclk_p; u32 rate; + u8 pll_r; u8 pll_j; u16 pll_d; u16 dosr; @@ -192,51 +193,51 @@ struct aic31xx_rate_divs { /* ADC dividers can be disabled by configuring them to 0 */ static const struct aic31xx_rate_divs aic31xx_divs[] = { - /* mclk/p rate pll: j d dosr ndac mdac aors nadc madc */ + /* mclk/p rate pll: r j d dosr ndac mdac aors nadc madc */ /* 8k rate */ - {12000000, 8000, 8, 1920, 128, 48, 2, 128, 48, 2}, - {12000000, 8000, 8, 1920, 128, 32, 3, 128, 32, 3}, - {12500000, 8000, 7, 8643, 128, 48, 2, 128, 48, 2}, + {12000000, 8000, 1, 8, 1920, 128, 48, 2, 128, 48, 2}, + {12000000, 8000, 1, 8, 1920, 128, 32, 3, 128, 32, 3}, + {12500000, 8000, 1, 7, 8643, 128, 48, 2, 128, 48, 2}, /* 11.025k rate */ - {12000000, 11025, 7, 5264, 128, 32, 2, 128, 32, 2}, - {12000000, 11025, 8, 4672, 128, 24, 3, 128, 24, 3}, - {12500000, 11025, 7, 2253, 128, 32, 2, 128, 32, 2}, + {12000000, 11025, 1, 7, 5264, 128, 32, 2, 128, 32, 2}, + {12000000, 11025, 1, 8, 4672, 128, 24, 3, 128, 24, 3}, + {12500000, 11025, 1, 7, 2253, 128, 32, 2, 128, 32, 2}, /* 16k rate */ - {12000000, 16000, 8, 1920, 128, 24, 2, 128, 24, 2}, - {12000000, 16000, 8, 1920, 128, 16, 3, 128, 16, 3}, - {12500000, 16000, 7, 8643, 128, 24, 2, 128, 24, 2}, + {12000000, 16000, 1, 8, 1920, 128, 24, 2, 128, 24, 2}, + {12000000, 16000, 1, 8, 1920, 128, 16, 3, 128, 16, 3}, + {12500000, 16000, 1, 7, 8643, 128, 24, 2, 128, 24, 2}, /* 22.05k rate */ - {12000000, 22050, 7, 5264, 128, 16, 2, 128, 16, 2}, - {12000000, 22050, 8, 4672, 128, 12, 3, 128, 12, 3}, - {12500000, 22050, 7, 2253, 128, 16, 2, 128, 16, 2}, + {12000000, 22050, 1, 7, 5264, 128, 16, 2, 128, 16, 2}, + {12000000, 22050, 1, 8, 4672, 128, 12, 3, 128, 12, 3}, + {12500000, 22050, 1, 7, 2253, 128, 16, 2, 128, 16, 2}, /* 32k rate */ - {12000000, 32000, 8, 1920, 128, 12, 2, 128, 12, 2}, - {12000000, 32000, 8, 1920, 128, 8, 3, 128, 8, 3}, - {12500000, 32000, 7, 8643, 128, 12, 2, 128, 12, 2}, + {12000000, 32000, 1, 8, 1920, 128, 12, 2, 128, 12, 2}, + {12000000, 32000, 1, 8, 1920, 128, 8, 3, 128, 8, 3}, + {12500000, 32000, 1, 7, 8643, 128, 12, 2, 128, 12, 2}, /* 44.1k rate */ - {12000000, 44100, 7, 5264, 128, 8, 2, 128, 8, 2}, - {12000000, 44100, 8, 4672, 128, 6, 3, 128, 6, 3}, - {12500000, 44100, 7, 2253, 128, 8, 2, 128, 8, 2}, + {12000000, 44100, 1, 7, 5264, 128, 8, 2, 128, 8, 2}, + {12000000, 44100, 1, 8, 4672, 128, 6, 3, 128, 6, 3}, + {12500000, 44100, 1, 7, 2253, 128, 8, 2, 128, 8, 2}, /* 48k rate */ - {12000000, 48000, 8, 1920, 128, 8, 2, 128, 8, 2}, - {12000000, 48000, 7, 6800, 96, 5, 4, 96, 5, 4}, - {12500000, 48000, 7, 8643, 128, 8, 2, 128, 8, 2}, + {12000000, 48000, 1, 8, 1920, 128, 8, 2, 128, 8, 2}, + {12000000, 48000, 1, 7, 6800, 96, 5, 4, 96, 5, 4}, + {12500000, 48000, 1, 7, 8643, 128, 8, 2, 128, 8, 2}, /* 88.2k rate */ - {12000000, 88200, 7, 5264, 64, 8, 2, 64, 8, 2}, - {12000000, 88200, 8, 4672, 64, 6, 3, 64, 6, 3}, - {12500000, 88200, 7, 2253, 64, 8, 2, 64, 8, 2}, + {12000000, 88200, 1, 7, 5264, 64, 8, 2, 64, 8, 2}, + {12000000, 88200, 1, 8, 4672, 64, 6, 3, 64, 6, 3}, + {12500000, 88200, 1, 7, 2253, 64, 8, 2, 64, 8, 2}, /* 96k rate */ - {12000000, 96000, 8, 1920, 64, 8, 2, 64, 8, 2}, - {12000000, 96000, 7, 6800, 48, 5, 4, 48, 5, 4}, - {12500000, 96000, 7, 8643, 64, 8, 2, 64, 8, 2}, + {12000000, 96000, 1, 8, 1920, 64, 8, 2, 64, 8, 2}, + {12000000, 96000, 1, 7, 6800, 48, 5, 4, 48, 5, 4}, + {12500000, 96000, 1, 7, 8643, 64, 8, 2, 64, 8, 2}, /* 176.4k rate */ - {12000000, 176400, 7, 5264, 32, 8, 2, 32, 8, 2}, - {12000000, 176400, 8, 4672, 32, 6, 3, 32, 6, 3}, - {12500000, 176400, 7, 2253, 32, 8, 2, 32, 8, 2}, + {12000000, 176400, 1, 7, 5264, 32, 8, 2, 32, 8, 2}, + {12000000, 176400, 1, 8, 4672, 32, 6, 3, 32, 6, 3}, + {12500000, 176400, 1, 7, 2253, 32, 8, 2, 32, 8, 2}, /* 192k rate */ - {12000000, 192000, 8, 1920, 32, 8, 2, 32, 8, 2}, - {12000000, 192000, 7, 6800, 24, 5, 4, 24, 5, 4}, - {12500000, 192000, 7, 8643, 32, 8, 2, 32, 8, 2}, + {12000000, 192000, 1, 8, 1920, 32, 8, 2, 32, 8, 2}, + {12000000, 192000, 1, 7, 6800, 24, 5, 4, 24, 5, 4}, + {12500000, 192000, 1, 7, 8643, 32, 8, 2, 32, 8, 2}, }; static const char * const ldac_in_text[] = { @@ -888,7 +889,7 @@ static int aic31xx_setup_pll(struct snd_soc_component *component, /* PLL configuration */ snd_soc_component_update_bits(component, AIC31XX_PLLPR, AIC31XX_PLL_MASK, - (aic31xx->p_div << 4) | 0x01); + (aic31xx->p_div << 4) | aic31xx_divs[i].pll_r); snd_soc_component_write(component, AIC31XX_PLLJ, aic31xx_divs[i].pll_j); snd_soc_component_write(component, AIC31XX_PLLDMSB, From 6e6752a9c78738e27bde6da5cefa393b589276bb Mon Sep 17 00:00:00 2001 From: Ariel D'Alessandro Date: Fri, 19 Nov 2021 12:32:46 -0300 Subject: [PATCH 091/327] ASoC: tlv320aic31xx: Add divs for bclk as clk_in Add divisors for rates needed when the clk_in is set to BCLK. Signed-off-by: Michael Trimarchi Signed-off-by: Ariel D'Alessandro Link: https://lore.kernel.org/r/20211119153248.419802-4-ariel.dalessandro@collabora.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 1aec03d834d05..e8307f0737f26 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -195,46 +195,66 @@ struct aic31xx_rate_divs { static const struct aic31xx_rate_divs aic31xx_divs[] = { /* mclk/p rate pll: r j d dosr ndac mdac aors nadc madc */ /* 8k rate */ + { 512000, 8000, 4, 48, 0, 128, 48, 2, 128, 48, 2}, {12000000, 8000, 1, 8, 1920, 128, 48, 2, 128, 48, 2}, {12000000, 8000, 1, 8, 1920, 128, 32, 3, 128, 32, 3}, {12500000, 8000, 1, 7, 8643, 128, 48, 2, 128, 48, 2}, /* 11.025k rate */ + { 705600, 11025, 3, 48, 0, 128, 24, 3, 128, 24, 3}, {12000000, 11025, 1, 7, 5264, 128, 32, 2, 128, 32, 2}, {12000000, 11025, 1, 8, 4672, 128, 24, 3, 128, 24, 3}, {12500000, 11025, 1, 7, 2253, 128, 32, 2, 128, 32, 2}, /* 16k rate */ + { 512000, 16000, 4, 48, 0, 128, 16, 3, 128, 16, 3}, + { 1024000, 16000, 2, 48, 0, 128, 16, 3, 128, 16, 3}, {12000000, 16000, 1, 8, 1920, 128, 24, 2, 128, 24, 2}, {12000000, 16000, 1, 8, 1920, 128, 16, 3, 128, 16, 3}, {12500000, 16000, 1, 7, 8643, 128, 24, 2, 128, 24, 2}, /* 22.05k rate */ + { 705600, 22050, 4, 36, 0, 128, 12, 3, 128, 12, 3}, + { 1411200, 22050, 2, 36, 0, 128, 12, 3, 128, 12, 3}, {12000000, 22050, 1, 7, 5264, 128, 16, 2, 128, 16, 2}, {12000000, 22050, 1, 8, 4672, 128, 12, 3, 128, 12, 3}, {12500000, 22050, 1, 7, 2253, 128, 16, 2, 128, 16, 2}, /* 32k rate */ + { 1024000, 32000, 2, 48, 0, 128, 12, 2, 128, 12, 2}, + { 2048000, 32000, 1, 48, 0, 128, 12, 2, 128, 12, 2}, {12000000, 32000, 1, 8, 1920, 128, 12, 2, 128, 12, 2}, {12000000, 32000, 1, 8, 1920, 128, 8, 3, 128, 8, 3}, {12500000, 32000, 1, 7, 8643, 128, 12, 2, 128, 12, 2}, /* 44.1k rate */ + { 1411200, 44100, 2, 32, 0, 128, 8, 2, 128, 8, 2}, + { 2822400, 44100, 1, 32, 0, 128, 8, 2, 128, 8, 2}, {12000000, 44100, 1, 7, 5264, 128, 8, 2, 128, 8, 2}, {12000000, 44100, 1, 8, 4672, 128, 6, 3, 128, 6, 3}, {12500000, 44100, 1, 7, 2253, 128, 8, 2, 128, 8, 2}, /* 48k rate */ + { 1536000, 48000, 2, 32, 0, 128, 8, 2, 128, 8, 2}, + { 3072000, 48000, 1, 32, 0, 128, 8, 2, 128, 8, 2}, {12000000, 48000, 1, 8, 1920, 128, 8, 2, 128, 8, 2}, {12000000, 48000, 1, 7, 6800, 96, 5, 4, 96, 5, 4}, {12500000, 48000, 1, 7, 8643, 128, 8, 2, 128, 8, 2}, /* 88.2k rate */ + { 2822400, 88200, 2, 16, 0, 64, 8, 2, 64, 8, 2}, + { 5644800, 88200, 1, 16, 0, 64, 8, 2, 64, 8, 2}, {12000000, 88200, 1, 7, 5264, 64, 8, 2, 64, 8, 2}, {12000000, 88200, 1, 8, 4672, 64, 6, 3, 64, 6, 3}, {12500000, 88200, 1, 7, 2253, 64, 8, 2, 64, 8, 2}, /* 96k rate */ + { 3072000, 96000, 2, 16, 0, 64, 8, 2, 64, 8, 2}, + { 6144000, 96000, 1, 16, 0, 64, 8, 2, 64, 8, 2}, {12000000, 96000, 1, 8, 1920, 64, 8, 2, 64, 8, 2}, {12000000, 96000, 1, 7, 6800, 48, 5, 4, 48, 5, 4}, {12500000, 96000, 1, 7, 8643, 64, 8, 2, 64, 8, 2}, /* 176.4k rate */ + { 5644800, 176400, 2, 8, 0, 32, 8, 2, 32, 8, 2}, + {11289600, 176400, 1, 8, 0, 32, 8, 2, 32, 8, 2}, {12000000, 176400, 1, 7, 5264, 32, 8, 2, 32, 8, 2}, {12000000, 176400, 1, 8, 4672, 32, 6, 3, 32, 6, 3}, {12500000, 176400, 1, 7, 2253, 32, 8, 2, 32, 8, 2}, /* 192k rate */ + { 6144000, 192000, 2, 8, 0, 32, 8, 2, 32, 8, 2}, + {12288000, 192000, 1, 8, 0, 32, 8, 2, 32, 8, 2}, {12000000, 192000, 1, 8, 1920, 32, 8, 2, 32, 8, 2}, {12000000, 192000, 1, 7, 6800, 24, 5, 4, 24, 5, 4}, {12500000, 192000, 1, 7, 8643, 32, 8, 2, 32, 8, 2}, From c5d22d5e12e776fee4e346dc098fe51d00c2f983 Mon Sep 17 00:00:00 2001 From: Ariel D'Alessandro Date: Fri, 19 Nov 2021 12:32:47 -0300 Subject: [PATCH 092/327] ASoC: tlv320aic31xx: Handle BCLK set as PLL input configuration If BCLK is used as PLL input, the sysclk is determined by the hw params. So it must be updated here to match the input frequency, based on sample rate, format and channels. Signed-off-by: Ariel D'Alessandro Signed-off-by: Michael Trimarchi Link: https://lore.kernel.org/r/20211119153248.419802-5-ariel.dalessandro@collabora.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index e8307f0737f26..4224b4b3cae62 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -169,6 +170,7 @@ struct aic31xx_priv { struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES]; struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES]; struct snd_soc_jack *jack; + u32 sysclk_id; unsigned int sysclk; u8 p_div; int rate_div_line; @@ -962,6 +964,7 @@ static int aic31xx_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; + struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component); u8 data = 0; dev_dbg(component->dev, "## %s: width %d rate %d\n", @@ -993,6 +996,16 @@ static int aic31xx_hw_params(struct snd_pcm_substream *substream, AIC31XX_IFACE1_DATALEN_MASK, data); + /* + * If BCLK is used as PLL input, the sysclk is determined by the hw + * params. So it must be updated here to match the input frequency. + */ + if (aic31xx->sysclk_id == AIC31XX_PLL_CLKIN_BCLK) { + aic31xx->sysclk = params_rate(params) * params_width(params) * + params_channels(params); + aic31xx->p_div = 1; + } + return aic31xx_setup_pll(component, params); } @@ -1177,6 +1190,7 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, snd_soc_component_update_bits(component, AIC31XX_CLKMUX, AIC31XX_PLL_CLKIN_MASK, clk_id << AIC31XX_PLL_CLKIN_SHIFT); + aic31xx->sysclk_id = clk_id; aic31xx->sysclk = freq; return 0; From 8c9b9cfb7724685ce705f511b882f30597596536 Mon Sep 17 00:00:00 2001 From: Ariel D'Alessandro Date: Fri, 19 Nov 2021 12:32:48 -0300 Subject: [PATCH 093/327] ASoC: fsl-asoc-card: Support fsl,imx-audio-tlv320aic31xx codec Add entry for fsl,imx-audio-tlv320aic31xx audio codec. This codec is configured to use BCLK as clock input. Signed-off-by: Michael Trimarchi Signed-off-by: Ariel D'Alessandro Link: https://lore.kernel.org/r/20211119153248.419802-6-ariel.dalessandro@collabora.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl-asoc-card.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 6e6494f9f399e..90cbed496f98f 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -26,6 +26,7 @@ #include "../codecs/wm8962.h" #include "../codecs/wm8960.h" #include "../codecs/wm8994.h" +#include "../codecs/tlv320aic31xx.h" #define CS427x_SYSCLK_MCLK 0 @@ -629,6 +630,16 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) } else if (of_device_is_compatible(np, "fsl,imx-audio-tlv320aic32x4")) { codec_dai_name = "tlv320aic32x4-hifi"; priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; + } else if (of_device_is_compatible(np, "fsl,imx-audio-tlv320aic31xx")) { + codec_dai_name = "tlv320dac31xx-hifi"; + priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; + priv->dai_link[1].dpcm_capture = 0; + priv->dai_link[2].dpcm_capture = 0; + priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT; + priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT; + priv->codec_priv.mclk_id = AIC31XX_PLL_CLKIN_BCLK; + priv->card.dapm_routes = audio_map_tx; + priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx); } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8962")) { codec_dai_name = "wm8962"; priv->codec_priv.mclk_id = WM8962_SYSCLK_MCLK; @@ -888,6 +899,7 @@ static const struct of_device_id fsl_asoc_card_dt_ids[] = { { .compatible = "fsl,imx-audio-cs42888", }, { .compatible = "fsl,imx-audio-cs427x", }, { .compatible = "fsl,imx-audio-tlv320aic32x4", }, + { .compatible = "fsl,imx-audio-tlv320aic31xx", }, { .compatible = "fsl,imx-audio-sgtl5000", }, { .compatible = "fsl,imx-audio-wm8962", }, { .compatible = "fsl,imx-audio-wm8960", }, From 0e888a74e52db369e19aec908131cf171079b306 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 19 Nov 2021 17:08:49 -0600 Subject: [PATCH 094/327] ALSA: pcm: unconditionally check if appl_ptr is in 0..boundary range In some cases, the appl_ptr passed by userspace is not checked before being used. This patch adds an unconditional check and returns an error code should the appl_ptr exceed the ALSA 'boundary'. Suggested-by: Takashi Iwai Reviewed-by: Takashi Iwai Reviewed-by: Ranjani Sridharan Reviewed-by: Kai Vehmanen Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20211119230852.206310-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/core/pcm_lib.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 4f4b4739f9871..fdd992772b20c 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -2133,6 +2133,9 @@ int pcm_lib_apply_appl_ptr(struct snd_pcm_substream *substream, if (old_appl_ptr == appl_ptr) return 0; + if (appl_ptr >= runtime->boundary) + return -EINVAL; + runtime->control->appl_ptr = appl_ptr; if (substream->ops->ack) { ret = substream->ops->ack(substream); From b456abe63f60ad93c83a526d33b71574bc32656c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 19 Nov 2021 17:08:50 -0600 Subject: [PATCH 095/327] ALSA: pcm: introduce INFO_NO_REWINDS flag When the hardware can only deal with a monotonically increasing appl_ptr, this flag can be set. In case the application requests a rewind, be it with a snd_pcm_rewind() or with a direct change of a mmap'ed pointer followed by a SNDRV_PCM_IOCTL_SYNC_PTR, this patch checks if a rewind occurred and returns an error. Credits to Takashi Iwai for identifying the path with SYNC_PTR and suggesting the pointer checks. Suggested-by: Takashi Iwai Reviewed-by: Takashi Iwai Reviewed-by: Ranjani Sridharan Reviewed-by: Kai Vehmanen Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20211119230852.206310-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/uapi/sound/asound.h | 2 +- sound/core/pcm_lib.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index 5fbb79e30819a..ff7e638221c53 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -300,7 +300,7 @@ typedef int __bitwise snd_pcm_subformat_t; #define SNDRV_PCM_INFO_HAS_LINK_ESTIMATED_ATIME 0x04000000 /* report estimated link audio time */ #define SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME 0x08000000 /* report synchronized audio/system time */ #define SNDRV_PCM_INFO_EXPLICIT_SYNC 0x10000000 /* needs explicit sync of pointers and data */ - +#define SNDRV_PCM_INFO_NO_REWINDS 0x20000000 /* hardware can only support monotonic changes of appl_ptr */ #define SNDRV_PCM_INFO_DRAIN_TRIGGER 0x40000000 /* internal kernel flag - trigger in drain */ #define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */ diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index fdd992772b20c..f2090025236b9 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -2128,6 +2128,7 @@ int pcm_lib_apply_appl_ptr(struct snd_pcm_substream *substream, { struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_uframes_t old_appl_ptr = runtime->control->appl_ptr; + snd_pcm_sframes_t diff; int ret; if (old_appl_ptr == appl_ptr) @@ -2135,6 +2136,19 @@ int pcm_lib_apply_appl_ptr(struct snd_pcm_substream *substream, if (appl_ptr >= runtime->boundary) return -EINVAL; + /* + * check if a rewind is requested by the application + */ + if (substream->runtime->info & SNDRV_PCM_INFO_NO_REWINDS) { + diff = appl_ptr - old_appl_ptr; + if (diff >= 0) { + if (diff > runtime->buffer_size) + return -EINVAL; + } else { + if (runtime->boundary + diff > runtime->buffer_size) + return -EINVAL; + } + } runtime->control->appl_ptr = appl_ptr; if (substream->ops->ack) { From 4a39ea3f07f14f21a6b97e78c972f71fc5761d3a Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 19 Nov 2021 17:08:51 -0600 Subject: [PATCH 096/327] ASoC: SOF: pcm: add .ack callback support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the indirections required at the core level for platform-specific operations on ack. Note that on errors in the .ack the ALSA core will restore the previous appl_ptr. Reviewed-by: Péter Ujfalusi Reviewed-by: Kai Vehmanen Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20211119230852.206310-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ops.h | 10 ++++++++++ sound/soc/sof/pcm.c | 9 +++++++++ sound/soc/sof/sof-priv.h | 3 +++ 3 files changed, 22 insertions(+) diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index a0648a13e3ebd..0226a53148c92 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -487,6 +487,16 @@ snd_sof_pcm_platform_pointer(struct snd_sof_dev *sdev, return 0; } +/* pcm ack */ +static inline int snd_sof_pcm_platform_ack(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + if (sof_ops(sdev) && sof_ops(sdev)->pcm_ack) + return sof_ops(sdev)->pcm_ack(sdev, substream); + + return 0; +} + #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES) static inline int snd_sof_probe_compr_assign(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 31dd79b794f15..98aa5a6579e3e 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -917,6 +917,14 @@ static void sof_pcm_remove(struct snd_soc_component *component) snd_soc_tplg_component_remove(component); } +static int sof_pcm_ack(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + + return snd_sof_pcm_platform_ack(sdev, substream); +} + void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) { struct snd_soc_component_driver *pd = &sdev->plat_drv; @@ -935,6 +943,7 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) pd->hw_free = sof_pcm_hw_free; pd->trigger = sof_pcm_trigger; pd->pointer = sof_pcm_pointer; + pd->ack = sof_pcm_ack; #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES) pd->compress_ops = &sof_probe_compressed_ops; diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index a9c5197617f16..16caf5c74035d 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -207,6 +207,9 @@ struct snd_sof_dsp_ops { snd_pcm_uframes_t (*pcm_pointer)(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream); /* optional */ + /* pcm ack */ + int (*pcm_ack)(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream); /* optional */ + #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES) /* Except for probe_pointer, all probe ops are mandatory */ int (*probe_assign)(struct snd_sof_dev *sdev, From 6c26b5054ce2b822856e32f1840d13f777c6f295 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 19 Nov 2021 17:08:52 -0600 Subject: [PATCH 097/327] ASoC: SOF: Intel: add .ack support for HDaudio platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we disable rewinds, then the .ack can be used to program SPIB with the application pointer, which allows the HDaudio DMA to save power by opportunistically bursting data transfers when the path to memory is enabled (and conversely to shut it down when there are no transfer requests). The SPIB register can only be programmed with incremental values with wrap-around after the DMA RUN bits are set. For simplicity, we set the INFO_NO_REWINDS flag in the .open callback when we already need to program the SNDRV_PCM_INFO_SYNC_APPLPTR flag. Rewinds are not used by many applications. One notable application using rewinds is PulseAudio. Practical experiments with Ubuntu/PulseAudio default settings did not show any audible issues, but the user may hear volume changes and notification with a delay, depending on the size of the ring buffer and latency constraints. The choice of disabling rewinds is exposed as a kernel parameter and not a Kconfig option to avoid any undesirable side-effects. Reviewed-by: Péter Ujfalusi Reviewed-by: Kai Vehmanen Co-developed-by: Pierre-Louis Bossart Signed-off-by: Pierre-Louis Bossart Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20211119230852.206310-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/apl.c | 1 + sound/soc/sof/intel/cnl.c | 1 + sound/soc/sof/intel/hda-pcm.c | 41 ++++++++++++++++++++++++++++++-- sound/soc/sof/intel/hda-stream.c | 2 ++ sound/soc/sof/intel/hda.h | 1 + sound/soc/sof/intel/icl.c | 1 + sound/soc/sof/intel/tgl.c | 1 + 7 files changed, 46 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 1baf0fddeb3d5..8778f46f1d37f 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -78,6 +78,7 @@ const struct snd_sof_dsp_ops sof_apl_ops = { .pcm_hw_free = hda_dsp_stream_hw_free, .pcm_trigger = hda_dsp_pcm_trigger, .pcm_pointer = hda_dsp_pcm_pointer, + .pcm_ack = hda_dsp_pcm_ack, #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES) /* probe callbacks */ diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index d455272bfc8eb..04daaa6100f12 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -283,6 +283,7 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { .pcm_hw_free = hda_dsp_stream_hw_free, .pcm_trigger = hda_dsp_pcm_trigger, .pcm_pointer = hda_dsp_pcm_pointer, + .pcm_ack = hda_dsp_pcm_ack, #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES) /* probe callbacks */ diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index cc8ddef37f37b..974383cd04407 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -32,6 +32,10 @@ static bool hda_always_enable_dmi_l1; module_param_named(always_enable_dmi_l1, hda_always_enable_dmi_l1, bool, 0444); MODULE_PARM_DESC(always_enable_dmi_l1, "SOF HDA always enable DMI l1"); +static bool hda_disable_rewinds = IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_DISABLE_REWINDS); +module_param_named(disable_rewinds, hda_disable_rewinds, bool, 0444); +MODULE_PARM_DESC(disable_rewinds, "SOF HDA disable rewinds"); + u32 hda_dsp_get_mult_div(struct snd_sof_dev *sdev, int rate) { switch (rate) { @@ -120,8 +124,11 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, return ret; } - /* disable SPIB, to enable buffer wrap for stream */ - hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_DISABLE, 0); + /* enable SPIB when rewinds are disabled */ + if (hda_disable_rewinds) + hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_ENABLE, 0); + else + hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_DISABLE, 0); /* update no_stream_position flag for ipc params */ if (hda && hda->no_ipc_position) { @@ -140,6 +147,29 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, return 0; } +/* update SPIB register with appl position */ +int hda_dsp_pcm_ack(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) +{ + struct hdac_stream *hstream = substream->runtime->private_data; + struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream); + struct snd_pcm_runtime *runtime = substream->runtime; + ssize_t appl_pos, buf_size; + u32 spib; + + appl_pos = frames_to_bytes(runtime, runtime->control->appl_ptr); + buf_size = frames_to_bytes(runtime, runtime->buffer_size); + + spib = appl_pos % buf_size; + + /* Allowable value for SPIB is 1 byte to max buffer size */ + if (!spib) + spib = buf_size; + + sof_io_write(sdev, hext_stream->spib_addr, spib); + + return 0; +} + int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, int cmd) { @@ -234,6 +264,13 @@ int hda_dsp_pcm_open(struct snd_sof_dev *sdev, return -EINVAL; } + /* + * if we want the .ack to work, we need to prevent the control from being mapped. + * The status can still be mapped. + */ + if (hda_disable_rewinds) + runtime->hw.info |= SNDRV_PCM_INFO_NO_REWINDS | SNDRV_PCM_INFO_SYNC_APPLPTR; + /* * All playback streams are DMI L1 capable, capture streams need * pause push/release to be disabled diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 1d845c2cbc33d..b6f0378153441 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -655,6 +655,8 @@ int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev, SOF_HDA_REG_PP_PPCTL, mask, 0); spin_unlock_irq(&bus->reg_lock); + hda_dsp_stream_spib_config(sdev, link_dev, HDA_DSP_SPIB_DISABLE, 0); + stream->substream = NULL; return 0; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 646f5d4dc8824..8ed4031ca0078 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -534,6 +534,7 @@ int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, int cmd); snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream); +int hda_dsp_pcm_ack(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream); /* * DSP Stream Operations. diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c index 6c5422157ec89..343c1af7c4532 100644 --- a/sound/soc/sof/intel/icl.c +++ b/sound/soc/sof/intel/icl.c @@ -77,6 +77,7 @@ const struct snd_sof_dsp_ops sof_icl_ops = { .pcm_hw_free = hda_dsp_stream_hw_free, .pcm_trigger = hda_dsp_pcm_trigger, .pcm_pointer = hda_dsp_pcm_pointer, + .pcm_ack = hda_dsp_pcm_ack, #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES) /* probe callbacks */ diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c index 237e92e790b72..7f7929c5cb88f 100644 --- a/sound/soc/sof/intel/tgl.c +++ b/sound/soc/sof/intel/tgl.c @@ -113,6 +113,7 @@ const struct snd_sof_dsp_ops sof_tgl_ops = { .pcm_hw_free = hda_dsp_stream_hw_free, .pcm_trigger = hda_dsp_pcm_trigger, .pcm_pointer = hda_dsp_pcm_pointer, + .pcm_ack = hda_dsp_pcm_ack, #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES) /* probe callbacks */ From 01429183f479c54c1b5d15453a8ce574ea43e525 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 23 Nov 2021 19:16:04 +0200 Subject: [PATCH 098/327] ASoC: SOF: sof-audio: setup sched widgets during pipeline complete step Older firmware prior to ABI 3.19 has a dependency where the scheduler widgets need to be setup last. Moving the call to sof_widget_setup() before the pipeline_complete() call also helps remove the need for the 'reverse' direction when walking through the widget list - this was only working because of the topology macros but the topology does not require any order. Fixes: 5fcdbb2d45df ("ASoC: SOF: Add support for dynamic pipelines") Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211123171606.129350-1-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-audio.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 0f2566f7c094e..f4e142ec0fbd5 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -637,16 +637,25 @@ const struct sof_ipc_pipe_new *snd_sof_pipeline_find(struct snd_sof_dev *sdev, int sof_set_up_pipelines(struct snd_sof_dev *sdev, bool verify) { + struct sof_ipc_fw_version *v = &sdev->fw_ready.version; struct snd_sof_widget *swidget; struct snd_sof_route *sroute; int ret; /* restore pipeline components */ - list_for_each_entry_reverse(swidget, &sdev->widget_list, list) { + list_for_each_entry(swidget, &sdev->widget_list, list) { /* only set up the widgets belonging to static pipelines */ if (!verify && swidget->dynamic_pipeline_widget) continue; + /* + * For older firmware, skip scheduler widgets in this loop, + * sof_widget_setup() will be called in the 'complete pipeline' loop + */ + if (v->abi_version < SOF_ABI_VER(3, 19, 0) && + swidget->id == snd_soc_dapm_scheduler) + continue; + /* update DAI config. The IPC will be sent in sof_widget_setup() */ if (WIDGET_IS_DAI(swidget->id)) { struct snd_sof_dai *dai = swidget->private; @@ -694,6 +703,12 @@ int sof_set_up_pipelines(struct snd_sof_dev *sdev, bool verify) if (!verify && swidget->dynamic_pipeline_widget) continue; + if (v->abi_version < SOF_ABI_VER(3, 19, 0)) { + ret = sof_widget_setup(sdev, swidget); + if (ret < 0) + return ret; + } + swidget->complete = snd_sof_complete_pipeline(sdev, swidget); break; @@ -722,7 +737,7 @@ int sof_tear_down_pipelines(struct snd_sof_dev *sdev, bool verify) * sroute->setup because during suspend all streams are suspended and during topology * loading the sound card unavailable to open PCMs. */ - list_for_each_entry_reverse(swidget, &sdev->widget_list, list) { + list_for_each_entry(swidget, &sdev->widget_list, list) { if (swidget->dynamic_pipeline_widget) continue; From fb71d03b29bcbd8c03798d36e7b2a2297b6dea45 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 23 Nov 2021 19:16:05 +0200 Subject: [PATCH 099/327] ASoC: SOF: topology: don't use list_for_each_entry_reverse() It's not clear why we would walk the list backwards. That makes no difference. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211123171606.129350-2-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 63948bb30710d..b3ad3a6049189 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -3529,7 +3529,7 @@ static int sof_complete(struct snd_soc_component *scomp) * Apply the dynamic_pipeline_widget flag and set the pipe_widget field * for all widgets that have the same pipeline ID as the scheduler widget */ - list_for_each_entry_reverse(comp_swidget, &sdev->widget_list, list) + list_for_each_entry(comp_swidget, &sdev->widget_list, list) if (comp_swidget->pipeline_id == swidget->pipeline_id) { ret = sof_set_pipe_widget(sdev, swidget, comp_swidget); if (ret < 0) From 96da174024b9c63bd5d3358668d0bc12677be877 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 23 Nov 2021 19:16:06 +0200 Subject: [PATCH 100/327] ASoC: SOF: handle paused streams during system suspend During system suspend, paused streams do not get suspended. Therefore, we need to explicitly free these PCMs in the DSP and free the associated DAPM widgets so that they can be set up again during resume. Fixes: 5fcdbb2d45df ("ASoC: SOF: Add support for dynamic pipelines") Signed-off-by: Ranjani Sridharan Reviewed-by: Paul Olaru Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211123171606.129350-3-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/pcm.c | 5 ++- sound/soc/sof/sof-audio.c | 74 +++++++++++++++++++++++++++++++++++++-- sound/soc/sof/sof-audio.h | 2 ++ 3 files changed, 76 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 31dd79b794f15..0ceb1a9cbf730 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -100,9 +100,8 @@ void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream) } EXPORT_SYMBOL(snd_sof_pcm_period_elapsed); -static int sof_pcm_dsp_pcm_free(struct snd_pcm_substream *substream, - struct snd_sof_dev *sdev, - struct snd_sof_pcm *spcm) +int sof_pcm_dsp_pcm_free(struct snd_pcm_substream *substream, struct snd_sof_dev *sdev, + struct snd_sof_pcm *spcm) { struct sof_ipc_stream stream; struct sof_ipc_reply reply; diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index f4e142ec0fbd5..e00ce275052f9 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -129,6 +129,14 @@ int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) case snd_soc_dapm_buffer: ipc_free.hdr.cmd |= SOF_IPC_TPLG_BUFFER_FREE; break; + case snd_soc_dapm_dai_in: + case snd_soc_dapm_dai_out: + { + struct snd_sof_dai *dai = swidget->private; + + dai->configured = false; + fallthrough; + } default: ipc_free.hdr.cmd |= SOF_IPC_TPLG_COMP_FREE; break; @@ -720,6 +728,55 @@ int sof_set_up_pipelines(struct snd_sof_dev *sdev, bool verify) return 0; } +/* + * Free the PCM, its associated widgets and set the prepared flag to false for all PCMs that + * did not get suspended(ex: paused streams) so the widgets can be set up again during resume. + */ +static int sof_tear_down_left_over_pipelines(struct snd_sof_dev *sdev) +{ + struct snd_sof_widget *swidget; + struct snd_sof_pcm *spcm; + int dir, ret; + + /* + * free all PCMs and their associated DAPM widgets if their connected DAPM widget + * list is not NULL. This should only be true for paused streams at this point. + * This is equivalent to the handling of FE DAI suspend trigger for running streams. + */ + list_for_each_entry(spcm, &sdev->pcm_list, list) + for_each_pcm_streams(dir) { + struct snd_pcm_substream *substream = spcm->stream[dir].substream; + + if (!substream || !substream->runtime) + continue; + + if (spcm->stream[dir].list) { + ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); + if (ret < 0) + return ret; + + ret = sof_widget_list_free(sdev, spcm, dir); + if (ret < 0) { + dev_err(sdev->dev, "failed to free widgets during suspend\n"); + return ret; + } + } + } + + /* + * free any left over DAI widgets. This is equivalent to the handling of suspend trigger + * for the BE DAI for running streams. + */ + list_for_each_entry(swidget, &sdev->widget_list, list) + if (WIDGET_IS_DAI(swidget->id) && swidget->use_count == 1) { + ret = sof_widget_free(sdev, swidget); + if (ret < 0) + return ret; + } + + return 0; +} + /* * For older firmware, this function doesn't free widgets for static pipelines during suspend. * It only resets use_count for all widgets. @@ -734,8 +791,8 @@ int sof_tear_down_pipelines(struct snd_sof_dev *sdev, bool verify) /* * This function is called during suspend and for one-time topology verification during * first boot. In both cases, there is no need to protect swidget->use_count and - * sroute->setup because during suspend all streams are suspended and during topology - * loading the sound card unavailable to open PCMs. + * sroute->setup because during suspend all running streams are suspended and during + * topology loading the sound card unavailable to open PCMs. */ list_for_each_entry(swidget, &sdev->widget_list, list) { if (swidget->dynamic_pipeline_widget) @@ -754,6 +811,19 @@ int sof_tear_down_pipelines(struct snd_sof_dev *sdev, bool verify) return ret; } + /* + * Tear down all pipelines associated with PCMs that did not get suspended + * and unset the prepare flag so that they can be set up again during resume. + * Skip this step for older firmware. + */ + if (!verify && v->abi_version >= SOF_ABI_VER(3, 19, 0)) { + ret = sof_tear_down_left_over_pipelines(sdev); + if (ret < 0) { + dev_err(sdev->dev, "failed to tear down paused pipelines\n"); + return ret; + } + } + list_for_each_entry(sroute, &sdev->route_list, list) sroute->setup = false; diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 389d56ac3aba5..1c4f59d347177 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -265,4 +265,6 @@ int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget); /* PCM */ int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir); int sof_widget_list_free(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir); +int sof_pcm_dsp_pcm_free(struct snd_pcm_substream *substream, struct snd_sof_dev *sdev, + struct snd_sof_pcm *spcm); #endif From faf695517c1c77bb4a4b46d54007a283962eb00e Mon Sep 17 00:00:00 2001 From: Jiaxin Yu Date: Thu, 25 Nov 2021 12:24:22 +0800 Subject: [PATCH 101/327] ASoC: mediatek: remove unnecessary CONFIG_PM The unnecessary conditional inclusion caused the following warning. Such as: >> sound/soc/mediatek/mt8192/mt8192-afe-pcm.c:2368:32: warning: unused >> variable 'mt8192_afe_pm_ops' [-Wunused-const-variable] static const struct dev_pm_ops mt8192_afe_pm_ops = { Because runtime_pm already handles the case without CONFIG_PM, we can remove CONFIG_PM condition. Signed-off-by: Jiaxin Yu Reported-by: kernel test robot Acked-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20211125042422.2349-1-jiaxin.yu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt2701/mt2701-afe-pcm.c | 2 -- sound/soc/mediatek/mt6797/mt6797-afe-pcm.c | 2 -- sound/soc/mediatek/mt8173/mt8173-max98090.c | 2 -- sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c | 2 -- sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c | 2 -- sound/soc/mediatek/mt8173/mt8173-rt5650.c | 2 -- sound/soc/mediatek/mt8183/mt8183-afe-pcm.c | 2 -- sound/soc/mediatek/mt8192/mt8192-afe-pcm.c | 2 -- 8 files changed, 16 deletions(-) diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c index bc3d0466472ba..0f178de92a0fa 100644 --- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c +++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c @@ -1474,9 +1474,7 @@ static struct platform_driver mt2701_afe_pcm_driver = { .driver = { .name = "mt2701-audio", .of_match_table = mt2701_afe_pcm_dt_match, -#ifdef CONFIG_PM .pm = &mt2701_afe_pm_ops, -#endif }, .probe = mt2701_afe_pcm_dev_probe, .remove = mt2701_afe_pcm_dev_remove, diff --git a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c index 3d68e4726ea24..fb4abec9aa5f9 100644 --- a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c +++ b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c @@ -901,9 +901,7 @@ static struct platform_driver mt6797_afe_pcm_driver = { .driver = { .name = "mt6797-audio", .of_match_table = mt6797_afe_pcm_dt_match, -#ifdef CONFIG_PM .pm = &mt6797_afe_pm_ops, -#endif }, .probe = mt6797_afe_pcm_dev_probe, .remove = mt6797_afe_pcm_dev_remove, diff --git a/sound/soc/mediatek/mt8173/mt8173-max98090.c b/sound/soc/mediatek/mt8173/mt8173-max98090.c index fc94314bfc02f..2408c9d3d9b39 100644 --- a/sound/soc/mediatek/mt8173/mt8173-max98090.c +++ b/sound/soc/mediatek/mt8173/mt8173-max98090.c @@ -193,9 +193,7 @@ static struct platform_driver mt8173_max98090_driver = { .driver = { .name = "mt8173-max98090", .of_match_table = mt8173_max98090_dt_match, -#ifdef CONFIG_PM .pm = &snd_soc_pm_ops, -#endif }, .probe = mt8173_max98090_dev_probe, }; diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c index 0f28dc2217c09..e6e824f3d24ae 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c @@ -231,9 +231,7 @@ static struct platform_driver mt8173_rt5650_rt5514_driver = { .driver = { .name = "mtk-rt5650-rt5514", .of_match_table = mt8173_rt5650_rt5514_dt_match, -#ifdef CONFIG_PM .pm = &snd_soc_pm_ops, -#endif }, .probe = mt8173_rt5650_rt5514_dev_probe, }; diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c index 077c6ee067806..ba6fe3d90bfc1 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c @@ -298,9 +298,7 @@ static struct platform_driver mt8173_rt5650_rt5676_driver = { .driver = { .name = "mtk-rt5650-rt5676", .of_match_table = mt8173_rt5650_rt5676_dt_match, -#ifdef CONFIG_PM .pm = &snd_soc_pm_ops, -#endif }, .probe = mt8173_rt5650_rt5676_dev_probe, }; diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c index 2cbf679f5c74b..9b933cce0b209 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c @@ -336,9 +336,7 @@ static struct platform_driver mt8173_rt5650_driver = { .driver = { .name = "mtk-rt5650", .of_match_table = mt8173_rt5650_dt_match, -#ifdef CONFIG_PM .pm = &snd_soc_pm_ops, -#endif }, .probe = mt8173_rt5650_dev_probe, }; diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c index 14e77df06b011..86c8a523fe9e3 100644 --- a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c +++ b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c @@ -1279,9 +1279,7 @@ static struct platform_driver mt8183_afe_pcm_driver = { .driver = { .name = "mt8183-audio", .of_match_table = mt8183_afe_pcm_dt_match, -#ifdef CONFIG_PM .pm = &mt8183_afe_pm_ops, -#endif }, .probe = mt8183_afe_pcm_dev_probe, .remove = mt8183_afe_pcm_dev_remove, diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c index 31c280339c503..e1e4ca9315518 100644 --- a/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c +++ b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c @@ -2381,9 +2381,7 @@ static struct platform_driver mt8192_afe_pcm_driver = { .driver = { .name = "mt8192-audio", .of_match_table = mt8192_afe_pcm_dt_match, -#ifdef CONFIG_PM .pm = &mt8192_afe_pm_ops, -#endif }, .probe = mt8192_afe_pcm_dev_probe, .remove = mt8192_afe_pcm_dev_remove, From fc6c62cf1cbf24c81ccb1d248120311336d5f3cc Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Thu, 25 Nov 2021 15:16:08 +0800 Subject: [PATCH 102/327] ASoC: SOF: mediatek: Add missing of_node_put() in platform_parse_resource() The node pointer is returned by of_parse_phandle() with refcount incremented in platform_parse_resource(). Calling of_node_put() to aovid the refcount leak. Reported-by: Hulk Robot Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20211125071608.3056715-1-yangyingliang@huawei.com Signed-off-by: Mark Brown --- sound/soc/sof/mediatek/mt8195/mt8195.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index 40e5a25875a6a..55d9812870a45 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -43,6 +43,7 @@ static int platform_parse_resource(struct platform_device *pdev, void *data) } ret = of_address_to_resource(mem_region, 0, &res); + of_node_put(mem_region); if (ret) { dev_err(dev, "of_address_to_resource dma failed\n"); return ret; @@ -64,6 +65,7 @@ static int platform_parse_resource(struct platform_device *pdev, void *data) } ret = of_address_to_resource(mem_region, 0, &res); + of_node_put(mem_region); if (ret) { dev_err(dev, "of_address_to_resource sysmem failed\n"); return ret; From 49f893253ab43566e34332a969324531fea463f6 Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Thu, 25 Nov 2021 10:51:57 +0100 Subject: [PATCH 103/327] ASoC: uniphier: drop selecting non-existing SND_SOC_UNIPHIER_AIO_DMA Commit f37fe2f9987b ("ASoC: uniphier: add support for UniPhier AIO common driver") adds configs SND_SOC_UNIPHIER_{LD11,PXS2}, which select the non-existing config SND_SOC_UNIPHIER_AIO_DMA. Hence, ./scripts/checkkconfigsymbols.py warns: SND_SOC_UNIPHIER_AIO_DMA Referencing files: sound/soc/uniphier/Kconfig Probably, there is actually no further config intended to be selected here. So, just drop selecting the non-existing config. Fixes: f37fe2f9987b ("ASoC: uniphier: add support for UniPhier AIO common driver") Signed-off-by: Lukas Bulwahn Link: https://lore.kernel.org/r/20211125095158.8394-2-lukas.bulwahn@gmail.com Signed-off-by: Mark Brown --- sound/soc/uniphier/Kconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/uniphier/Kconfig b/sound/soc/uniphier/Kconfig index aa3592ee1358b..ddfa6424c656b 100644 --- a/sound/soc/uniphier/Kconfig +++ b/sound/soc/uniphier/Kconfig @@ -23,7 +23,6 @@ config SND_SOC_UNIPHIER_LD11 tristate "UniPhier LD11/LD20 Device Driver" depends on SND_SOC_UNIPHIER select SND_SOC_UNIPHIER_AIO - select SND_SOC_UNIPHIER_AIO_DMA help This adds ASoC driver for Socionext UniPhier LD11/LD20 input and output that can be used with other codecs. @@ -34,7 +33,6 @@ config SND_SOC_UNIPHIER_PXS2 tristate "UniPhier PXs2 Device Driver" depends on SND_SOC_UNIPHIER select SND_SOC_UNIPHIER_AIO - select SND_SOC_UNIPHIER_AIO_DMA help This adds ASoC driver for Socionext UniPhier PXs2 input and output that can be used with other codecs. From 2039cc1da4bee1fd0df644e26b28ed769cd32a81 Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Thu, 25 Nov 2021 10:51:58 +0100 Subject: [PATCH 104/327] ASoC: codecs: wcd938x: add SND_SOC_WCD938_SDW to codec list instead Commit 045442228868 ("ASoC: codecs: wcd938x: add audio routing and Kconfig") adds SND_SOC_WCD937X, which does not exist, and SND_SOC_WCD938X, which seems not really to be the intended config to be selected, but only a supporting config symbol to the actual config SND_SOC_WCD938X_SDW for the codec. Add SND_SOC_WCD938_SDW to the list instead of SND_SOC_WCD93{7,8}X. The issue was identified with ./scripts/checkkconfigsymbols.py. Fixes: 045442228868 ("ASoC: codecs: wcd938x: add audio routing and Kconfig") Signed-off-by: Lukas Bulwahn Link: https://lore.kernel.org/r/20211125095158.8394-3-lukas.bulwahn@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 3fe62df322386..b6d1827e7986d 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -241,8 +241,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_UDA1380 imply SND_SOC_WCD9335 imply SND_SOC_WCD934X - imply SND_SOC_WCD937X - imply SND_SOC_WCD938X + imply SND_SOC_WCD938X_SDW imply SND_SOC_LPASS_RX_MACRO imply SND_SOC_LPASS_TX_MACRO imply SND_SOC_WL1273 From 083a7fba38885a8ffa03a2857e383421cefd36e6 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Thu, 25 Nov 2021 13:58:11 +0800 Subject: [PATCH 105/327] ASoC: rt5640: Add the binding include file for the HDA header support The patch adds the binding include file for the HDA header support. Signed-off-by: Oder Chiou Link: https://lore.kernel.org/r/20211125055812.8911-1-oder_chiou@realtek.com Signed-off-by: Mark Brown --- include/dt-bindings/sound/rt5640.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/dt-bindings/sound/rt5640.h b/include/dt-bindings/sound/rt5640.h index 154c9b4414f27..655f6946388ae 100644 --- a/include/dt-bindings/sound/rt5640.h +++ b/include/dt-bindings/sound/rt5640.h @@ -16,6 +16,7 @@ #define RT5640_JD_SRC_GPIO2 4 #define RT5640_JD_SRC_GPIO3 5 #define RT5640_JD_SRC_GPIO4 6 +#define RT5640_JD_SRC_HDA_HEADER 7 #define RT5640_OVCD_SF_0P5 0 #define RT5640_OVCD_SF_0P75 1 From 2b9c8d2b3c89708d53b6124dc49c212dc5341840 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Thu, 25 Nov 2021 13:58:12 +0800 Subject: [PATCH 106/327] ASoC: rt5640: Add the HDA header support The patch adds the HDA header support. Signed-off-by: Oder Chiou Link: https://lore.kernel.org/r/20211125055812.8911-2-oder_chiou@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5640.c | 97 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 94 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index d01fe73ab9c85..08b37878cb002 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -195,6 +195,7 @@ static bool rt5640_volatile_register(struct device *dev, unsigned int reg) case RT5640_PRIV_DATA: case RT5640_PGM_REG_ARR1: case RT5640_PGM_REG_ARR3: + case RT5640_DUMMY2: case RT5640_VENDOR_ID: case RT5640_VENDOR_ID1: case RT5640_VENDOR_ID2: @@ -2301,6 +2302,38 @@ static void rt5640_jack_work(struct work_struct *work) struct snd_soc_component *component = rt5640->component; int status; + if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER) { + int val, jack_type = 0, hda_mic_plugged, hda_hp_plugged; + + /* mic jack */ + val = snd_soc_component_read(component, RT5640_INT_IRQ_ST); + hda_mic_plugged = !(val & RT5640_JD_STATUS); + dev_dbg(component->dev, "mic jack status %d\n", + hda_mic_plugged); + + snd_soc_component_update_bits(component, RT5640_IRQ_CTRL1, + RT5640_JD_P_MASK, !hda_mic_plugged << RT5640_JD_P_SFT); + + if (hda_mic_plugged) + jack_type |= SND_JACK_MICROPHONE; + + /* headphone jack */ + val = snd_soc_component_read(component, RT5640_DUMMY2); + hda_hp_plugged = !(val & (0x1 << 11)); + dev_dbg(component->dev, "headphone jack status %d\n", + hda_hp_plugged); + + snd_soc_component_update_bits(component, RT5640_DUMMY2, + (0x1 << 10), !hda_hp_plugged << 10); + + if (hda_hp_plugged) + jack_type |= SND_JACK_HEADPHONE; + + snd_soc_jack_report(rt5640->jack, jack_type, SND_JACK_HEADSET); + + return; + } + if (!rt5640_jack_inserted(component)) { /* Jack removed, or spurious IRQ? */ if (rt5640->jack->status & SND_JACK_HEADPHONE) { @@ -2478,13 +2511,57 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component, queue_work(system_long_wq, &rt5640->jack_work); } +static void rt5640_enable_hda_jack_detect( + struct snd_soc_component *component, struct snd_soc_jack *jack) +{ + struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); + int ret; + + /* Select JD1 for Mic */ + snd_soc_component_update_bits(component, RT5640_JD_CTRL, + RT5640_JD_MASK, RT5640_JD_JD1_IN4P); + snd_soc_component_write(component, RT5640_IRQ_CTRL1, RT5640_IRQ_JD_NOR); + + /* Select JD2 for Headphone */ + snd_soc_component_update_bits(component, RT5640_DUMMY2, 0x1100, 0x1100); + + /* Selecting GPIO01 as an interrupt */ + snd_soc_component_update_bits(component, RT5640_GPIO_CTRL1, + RT5640_GP1_PIN_MASK, RT5640_GP1_PIN_IRQ); + + /* Set GPIO1 output */ + snd_soc_component_update_bits(component, RT5640_GPIO_CTRL3, + RT5640_GP1_PF_MASK, RT5640_GP1_PF_OUT); + + snd_soc_component_update_bits(component, RT5640_DUMMY1, 0x700, 0x300); + + rt5640->jack = jack; + + ret = request_irq(rt5640->irq, rt5640_irq, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, "rt5640", rt5640); + if (ret) { + dev_warn(component->dev, "Failed to reguest IRQ %d: %d\n", rt5640->irq, ret); + rt5640->irq = -ENXIO; + return; + } + + /* sync initial jack state */ + queue_work(system_long_wq, &rt5640->jack_work); +} + static int rt5640_set_jack(struct snd_soc_component *component, struct snd_soc_jack *jack, void *data) { - if (jack) - rt5640_enable_jack_detect(component, jack); - else + struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); + + if (jack) { + if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER) + rt5640_enable_hda_jack_detect(component, jack); + else + rt5640_enable_jack_detect(component, jack); + } else { rt5640_disable_jack_detect(component); + } return 0; } @@ -2576,6 +2653,8 @@ static int rt5640_probe(struct snd_soc_component *component) "realtek,jack-detect-source", &val) == 0) { if (val <= RT5640_JD_SRC_GPIO4) rt5640->jd_src = val << RT5640_JD_SFT; + else if (val == RT5640_JD_SRC_HDA_HEADER) + rt5640->jd_src = RT5640_JD_SRC_HDA_HEADER; else dev_warn(component->dev, "Warning: Invalid jack-detect-source value: %d, leaving jack-detect disabled\n", val); @@ -2632,6 +2711,7 @@ static int rt5640_suspend(struct snd_soc_component *component) { struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); + rt5640_cancel_work(rt5640); snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF); rt5640_reset(component); regcache_cache_only(rt5640->regmap, true); @@ -2654,6 +2734,17 @@ static int rt5640_resume(struct snd_soc_component *component) regcache_cache_only(rt5640->regmap, false); regcache_sync(rt5640->regmap); + if (rt5640->jd_src) { + if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER) + snd_soc_component_update_bits(component, + RT5640_DUMMY2, 0x1100, 0x1100); + else + snd_soc_component_write(component, RT5640_DUMMY2, + 0x4001); + + queue_work(system_long_wq, &rt5640->jack_work); + } + return 0; } #else From e14cddc5888418cc9f2ba66c01a04cdbab3b5b25 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 25 Nov 2021 12:15:11 +0200 Subject: [PATCH 107/327] ASoC: SOF: Intel: hda: clear stream before freeing the DAI widget The DAI_CONFIG IPC that is sent during the STOP trigger is used for stopping the DMA in the FW. This must be done after the DMA RUN bit is cleared by the host. So move the call to snd_hdac_ext_link_stream_clear() before hda_link_dai_widget_update() to follow the correct programming sequence for DMA stop for HDA DAIs. Signed-off-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211125101520.291581-2-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dai.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 5c9ee6c494732..748e8ed61475a 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -329,6 +329,8 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: + snd_hdac_ext_link_stream_clear(link_dev); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) w = dai->playback_widget; else @@ -347,8 +349,7 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, } link_dev->link_prepared = 0; - - fallthrough; + break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: snd_hdac_ext_link_stream_clear(link_dev); break; From 2b1acedccf36434924ae530410e008e7eb427cd3 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 25 Nov 2021 12:15:12 +0200 Subject: [PATCH 108/327] ASoC: SOF: Intel: hda: Add a helper function for stream reset Add a helper function to perform stream reset. Signed-off-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211125101520.291581-3-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-stream.c | 76 ++++++++++++++++++-------------- sound/soc/sof/intel/hda.h | 2 + 2 files changed, 46 insertions(+), 32 deletions(-) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index b6f0378153441..c2895bdd3f079 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -279,6 +279,45 @@ int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag) return 0; } +static int hda_dsp_stream_reset(struct snd_sof_dev *sdev, struct hdac_stream *hstream) +{ + int sd_offset = SOF_STREAM_SD_OFFSET(hstream); + int timeout = HDA_DSP_STREAM_RESET_TIMEOUT; + u32 val; + + /* enter stream reset */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, SOF_STREAM_SD_OFFSET_CRST, + SOF_STREAM_SD_OFFSET_CRST); + do { + val = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, sd_offset); + if (val & SOF_STREAM_SD_OFFSET_CRST) + break; + } while (--timeout); + if (timeout == 0) { + dev_err(sdev->dev, "timeout waiting for stream reset\n"); + return -ETIMEDOUT; + } + + timeout = HDA_DSP_STREAM_RESET_TIMEOUT; + + /* exit stream reset and wait to read a zero before reading any other register */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, SOF_STREAM_SD_OFFSET_CRST, 0x0); + + /* wait for hardware to report that stream is out of reset */ + udelay(3); + do { + val = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, sd_offset); + if ((val & SOF_STREAM_SD_OFFSET_CRST) == 0) + break; + } while (--timeout); + if (timeout == 0) { + dev_err(sdev->dev, "timeout waiting for stream to exit reset\n"); + return -ETIMEDOUT; + } + + return 0; +} + int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream, int cmd) { @@ -436,9 +475,9 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_stream *hstream = &stream->hstream; int sd_offset = SOF_STREAM_SD_OFFSET(hstream); - int ret, timeout = HDA_DSP_STREAM_RESET_TIMEOUT; + int ret; u32 dma_start = SOF_HDA_SD_CTL_DMA_START; - u32 val, mask; + u32 mask; u32 run; if (!stream) { @@ -483,36 +522,9 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, SOF_HDA_CL_DMA_SD_INT_MASK); /* stream reset */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, 0x1, - 0x1); - udelay(3); - do { - val = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, - sd_offset); - if (val & 0x1) - break; - } while (--timeout); - if (timeout == 0) { - dev_err(sdev->dev, "error: stream reset failed\n"); - return -ETIMEDOUT; - } - - timeout = HDA_DSP_STREAM_RESET_TIMEOUT; - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, 0x1, - 0x0); - - /* wait for hardware to report that stream is out of reset */ - udelay(3); - do { - val = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, - sd_offset); - if ((val & 0x1) == 0) - break; - } while (--timeout); - if (timeout == 0) { - dev_err(sdev->dev, "error: timeout waiting for stream reset\n"); - return -ETIMEDOUT; - } + ret = hda_dsp_stream_reset(sdev, hstream); + if (ret < 0) + return ret; if (hstream->posbuf) *hstream->posbuf = 0; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 8ed4031ca0078..60139ea9b8ded 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -487,6 +487,8 @@ struct sof_intel_hda_stream { (SOF_HDA_ADSP_SD_ENTRY_SIZE * ((s)->index) \ + SOF_HDA_ADSP_LOADER_BASE) +#define SOF_STREAM_SD_OFFSET_CRST 0x1 + /* * DSP Core services. */ From 4794601a52d40a425542be1b88f8f5614fcf45b4 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 25 Nov 2021 12:15:13 +0200 Subject: [PATCH 109/327] ASoC: SOF: Intel: hda: reset stream before coupling host and link DMA's The recommended programming sequence for HD-Audio DMA is to reset the stream before coupling the link and host DMA's. Signed-off-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211125101520.291581-4-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-stream.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index c2895bdd3f079..440827ce390dc 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -659,6 +659,11 @@ int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev, hstream); struct hdac_bus *bus = sof_to_bus(sdev); u32 mask = 0x1 << stream->index; + int ret; + + ret = hda_dsp_stream_reset(sdev, stream); + if (ret < 0) + return ret; spin_lock_irq(&bus->reg_lock); /* couple host and link DMA if link DMA channel is idle */ From 0dd71a3340b92b503278af4565156f086ccbca3f Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 25 Nov 2021 12:15:14 +0200 Subject: [PATCH 110/327] ASoC: SOF: pcm: invoke platform hw_free for STOP/SUSPEND triggers snd_sof_pcm_platform_hw_params() will be called when the stream is restarted with a prepare ioctl. This happens in two cases i.e. when a suspended stream is resumed or when a stream is restarted without intermediate call to sof_pcm_hw_free(). Make sure to call snd_sof_pcm_platform_hw_free() in both these cases to keep it balanced. Signed-off-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211125101520.291581-5-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/pcm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 1bf7e60be7721..1d0d90551e8f8 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -470,6 +470,10 @@ static int sof_pcm_trigger(struct snd_soc_component *component, if (ret < 0) return ret; + ret = snd_sof_pcm_platform_hw_free(sdev, substream); + if (ret < 0) + return ret; + /* free widget list only for SUSPEND trigger */ if (free_widget_list) ret = sof_widget_list_free(sdev, spcm, substream->stream); From 47934e0fcbbe2bf488bcae2d68431b9ea5972488 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 25 Nov 2021 12:15:15 +0200 Subject: [PATCH 111/327] ASoC: SOF: call platform hw_free for paused streams during suspend Paused streams must be stopped and platform hw_free should be invoked during system suspend so they can be restarted properly after system resume. Signed-off-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211125101520.291581-6-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-audio.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index e00ce275052f9..d81071b398258 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -751,10 +751,17 @@ static int sof_tear_down_left_over_pipelines(struct snd_sof_dev *sdev) continue; if (spcm->stream[dir].list) { + /* Free PCM in the DSP */ ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); if (ret < 0) return ret; + /* stop DMA */ + ret = snd_sof_pcm_platform_hw_free(sdev, substream); + if (ret < 0) + return ret; + + /* free the DAPM widget list */ ret = sof_widget_list_free(sdev, spcm, dir); if (ret < 0) { dev_err(sdev->dev, "failed to free widgets during suspend\n"); From d9a7246534753efa383ad8d05ab3691df846c4b4 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 25 Nov 2021 12:15:16 +0200 Subject: [PATCH 112/327] ASoC: SOF: Add a helper for freeing PCM stream Add a helper function to free PCM in the FW, stop the DMA and free the widget list. These actions are performed both during PCM trigger STOP and when a paused stream is freed during system suspend. Signed-off-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211125101520.291581-7-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/pcm.c | 11 ++--------- sound/soc/sof/sof-audio.c | 40 +++++++++++++++++++++++++-------------- sound/soc/sof/sof-audio.h | 2 ++ 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 1d0d90551e8f8..3aa708b1ac26f 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -466,17 +466,10 @@ static int sof_pcm_trigger(struct snd_soc_component *component, /* free PCM if reset_hw_params is set and the STOP IPC is successful */ if (!ret && reset_hw_params) { - ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); + ret = sof_pcm_stream_free(sdev, substream, spcm, substream->stream, + free_widget_list); if (ret < 0) return ret; - - ret = snd_sof_pcm_platform_hw_free(sdev, substream); - if (ret < 0) - return ret; - - /* free widget list only for SUSPEND trigger */ - if (free_widget_list) - ret = sof_widget_list_free(sdev, spcm, substream->stream); } return ret; diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index d81071b398258..a275f7b7c812c 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -728,6 +728,31 @@ int sof_set_up_pipelines(struct snd_sof_dev *sdev, bool verify) return 0; } +int sof_pcm_stream_free(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, + struct snd_sof_pcm *spcm, int dir, bool free_widget_list) +{ + int ret; + + /* Send PCM_FREE IPC to reset pipeline */ + ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); + if (ret < 0) + return ret; + + /* stop the DMA */ + ret = snd_sof_pcm_platform_hw_free(sdev, substream); + if (ret < 0) + return ret; + + /* free widget list */ + if (free_widget_list) { + ret = sof_widget_list_free(sdev, spcm, dir); + if (ret < 0) + dev_err(sdev->dev, "failed to free widgets during suspend\n"); + } + + return ret; +} + /* * Free the PCM, its associated widgets and set the prepared flag to false for all PCMs that * did not get suspended(ex: paused streams) so the widgets can be set up again during resume. @@ -751,22 +776,9 @@ static int sof_tear_down_left_over_pipelines(struct snd_sof_dev *sdev) continue; if (spcm->stream[dir].list) { - /* Free PCM in the DSP */ - ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); - if (ret < 0) - return ret; - - /* stop DMA */ - ret = snd_sof_pcm_platform_hw_free(sdev, substream); + ret = sof_pcm_stream_free(sdev, substream, spcm, dir, true); if (ret < 0) return ret; - - /* free the DAPM widget list */ - ret = sof_widget_list_free(sdev, spcm, dir); - if (ret < 0) { - dev_err(sdev->dev, "failed to free widgets during suspend\n"); - return ret; - } } } diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 1c4f59d347177..e419e7082c28f 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -267,4 +267,6 @@ int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, in int sof_widget_list_free(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir); int sof_pcm_dsp_pcm_free(struct snd_pcm_substream *substream, struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm); +int sof_pcm_stream_free(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, + struct snd_sof_pcm *spcm, int dir, bool free_widget_list); #endif From 85d7acd0ef18725b1d3a7980eee8b84d46296b91 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 25 Nov 2021 12:15:17 +0200 Subject: [PATCH 113/327] ASoC: SOF: pcm: move the check for prepared flag Move the check for the prepared flag inside snd_pcm_dsp_pcm_free() to avoid having to check it before every invocation of the function. Signed-off-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211125101520.291581-8-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/pcm.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 3aa708b1ac26f..c61cd3cc4f024 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -107,6 +107,9 @@ int sof_pcm_dsp_pcm_free(struct snd_pcm_substream *substream, struct snd_sof_dev struct sof_ipc_reply reply; int ret; + if (!spcm->prepared[substream->stream]) + return 0; + stream.hdr.size = sizeof(stream); stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE; stream.comp_id = spcm->stream[substream->stream].comp_id; @@ -178,11 +181,9 @@ static int sof_pcm_hw_params(struct snd_soc_component *component, * Handle repeated calls to hw_params() without free_pcm() in * between. At least ALSA OSS emulation depends on this. */ - if (spcm->prepared[substream->stream]) { - ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); - if (ret < 0) - return ret; - } + ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); + if (ret < 0) + return ret; dev_dbg(component->dev, "pcm: hw params stream %d dir %d\n", spcm->pcm.pcm_id, substream->stream); @@ -298,11 +299,9 @@ static int sof_pcm_hw_free(struct snd_soc_component *component, dev_dbg(component->dev, "pcm: free stream %d dir %d\n", spcm->pcm.pcm_id, substream->stream); - if (spcm->prepared[substream->stream]) { - ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); - if (ret < 0) - err = ret; - } + ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); + if (ret < 0) + err = ret; ret = sof_widget_list_free(sdev, spcm, substream->stream); if (ret < 0) From 0b639dcd457b1d3fc660e5a77b02cf65acde3b5a Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 25 Nov 2021 12:15:18 +0200 Subject: [PATCH 114/327] ASoC: SOF: align the hw_free sequence with stop Even though the order of stopping the DMA and freeing the widget list is not important, align the sequence to match with the stop trigger to avoid confusion. Signed-off-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211125101520.291581-9-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/pcm.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index c61cd3cc4f024..e4446defe51e9 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -299,22 +299,26 @@ static int sof_pcm_hw_free(struct snd_soc_component *component, dev_dbg(component->dev, "pcm: free stream %d dir %d\n", spcm->pcm.pcm_id, substream->stream); + /* free PCM in the DSP */ ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); if (ret < 0) err = ret; - ret = sof_widget_list_free(sdev, spcm, substream->stream); - if (ret < 0) - err = ret; - - cancel_work_sync(&spcm->stream[substream->stream].period_elapsed_work); + /* stop DMA */ ret = snd_sof_pcm_platform_hw_free(sdev, substream); if (ret < 0) { dev_err(component->dev, "error: platform hw free failed\n"); err = ret; } + /* free the DAPM widget list */ + ret = sof_widget_list_free(sdev, spcm, substream->stream); + if (ret < 0) + err = ret; + + cancel_work_sync(&spcm->stream[substream->stream].period_elapsed_work); + return err; } From a0f84dfb3f6d9f78f862cbe885036d3e4449fc6f Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 25 Nov 2021 12:15:19 +0200 Subject: [PATCH 115/327] ASoC: SOF: IPC: dai: Expand DAI_CONFIG IPC flags Some DAI components, such as HDaudio, need to be stopped in two steps a) stop the DAI component b) stop the DAI DMA This patch enables this two-step stop by expanding the DAI_CONFIG IPC flags and split them into 2 parts. The 4 LSB bits indicate when the DAI_CONFIG IPC is sent, ex: hw_params, hw_free or pause. The 4 MSB bits are used as the quirk flags to be used along with the command flags. The quirk flag called SOF_DAI_CONFIG_FLAGS_2_STEP_STOP shall be set along with the HW_PARAMS command flag, i.e. before the pipeline is started so that the stop/pause trigger op in the FW can take the appropriate action to either perform/skip the DMA stop. If set, the DMA stop will be executed when the DAI_CONFIG IPC is sent during hw_free. In the case of pause, DMA pause will be handled when the DAI_CONFIG IPC is sent with the PAUSE command flag. Along with this, modify the signature for the hda_ctrl_dai_widget_setup/ hda_ctrl_dai_widget_free() functions to take additional flags as an argument and modify all users to pass the appropriate quirk flags. Only the HDA DAI's need to pass the SOF_DAI_CONFIG_FLAGS_2_STEP_STOP quirk flag during hw_params to indicate that it supports two-step stop and pause. Signed-off-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211125101520.291581-10-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/dai.h | 25 +++++++++++++++++++------ sound/soc/sof/intel/hda-dai.c | 8 ++++---- sound/soc/sof/intel/hda.c | 26 ++++++++++++++++++-------- sound/soc/sof/intel/hda.h | 4 ++-- sound/soc/sof/sof-audio.c | 2 +- 5 files changed, 44 insertions(+), 21 deletions(-) diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h index 5132bc60f54bf..59ee50ac77053 100644 --- a/include/sound/sof/dai.h +++ b/include/sound/sof/dai.h @@ -52,12 +52,25 @@ #define SOF_DAI_FMT_INV_MASK 0x0f00 #define SOF_DAI_FMT_CLOCK_PROVIDER_MASK 0xf000 -/* DAI_CONFIG flags */ -#define SOF_DAI_CONFIG_FLAGS_MASK 0x3 -#define SOF_DAI_CONFIG_FLAGS_NONE (0 << 0) /**< DAI_CONFIG sent without stage information */ -#define SOF_DAI_CONFIG_FLAGS_HW_PARAMS (1 << 0) /**< DAI_CONFIG sent during hw_params stage */ -#define SOF_DAI_CONFIG_FLAGS_HW_FREE (2 << 0) /**< DAI_CONFIG sent during hw_free stage */ -#define SOF_DAI_CONFIG_FLAGS_RFU (3 << 0) /**< not used, reserved for future use */ +/* + * DAI_CONFIG flags. The 4 LSB bits are used for the commands, HW_PARAMS, HW_FREE and PAUSE + * representing when the IPC is sent. The 4 MSB bits are used to add quirks along with the above + * commands. + */ +#define SOF_DAI_CONFIG_FLAGS_CMD_MASK 0xF +#define SOF_DAI_CONFIG_FLAGS_NONE 0 /**< DAI_CONFIG sent without stage information */ +#define SOF_DAI_CONFIG_FLAGS_HW_PARAMS BIT(0) /**< DAI_CONFIG sent during hw_params stage */ +#define SOF_DAI_CONFIG_FLAGS_HW_FREE BIT(1) /**< DAI_CONFIG sent during hw_free stage */ +/**< DAI_CONFIG sent during pause trigger. Only available ABI 3.20 onwards */ +#define SOF_DAI_CONFIG_FLAGS_PAUSE BIT(2) +#define SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT 4 +#define SOF_DAI_CONFIG_FLAGS_QUIRK_MASK (0xF << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT) +/* + * This should be used along with the SOF_DAI_CONFIG_FLAGS_HW_PARAMS to indicate that pipeline + * stop/pause and DAI DMA stop/pause should happen in two steps. This change is only available + * ABI 3.20 onwards. + */ +#define SOF_DAI_CONFIG_FLAGS_2_STEP_STOP BIT(0) /** \brief Types of DAI */ enum sof_ipc_dai_type { diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 748e8ed61475a..bce5366cf9137 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -197,9 +197,9 @@ static int hda_link_dai_widget_update(struct sof_intel_hda_stream *hda_stream, /* set up/free DAI widget and send DAI_CONFIG IPC */ if (widget_setup) - return hda_ctrl_dai_widget_setup(w); + return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_2_STEP_STOP); - return hda_ctrl_dai_widget_free(w); + return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE); } static int hda_link_hw_params(struct snd_pcm_substream *substream, @@ -452,9 +452,9 @@ static int ssp_dai_setup_or_free(struct snd_pcm_substream *substream, struct snd return 0; if (setup) - return hda_ctrl_dai_widget_setup(w); + return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_NONE); - return hda_ctrl_dai_widget_free(w); + return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE); } static int ssp_dai_startup(struct snd_pcm_substream *substream, diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 1e1e9659ea86b..cfe026dbf1242 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -41,7 +41,7 @@ #define EXCEPT_MAX_HDR_SIZE 0x400 #define HDA_EXT_ROM_STATUS_SIZE 8 -int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w) +int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w, unsigned int quirk_flags) { struct snd_sof_widget *swidget = w->dobj.private; struct snd_soc_component *component = swidget->scomp; @@ -58,6 +58,13 @@ int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w) return -EINVAL; } + /* DAI already configured, reset it before reconfiguring it */ + if (sof_dai->configured) { + ret = hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE); + if (ret < 0) + return ret; + } + config = &sof_dai->dai_config[sof_dai->current_config]; /* @@ -71,8 +78,10 @@ int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w) return ret; } - /* set HW_PARAMS flag */ - config->flags = FIELD_PREP(SOF_DAI_CONFIG_FLAGS_MASK, SOF_DAI_CONFIG_FLAGS_HW_PARAMS); + /* set HW_PARAMS flag along with quirks */ + config->flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS | + quirk_flags << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT; + /* send DAI_CONFIG IPC */ ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size, @@ -87,7 +96,7 @@ int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w) return 0; } -int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w) +int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w, unsigned int quirk_flags) { struct snd_sof_widget *swidget = w->dobj.private; struct snd_soc_component *component = swidget->scomp; @@ -110,8 +119,9 @@ int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w) config = &sof_dai->dai_config[sof_dai->current_config]; - /* set HW_FREE flag */ - config->flags = FIELD_PREP(SOF_DAI_CONFIG_FLAGS_MASK, SOF_DAI_CONFIG_FLAGS_HW_FREE); + /* set HW_FREE flag along with any quirks */ + config->flags = SOF_DAI_CONFIG_FLAGS_HW_FREE | + quirk_flags << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT; ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size, &reply, sizeof(reply)); @@ -166,9 +176,9 @@ static int sdw_dai_config_ipc(struct snd_sof_dev *sdev, config->alh.stream_id = alh_stream_id; if (setup) - return hda_ctrl_dai_widget_setup(w); + return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_NONE); - return hda_ctrl_dai_widget_free(w); + return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE); } static int sdw_params_stream(struct device *dev, diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 60139ea9b8ded..72e78c449aa82 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -739,7 +739,7 @@ int hda_pci_intel_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) struct snd_sof_dai; struct sof_ipc_dai_config; -int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w); -int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w); +int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w, unsigned int quirk_flags); +int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w, unsigned int quirk_flags); #endif diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index a275f7b7c812c..58a62bfb16ab7 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -57,7 +57,7 @@ static int sof_dai_config_setup(struct snd_sof_dev *sdev, struct snd_sof_dai *da } /* set NONE flag to clear all previous settings */ - config->flags = FIELD_PREP(SOF_DAI_CONFIG_FLAGS_MASK, SOF_DAI_CONFIG_FLAGS_NONE); + config->flags = SOF_DAI_CONFIG_FLAGS_NONE; ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size, &reply, sizeof(reply)); From 69acac569031426e2ab9b5244593b60d0c9abd04 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 25 Nov 2021 12:15:20 +0200 Subject: [PATCH 116/327] ASoC: SOF: Intel: hda: send DAI_CONFIG IPC during pause For HDA DAI's the DMA must be paused after the RUN bit is cleared by the host. So, send the DAI_CONFIG IPC with just the SOF_DAI_CONFIG_FLAGS_PAUSE flag set to indicate this to the firmware. Signed-off-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211125101520.291581-11-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dai.c | 42 ++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index bce5366cf9137..8c1d7ddb00e2e 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -287,6 +287,36 @@ static int hda_link_pcm_prepare(struct snd_pcm_substream *substream, dai); } +static int hda_link_dai_config_pause_push_ipc(struct snd_soc_dapm_widget *w) +{ + struct snd_sof_widget *swidget = w->dobj.private; + struct snd_soc_component *component = swidget->scomp; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct sof_ipc_dai_config *config; + struct snd_sof_dai *sof_dai; + struct sof_ipc_reply reply; + int ret; + + sof_dai = swidget->private; + + if (!sof_dai || !sof_dai->dai_config) { + dev_err(sdev->dev, "No config for DAI %s\n", w->name); + return -EINVAL; + } + + config = &sof_dai->dai_config[sof_dai->current_config]; + + /* set PAUSE command flag */ + config->flags = FIELD_PREP(SOF_DAI_CONFIG_FLAGS_CMD_MASK, SOF_DAI_CONFIG_FLAGS_PAUSE); + + ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size, + &reply, sizeof(reply)); + if (ret < 0) + dev_err(sdev->dev, "DAI config for %s failed during pause push\n", w->name); + + return ret; +} + static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { @@ -312,6 +342,9 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, hda_stream = hstream_to_sof_hda_stream(link_dev); dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd); + + w = snd_soc_dai_get_widget(dai, substream->stream); + switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: /* set up hw_params */ @@ -331,11 +364,6 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_STOP: snd_hdac_ext_link_stream_clear(link_dev); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - w = dai->playback_widget; - else - w = dai->capture_widget; - /* * free DAI widget during stop/suspend to keep widget use_count's balanced. */ @@ -352,6 +380,10 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: snd_hdac_ext_link_stream_clear(link_dev); + + ret = hda_link_dai_config_pause_push_ipc(w); + if (ret < 0) + return ret; break; default: return -EINVAL; From f670b274f7f6f4b2722d7f08d0fddf606a727e92 Mon Sep 17 00:00:00 2001 From: Ye Guojin Date: Wed, 10 Nov 2021 00:29:10 +0000 Subject: [PATCH 117/327] ASoC: imx-hdmi: add put_device() after of_find_device_by_node() This was found by coccicheck: ./sound/soc/fsl/imx-hdmi.c,209,1-7,ERROR missing put_device; call of_find_device_by_node on line 119, but without a corresponding object release within this function. Reported-by: Zeal Robot Signed-off-by: Ye Guojin Link: https://lore.kernel.org/r/20211110002910.134915-1-ye.guojin@zte.com.cn Signed-off-by: Mark Brown --- sound/soc/fsl/imx-hdmi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/fsl/imx-hdmi.c b/sound/soc/fsl/imx-hdmi.c index f10359a288005..929f69b758af4 100644 --- a/sound/soc/fsl/imx-hdmi.c +++ b/sound/soc/fsl/imx-hdmi.c @@ -145,6 +145,8 @@ static int imx_hdmi_probe(struct platform_device *pdev) data->dai.capture_only = false; data->dai.init = imx_hdmi_init; + put_device(&cpu_pdev->dev); + if (of_node_name_eq(cpu_np, "sai")) { data->cpu_priv.sysclk_id[1] = FSL_SAI_CLK_MAST1; data->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1; From 0b189395945dc59d327c1e0588d144ce439dfa55 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 25 Nov 2021 23:25:43 +0000 Subject: [PATCH 118/327] ASoC: codecs/jz4770: Add missing gain control after DAC/ADC mixer The capture and playback paths both have a configurable gain after their respective mixer, which can be set from -31 dB to 0 dB in 32 steps. Signed-off-by: Paul Cercueil Link: https://lore.kernel.org/r/20211125232543.117074-1-paul@crapouillou.net Signed-off-by: Mark Brown --- sound/soc/codecs/jz4770.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/codecs/jz4770.c b/sound/soc/codecs/jz4770.c index 6b60120f59a68..1d0c467ab57b4 100644 --- a/sound/soc/codecs/jz4770.c +++ b/sound/soc/codecs/jz4770.c @@ -307,6 +307,7 @@ static const DECLARE_TLV_DB_MINMAX_MUTE(dac_tlv, -3100, 0); static const DECLARE_TLV_DB_SCALE(adc_tlv, 0, 100, 0); static const DECLARE_TLV_DB_MINMAX(out_tlv, -2500, 600); static const DECLARE_TLV_DB_SCALE(linein_tlv, -2500, 100, 0); +static const DECLARE_TLV_DB_MINMAX(mixer_tlv, -3100, 0); /* Unconditional controls. */ static const struct snd_kcontrol_new jz4770_codec_snd_controls[] = { @@ -319,6 +320,14 @@ static const struct snd_kcontrol_new jz4770_codec_snd_controls[] = { SOC_DOUBLE_R_TLV("Line In Bypass Playback Volume", JZ4770_CODEC_REG_GCR_LIBYL, JZ4770_CODEC_REG_GCR_LIBYR, REG_GCR_GAIN_OFFSET, REG_GCR_GAIN_MAX, 1, linein_tlv), + + SOC_SINGLE_TLV("Mixer Capture Volume", + JZ4770_CODEC_REG_GCR_MIXADC, + REG_GCR_GAIN_OFFSET, REG_GCR_GAIN_MAX, 1, mixer_tlv), + + SOC_SINGLE_TLV("Mixer Playback Volume", + JZ4770_CODEC_REG_GCR_MIXDAC, + REG_GCR_GAIN_OFFSET, REG_GCR_GAIN_MAX, 1, mixer_tlv), }; static const struct snd_kcontrol_new jz4770_codec_pcm_playback_controls[] = { From a5e0091d62abb9599d9dea505ec0e8c820001831 Mon Sep 17 00:00:00 2001 From: Lucas Tanure Date: Thu, 25 Nov 2021 14:35:01 +0000 Subject: [PATCH 119/327] ASoC: cs35l41: Fix link problem Can't link I2C and SPI to the same binary, better to move CS35L41 to 3 modules approach. And instead of exposing cs35l41_reg, volatile_reg, readable_reg and precious_reg arrays, move cs35l41_regmap_i2c/spi to new module and expose it. Signed-off-by: Lucas Tanure Link: https://lore.kernel.org/r/20211125143501.7720-1-tanureal@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 5 ++++ sound/soc/codecs/Makefile | 6 +++-- sound/soc/codecs/cs35l41-i2c.c | 15 ----------- sound/soc/codecs/cs35l41-spi.c | 16 ------------ sound/soc/codecs/cs35l41-tables.c | 41 ++++++++++++++++++++++++++++--- sound/soc/codecs/cs35l41.c | 2 ++ sound/soc/codecs/cs35l41.h | 7 ++---- 7 files changed, 50 insertions(+), 42 deletions(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index b6d1827e7986d..b4f70e27342c2 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -612,14 +612,19 @@ config SND_SOC_CS35L36 tristate "Cirrus Logic CS35L36 CODEC" depends on I2C +config SND_SOC_CS35L41 + tristate + config SND_SOC_CS35L41_SPI tristate "Cirrus Logic CS35L41 CODEC (SPI)" depends on SPI_MASTER + select SND_SOC_CS35L41 select REGMAP_SPI config SND_SOC_CS35L41_I2C tristate "Cirrus Logic CS35L41 CODEC (I2C)" depends on I2C + select SND_SOC_CS35L41 select REGMAP_I2C config SND_SOC_CS42L42 diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 9acfbcbfc46d8..485eee75502b0 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -54,8 +54,9 @@ snd-soc-cs35l33-objs := cs35l33.o snd-soc-cs35l34-objs := cs35l34.o snd-soc-cs35l35-objs := cs35l35.o snd-soc-cs35l36-objs := cs35l36.o -snd-soc-cs35l41-spi-objs := cs35l41-spi.o cs35l41.o cs35l41-tables.o -snd-soc-cs35l41-i2c-objs := cs35l41-i2c.o cs35l41.o cs35l41-tables.o +snd-soc-cs35l41-objs := cs35l41.o cs35l41-tables.o +snd-soc-cs35l41-spi-objs := cs35l41-spi.o +snd-soc-cs35l41-i2c-objs := cs35l41-i2c.o snd-soc-cs42l42-objs := cs42l42.o snd-soc-cs42l51-objs := cs42l51.o snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o @@ -391,6 +392,7 @@ obj-$(CONFIG_SND_SOC_CS35L33) += snd-soc-cs35l33.o obj-$(CONFIG_SND_SOC_CS35L34) += snd-soc-cs35l34.o obj-$(CONFIG_SND_SOC_CS35L35) += snd-soc-cs35l35.o obj-$(CONFIG_SND_SOC_CS35L36) += snd-soc-cs35l36.o +obj-$(CONFIG_SND_SOC_CS35L41) += snd-soc-cs35l41.o obj-$(CONFIG_SND_SOC_CS35L41_SPI) += snd-soc-cs35l41-spi.o obj-$(CONFIG_SND_SOC_CS35L41_I2C) += snd-soc-cs35l41-i2c.o obj-$(CONFIG_SND_SOC_CS42L42) += snd-soc-cs42l42.o diff --git a/sound/soc/codecs/cs35l41-i2c.c b/sound/soc/codecs/cs35l41-i2c.c index d5fa8d2c4a703..c9b604af6b71e 100644 --- a/sound/soc/codecs/cs35l41-i2c.c +++ b/sound/soc/codecs/cs35l41-i2c.c @@ -20,21 +20,6 @@ #include #include "cs35l41.h" -static struct regmap_config cs35l41_regmap_i2c = { - .reg_bits = 32, - .val_bits = 32, - .reg_stride = CS35L41_REGSTRIDE, - .reg_format_endian = REGMAP_ENDIAN_BIG, - .val_format_endian = REGMAP_ENDIAN_BIG, - .max_register = CS35L41_LASTREG, - .reg_defaults = cs35l41_reg, - .num_reg_defaults = ARRAY_SIZE(cs35l41_reg), - .volatile_reg = cs35l41_volatile_reg, - .readable_reg = cs35l41_readable_reg, - .precious_reg = cs35l41_precious_reg, - .cache_type = REGCACHE_RBTREE, -}; - static const struct i2c_device_id cs35l41_id_i2c[] = { { "cs35l40", 0 }, { "cs35l41", 0 }, diff --git a/sound/soc/codecs/cs35l41-spi.c b/sound/soc/codecs/cs35l41-spi.c index 90a921f726c3b..5d6cf39abec4b 100644 --- a/sound/soc/codecs/cs35l41-spi.c +++ b/sound/soc/codecs/cs35l41-spi.c @@ -18,22 +18,6 @@ #include #include "cs35l41.h" -static struct regmap_config cs35l41_regmap_spi = { - .reg_bits = 32, - .val_bits = 32, - .pad_bits = 16, - .reg_stride = CS35L41_REGSTRIDE, - .reg_format_endian = REGMAP_ENDIAN_BIG, - .val_format_endian = REGMAP_ENDIAN_BIG, - .max_register = CS35L41_LASTREG, - .reg_defaults = cs35l41_reg, - .num_reg_defaults = ARRAY_SIZE(cs35l41_reg), - .volatile_reg = cs35l41_volatile_reg, - .readable_reg = cs35l41_readable_reg, - .precious_reg = cs35l41_precious_reg, - .cache_type = REGCACHE_RBTREE, -}; - static const struct spi_device_id cs35l41_id_spi[] = { { "cs35l40", 0 }, { "cs35l41", 0 }, diff --git a/sound/soc/codecs/cs35l41-tables.c b/sound/soc/codecs/cs35l41-tables.c index 9d1a7d7dd24d1..3eb18b17a7b0f 100644 --- a/sound/soc/codecs/cs35l41-tables.c +++ b/sound/soc/codecs/cs35l41-tables.c @@ -8,7 +8,7 @@ #include "cs35l41.h" -const struct reg_default cs35l41_reg[CS35L41_MAX_CACHE_REG] = { +static const struct reg_default cs35l41_reg[] = { { CS35L41_PWR_CTRL1, 0x00000000 }, { CS35L41_PWR_CTRL3, 0x01000010 }, { CS35L41_GPIO_PAD_CONTROL, 0x00000000 }, @@ -47,7 +47,7 @@ const struct reg_default cs35l41_reg[CS35L41_MAX_CACHE_REG] = { { CS35L41_MIXER_NGATE_CH2_CFG, 0x00000303 }, }; -bool cs35l41_readable_reg(struct device *dev, unsigned int reg) +static bool cs35l41_readable_reg(struct device *dev, unsigned int reg) { switch (reg) { case CS35L41_DEVID: @@ -331,7 +331,7 @@ bool cs35l41_readable_reg(struct device *dev, unsigned int reg) } } -bool cs35l41_precious_reg(struct device *dev, unsigned int reg) +static bool cs35l41_precious_reg(struct device *dev, unsigned int reg) { switch (reg) { case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31: @@ -344,7 +344,7 @@ bool cs35l41_precious_reg(struct device *dev, unsigned int reg) } } -bool cs35l41_volatile_reg(struct device *dev, unsigned int reg) +static bool cs35l41_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { case CS35L41_DEVID: @@ -688,3 +688,36 @@ const struct cs35l41_otp_map_element_t cs35l41_otp_map_map[CS35L41_NUM_OTP_MAPS] .word_offset = 2, }, }; + +struct regmap_config cs35l41_regmap_i2c = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = CS35L41_REGSTRIDE, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, + .max_register = CS35L41_LASTREG, + .reg_defaults = cs35l41_reg, + .num_reg_defaults = ARRAY_SIZE(cs35l41_reg), + .volatile_reg = cs35l41_volatile_reg, + .readable_reg = cs35l41_readable_reg, + .precious_reg = cs35l41_precious_reg, + .cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(cs35l41_regmap_i2c); + +struct regmap_config cs35l41_regmap_spi = { + .reg_bits = 32, + .val_bits = 32, + .pad_bits = 16, + .reg_stride = CS35L41_REGSTRIDE, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, + .max_register = CS35L41_LASTREG, + .reg_defaults = cs35l41_reg, + .num_reg_defaults = ARRAY_SIZE(cs35l41_reg), + .volatile_reg = cs35l41_volatile_reg, + .readable_reg = cs35l41_readable_reg, + .precious_reg = cs35l41_precious_reg, + .cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(cs35l41_regmap_spi); diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c index afb07d2991ba4..e04924526883d 100644 --- a/sound/soc/codecs/cs35l41.c +++ b/sound/soc/codecs/cs35l41.c @@ -1731,6 +1731,7 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, return ret; } +EXPORT_SYMBOL_GPL(cs35l41_probe); void cs35l41_remove(struct cs35l41_private *cs35l41) { @@ -1739,6 +1740,7 @@ void cs35l41_remove(struct cs35l41_private *cs35l41) regulator_bulk_disable(CS35L41_NUM_SUPPLIES, cs35l41->supplies); gpiod_set_value_cansleep(cs35l41->reset_gpio, 0); } +EXPORT_SYMBOL_GPL(cs35l41_remove); MODULE_DESCRIPTION("ASoC CS35L41 driver"); MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, "); diff --git a/sound/soc/codecs/cs35l41.h b/sound/soc/codecs/cs35l41.h index eea3b14acb0b4..f82075ea855fc 100644 --- a/sound/soc/codecs/cs35l41.h +++ b/sound/soc/codecs/cs35l41.h @@ -538,7 +538,6 @@ #define CS35L41_OTP_TRIM_35 0x0000400C #define CS35L41_OTP_TRIM_36 0x00002030 -#define CS35L41_MAX_CACHE_REG 36 #define CS35L41_OTP_SIZE_WORDS 32 #define CS35L41_NUM_OTP_ELEM 100 #define CS35L41_NUM_OTP_MAPS 5 @@ -734,9 +733,8 @@ #define CS35L41_RX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) #define CS35L41_TX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) -bool cs35l41_readable_reg(struct device *dev, unsigned int reg); -bool cs35l41_precious_reg(struct device *dev, unsigned int reg); -bool cs35l41_volatile_reg(struct device *dev, unsigned int reg); +extern struct regmap_config cs35l41_regmap_i2c; +extern struct regmap_config cs35l41_regmap_spi; struct cs35l41_otp_packed_element_t { u32 reg; @@ -752,7 +750,6 @@ struct cs35l41_otp_map_element_t { u32 word_offset; }; -extern const struct reg_default cs35l41_reg[CS35L41_MAX_CACHE_REG]; extern const struct cs35l41_otp_map_element_t cs35l41_otp_map_map[CS35L41_NUM_OTP_MAPS]; From 4dcddadf5530a0da00e6b2eb8194297b49d33506 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 23 Nov 2021 11:30:13 +0100 Subject: [PATCH 120/327] ASoC: SOF: mediatek: Use %pR/%pa to print resources/physical addresses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On 32-bit with CONFIG_ARCH_DMA_ADDR_T_64BIT=n: sound/soc/sof/mediatek/mt8195/mt8195.c: In function ‘platform_parse_resource’: sound/soc/sof/mediatek/mt8195/mt8195.c:51:15: error: format ‘%llx’ expects argument of type ‘long long unsigned int’, but argument 4 has type ‘unsigned int’ [-Werror=format=] 51 | dev_dbg(dev, "DMA pbase=0x%llx, size=0x%llx\n", | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sound/soc/sof/mediatek/mt8195/mt8195.c: In function ‘adsp_memory_remap_init’: sound/soc/sof/mediatek/mt8195/mt8195.c:167:15: error: format ‘%llx’ expects argument of type ‘long long unsigned int’, but argument 4 has type ‘phys_addr_t’ {aka ‘unsigned int’} [-Werror=format=] 167 | dev_dbg(dev, "adsp->pa_dram %llx, offset %#x\n", adsp->pa_dram, offset); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sound/soc/sof/mediatek/mt8195/mt8195.c: In function ‘adsp_shared_base_ioremap’: sound/soc/sof/mediatek/mt8195/mt8195.c:196:15: error: format ‘%llx’ expects argument of type ‘long long unsigned int’, but argument 5 has type ‘phys_addr_t’ {aka ‘unsigned int’} [-Werror=format=] 196 | dev_dbg(dev, "shared-dram vbase=%p, phy addr :%llx, size=%#x\n", | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Fix the first cases by printing the full resource using %pR. Fix the other cases by printing the physical addresses using %pa. Reported-by: noreply@ellerman.id.au Fixes: 32d7e03d26fd9318 ("ASoC: SOF: mediatek: Add mt8195 hardware support") Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20211123103013.73645-1-geert@linux-m68k.org Signed-off-by: Mark Brown --- sound/soc/sof/mediatek/mt8195/mt8195.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index 55d9812870a45..c719ba4706202 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -49,8 +49,7 @@ static int platform_parse_resource(struct platform_device *pdev, void *data) return ret; } - dev_dbg(dev, "DMA pbase=0x%llx, size=0x%llx\n", - (phys_addr_t)res.start, resource_size(&res)); + dev_dbg(dev, "DMA %pR\n", &res); ret = of_reserved_mem_device_init(dev); if (ret) { @@ -166,7 +165,7 @@ static int adsp_memory_remap_init(struct device *dev, struct mtk_adsp_chip_info offset = adsp->pa_dram - DRAM_PHYS_BASE_FROM_DSP_VIEW; adsp->dram_offset = offset; offset >>= DRAM_REMAP_SHIFT; - dev_dbg(dev, "adsp->pa_dram %llx, offset %#x\n", adsp->pa_dram, offset); + dev_dbg(dev, "adsp->pa_dram %pa, offset %#x\n", &adsp->pa_dram, offset); writel(offset, vaddr_emi_map); if (offset != readl(vaddr_emi_map)) { dev_err(dev, "write emi map fail : %#x\n", readl(vaddr_emi_map)); @@ -195,8 +194,8 @@ static int adsp_shared_base_ioremap(struct platform_device *pdev, void *data) return -ENOMEM; } } - dev_dbg(dev, "shared-dram vbase=%p, phy addr :%llx, size=%#x\n", - adsp->shared_dram, adsp->pa_shared_dram, shared_size); + dev_dbg(dev, "shared-dram vbase=%p, phy addr :%pa, size=%#x\n", + adsp->shared_dram, &adsp->pa_shared_dram, shared_size); return 0; } From 8544f08c816292c2219f28c6eaa69236b978bfb9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 Nov 2021 16:45:12 +0900 Subject: [PATCH 121/327] ASoC: soc-dai: update snd_soc_dai_delay() to snd_soc_pcm_dai_delay() Current soc_pcm_pointer() is manually calculating both CPU-DAI's max delay (= A) and Codec-DAI's max delay (= B). static snd_pcm_uframes_t soc_pcm_pointer(...) { ... ^ for_each_rtd_cpu_dais(rtd, i, cpu_dai) (A) cpu_delay = max(cpu_delay, ...); v delay += cpu_delay; ^ for_each_rtd_codec_dais(rtd, i, codec_dai) (B) codec_delay = max(codec_delay, ...); v delay += codec_delay; runtime->delay = delay; ... } Current soc_pcm_pointer() and the total delay calculating is not readable / difficult to understand. This patch update snd_soc_dai_delay() to snd_soc_pcm_dai_delay(), and calcule both CPU/Codec delay in one function. Link: https://lore.kernel.org/r/87fszl4yrq.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/875yssy25z.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 4 ++-- sound/soc/soc-dai.c | 40 ++++++++++++++++++++++++++++------------ sound/soc/soc-pcm.c | 18 ++---------------- 3 files changed, 32 insertions(+), 30 deletions(-) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 0dcb361a98bb3..5d4dd7c5450bc 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -208,8 +208,6 @@ int snd_soc_dai_startup(struct snd_soc_dai *dai, struct snd_pcm_substream *substream); void snd_soc_dai_shutdown(struct snd_soc_dai *dai, struct snd_pcm_substream *substream, int rollback); -snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai, - struct snd_pcm_substream *substream); void snd_soc_dai_suspend(struct snd_soc_dai *dai); void snd_soc_dai_resume(struct snd_soc_dai *dai); int snd_soc_dai_compress_new(struct snd_soc_dai *dai, @@ -238,6 +236,8 @@ int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream, int cmd, int rollback); int snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream, int cmd); +void snd_soc_pcm_dai_delay(struct snd_pcm_substream *substream, + snd_pcm_sframes_t *cpu_delay, snd_pcm_sframes_t *codec_delay); int snd_soc_dai_compr_startup(struct snd_soc_dai *dai, struct snd_compr_stream *cstream); diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 3db0fcf24385a..6078afe335f88 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -453,18 +453,6 @@ void snd_soc_dai_shutdown(struct snd_soc_dai *dai, soc_dai_mark_pop(dai, substream, startup); } -snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai, - struct snd_pcm_substream *substream) -{ - int delay = 0; - - if (dai->driver->ops && - dai->driver->ops->delay) - delay = dai->driver->ops->delay(substream, dai); - - return delay; -} - int snd_soc_dai_compress_new(struct snd_soc_dai *dai, struct snd_soc_pcm_runtime *rtd, int num) { @@ -693,6 +681,34 @@ int snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream, return 0; } +void snd_soc_pcm_dai_delay(struct snd_pcm_substream *substream, + snd_pcm_sframes_t *cpu_delay, + snd_pcm_sframes_t *codec_delay) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_dai *dai; + int i; + + /* + * We're looking for the delay through the full audio path so it needs to + * be the maximum of the DAIs doing transmit and the maximum of the DAIs + * doing receive (ie, all CPUs and all CODECs) rather than just the maximum + * of all DAIs. + */ + + /* for CPU */ + for_each_rtd_cpu_dais(rtd, i, dai) + if (dai->driver->ops && + dai->driver->ops->delay) + *cpu_delay = max(*cpu_delay, dai->driver->ops->delay(substream, dai)); + + /* for Codec */ + for_each_rtd_codec_dais(rtd, i, dai) + if (dai->driver->ops && + dai->driver->ops->delay) + *codec_delay = max(*codec_delay, dai->driver->ops->delay(substream, dai)); +} + int snd_soc_dai_compr_startup(struct snd_soc_dai *dai, struct snd_compr_stream *cstream) { diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 4d41ad3028029..82fd170e16afa 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1084,15 +1084,11 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) */ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *cpu_dai; - struct snd_soc_dai *codec_dai; struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_uframes_t offset = 0; snd_pcm_sframes_t delay = 0; snd_pcm_sframes_t codec_delay = 0; snd_pcm_sframes_t cpu_delay = 0; - int i; /* clearing the previous total delay */ runtime->delay = 0; @@ -1102,19 +1098,9 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) /* base delay if assigned in pointer callback */ delay = runtime->delay; - for_each_rtd_cpu_dais(rtd, i, cpu_dai) { - cpu_delay = max(cpu_delay, - snd_soc_dai_delay(cpu_dai, substream)); - } - delay += cpu_delay; - - for_each_rtd_codec_dais(rtd, i, codec_dai) { - codec_delay = max(codec_delay, - snd_soc_dai_delay(codec_dai, substream)); - } - delay += codec_delay; + snd_soc_pcm_dai_delay(substream, &cpu_delay, &codec_delay); - runtime->delay = delay; + runtime->delay = delay + cpu_delay + codec_delay; return offset; } From 403f830e7a0be5a9e33c7a9d208574f79887ec57 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 Nov 2021 16:45:18 +0900 Subject: [PATCH 122/327] ASoC: soc-component: add snd_soc_pcm_component_delay() Current soc-pcm.c :: soc_pcm_pointer() is assuming that component driver might update runtime->delay silently in snd_soc_pcm_component_pointer() (= A). static snd_pcm_uframes_t soc_pcm_pointer(...) { ... /* clearing the previous total delay */ => runtime->delay = 0; (A) offset = snd_soc_pcm_component_pointer(substream); /* base delay if assigned in pointer callback */ => delay = runtime->delay; ... } 1) The behavior that ".pointer callback secretly updates runtime->delay" is strange and confusable. 2) Current snd_soc_pcm_component_pointer() uses 1st found component's .pointer callback only, thus it is no problem for now. But runtime->delay might be overwrote if it adjusted to multiple components in the future. 3) Component delay is updated at .pointer callback timing (secretly). But some components which doesn't have .pointer callback might want to increase runtime->delay for some reasons. We already have .delay function for DAI, but not have for Component. This patch adds new snd_soc_pcm_component_delay() for it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/874k8cy25t.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 4 ++++ sound/soc/soc-component.c | 28 ++++++++++++++++++++++++++++ sound/soc/soc-pcm.c | 2 ++ 3 files changed, 34 insertions(+) diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index a4317144ab627..a52080407b98c 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -148,6 +148,8 @@ struct snd_soc_component_driver { struct vm_area_struct *vma); int (*ack)(struct snd_soc_component *component, struct snd_pcm_substream *substream); + snd_pcm_sframes_t (*delay)(struct snd_soc_component *component, + struct snd_pcm_substream *substream); const struct snd_compress_ops *compress_ops; @@ -505,5 +507,7 @@ int snd_soc_pcm_component_pm_runtime_get(struct snd_soc_pcm_runtime *rtd, void snd_soc_pcm_component_pm_runtime_put(struct snd_soc_pcm_runtime *rtd, void *stream, int rollback); int snd_soc_pcm_component_ack(struct snd_pcm_substream *substream); +void snd_soc_pcm_component_delay(struct snd_pcm_substream *substream, + snd_pcm_sframes_t *cpu_delay, snd_pcm_sframes_t *codec_delay); #endif /* __SOC_COMPONENT_H */ diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index c76ff9c59dfb9..c0664f94990c8 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -932,6 +932,34 @@ int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream) return 0; } +void snd_soc_pcm_component_delay(struct snd_pcm_substream *substream, + snd_pcm_sframes_t *cpu_delay, + snd_pcm_sframes_t *codec_delay) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_component *component; + snd_pcm_sframes_t delay; + int i; + + /* + * We're looking for the delay through the full audio path so it needs to + * be the maximum of the Components doing transmit and the maximum of the + * Components doing receive (ie, all CPUs and all CODECs) rather than + * just the maximum of all Components. + */ + for_each_rtd_components(rtd, i, component) { + if (!component->driver->delay) + continue; + + delay = component->driver->delay(component, substream); + + if (snd_soc_component_is_codec(component)) + *codec_delay = max(*codec_delay, delay); + else + *cpu_delay = max(*cpu_delay, delay); + } +} + int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg) { diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 82fd170e16afa..493d231a2ffdc 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1098,7 +1098,9 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) /* base delay if assigned in pointer callback */ delay = runtime->delay; + /* should be called *after* snd_soc_pcm_component_pointer() */ snd_soc_pcm_dai_delay(substream, &cpu_delay, &codec_delay); + snd_soc_pcm_component_delay(substream, &cpu_delay, &codec_delay); runtime->delay = delay + cpu_delay + codec_delay; From feea640aaf1a5ae9dff6e33931e680542432e8dd Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 Nov 2021 16:45:23 +0900 Subject: [PATCH 123/327] ASoC: amd: acp-pcm-dma: add .delay support Now ALSA SoC supports .delay for component. This patch uses it, and not update runtime->delay on .pointer directly / secretly. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/8735nwy25o.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/amd/acp-pcm-dma.c | 15 ++++++++++++++- sound/soc/amd/acp.h | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c index 1f322accd9ead..8fa2e2fde4f1f 100644 --- a/sound/soc/amd/acp-pcm-dma.c +++ b/sound/soc/amd/acp-pcm-dma.c @@ -1003,6 +1003,7 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_soc_component *component, struct snd_pcm_runtime *runtime = substream->runtime; struct audio_substream_data *rtd = runtime->private_data; + struct audio_drv_data *adata = dev_get_drvdata(component->dev); if (!rtd) return -EINVAL; @@ -1023,7 +1024,7 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_soc_component *component, } if (bytescount > 0) { delay = do_div(bytescount, period_bytes); - runtime->delay = bytes_to_frames(runtime, delay); + adata->delay += bytes_to_frames(runtime, delay); } } else { buffersize = frames_to_bytes(runtime, runtime->buffer_size); @@ -1035,6 +1036,17 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_soc_component *component, return bytes_to_frames(runtime, pos); } +static snd_pcm_sframes_t acp_dma_delay(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct audio_drv_data *adata = dev_get_drvdata(component->dev); + snd_pcm_sframes_t delay = adata->delay; + + adata->delay = 0; + + return delay; +} + static int acp_dma_prepare(struct snd_soc_component *component, struct snd_pcm_substream *substream) { @@ -1198,6 +1210,7 @@ static const struct snd_soc_component_driver acp_asoc_platform = { .hw_params = acp_dma_hw_params, .trigger = acp_dma_trigger, .pointer = acp_dma_pointer, + .delay = acp_dma_delay, .prepare = acp_dma_prepare, .pcm_construct = acp_dma_new, }; diff --git a/sound/soc/amd/acp.h b/sound/soc/amd/acp.h index 85529ed7e5f50..db80a73aa5932 100644 --- a/sound/soc/amd/acp.h +++ b/sound/soc/amd/acp.h @@ -151,6 +151,7 @@ struct audio_drv_data { struct snd_pcm_substream *capture_i2sbt_stream; void __iomem *acp_mmio; u32 asic_type; + snd_pcm_sframes_t delay; }; /* From 796b64a72db0b416f0aa1815e87aa28388b4715d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 Nov 2021 16:45:29 +0900 Subject: [PATCH 124/327] ASoC: intel: sst-mfld-platform-pcm: add .delay support Now ALSA SoC supports .delay for component. This patch uses it, and not update runtime->delay on .pointer directly / secretly. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/871r3gy25j.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 5db2f4865bbba..a56dd48c045f3 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -653,10 +653,21 @@ static snd_pcm_uframes_t sst_soc_pointer(struct snd_soc_component *component, dev_err(rtd->dev, "sst: error code = %d\n", ret_val); return ret_val; } - substream->runtime->delay = str_info->pcm_delay; return str_info->buffer_ptr; } +static snd_pcm_sframes_t sst_soc_delay(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct sst_runtime_stream *stream = substream->runtime->private_data; + struct pcm_stream_info *str_info = &stream->stream_info; + + if (sst_get_stream_status(stream) == SST_PLATFORM_INIT) + return 0; + + return str_info->pcm_delay; +} + static int sst_soc_pcm_new(struct snd_soc_component *component, struct snd_soc_pcm_runtime *rtd) { @@ -695,6 +706,7 @@ static const struct snd_soc_component_driver sst_soc_platform_drv = { .open = sst_soc_open, .trigger = sst_soc_trigger, .pointer = sst_soc_pointer, + .delay = sst_soc_delay, .compress_ops = &sst_platform_compress_ops, .pcm_construct = sst_soc_pcm_new, }; From dd894f4caf7df77cf72dc6ae7547900b55d0de42 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 Nov 2021 16:45:34 +0900 Subject: [PATCH 125/327] ASoC: soc-pcm: tidyup soc_pcm_pointer()'s delay update method No driver directly updates runtime->delay in .pointer. This patch cleanups its method. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87zgq4wnkx.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 493d231a2ffdc..3b44121833447 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1080,29 +1080,22 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) /* * soc level wrapper for pointer callback * If cpu_dai, codec_dai, component driver has the delay callback, then - * the runtime->delay will be updated accordingly. + * the runtime->delay will be updated via snd_soc_pcm_component/dai_delay(). */ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_uframes_t offset = 0; - snd_pcm_sframes_t delay = 0; snd_pcm_sframes_t codec_delay = 0; snd_pcm_sframes_t cpu_delay = 0; - /* clearing the previous total delay */ - runtime->delay = 0; - offset = snd_soc_pcm_component_pointer(substream); - /* base delay if assigned in pointer callback */ - delay = runtime->delay; - /* should be called *after* snd_soc_pcm_component_pointer() */ snd_soc_pcm_dai_delay(substream, &cpu_delay, &codec_delay); snd_soc_pcm_component_delay(substream, &cpu_delay, &codec_delay); - runtime->delay = delay + cpu_delay + codec_delay; + runtime->delay = cpu_delay + codec_delay; return offset; } From fd03cf7f5b4726028cfc2ef76e42d0d5c66377aa Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 17 Nov 2021 21:36:45 -0600 Subject: [PATCH 126/327] ASoC: sun8i-codec: Add AIF, ADC, and DAC volume controls This allows changing the volume of each digital input/output independently, and provides the only "master volume" for the DAC. (The ADC also has a gain control on the analog side.) While the hardware supports digital gain up to +72dB, the controls here are limited to +24dB maximum, as any gain above that level makes volume sliders difficult to use, and is extremely likely to cause clipping. Signed-off-by: Samuel Holland Link: https://lore.kernel.org/r/20211118033645.43524-1-samuel@sholland.org Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec.c | 56 +++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 518bfb724a5b2..0bea2162f68d9 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -21,6 +21,7 @@ #include #include #include +#include #define SUN8I_SYSCLK_CTL 0x00c #define SUN8I_SYSCLK_CTL_AIF1CLK_ENA 11 @@ -72,6 +73,12 @@ #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR 10 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR 9 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL 8 +#define SUN8I_AIF1_VOL_CTRL1 0x050 +#define SUN8I_AIF1_VOL_CTRL1_AD0L_VOL 8 +#define SUN8I_AIF1_VOL_CTRL1_AD0R_VOL 0 +#define SUN8I_AIF1_VOL_CTRL3 0x058 +#define SUN8I_AIF1_VOL_CTRL3_DA0L_VOL 8 +#define SUN8I_AIF1_VOL_CTRL3_DA0R_VOL 0 #define SUN8I_AIF2_ADCDAT_CTRL 0x084 #define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_ENA 15 #define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_ENA 14 @@ -91,6 +98,12 @@ #define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA1R 10 #define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF2DACL 9 #define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_ADCR 8 +#define SUN8I_AIF2_VOL_CTRL1 0x090 +#define SUN8I_AIF2_VOL_CTRL1_ADCL_VOL 8 +#define SUN8I_AIF2_VOL_CTRL1_ADCR_VOL 0 +#define SUN8I_AIF2_VOL_CTRL2 0x098 +#define SUN8I_AIF2_VOL_CTRL2_DACL_VOL 8 +#define SUN8I_AIF2_VOL_CTRL2_DACR_VOL 0 #define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF1 (0x0 << 0) #define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF2 (0x1 << 0) #define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF1CLK (0x2 << 0) @@ -102,8 +115,14 @@ #define SUN8I_ADC_DIG_CTRL_ENAD 15 #define SUN8I_ADC_DIG_CTRL_ADOUT_DTS 2 #define SUN8I_ADC_DIG_CTRL_ADOUT_DLY 1 +#define SUN8I_ADC_VOL_CTRL 0x104 +#define SUN8I_ADC_VOL_CTRL_ADCL_VOL 8 +#define SUN8I_ADC_VOL_CTRL_ADCR_VOL 0 #define SUN8I_DAC_DIG_CTRL 0x120 #define SUN8I_DAC_DIG_CTRL_ENDA 15 +#define SUN8I_DAC_VOL_CTRL 0x124 +#define SUN8I_DAC_VOL_CTRL_DACL_VOL 8 +#define SUN8I_DAC_VOL_CTRL_DACR_VOL 0 #define SUN8I_DAC_MXR_SRC 0x130 #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L 15 #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L 14 @@ -696,6 +715,41 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = { }, }; +static const DECLARE_TLV_DB_SCALE(sun8i_codec_vol_scale, -12000, 75, 1); + +static const struct snd_kcontrol_new sun8i_codec_controls[] = { + SOC_DOUBLE_TLV("AIF1 AD0 Capture Volume", + SUN8I_AIF1_VOL_CTRL1, + SUN8I_AIF1_VOL_CTRL1_AD0L_VOL, + SUN8I_AIF1_VOL_CTRL1_AD0R_VOL, + 0xc0, 0, sun8i_codec_vol_scale), + SOC_DOUBLE_TLV("AIF1 DA0 Playback Volume", + SUN8I_AIF1_VOL_CTRL3, + SUN8I_AIF1_VOL_CTRL3_DA0L_VOL, + SUN8I_AIF1_VOL_CTRL3_DA0R_VOL, + 0xc0, 0, sun8i_codec_vol_scale), + SOC_DOUBLE_TLV("AIF2 ADC Capture Volume", + SUN8I_AIF2_VOL_CTRL1, + SUN8I_AIF2_VOL_CTRL1_ADCL_VOL, + SUN8I_AIF2_VOL_CTRL1_ADCR_VOL, + 0xc0, 0, sun8i_codec_vol_scale), + SOC_DOUBLE_TLV("AIF2 DAC Playback Volume", + SUN8I_AIF2_VOL_CTRL2, + SUN8I_AIF2_VOL_CTRL2_DACL_VOL, + SUN8I_AIF2_VOL_CTRL2_DACR_VOL, + 0xc0, 0, sun8i_codec_vol_scale), + SOC_DOUBLE_TLV("ADC Capture Volume", + SUN8I_ADC_VOL_CTRL, + SUN8I_ADC_VOL_CTRL_ADCL_VOL, + SUN8I_ADC_VOL_CTRL_ADCR_VOL, + 0xc0, 0, sun8i_codec_vol_scale), + SOC_DOUBLE_TLV("DAC Playback Volume", + SUN8I_DAC_VOL_CTRL, + SUN8I_DAC_VOL_CTRL_DACL_VOL, + SUN8I_DAC_VOL_CTRL_DACR_VOL, + 0xc0, 0, sun8i_codec_vol_scale), +}; + static int sun8i_codec_aif_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -1215,6 +1269,8 @@ static int sun8i_codec_component_probe(struct snd_soc_component *component) } static const struct snd_soc_component_driver sun8i_soc_component = { + .controls = sun8i_codec_controls, + .num_controls = ARRAY_SIZE(sun8i_codec_controls), .dapm_widgets = sun8i_codec_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(sun8i_codec_dapm_widgets), .dapm_routes = sun8i_codec_dapm_routes, From 425c5fce8a03c9da70a4c763cd7db22fbb422dcf Mon Sep 17 00:00:00 2001 From: lvzhaoxiong Date: Tue, 23 Nov 2021 10:43:29 +0800 Subject: [PATCH 127/327] ASoC: qcom: Add support for ALC5682I-VS codec Qcom machine driver adds rt5682s support in this patch. Card name can be specified from dts by model property, and driver makes use of the name to distinguish which headset codec is on the board. Signed-off-by: lvzhaoxiong Link: https://lore.kernel.org/r/20211123024329.21998-1-lvzhaoxiong@huaqin.corp-partner.google.com Signed-off-by: Mark Brown --- sound/soc/qcom/Kconfig | 1 + sound/soc/qcom/sc7180.c | 24 +++++++++++++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index b2173847dc476..cf3e151bb6350 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -169,6 +169,7 @@ config SND_SOC_SC7180 select SND_SOC_LPASS_SC7180 select SND_SOC_MAX98357A select SND_SOC_RT5682_I2C + select SND_SOC_RT5682S select SND_SOC_ADAU7002 help To add support for audio on Qualcomm Technologies Inc. diff --git a/sound/soc/qcom/sc7180.c b/sound/soc/qcom/sc7180.c index 768566bb57a5f..2fff764a00a72 100644 --- a/sound/soc/qcom/sc7180.c +++ b/sound/soc/qcom/sc7180.c @@ -17,6 +17,7 @@ #include #include "../codecs/rt5682.h" +#include "../codecs/rt5682s.h" #include "common.h" #include "lpass.h" @@ -128,7 +129,21 @@ static int sc7180_snd_startup(struct snd_pcm_substream *substream) struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card); struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - int ret; + int pll_id, pll_source, pll_in, pll_out, clk_id, ret; + + if (!(strcmp(card->name, "sc7180-rt5682-max98357a-1mic"))) { + pll_source = RT5682_PLL1_S_MCLK; + pll_id = 0; + clk_id = RT5682_SCLK_S_PLL1; + pll_out = RT5682_PLL1_FREQ; + pll_in = DEFAULT_MCLK_RATE; + } else if (!(strcmp(card->name, "sc7180-rt5682s-max98357a-1mic"))) { + pll_source = RT5682S_PLL_S_MCLK; + pll_id = RT5682S_PLL2; + clk_id = RT5682S_SCLK_S_PLL2; + pll_out = RT5682_PLL1_FREQ; + pll_in = DEFAULT_MCLK_RATE; + } switch (cpu_dai->id) { case MI2S_PRIMARY: @@ -145,16 +160,15 @@ static int sc7180_snd_startup(struct snd_pcm_substream *substream) SND_SOC_DAIFMT_I2S); /* Configure PLL1 for codec */ - ret = snd_soc_dai_set_pll(codec_dai, 0, RT5682_PLL1_S_MCLK, - DEFAULT_MCLK_RATE, RT5682_PLL1_FREQ); + ret = snd_soc_dai_set_pll(codec_dai, pll_id, pll_source, + pll_in, pll_out); if (ret) { dev_err(rtd->dev, "can't set codec pll: %d\n", ret); return ret; } /* Configure sysclk for codec */ - ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, - RT5682_PLL1_FREQ, + ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, pll_out, SND_SOC_CLOCK_IN); if (ret) dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", From 679de7b64f9622eff8f74357fc3ee071629d25b3 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Wed, 17 Nov 2021 20:44:58 +0100 Subject: [PATCH 128/327] ASoC: sunxi: sun4i-spdif: Implement IEC958 control SPDIF core is capable of sending custom status. Implement IEC958 control handling. Signed-off-by: Jernej Skrabec Link: https://lore.kernel.org/r/20211117194458.2249643-1-jernej.skrabec@gmail.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-spdif.c | 115 ++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c index a10949bf0ca1e..17090f43150e0 100644 --- a/sound/soc/sunxi/sun4i-spdif.c +++ b/sound/soc/sunxi/sun4i-spdif.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include #include @@ -186,6 +188,7 @@ struct sun4i_spdif_dev { struct regmap *regmap; struct snd_dmaengine_dai_dma_data dma_params_tx; const struct sun4i_spdif_quirks *quirks; + spinlock_t lock; }; static void sun4i_spdif_configure(struct sun4i_spdif_dev *host) @@ -385,11 +388,122 @@ static int sun4i_spdif_trigger(struct snd_pcm_substream *substream, int cmd, return ret; } +static int sun4i_spdif_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; + uinfo->count = 1; + + return 0; +} + +static int sun4i_spdif_get_status_mask(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 *status = ucontrol->value.iec958.status; + + status[0] = 0xff; + status[1] = 0xff; + status[2] = 0xff; + status[3] = 0xff; + status[4] = 0xff; + status[5] = 0x03; + + return 0; +} + +static int sun4i_spdif_get_status(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(cpu_dai); + u8 *status = ucontrol->value.iec958.status; + unsigned long flags; + unsigned int reg; + + spin_lock_irqsave(&host->lock, flags); + + regmap_read(host->regmap, SUN4I_SPDIF_TXCHSTA0, ®); + + status[0] = reg & 0xff; + status[1] = (reg >> 8) & 0xff; + status[2] = (reg >> 16) & 0xff; + status[3] = (reg >> 24) & 0xff; + + regmap_read(host->regmap, SUN4I_SPDIF_TXCHSTA1, ®); + + status[4] = reg & 0xff; + status[5] = (reg >> 8) & 0x3; + + spin_unlock_irqrestore(&host->lock, flags); + + return 0; +} + +static int sun4i_spdif_set_status(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(cpu_dai); + u8 *status = ucontrol->value.iec958.status; + unsigned long flags; + unsigned int reg; + bool chg0, chg1; + + spin_lock_irqsave(&host->lock, flags); + + reg = (u32)status[3] << 24; + reg |= (u32)status[2] << 16; + reg |= (u32)status[1] << 8; + reg |= (u32)status[0]; + + regmap_update_bits_check(host->regmap, SUN4I_SPDIF_TXCHSTA0, + GENMASK(31,0), reg, &chg0); + + reg = (u32)status[5] << 8; + reg |= (u32)status[4]; + + regmap_update_bits_check(host->regmap, SUN4I_SPDIF_TXCHSTA1, + GENMASK(9,0), reg, &chg1); + + reg = SUN4I_SPDIF_TXCFG_CHSTMODE; + if (status[0] & IEC958_AES0_NONAUDIO) + reg |= SUN4I_SPDIF_TXCFG_NONAUDIO; + + regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG, + SUN4I_SPDIF_TXCFG_CHSTMODE | + SUN4I_SPDIF_TXCFG_NONAUDIO, reg); + + spin_unlock_irqrestore(&host->lock, flags); + + return chg0 || chg1; +} + +static struct snd_kcontrol_new sun4i_spdif_controls[] = { + { + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK), + .info = sun4i_spdif_info, + .get = sun4i_spdif_get_status_mask + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), + .info = sun4i_spdif_info, + .get = sun4i_spdif_get_status, + .put = sun4i_spdif_set_status + } +}; + static int sun4i_spdif_soc_dai_probe(struct snd_soc_dai *dai) { struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(dai); snd_soc_dai_init_dma_data(dai, &host->dma_params_tx, NULL); + snd_soc_add_dai_controls(dai, sun4i_spdif_controls, + ARRAY_SIZE(sun4i_spdif_controls)); + return 0; } @@ -512,6 +626,7 @@ static int sun4i_spdif_probe(struct platform_device *pdev) return -ENOMEM; host->pdev = pdev; + spin_lock_init(&host->lock); /* Initialize this copy of the CPU DAI driver structure */ memcpy(&host->cpu_dai_drv, &sun4i_spdif_dai, sizeof(sun4i_spdif_dai)); From 8752d9a82fd065ef60c9a0e0e8ec820327509382 Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Sat, 27 Nov 2021 10:31:47 +0100 Subject: [PATCH 129/327] ASoC: mediatek: mt8195: Constify static snd_soc_ops These are only assigned to the ops field in the snd_soc_dai_link which is a pointer to const struct snd_soc_ops. Make them const to allow the compiler to put them in read-only memory. Signed-off-by: Rikard Falkeborn Link: https://lore.kernel.org/r/20211127093147.17368-1-rikard.falkeborn@gmail.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c | 2 +- sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c index e103102d7ef6d..9e6b54e19c232 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c @@ -421,7 +421,7 @@ static int mt8195_dptx_hw_params(struct snd_pcm_substream *substream, SND_SOC_CLOCK_OUT); } -static struct snd_soc_ops mt8195_dptx_ops = { +static const struct snd_soc_ops mt8195_dptx_ops = { .hw_params = mt8195_dptx_hw_params, }; diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c index 95abaadcd8420..e22e5fd409846 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c @@ -391,7 +391,7 @@ static int mt8195_dptx_hw_params(struct snd_pcm_substream *substream, SND_SOC_CLOCK_OUT); } -static struct snd_soc_ops mt8195_dptx_ops = { +static const struct snd_soc_ops mt8195_dptx_ops = { .hw_params = mt8195_dptx_hw_params, }; From 11918cdcffb127b6b35fe5c438e2ca8aa78249d0 Mon Sep 17 00:00:00 2001 From: Chris Down Date: Sun, 28 Nov 2021 14:31:46 +0000 Subject: [PATCH 130/327] ASoC: Intel: hda_dsp_common: don't multiline PCM topology warning On my T14s Gen2 I saw the following: [ 16.057258] skl_hda_dsp_generic skl_hda_dsp_generic: hda_dsp_hdmi_build_controls: no PCM in topology for HDMI converter 3 [ 16.057261] skl_hda_dsp_generic skl_hda_dsp_generic: hda_dsp_hdmi_build_controls: no PCM in topology for HDMI converter 4 [ 16.057263] skl_hda_dsp_generic skl_hda_dsp_generic: hda_dsp_hdmi_build_controls: no PCM in topology for HDMI converter 5 [...and so on.] It looks like the double newline is a mistake, so remove one. Signed-off-by: Chris Down Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/YaOS0sBueAfApwOx@chrisdown.name Signed-off-by: Mark Brown --- sound/soc/intel/boards/hda_dsp_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/hda_dsp_common.c b/sound/soc/intel/boards/hda_dsp_common.c index efdc4bc4bb1f9..5c31ddc0884ab 100644 --- a/sound/soc/intel/boards/hda_dsp_common.c +++ b/sound/soc/intel/boards/hda_dsp_common.c @@ -68,7 +68,7 @@ int hda_dsp_hdmi_build_controls(struct snd_soc_card *card, hpcm->pcm = NULL; hpcm->device = SNDRV_PCM_INVALID_DEVICE; dev_warn(card->dev, - "%s: no PCM in topology for HDMI converter %d\n\n", + "%s: no PCM in topology for HDMI converter %d\n", __func__, i); } i++; From 10b155fd413d31c89057986d0fc3d4ceef8e0e9f Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Sat, 27 Nov 2021 10:19:54 +0100 Subject: [PATCH 131/327] ASoC: intel: boards: bytcht*: Constify static snd_soc_ops These are only assigned to the ops fields in the snd_soc_dai_link struct which is a pointer to const struct snd_soc_ops. Make them const to allow the compiler to put them in read-only memory. Signed-off-by: Rikard Falkeborn Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20211127091954.12075-1-rikard.falkeborn@gmail.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_cx2072x.c | 2 +- sound/soc/intel/boards/bytcht_nocodec.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_cx2072x.c b/sound/soc/intel/boards/bytcht_cx2072x.c index 0a736308052a9..ffd497a5b5a5f 100644 --- a/sound/soc/intel/boards/bytcht_cx2072x.c +++ b/sound/soc/intel/boards/bytcht_cx2072x.c @@ -147,7 +147,7 @@ static int byt_cht_cx2072x_aif1_startup(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_RATE, 48000); } -static struct snd_soc_ops byt_cht_cx2072x_aif1_ops = { +static const struct snd_soc_ops byt_cht_cx2072x_aif1_ops = { .startup = byt_cht_cx2072x_aif1_startup, }; diff --git a/sound/soc/intel/boards/bytcht_nocodec.c b/sound/soc/intel/boards/bytcht_nocodec.c index 67b3c4e978640..115c2bcaabd4f 100644 --- a/sound/soc/intel/boards/bytcht_nocodec.c +++ b/sound/soc/intel/boards/bytcht_nocodec.c @@ -93,7 +93,7 @@ static int aif1_startup(struct snd_pcm_substream *substream) &constraints_48000); } -static struct snd_soc_ops aif1_ops = { +static const struct snd_soc_ops aif1_ops = { .startup = aif1_startup, }; From 043c0a6278ca443b1835726239dc2814c1313a9e Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 30 Nov 2021 10:28:42 +0000 Subject: [PATCH 132/327] firmware: cs_dsp: Move lockdep asserts to avoid potential null pointer Move the lockdep asserts until after the ctl pointer has been checked for NULL, to avoid potentially NULL pointer dereferences. Fixes: fb2f364fb5b9 ("firmware: cs_dsp: Add lockdep asserts to interface functions") Reported-by: kernel test robot Reported-by: Dan Carpenter Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20211130102842.26410-1-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/firmware/cirrus/cs_dsp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c index 3814cbba0a544..5af8171d6cedf 100644 --- a/drivers/firmware/cirrus/cs_dsp.c +++ b/drivers/firmware/cirrus/cs_dsp.c @@ -759,11 +759,11 @@ int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl, { int ret = 0; - lockdep_assert_held(&ctl->dsp->pwr_lock); - if (!ctl) return -ENOENT; + lockdep_assert_held(&ctl->dsp->pwr_lock); + if (len + off * sizeof(u32) > ctl->len) return -EINVAL; @@ -827,11 +827,11 @@ int cs_dsp_coeff_read_ctrl(struct cs_dsp_coeff_ctl *ctl, { int ret = 0; - lockdep_assert_held(&ctl->dsp->pwr_lock); - if (!ctl) return -ENOENT; + lockdep_assert_held(&ctl->dsp->pwr_lock); + if (len + off * sizeof(u32) > ctl->len) return -EINVAL; From 91745b034dca6044407b559fe28dd1cf7efccc29 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 29 Nov 2021 22:42:36 +0000 Subject: [PATCH 133/327] ASoC: mediatek: mt8195: make several arrays static const Don't populate various arrays on the stack but instead make them static const. Also makes the object code smaller by a few hundred bytes. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20211129224236.506883-1-colin.i.king@gmail.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8195/mt8195-afe-clk.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/mediatek/mt8195/mt8195-afe-clk.c b/sound/soc/mediatek/mt8195/mt8195-afe-clk.c index 8420b2c71332a..c2543f4cffb72 100644 --- a/sound/soc/mediatek/mt8195/mt8195-afe-clk.c +++ b/sound/soc/mediatek/mt8195/mt8195-afe-clk.c @@ -326,7 +326,7 @@ int mt8195_afe_enable_reg_rw_clk(struct mtk_base_afe *afe) { struct mt8195_afe_private *afe_priv = afe->platform_priv; int i; - unsigned int clk_array[] = { + static const unsigned int clk_array[] = { MT8195_CLK_SCP_ADSP_AUDIODSP, /* bus clock for infra */ MT8195_CLK_TOP_AUDIO_H_SEL, /* clock for ADSP bus */ MT8195_CLK_TOP_AUDIO_LOCAL_BUS_SEL, /* bus clock for DRAM access */ @@ -347,7 +347,7 @@ int mt8195_afe_disable_reg_rw_clk(struct mtk_base_afe *afe) { struct mt8195_afe_private *afe_priv = afe->platform_priv; int i; - unsigned int clk_array[] = { + static const unsigned int clk_array[] = { MT8195_CLK_AUD_A1SYS, MT8195_CLK_AUD_A1SYS_HP, MT8195_CLK_AUD_AFE, @@ -380,11 +380,11 @@ static int mt8195_afe_enable_timing_sys(struct mtk_base_afe *afe) { struct mt8195_afe_private *afe_priv = afe->platform_priv; int i; - unsigned int clk_array[] = { + static const unsigned int clk_array[] = { MT8195_CLK_AUD_A1SYS, MT8195_CLK_AUD_A2SYS, }; - unsigned int cg_array[] = { + static const unsigned int cg_array[] = { MT8195_TOP_CG_A1SYS_TIMING, MT8195_TOP_CG_A2SYS_TIMING, MT8195_TOP_CG_26M_TIMING, @@ -403,11 +403,11 @@ static int mt8195_afe_disable_timing_sys(struct mtk_base_afe *afe) { struct mt8195_afe_private *afe_priv = afe->platform_priv; int i; - unsigned int clk_array[] = { + static const unsigned int clk_array[] = { MT8195_CLK_AUD_A2SYS, MT8195_CLK_AUD_A1SYS, }; - unsigned int cg_array[] = { + static const unsigned int cg_array[] = { MT8195_TOP_CG_26M_TIMING, MT8195_TOP_CG_A2SYS_TIMING, MT8195_TOP_CG_A1SYS_TIMING, From f316c9d9ba8ea08d6994bc5ba8fa276eab186208 Mon Sep 17 00:00:00 2001 From: Mac Chiang Date: Wed, 24 Nov 2021 22:04:53 -0500 Subject: [PATCH 134/327] ASoC: Intel: boards: add max98390 2/4 speakers support support 2 hw boards. 1. SSP2 connects max98390, 2 speakers. 2. SSP1 connects max98390, 2/4 speakers. 2 or 4 speakers playback add echo reference capture add bt offload support add DMI_OEM_STRING for board variants add ALC5682I-VS support Signed-off-by: Mark Hsieh Signed-off-by: Mac Chiang Signed-off-by: Kieth Tzeng Signed-off-by: Brent Lu Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20211125030453.4382-1-mac.chiang@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 1 + sound/soc/intel/boards/sof_maxim_common.c | 180 ++++++++++++++++++ sound/soc/intel/boards/sof_maxim_common.h | 16 ++ sound/soc/intel/boards/sof_rt5682.c | 72 +++++++ .../intel/common/soc-acpi-intel-adl-match.c | 13 ++ sound/soc/sof/sof-pci-dev.c | 9 + 6 files changed, 291 insertions(+) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 849445fcc05dc..34ccefcc30c7a 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -467,6 +467,7 @@ config SND_SOC_INTEL_SOF_RT5682_MACH (MFD_INTEL_LPSS || COMPILE_TEST)) ||\ (SND_SOC_SOF_BAYTRAIL && (X86_INTEL_LPSS || COMPILE_TEST)) select SND_SOC_MAX98373_I2C + select SND_SOC_MAX98390 select SND_SOC_RT1011 select SND_SOC_RT1015 select SND_SOC_RT1015P diff --git a/sound/soc/intel/boards/sof_maxim_common.c b/sound/soc/intel/boards/sof_maxim_common.c index e66dfe6669153..9171d9cd179ea 100644 --- a/sound/soc/intel/boards/sof_maxim_common.c +++ b/sound/soc/intel/boards/sof_maxim_common.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -133,6 +134,185 @@ void max_98373_set_codec_conf(struct snd_soc_card *card) } EXPORT_SYMBOL_NS(max_98373_set_codec_conf, SND_SOC_INTEL_SOF_MAXIM_COMMON); +/* + * Maxim MAX98390 + */ +const struct snd_soc_dapm_route max_98390_dapm_routes[] = { + /* speaker */ + { "Left Spk", NULL, "Left BE_OUT" }, + { "Right Spk", NULL, "Right BE_OUT" }, +}; + +static const struct snd_kcontrol_new max_98390_tt_kcontrols[] = { + SOC_DAPM_PIN_SWITCH("TL Spk"), + SOC_DAPM_PIN_SWITCH("TR Spk"), +}; + +static const struct snd_soc_dapm_widget max_98390_tt_dapm_widgets[] = { + SND_SOC_DAPM_SPK("TL Spk", NULL), + SND_SOC_DAPM_SPK("TR Spk", NULL), +}; + +const struct snd_soc_dapm_route max_98390_tt_dapm_routes[] = { + /* Tweeter speaker */ + { "TL Spk", NULL, "Tweeter Left BE_OUT" }, + { "TR Spk", NULL, "Tweeter Right BE_OUT" }, +}; + +static struct snd_soc_codec_conf max_98390_codec_conf[] = { + { + .dlc = COMP_CODEC_CONF(MAX_98390_DEV0_NAME), + .name_prefix = "Right", + }, + { + .dlc = COMP_CODEC_CONF(MAX_98390_DEV1_NAME), + .name_prefix = "Left", + }, +}; + +static struct snd_soc_codec_conf max_98390_4spk_codec_conf[] = { + { + .dlc = COMP_CODEC_CONF(MAX_98390_DEV0_NAME), + .name_prefix = "Right", + }, + { + .dlc = COMP_CODEC_CONF(MAX_98390_DEV1_NAME), + .name_prefix = "Left", + }, + { + .dlc = COMP_CODEC_CONF(MAX_98390_DEV2_NAME), + .name_prefix = "Tweeter Right", + }, + { + .dlc = COMP_CODEC_CONF(MAX_98390_DEV3_NAME), + .name_prefix = "Tweeter Left", + }, +}; + +struct snd_soc_dai_link_component max_98390_components[] = { + { + .name = MAX_98390_DEV0_NAME, + .dai_name = MAX_98390_CODEC_DAI, + }, + { + .name = MAX_98390_DEV1_NAME, + .dai_name = MAX_98390_CODEC_DAI, + }, +}; +EXPORT_SYMBOL_NS(max_98390_components, SND_SOC_INTEL_SOF_MAXIM_COMMON); + +struct snd_soc_dai_link_component max_98390_4spk_components[] = { + { + .name = MAX_98390_DEV0_NAME, + .dai_name = MAX_98390_CODEC_DAI, + }, + { + .name = MAX_98390_DEV1_NAME, + .dai_name = MAX_98390_CODEC_DAI, + }, + { + .name = MAX_98390_DEV2_NAME, + .dai_name = MAX_98390_CODEC_DAI, + }, + { + .name = MAX_98390_DEV3_NAME, + .dai_name = MAX_98390_CODEC_DAI, + }, +}; +EXPORT_SYMBOL_NS(max_98390_4spk_components, SND_SOC_INTEL_SOF_MAXIM_COMMON); + +static int max_98390_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai; + int i; + + for_each_rtd_codec_dais(rtd, i, codec_dai) { + if (i >= ARRAY_SIZE(max_98390_4spk_components)) { + dev_err(codec_dai->dev, "invalid codec index %d\n", i); + return -ENODEV; + } + + if (!strcmp(codec_dai->component->name, MAX_98390_DEV0_NAME)) { + /* DEV0 tdm slot configuration Right */ + snd_soc_dai_set_tdm_slot(codec_dai, 0x01, 3, 4, 32); + } + if (!strcmp(codec_dai->component->name, MAX_98390_DEV1_NAME)) { + /* DEV1 tdm slot configuration Left */ + snd_soc_dai_set_tdm_slot(codec_dai, 0x02, 3, 4, 32); + } + + if (!strcmp(codec_dai->component->name, MAX_98390_DEV2_NAME)) { + /* DEVi2 tdm slot configuration Tweeter Right */ + snd_soc_dai_set_tdm_slot(codec_dai, 0x04, 3, 4, 32); + } + if (!strcmp(codec_dai->component->name, MAX_98390_DEV3_NAME)) { + /* DEV3 tdm slot configuration Tweeter Left */ + snd_soc_dai_set_tdm_slot(codec_dai, 0x08, 3, 4, 32); + } + } + return 0; +} + +int max_98390_spk_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + /* add regular speakers dapm route */ + ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_dapm_routes, + ARRAY_SIZE(max_98390_dapm_routes)); + if (ret) { + dev_err(rtd->dev, "unable to add Left/Right Speaker dapm, ret %d\n", ret); + return ret; + } + + /* add widgets/controls/dapm for tweeter speakers */ + if (acpi_dev_present("MX98390", "3", -1)) { + ret = snd_soc_dapm_new_controls(&card->dapm, max_98390_tt_dapm_widgets, + ARRAY_SIZE(max_98390_tt_dapm_widgets)); + + if (ret) { + dev_err(rtd->dev, "unable to add tweeter dapm controls, ret %d\n", ret); + /* Don't need to add routes if widget addition failed */ + return ret; + } + + ret = snd_soc_add_card_controls(card, max_98390_tt_kcontrols, + ARRAY_SIZE(max_98390_tt_kcontrols)); + if (ret) { + dev_err(rtd->dev, "unable to add tweeter card controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_tt_dapm_routes, + ARRAY_SIZE(max_98390_tt_dapm_routes)); + if (ret) + dev_err(rtd->dev, + "unable to add Tweeter Left/Right Speaker dapm, ret %d\n", ret); + } + return ret; +} +EXPORT_SYMBOL_NS(max_98390_spk_codec_init, SND_SOC_INTEL_SOF_MAXIM_COMMON); + +const struct snd_soc_ops max_98390_ops = { + .hw_params = max_98390_hw_params, +}; +EXPORT_SYMBOL_NS(max_98390_ops, SND_SOC_INTEL_SOF_MAXIM_COMMON); + +void max_98390_set_codec_conf(struct snd_soc_card *card, int ch) +{ + if (ch == ARRAY_SIZE(max_98390_4spk_codec_conf)) { + card->codec_conf = max_98390_4spk_codec_conf; + card->num_configs = ARRAY_SIZE(max_98390_4spk_codec_conf); + } else { + card->codec_conf = max_98390_codec_conf; + card->num_configs = ARRAY_SIZE(max_98390_codec_conf); + } +} +EXPORT_SYMBOL_NS(max_98390_set_codec_conf, SND_SOC_INTEL_SOF_MAXIM_COMMON); + /* * Maxim MAX98357A/MAX98360A */ diff --git a/sound/soc/intel/boards/sof_maxim_common.h b/sound/soc/intel/boards/sof_maxim_common.h index 3ff5e8fec4de4..7a8c53049e4d5 100644 --- a/sound/soc/intel/boards/sof_maxim_common.h +++ b/sound/soc/intel/boards/sof_maxim_common.h @@ -24,6 +24,22 @@ int max_98373_spk_codec_init(struct snd_soc_pcm_runtime *rtd); void max_98373_set_codec_conf(struct snd_soc_card *card); int max_98373_trigger(struct snd_pcm_substream *substream, int cmd); +/* + * Maxim MAX98390 + */ +#define MAX_98390_CODEC_DAI "max98390-aif1" +#define MAX_98390_DEV0_NAME "i2c-MX98390:00" +#define MAX_98390_DEV1_NAME "i2c-MX98390:01" +#define MAX_98390_DEV2_NAME "i2c-MX98390:02" +#define MAX_98390_DEV3_NAME "i2c-MX98390:03" + +extern struct snd_soc_dai_link_component max_98390_components[2]; +extern struct snd_soc_dai_link_component max_98390_4spk_components[4]; +extern const struct snd_soc_ops max_98390_ops; + +void max_98390_set_codec_conf(struct snd_soc_card *card, int ch); +int max_98390_spk_codec_init(struct snd_soc_pcm_runtime *rtd); + /* * Maxim MAX98357A/MAX98360A */ diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index c41f386b41388..6cadb5fb72e0c 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -59,6 +59,9 @@ (((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK) #define SOF_SSP_BT_OFFLOAD_PRESENT BIT(22) #define SOF_RT5682S_HEADPHONE_CODEC_PRESENT BIT(23) +#define SOF_MAX98390_SPEAKER_AMP_PRESENT BIT(24) +#define SOF_MAX98390_TWEETER_SPEAKER_PRESENT BIT(25) + /* Default: MCLK on, MCLK 19.2M, SSP0 */ static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN | @@ -179,6 +182,36 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { SOF_RT5682_SSP_AMP(2) | SOF_RT5682_NUM_HDMIDEV(4)), }, + { + .callback = sof_rt5682_quirk_cb, + .matches = { + DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"), + DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98390_ALC5682I_I2S"), + }, + .driver_data = (void *)(SOF_RT5682_MCLK_EN | + SOF_RT5682_SSP_CODEC(0) | + SOF_SPEAKER_AMP_PRESENT | + SOF_MAX98390_SPEAKER_AMP_PRESENT | + SOF_RT5682_SSP_AMP(2) | + SOF_RT5682_NUM_HDMIDEV(4)), + }, + { + .callback = sof_rt5682_quirk_cb, + .matches = { + DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"), + DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98390_ALC5682I_I2S_4SPK"), + }, + .driver_data = (void *)(SOF_RT5682_MCLK_EN | + SOF_RT5682_SSP_CODEC(0) | + SOF_SPEAKER_AMP_PRESENT | + SOF_MAX98390_SPEAKER_AMP_PRESENT | + SOF_MAX98390_TWEETER_SPEAKER_PRESENT | + SOF_RT5682_SSP_AMP(1) | + SOF_RT5682_NUM_HDMIDEV(4) | + SOF_BT_OFFLOAD_SSP(2) | + SOF_SSP_BT_OFFLOAD_PRESENT), + + }, {} }; @@ -486,6 +519,7 @@ static int sof_card_late_probe(struct snd_soc_card *card) if (err < 0) return err; } + return hdac_hdmi_jack_port_init(component, &card->dapm); } @@ -784,6 +818,20 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, } else if (sof_rt5682_quirk & SOF_RT1011_SPEAKER_AMP_PRESENT) { sof_rt1011_dai_link(&links[id]); + } else if (sof_rt5682_quirk & + SOF_MAX98390_SPEAKER_AMP_PRESENT) { + if (sof_rt5682_quirk & + SOF_MAX98390_TWEETER_SPEAKER_PRESENT) { + links[id].codecs = max_98390_4spk_components; + links[id].num_codecs = ARRAY_SIZE(max_98390_4spk_components); + } else { + links[id].codecs = max_98390_components; + links[id].num_codecs = ARRAY_SIZE(max_98390_components); + } + links[id].init = max_98390_spk_codec_init; + links[id].ops = &max_98390_ops; + links[id].dpcm_capture = 1; + } else { max_98357a_dai_link(&links[id]); } @@ -868,6 +916,10 @@ static int sof_audio_probe(struct platform_device *pdev) if (acpi_dev_present("RTL5682", NULL, -1)) sof_rt5682_quirk |= SOF_RT5682S_HEADPHONE_CODEC_PRESENT; + /* Detect the headset codec variant to support machines in DMI quirk */ + if (acpi_dev_present("RTL5682", NULL, -1)) + sof_rt5682_quirk |= SOF_RT5682S_HEADPHONE_CODEC_PRESENT; + if (soc_intel_is_byt() || soc_intel_is_cht()) { is_legacy_cpu = 1; dmic_be_num = 0; @@ -924,6 +976,14 @@ static int sof_audio_probe(struct platform_device *pdev) sof_rt1011_codec_conf(&sof_audio_card_rt5682); else if (sof_rt5682_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT) sof_rt1015p_codec_conf(&sof_audio_card_rt5682); + else if (sof_rt5682_quirk & SOF_MAX98390_SPEAKER_AMP_PRESENT) { + if (sof_rt5682_quirk & SOF_MAX98390_TWEETER_SPEAKER_PRESENT) + max_98390_set_codec_conf(&sof_audio_card_rt5682, + ARRAY_SIZE(max_98390_4spk_components)); + else + max_98390_set_codec_conf(&sof_audio_card_rt5682, + ARRAY_SIZE(max_98390_components)); + } if (sof_rt5682_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) sof_audio_card_rt5682.num_links++; @@ -1050,6 +1110,17 @@ static const struct platform_device_id board_ids[] = { SOF_RT5682_SSP_AMP(2) | SOF_RT5682_NUM_HDMIDEV(4)), }, + { + .name = "adl_max98390_rt5682", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_RT5682_SSP_CODEC(0) | + SOF_SPEAKER_AMP_PRESENT | + SOF_MAX98390_SPEAKER_AMP_PRESENT | + SOF_RT5682_SSP_AMP(1) | + SOF_RT5682_NUM_HDMIDEV(4) | + SOF_BT_OFFLOAD_SSP(2) | + SOF_SSP_BT_OFFLOAD_PRESENT), + }, { .name = "adl_mx98360_rt5682", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | @@ -1080,6 +1151,7 @@ MODULE_DESCRIPTION("SOF Audio Machine driver"); MODULE_AUTHOR("Bard Liao "); MODULE_AUTHOR("Sathya Prakash M R "); MODULE_AUTHOR("Brent Lu "); +MODULE_AUTHOR("Mac Chiang "); MODULE_LICENSE("GPL v2"); MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON); diff --git a/sound/soc/intel/common/soc-acpi-intel-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c index fde310e5724ba..f32bcb2b2e094 100644 --- a/sound/soc/intel/common/soc-acpi-intel-adl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c @@ -379,6 +379,11 @@ static const struct snd_soc_acpi_codecs adl_rt1019p_amp = { .codecs = {"RTL1019"} }; +static const struct snd_soc_acpi_codecs adl_max98390_amp = { + .num_codecs = 1, + .codecs = {"MX98390"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { { .comp_ids = &adl_rt5682_rt5682s_hp, @@ -434,6 +439,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { .sof_fw_filename = "sof-adl.ri", .sof_tplg_filename = "sof-adl-nau8825.tplg", }, + { + .comp_ids = &adl_rt5682_rt5682s_hp, + .drv_name = "adl_max98390_rt5682", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &adl_max98390_amp, + .sof_fw_filename = "sof-adl.ri", + .sof_tplg_filename = "sof-adl-max98390-rt5682.tplg", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_adl_machines); diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index b4bc4f887b43e..20c6ca37dbc44 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -59,6 +59,15 @@ static const struct dmi_system_id sof_tplg_table[] = { }, .driver_data = "sof-adl-rt5682-ssp0-max98373-ssp2.tplg", }, + { + .callback = sof_tplg_cb, + .matches = { + DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"), + DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98390_ALC5682I_I2S"), + }, + .driver_data = "sof-adl-max98390-ssp2-rt5682-ssp0.tplg", + }, + {} }; From 0d242698fa693ab8cb98c11ba7cf7fc8f7242c0b Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Tue, 30 Nov 2021 18:53:25 +0530 Subject: [PATCH 135/327] ASoC: tegra: Add master volume/mute control support The MVC module has a per channel control bit, based on which it decides to apply channel specific volume/mute settings. When per channel control bit is enabled (which is the default HW configuration), all MVC channel volume/mute can be independently controlled. If the control is disabled, channel-0 volume/mute setting is applied by HW to all remaining channels. Thus add support to leverage this HW feature by exposing master controls for volume/mute. With this, now there are per channel and master volume/mute controls. Users need to just use controls which are suitable for their applications. The per channel control enable/disable is mananged in driver and hidden from users, so that they need to just worry about respective volume/mute controls. Signed-off-by: Sameer Pujar Link: https://lore.kernel.org/r/1638278605-28225-1-git-send-email-spujar@nvidia.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra210_mvc.c | 209 ++++++++++++++++++++++++++------- sound/soc/tegra/tegra210_mvc.h | 5 + 2 files changed, 169 insertions(+), 45 deletions(-) diff --git a/sound/soc/tegra/tegra210_mvc.c b/sound/soc/tegra/tegra210_mvc.c index acf59328dcb6d..725385e17d845 100644 --- a/sound/soc/tegra/tegra210_mvc.c +++ b/sound/soc/tegra/tegra210_mvc.c @@ -108,67 +108,152 @@ static void tegra210_mvc_conv_vol(struct tegra210_mvc *mvc, u8 chan, s32 val) } } -static int tegra210_mvc_get_mute(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static u32 tegra210_mvc_get_ctrl_reg(struct snd_kcontrol *kcontrol) { struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt); - u8 mute_mask; u32 val; pm_runtime_get_sync(cmpnt->dev); regmap_read(mvc->regmap, TEGRA210_MVC_CTRL, &val); pm_runtime_put(cmpnt->dev); - mute_mask = (val >> TEGRA210_MVC_MUTE_SHIFT) & - TEGRA210_MUTE_MASK_EN; + return val; +} + +static int tegra210_mvc_get_mute(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u32 val = tegra210_mvc_get_ctrl_reg(kcontrol); + u8 mute_mask = TEGRA210_GET_MUTE_VAL(val); - ucontrol->value.integer.value[0] = mute_mask; + /* + * If per channel control is enabled, then return + * exact mute/unmute setting of all channels. + * + * Else report setting based on CH0 bit to reflect + * the correct HW state. + */ + if (val & TEGRA210_MVC_PER_CHAN_CTRL_EN) { + ucontrol->value.integer.value[0] = mute_mask; + } else { + if (mute_mask & TEGRA210_MVC_CH0_MUTE_EN) + ucontrol->value.integer.value[0] = + TEGRA210_MUTE_MASK_EN; + else + ucontrol->value.integer.value[0] = 0; + } return 0; } -static int tegra210_mvc_put_mute(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int tegra210_mvc_get_master_mute(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u32 val = tegra210_mvc_get_ctrl_reg(kcontrol); + u8 mute_mask = TEGRA210_GET_MUTE_VAL(val); + + /* + * If per channel control is disabled, then return + * master mute/unmute setting based on CH0 bit. + * + * Else report settings based on state of all + * channels. + */ + if (!(val & TEGRA210_MVC_PER_CHAN_CTRL_EN)) { + ucontrol->value.integer.value[0] = + mute_mask & TEGRA210_MVC_CH0_MUTE_EN; + } else { + if (mute_mask == TEGRA210_MUTE_MASK_EN) + ucontrol->value.integer.value[0] = + TEGRA210_MVC_CH0_MUTE_EN; + else + ucontrol->value.integer.value[0] = 0; + } + + return 0; +} + +static int tegra210_mvc_volume_switch_timeout(struct snd_soc_component *cmpnt) { - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt); - unsigned int value; - u8 new_mask, old_mask; + u32 value; int err; - pm_runtime_get_sync(cmpnt->dev); - - /* Check if VOLUME_SWITCH is triggered */ err = regmap_read_poll_timeout(mvc->regmap, TEGRA210_MVC_SWITCH, value, !(value & TEGRA210_MVC_VOLUME_SWITCH_MASK), 10, 10000); if (err < 0) - goto end; + dev_err(cmpnt->dev, + "Volume switch trigger is still active, err = %d\n", + err); - regmap_read(mvc->regmap, TEGRA210_MVC_CTRL, &value); + return err; +} - old_mask = (value >> TEGRA210_MVC_MUTE_SHIFT) & TEGRA210_MUTE_MASK_EN; - new_mask = ucontrol->value.integer.value[0]; +static int tegra210_mvc_update_mute(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol, + bool per_chan_ctrl) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt); + u32 mute_val = ucontrol->value.integer.value[0]; + u32 per_ch_ctrl_val; + bool change = false; + int err; - if (new_mask == old_mask) { - err = 0; + pm_runtime_get_sync(cmpnt->dev); + + err = tegra210_mvc_volume_switch_timeout(cmpnt); + if (err < 0) goto end; + + if (per_chan_ctrl) { + per_ch_ctrl_val = TEGRA210_MVC_PER_CHAN_CTRL_EN; + } else { + per_ch_ctrl_val = 0; + + if (mute_val) + mute_val = TEGRA210_MUTE_MASK_EN; } - err = regmap_update_bits(mvc->regmap, mc->reg, + regmap_update_bits_check(mvc->regmap, TEGRA210_MVC_CTRL, TEGRA210_MVC_MUTE_MASK, - new_mask << TEGRA210_MVC_MUTE_SHIFT); - if (err < 0) - goto end; + mute_val << TEGRA210_MVC_MUTE_SHIFT, + &change); - err = 1; + if (change) { + regmap_update_bits(mvc->regmap, TEGRA210_MVC_CTRL, + TEGRA210_MVC_PER_CHAN_CTRL_EN_MASK, + per_ch_ctrl_val); + + regmap_update_bits(mvc->regmap, TEGRA210_MVC_SWITCH, + TEGRA210_MVC_VOLUME_SWITCH_MASK, + TEGRA210_MVC_VOLUME_SWITCH_TRIGGER); + } end: pm_runtime_put(cmpnt->dev); - return err; + + if (err < 0) + return err; + + if (change) + return 1; + + return 0; +} + +static int tegra210_mvc_put_mute(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return tegra210_mvc_update_mute(kcontrol, ucontrol, true); +} + +static int tegra210_mvc_put_master_mute(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return tegra210_mvc_update_mute(kcontrol, ucontrol, false); } static int tegra210_mvc_get_vol(struct snd_kcontrol *kcontrol, @@ -178,7 +263,7 @@ static int tegra210_mvc_get_vol(struct snd_kcontrol *kcontrol, (struct soc_mixer_control *)kcontrol->private_value; struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt); - u8 chan = (mc->reg - TEGRA210_MVC_TARGET_VOL) / REG_SIZE; + u8 chan = TEGRA210_MVC_GET_CHAN(mc->reg, TEGRA210_MVC_TARGET_VOL); s32 val = mvc->volume[chan]; if (mvc->curve_type == CURVE_POLY) { @@ -193,44 +278,55 @@ static int tegra210_mvc_get_vol(struct snd_kcontrol *kcontrol, return 0; } -static int tegra210_mvc_put_vol(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int tegra210_mvc_get_master_vol(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return tegra210_mvc_get_vol(kcontrol, ucontrol); +} + +static int tegra210_mvc_update_vol(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol, + bool per_ch_enable) { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt); - unsigned int reg = mc->reg; - unsigned int value; - u8 chan; - int err, old_volume; + u8 chan = TEGRA210_MVC_GET_CHAN(mc->reg, TEGRA210_MVC_TARGET_VOL); + int old_volume = mvc->volume[chan]; + int err, i; pm_runtime_get_sync(cmpnt->dev); - /* Check if VOLUME_SWITCH is triggered */ - err = regmap_read_poll_timeout(mvc->regmap, TEGRA210_MVC_SWITCH, - value, !(value & TEGRA210_MVC_VOLUME_SWITCH_MASK), - 10, 10000); + err = tegra210_mvc_volume_switch_timeout(cmpnt); if (err < 0) goto end; - chan = (reg - TEGRA210_MVC_TARGET_VOL) / REG_SIZE; - old_volume = mvc->volume[chan]; - - tegra210_mvc_conv_vol(mvc, chan, - ucontrol->value.integer.value[0]); + tegra210_mvc_conv_vol(mvc, chan, ucontrol->value.integer.value[0]); if (mvc->volume[chan] == old_volume) { err = 0; goto end; } + if (per_ch_enable) { + regmap_update_bits(mvc->regmap, TEGRA210_MVC_CTRL, + TEGRA210_MVC_PER_CHAN_CTRL_EN_MASK, + TEGRA210_MVC_PER_CHAN_CTRL_EN); + } else { + regmap_update_bits(mvc->regmap, TEGRA210_MVC_CTRL, + TEGRA210_MVC_PER_CHAN_CTRL_EN_MASK, 0); + + for (i = 1; i < TEGRA210_MVC_MAX_CHAN_COUNT; i++) + mvc->volume[i] = mvc->volume[chan]; + } + /* Configure init volume same as target volume */ regmap_write(mvc->regmap, TEGRA210_MVC_REG_OFFSET(TEGRA210_MVC_INIT_VOL, chan), mvc->volume[chan]); - regmap_write(mvc->regmap, reg, mvc->volume[chan]); + regmap_write(mvc->regmap, mc->reg, mvc->volume[chan]); regmap_update_bits(mvc->regmap, TEGRA210_MVC_SWITCH, TEGRA210_MVC_VOLUME_SWITCH_MASK, @@ -240,9 +336,22 @@ static int tegra210_mvc_put_vol(struct snd_kcontrol *kcontrol, end: pm_runtime_put(cmpnt->dev); + return err; } +static int tegra210_mvc_put_vol(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return tegra210_mvc_update_vol(kcontrol, ucontrol, true); +} + +static int tegra210_mvc_put_master_vol(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return tegra210_mvc_update_vol(kcontrol, ucontrol, false); +} + static void tegra210_mvc_reset_vol_settings(struct tegra210_mvc *mvc, struct device *dev) { @@ -436,6 +545,16 @@ static const struct snd_kcontrol_new tegra210_mvc_vol_ctrl[] = { TEGRA210_MVC_CTRL, 0, TEGRA210_MUTE_MASK_EN, 0, tegra210_mvc_get_mute, tegra210_mvc_put_mute), + /* Master volume */ + SOC_SINGLE_EXT("Volume", TEGRA210_MVC_TARGET_VOL, 0, 16000, 0, + tegra210_mvc_get_master_vol, + tegra210_mvc_put_master_vol), + + /* Master mute */ + SOC_SINGLE_EXT("Mute", TEGRA210_MVC_CTRL, 0, 1, 0, + tegra210_mvc_get_master_mute, + tegra210_mvc_put_master_mute), + SOC_ENUM_EXT("Curve Type", tegra210_mvc_curve_type_ctrl, tegra210_mvc_get_curve_type, tegra210_mvc_put_curve_type), }; diff --git a/sound/soc/tegra/tegra210_mvc.h b/sound/soc/tegra/tegra210_mvc.h index def29c4c72577..d775335dc60b5 100644 --- a/sound/soc/tegra/tegra210_mvc.h +++ b/sound/soc/tegra/tegra210_mvc.h @@ -59,6 +59,7 @@ #define TEGRA210_MUTE_MASK_EN 0xff #define TEGRA210_MVC_MUTE_MASK (TEGRA210_MUTE_MASK_EN << TEGRA210_MVC_MUTE_SHIFT) #define TEGRA210_MVC_MUTE_EN (TEGRA210_MUTE_MASK_EN << TEGRA210_MVC_MUTE_SHIFT) +#define TEGRA210_MVC_CH0_MUTE_EN 1 #define TEGRA210_MVC_PER_CHAN_CTRL_EN_SHIFT 30 #define TEGRA210_MVC_PER_CHAN_CTRL_EN_MASK (1 << TEGRA210_MVC_PER_CHAN_CTRL_EN_SHIFT) @@ -92,6 +93,10 @@ #define TEGRA210_MVC_MAX_CHAN_COUNT 8 #define TEGRA210_MVC_REG_OFFSET(reg, i) (reg + (REG_SIZE * i)) +#define TEGRA210_MVC_GET_CHAN(reg, base) (((reg) - (base)) / REG_SIZE) + +#define TEGRA210_GET_MUTE_VAL(val) (((val) >> TEGRA210_MVC_MUTE_SHIFT) & TEGRA210_MUTE_MASK_EN) + #define NUM_GAIN_POLY_COEFFS 9 enum { From b80155fe61a76784273c2e7b8b15ae8249eb7440 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 30 Nov 2021 16:05:05 +0000 Subject: [PATCH 136/327] ASoC: codecs: wcd934x: remove redundant ret variable return value form snd_soc_dapm_put_enum_double() directly instead of taking this in another redundant variable. Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20211130160507.22180-3-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd934x.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index 4f568abd59e24..f94cbce96d775 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -3379,7 +3379,7 @@ static int wcd934x_int_dem_inp_mux_put(struct snd_kcontrol *kc, { struct soc_enum *e = (struct soc_enum *)kc->private_value; struct snd_soc_component *component; - int reg, val, ret; + int reg, val; component = snd_soc_dapm_kcontrol_component(kc); val = ucontrol->value.enumerated.item[0]; @@ -3402,9 +3402,7 @@ static int wcd934x_int_dem_inp_mux_put(struct snd_kcontrol *kc, WCD934X_RX_DLY_ZN_EN_MASK, WCD934X_RX_DLY_ZN_DISABLE); - ret = snd_soc_dapm_put_enum_double(kc, ucontrol); - - return ret; + return snd_soc_dapm_put_enum_double(kc, ucontrol); } static int wcd934x_dec_enum_put(struct snd_kcontrol *kcontrol, From e3dd4424c2f40aae9080667c4da42b0d7f9be711 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Wed, 1 Dec 2021 17:56:29 +0800 Subject: [PATCH 137/327] ASoC: rt5640: Fix the wrong state of the JD in the HDA header The patch fixes the wrong state of the JD with 1M pull up resistor in the HDA header. Signed-off-by: Oder Chiou Link: https://lore.kernel.org/r/20211201095629.21818-1-oder_chiou@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5640.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 08b37878cb002..f3659b14c74eb 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -1973,7 +1973,7 @@ static int rt5640_set_bias_level(struct snd_soc_component *component, RT5640_PWR_FV1 | RT5640_PWR_FV2, RT5640_PWR_FV1 | RT5640_PWR_FV2); snd_soc_component_update_bits(component, RT5640_DUMMY1, - 0x0301, 0x0301); + 0x1, 0x1); snd_soc_component_update_bits(component, RT5640_MICBIAS, 0x0030, 0x0030); } @@ -2533,7 +2533,7 @@ static void rt5640_enable_hda_jack_detect( snd_soc_component_update_bits(component, RT5640_GPIO_CTRL3, RT5640_GP1_PF_MASK, RT5640_GP1_PF_OUT); - snd_soc_component_update_bits(component, RT5640_DUMMY1, 0x700, 0x300); + snd_soc_component_update_bits(component, RT5640_DUMMY1, 0x400, 0x0); rt5640->jack = jack; @@ -2651,13 +2651,16 @@ static int rt5640_probe(struct snd_soc_component *component) if (device_property_read_u32(component->dev, "realtek,jack-detect-source", &val) == 0) { - if (val <= RT5640_JD_SRC_GPIO4) + if (val <= RT5640_JD_SRC_GPIO4) { rt5640->jd_src = val << RT5640_JD_SFT; - else if (val == RT5640_JD_SRC_HDA_HEADER) + } else if (val == RT5640_JD_SRC_HDA_HEADER) { rt5640->jd_src = RT5640_JD_SRC_HDA_HEADER; - else + snd_soc_component_update_bits(component, RT5640_DUMMY1, + 0x0300, 0x0); + } else { dev_warn(component->dev, "Warning: Invalid jack-detect-source value: %d, leaving jack-detect disabled\n", val); + } } if (!device_property_read_bool(component->dev, "realtek,jack-detect-not-inverted")) From 19a628d8f1a6c16263d8037a918427207c8a95a0 Mon Sep 17 00:00:00 2001 From: Lucas Tanure Date: Wed, 1 Dec 2021 18:00:03 +0000 Subject: [PATCH 138/327] ASoC: amd: Fix dependency for SPI master Set SPI_MASTER as dependency as is using CS35L41 SPI driver Fixes: 96792fdd77cd1 ("ASoC: amd: enable vangogh platform machine driver build") Signed-off-by: Lucas Tanure Reported-by: kernel test robot Link: https://lore.kernel.org/r/20211201180004.1402156-1-tanureal@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/amd/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig index 092966ff5ea7d..8961b8fd23eb6 100644 --- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -68,7 +68,7 @@ config SND_SOC_AMD_VANGOGH_MACH tristate "AMD Vangogh support for NAU8821 CS35L41" select SND_SOC_NAU8821 select SND_SOC_CS35L41_SPI - depends on SND_SOC_AMD_ACP5x && I2C + depends on SND_SOC_AMD_ACP5x && I2C && SPI_MASTER help This option enables machine driver for Vangogh platform using NAU8821 and CS35L41 codecs. From 0695ad92fe1a0bb7697eb92c6a145a73c5ab0e24 Mon Sep 17 00:00:00 2001 From: Lucas Tanure Date: Wed, 1 Dec 2021 18:00:04 +0000 Subject: [PATCH 139/327] ASoC: cs35l41: Fix undefined reference to core functions Auto select core driver if i2c or spi bus drivers are selected Fixes: a5e0091d62ab ("ASoC: cs35l41: Fix link problem") Signed-off-by: Lucas Tanure Reported-by: kernel test robot Link: https://lore.kernel.org/r/20211201180004.1402156-2-tanureal@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index b4f70e27342c2..c033ee7d82e46 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -614,17 +614,19 @@ config SND_SOC_CS35L36 config SND_SOC_CS35L41 tristate + default y if SND_SOC_CS35L41_SPI=y + default y if SND_SOC_CS35L41_I2C=y + default m if SND_SOC_CS35L41_SPI=m + default m if SND_SOC_CS35L41_I2C=m config SND_SOC_CS35L41_SPI tristate "Cirrus Logic CS35L41 CODEC (SPI)" depends on SPI_MASTER - select SND_SOC_CS35L41 select REGMAP_SPI config SND_SOC_CS35L41_I2C tristate "Cirrus Logic CS35L41 CODEC (I2C)" depends on I2C - select SND_SOC_CS35L41 select REGMAP_I2C config SND_SOC_CS42L42 From 4d408ea0282c374a304ce402866cb7b8a56c6b05 Mon Sep 17 00:00:00 2001 From: Trevor Wu Date: Tue, 30 Nov 2021 13:39:04 +0800 Subject: [PATCH 140/327] ASoC: mediatek: mt8195: support reserved memory assignment For security purpose, restrict the memory assess region of AFE memif. The specified memory region should be assigned from DTS. Signed-off-by: Trevor Wu Link: https://lore.kernel.org/r/20211130053905.28470-2-trevor.wu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8195/mt8195-afe-pcm.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c b/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c index 2bb05a828e8d2..8a6db24116e39 100644 --- a/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c +++ b/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include "mt8195-afe-common.h" #include "mt8195-afe-clk.h" @@ -3061,6 +3062,12 @@ static int mt8195_afe_pcm_dev_probe(struct platform_device *pdev) int i, irq_id, ret; struct snd_soc_component *component; + ret = of_reserved_mem_device_init(dev); + if (ret) { + dev_err(dev, "failed to assign memory region: %d\n", ret); + return ret; + } + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(33)); if (ret) return ret; From b6ce5d85b1425d3a1211f85835ab152c9bf3803a Mon Sep 17 00:00:00 2001 From: Ariel D'Alessandro Date: Fri, 3 Dec 2021 14:50:18 -0300 Subject: [PATCH 141/327] ASoC: fsl-asoc-card: Add missing Kconfig option for tlv320aic31xx The following commit added support for tlv320aic31xx codec to fsl-asoc-card, but missed the related Kconfig option. Fix this. commit 8c9b9cfb7724685ce705f511b882f30597596536 Author: Ariel D'Alessandro Date: Fri Nov 19 12:32:48 2021 -0300 ASoC: fsl-asoc-card: Support fsl,imx-audio-tlv320aic31xx codec Signed-off-by: Ariel D'Alessandro Signed-off-by: Michael Trimarchi Link: https://lore.kernel.org/r/20211203175018.252641-2-ariel.dalessandro@collabora.com Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 8e05d092790e4..10fa387534533 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -311,6 +311,7 @@ config SND_SOC_FSL_ASOC_CARD select SND_SOC_FSL_ESAI select SND_SOC_FSL_SAI select SND_SOC_FSL_SSI + select SND_SOC_TLV320AIC31XX select SND_SOC_WM8994 select MFD_WM8994 help From c9d57a25de53800e54969f4bf2b672b3a58cdaf5 Mon Sep 17 00:00:00 2001 From: Trevor Wu Date: Mon, 29 Nov 2021 22:10:54 +0800 Subject: [PATCH 142/327] ASoC: mediatek: mt8195: add headset codec rt5682s support mt8195 machine driver adds rt5682s support in this patch. Card name can be specified from dts by model property, and driver makes use of the name to distinguish which headset codec is on the board. Signed-off-by: Trevor Wu Link: https://lore.kernel.org/r/20211129141057.12422-2-trevor.wu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/Kconfig | 2 ++ .../mt8195/mt8195-mt6359-rt1011-rt5682.c | 29 +++++++++++++----- .../mt8195/mt8195-mt6359-rt1019-rt5682.c | 30 ++++++++++++++----- 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 3b1ddea26a9ef..9306b7ca26442 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -205,6 +205,7 @@ config SND_SOC_MT8195_MT6359_RT1019_RT5682 select SND_SOC_MT6359 select SND_SOC_RT1015P select SND_SOC_RT5682_I2C + select SND_SOC_RT5682S select SND_SOC_DMIC select SND_SOC_HDMI_CODEC help @@ -220,6 +221,7 @@ config SND_SOC_MT8195_MT6359_RT1011_RT5682 select SND_SOC_MT6359 select SND_SOC_RT1011 select SND_SOC_RT5682_I2C + select SND_SOC_RT5682S select SND_SOC_DMIC select SND_SOC_HDMI_CODEC help diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c index 9e6b54e19c232..cca1c739e690b 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c @@ -27,6 +27,9 @@ #define RT5682_CODEC_DAI "rt5682-aif1" #define RT5682_DEV0_NAME "rt5682.2-001a" +#define RT5682S_CODEC_DAI "rt5682s-aif1" +#define RT5682S_DEV0_NAME "rt5682s.2-001a" + struct mt8195_mt6359_rt1011_rt5682_priv { struct device_node *platform_node; struct device_node *hdmi_node; @@ -691,14 +694,12 @@ SND_SOC_DAILINK_DEFS(ETDM1_IN_BE, SND_SOC_DAILINK_DEFS(ETDM2_IN_BE, DAILINK_COMP_ARRAY(COMP_CPU("ETDM2_IN")), - DAILINK_COMP_ARRAY(COMP_CODEC(RT5682_DEV0_NAME, - RT5682_CODEC_DAI)), + DAILINK_COMP_ARRAY(COMP_DUMMY()), DAILINK_COMP_ARRAY(COMP_EMPTY())); SND_SOC_DAILINK_DEFS(ETDM1_OUT_BE, DAILINK_COMP_ARRAY(COMP_CPU("ETDM1_OUT")), - DAILINK_COMP_ARRAY(COMP_CODEC(RT5682_DEV0_NAME, - RT5682_CODEC_DAI)), + DAILINK_COMP_ARRAY(COMP_DUMMY()), DAILINK_COMP_ARRAY(COMP_EMPTY())); SND_SOC_DAILINK_DEFS(ETDM2_OUT_BE, @@ -1046,9 +1047,19 @@ static int mt8195_mt6359_rt1011_rt5682_dev_probe(struct platform_device *pdev) struct snd_soc_card *card = &mt8195_mt6359_rt1011_rt5682_soc_card; struct snd_soc_dai_link *dai_link; struct mt8195_mt6359_rt1011_rt5682_priv *priv; + int is5682s = 0; int ret, i; card->dev = &pdev->dev; + ret = snd_soc_of_parse_card_name(card, "model"); + if (ret) { + dev_err(&pdev->dev, "%s new card name parsing error %d\n", + __func__, ret); + return ret; + } + + if (strstr(card->name, "_5682s")) + is5682s = 1; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -1078,9 +1089,7 @@ static int mt8195_mt6359_rt1011_rt5682_dev_probe(struct platform_device *pdev) dai_link->codecs->dai_name = "i2s-hifi"; dai_link->init = mt8195_dptx_codec_init; } - } - - if (strcmp(dai_link->name, "ETDM3_OUT_BE") == 0) { + } else if (strcmp(dai_link->name, "ETDM3_OUT_BE") == 0) { priv->hdmi_node = of_parse_phandle(pdev->dev.of_node, "mediatek,hdmi-codec", 0); @@ -1092,6 +1101,12 @@ static int mt8195_mt6359_rt1011_rt5682_dev_probe(struct platform_device *pdev) dai_link->codecs->dai_name = "i2s-hifi"; dai_link->init = mt8195_hdmi_codec_init; } + } else if (strcmp(dai_link->name, "ETDM1_OUT_BE") == 0 || + strcmp(dai_link->name, "ETDM2_IN_BE") == 0) { + dai_link->codecs->name = + is5682s ? RT5682S_DEV0_NAME : RT5682_DEV0_NAME; + dai_link->codecs->dai_name = + is5682s ? RT5682S_CODEC_DAI : RT5682_CODEC_DAI; } } diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c index e22e5fd409846..c33b69b4f8e78 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c @@ -25,6 +25,9 @@ #define RT5682_CODEC_DAI "rt5682-aif1" #define RT5682_DEV0_NAME "rt5682.2-001a" +#define RT5682S_CODEC_DAI "rt5682s-aif1" +#define RT5682S_DEV0_NAME "rt5682s.2-001a" + struct mt8195_mt6359_rt1019_rt5682_priv { struct device_node *platform_node; struct device_node *hdmi_node; @@ -661,14 +664,12 @@ SND_SOC_DAILINK_DEFS(ETDM1_IN_BE, SND_SOC_DAILINK_DEFS(ETDM2_IN_BE, DAILINK_COMP_ARRAY(COMP_CPU("ETDM2_IN")), - DAILINK_COMP_ARRAY(COMP_CODEC(RT5682_DEV0_NAME, - RT5682_CODEC_DAI)), + DAILINK_COMP_ARRAY(COMP_DUMMY()), DAILINK_COMP_ARRAY(COMP_EMPTY())); SND_SOC_DAILINK_DEFS(ETDM1_OUT_BE, DAILINK_COMP_ARRAY(COMP_CPU("ETDM1_OUT")), - DAILINK_COMP_ARRAY(COMP_CODEC(RT5682_DEV0_NAME, - RT5682_CODEC_DAI)), + DAILINK_COMP_ARRAY(COMP_DUMMY()), DAILINK_COMP_ARRAY(COMP_EMPTY())); SND_SOC_DAILINK_DEFS(ETDM2_OUT_BE, @@ -999,10 +1000,21 @@ static int mt8195_mt6359_rt1019_rt5682_dev_probe(struct platform_device *pdev) struct snd_soc_card *card = &mt8195_mt6359_rt1019_rt5682_soc_card; struct snd_soc_dai_link *dai_link; struct mt8195_mt6359_rt1019_rt5682_priv *priv; + int is5682s = 0; int ret, i; card->dev = &pdev->dev; + ret = snd_soc_of_parse_card_name(card, "model"); + if (ret) { + dev_err(&pdev->dev, "%s new card name parsing error %d\n", + __func__, ret); + return ret; + } + + if (strstr(card->name, "_5682s")) + is5682s = 1; + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -1031,9 +1043,7 @@ static int mt8195_mt6359_rt1019_rt5682_dev_probe(struct platform_device *pdev) dai_link->codecs->dai_name = "i2s-hifi"; dai_link->init = mt8195_dptx_codec_init; } - } - - if (strcmp(dai_link->name, "ETDM3_OUT_BE") == 0) { + } else if (strcmp(dai_link->name, "ETDM3_OUT_BE") == 0) { priv->hdmi_node = of_parse_phandle(pdev->dev.of_node, "mediatek,hdmi-codec", 0); @@ -1045,6 +1055,12 @@ static int mt8195_mt6359_rt1019_rt5682_dev_probe(struct platform_device *pdev) dai_link->codecs->dai_name = "i2s-hifi"; dai_link->init = mt8195_hdmi_codec_init; } + } else if (strcmp(dai_link->name, "ETDM1_OUT_BE") == 0 || + strcmp(dai_link->name, "ETDM2_IN_BE") == 0) { + dai_link->codecs->name = + is5682s ? RT5682S_DEV0_NAME : RT5682_DEV0_NAME; + dai_link->codecs->dai_name = + is5682s ? RT5682S_CODEC_DAI : RT5682_CODEC_DAI; } } From e733ab7e3e5dc1bf7d34e050e839fc902ce7ff98 Mon Sep 17 00:00:00 2001 From: Bernard Zhao Date: Sun, 5 Dec 2021 18:11:00 -0800 Subject: [PATCH 143/327] sound/soc: remove useless bool conversion to bool variable This patch remove useless bool conversion to bool variable Signed-off-by: Bernard Zhao Link: https://lore.kernel.org/r/20211206021100.321170-1-bernard@vivo.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l35.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index 7a5588f1df01a..961a3e07e70f2 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -1311,7 +1311,7 @@ static int cs35l35_handle_of_data(struct i2c_client *i2c_client, pdata->gain_zc = of_property_read_bool(np, "cirrus,amp-gain-zc"); classh = of_get_child_by_name(np, "cirrus,classh-internal-algo"); - classh_config->classh_algo_enable = classh ? true : false; + classh_config->classh_algo_enable = (classh != NULL); if (classh_config->classh_algo_enable) { classh_config->classh_bst_override = From c686316ec1210d43653c91e104c1e4cd0156dc89 Mon Sep 17 00:00:00 2001 From: Ameer Hamza Date: Mon, 6 Dec 2021 01:42:00 +0500 Subject: [PATCH 144/327] ASoC: test-component: fix null pointer dereference. Dereferncing of_id pointer will result in exception in current implementation since of_match_device() will assign it to NULL. Adding NULL check for protection. Signed-off-by: Ameer Hamza Link: https://lore.kernel.org/r/20211205204200.7852-1-amhamza.mgc@gmail.com Signed-off-by: Mark Brown --- sound/soc/generic/test-component.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/soc/generic/test-component.c b/sound/soc/generic/test-component.c index 85385a771d807..8fc97d3ff0110 100644 --- a/sound/soc/generic/test-component.c +++ b/sound/soc/generic/test-component.c @@ -532,13 +532,16 @@ static int test_driver_probe(struct platform_device *pdev) struct device_node *node = dev->of_node; struct device_node *ep; const struct of_device_id *of_id = of_match_device(test_of_match, &pdev->dev); - const struct test_adata *adata = of_id->data; + const struct test_adata *adata; struct snd_soc_component_driver *cdriv; struct snd_soc_dai_driver *ddriv; struct test_dai_name *dname; struct test_priv *priv; int num, ret, i; + if (!of_id) + return -EINVAL; + adata = of_id->data; num = of_graph_get_endpoint_count(node); if (!num) { dev_err(dev, "no port exits\n"); From 766cc7f12078fe80dd88469e3dfe045e49bdf2bb Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 2 Dec 2021 22:48:38 +0200 Subject: [PATCH 145/327] ASoC: zl38060: Setup parent device and get rid of unnecessary of_node assignment Some of the drivers do not set parent device. This may lead to obstacles during debugging or understanding the device relations from the Linux point of view. Assign parent device for GPIO chips created by these drivers. While at it, let GPIO library to assign of_node from the parent device. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211202204838.75287-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/zl38060.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/codecs/zl38060.c b/sound/soc/codecs/zl38060.c index d20ec15710106..6cae0fb08093b 100644 --- a/sound/soc/codecs/zl38060.c +++ b/sound/soc/codecs/zl38060.c @@ -589,9 +589,7 @@ static int zl38_spi_probe(struct spi_device *spi) sizeof(template_chip), GFP_KERNEL); if (!priv->gpio_chip) return -ENOMEM; -#ifdef CONFIG_OF_GPIO - priv->gpio_chip->of_node = dev->of_node; -#endif + priv->gpio_chip->parent = dev; err = devm_gpiochip_add_data(dev, priv->gpio_chip, priv->regmap); if (err) return err; From 4db32072b8ab18a8b90191c57c74f42d00bf9991 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 2 Dec 2021 22:56:11 +0200 Subject: [PATCH 146/327] ASoC: ti: davinci-mcasp: Get rid of duplicate of_node assignment GPIO library does copy the of_node from the parent device of the GPIO chip, there is no need to repeat this in the individual drivers. Remove assignment here. For the details one may look into the of_gpio_dev_init() implementation. Signed-off-by: Andy Shevchenko Acked-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20211202205612.76216-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/ti/davinci-mcasp.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index 56a19eeec5c7f..81c1ccec59040 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -2230,9 +2230,6 @@ static int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp) mcasp->gpio_chip = davinci_mcasp_template_chip; mcasp->gpio_chip.label = dev_name(mcasp->dev); mcasp->gpio_chip.parent = mcasp->dev; -#ifdef CONFIG_OF_GPIO - mcasp->gpio_chip.of_node = mcasp->dev->of_node; -#endif return devm_gpiochip_add_data(mcasp->dev, &mcasp->gpio_chip, mcasp); } From c1a77ba466c0dd0bdf1ec2bbebb8996d7cd7b8f7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 2 Dec 2021 22:56:12 +0200 Subject: [PATCH 147/327] ASoC: ti: davinci-mcasp: Remove unnecessary conditional Instead of double validating of_node, return value of the boolean property directly. We can't remove ifdeffery, because in OF_GPIO=n cases it might bring unwanted surprises. Signed-off-by: Andy Shevchenko Acked-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20211202205612.76216-2-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/ti/davinci-mcasp.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index 81c1ccec59040..3e105caac95ee 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -1870,12 +1870,10 @@ static int mcasp_reparent_fck(struct platform_device *pdev) static bool davinci_mcasp_have_gpiochip(struct davinci_mcasp *mcasp) { #ifdef CONFIG_OF_GPIO - if (mcasp->dev->of_node && - of_property_read_bool(mcasp->dev->of_node, "gpio-controller")) - return true; -#endif - + return of_property_read_bool(mcasp->dev->of_node, "gpio-controller"); +#else return false; +#endif } static int davinci_mcasp_get_config(struct davinci_mcasp *mcasp, From 9a83dfcc5ae8230fbf12b63e281d5bb8450ec0e7 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 3 Dec 2021 17:47:21 +0200 Subject: [PATCH 148/327] ASoC: SOF: Intel: fix build issue related to CODEC_PROBE_ENTRIES Fix following error: sound/soc/sof/intel/hda-codec.c:132:35: error: use of undeclared identifier 'CODEC_PROBE_RETRIES' Found with config: i386-randconfig-r033-20211202 (https://download.01.org/0day-ci/archive/20211203/202112031943.Twg19fWT-lkp@intel.com/config) Fixes: 046aede2f847 ("ASoC: SOF: Intel: Retry codec probing if it fails") Reported-by: kernel test robot Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211203154721.923496-1-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-codec.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index 13cd96e6724a4..2f3f4a733d9e6 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -20,9 +20,10 @@ #include "../../codecs/hdac_hda.h" #endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */ +#define CODEC_PROBE_RETRIES 3 + #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) #define IDISP_VID_INTEL 0x80860000 -#define CODEC_PROBE_RETRIES 3 /* load the legacy HDA codec driver */ static int request_codec_module(struct hda_codec *codec) From 7bef00106bc68beddcddcd06e3b02dde5525face Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Sat, 4 Dec 2021 12:08:48 +0100 Subject: [PATCH 149/327] ASoC: amd: acp6x-pdm-dma: Constify static snd_soc_dai_ops The only usage of acp6x_pdm_dai_ops is to assign its address to the ops field in the snd_soc_dai_driver struct, which is a pointer to const snd_soc_dai_ops. Make it const to allow the compiler to put it in read-only memory. Signed-off-by: Rikard Falkeborn Link: https://lore.kernel.org/r/20211204110848.21322-1-rikard.falkeborn@gmail.com Signed-off-by: Mark Brown --- sound/soc/amd/yc/acp6x-pdm-dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/amd/yc/acp6x-pdm-dma.c b/sound/soc/amd/yc/acp6x-pdm-dma.c index e604f4ea524f4..7e66393e41535 100644 --- a/sound/soc/amd/yc/acp6x-pdm-dma.c +++ b/sound/soc/amd/yc/acp6x-pdm-dma.c @@ -318,7 +318,7 @@ static int acp6x_pdm_dai_trigger(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_dai_ops acp6x_pdm_dai_ops = { +static const struct snd_soc_dai_ops acp6x_pdm_dai_ops = { .trigger = acp6x_pdm_dai_trigger, }; From 629e442761bae0c62b2fb14061d66bbd08b4155e Mon Sep 17 00:00:00 2001 From: Trevor Wu Date: Mon, 29 Nov 2021 22:10:55 +0800 Subject: [PATCH 150/327] ASoC: mediatek: mt8195: add model property This patch adds the description of model property used to specify card name from dts. Signed-off-by: Trevor Wu Acked-by: Rob Herring Link: https://lore.kernel.org/r/20211129141057.12422-3-trevor.wu@mediatek.com Signed-off-by: Mark Brown --- .../bindings/sound/mt8195-mt6359-rt1011-rt5682.yaml | 4 ++++ .../bindings/sound/mt8195-mt6359-rt1019-rt5682.yaml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/mt8195-mt6359-rt1011-rt5682.yaml b/Documentation/devicetree/bindings/sound/mt8195-mt6359-rt1011-rt5682.yaml index d354c30d3377e..cf6ad7933e23a 100644 --- a/Documentation/devicetree/bindings/sound/mt8195-mt6359-rt1011-rt5682.yaml +++ b/Documentation/devicetree/bindings/sound/mt8195-mt6359-rt1011-rt5682.yaml @@ -16,6 +16,10 @@ properties: compatible: const: mediatek,mt8195_mt6359_rt1011_rt5682 + model: + $ref: /schemas/types.yaml#/definitions/string + description: User specified audio sound card name + mediatek,platform: $ref: "/schemas/types.yaml#/definitions/phandle" description: The phandle of MT8195 ASoC platform. diff --git a/Documentation/devicetree/bindings/sound/mt8195-mt6359-rt1019-rt5682.yaml b/Documentation/devicetree/bindings/sound/mt8195-mt6359-rt1019-rt5682.yaml index 20bc0ffd0e343..e6786dece9a34 100644 --- a/Documentation/devicetree/bindings/sound/mt8195-mt6359-rt1019-rt5682.yaml +++ b/Documentation/devicetree/bindings/sound/mt8195-mt6359-rt1019-rt5682.yaml @@ -16,6 +16,10 @@ properties: compatible: const: mediatek,mt8195_mt6359_rt1019_rt5682 + model: + $ref: /schemas/types.yaml#/definitions/string + description: User specified audio sound card name + mediatek,platform: $ref: "/schemas/types.yaml#/definitions/phandle" description: The phandle of MT8195 ASoC platform. From 3d00d2c07f04f47aa4228700b440ac47abf13853 Mon Sep 17 00:00:00 2001 From: Trevor Wu Date: Mon, 29 Nov 2021 22:10:56 +0800 Subject: [PATCH 151/327] ASoC: mediatek: mt8195: add sof support on mt8195-mt6359-rt1019-rt5682 In the patch, widgets, routes and dai-link requrird by SOF are included, and late_probe is introduced for SOF route connection. Only when adsp phandle could be retrieved from DTS, the SOF related part of machine driver is executed. Additionally, supported dai-links could be specified from DTS, so that we can disable AP side hardware controls when DSP SOF controls the same audio FE. Signed-off-by: Trevor Wu Signed-off-by: YC Hung Link: https://lore.kernel.org/r/20211129141057.12422-4-trevor.wu@mediatek.com Signed-off-by: Mark Brown --- .../mt8195/mt8195-mt6359-rt1019-rt5682.c | 317 +++++++++++++++++- 1 file changed, 305 insertions(+), 12 deletions(-) diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c index c33b69b4f8e78..b240610dcef09 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c @@ -1,11 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 -// -// mt8195-mt6359-rt1019-rt5682.c -- -// MT8195-MT6359-RT1019-RT6358 ALSA SoC machine driver -// -// Copyright (c) 2021 MediaTek Inc. -// Author: Trevor Wu -// +/* + * mt8195-mt6359-rt1019-rt5682.c -- + * MT8195-MT6359-RT1019-RT5682 ALSA SoC machine driver + * + * Copyright (c) 2021 MediaTek Inc. + * Author: Trevor Wu + * YC Hung + */ #include #include @@ -13,6 +14,7 @@ #include #include #include +#include #include #include "../../codecs/mt6359.h" #include "../../codecs/rt5682.h" @@ -28,8 +30,21 @@ #define RT5682S_CODEC_DAI "rt5682s-aif1" #define RT5682S_DEV0_NAME "rt5682s.2-001a" +#define SOF_DMA_DL2 "SOF_DMA_DL2" +#define SOF_DMA_DL3 "SOF_DMA_DL3" +#define SOF_DMA_UL4 "SOF_DMA_UL4" +#define SOF_DMA_UL5 "SOF_DMA_UL5" + +struct sof_conn_stream { + const char *normal_link; + const char *sof_link; + const char *sof_dma; + int stream_dir; +}; + struct mt8195_mt6359_rt1019_rt5682_priv { struct device_node *platform_node; + struct device_node *adsp_node; struct device_node *hdmi_node; struct device_node *dp_node; struct snd_soc_jack headset_jack; @@ -42,6 +57,10 @@ static const struct snd_soc_dapm_widget SND_SOC_DAPM_SPK("Speakers", NULL), SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIXER(SOF_DMA_DL2, SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER(SOF_DMA_DL3, SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER(SOF_DMA_UL4, SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER(SOF_DMA_UL5, SND_SOC_NOPM, 0, 0, NULL, 0), }; static const struct snd_soc_dapm_route mt8195_mt6359_rt1019_rt5682_routes[] = { @@ -51,6 +70,16 @@ static const struct snd_soc_dapm_route mt8195_mt6359_rt1019_rt5682_routes[] = { { "Headphone Jack", NULL, "HPOL" }, { "Headphone Jack", NULL, "HPOR" }, { "IN1P", NULL, "Headset Mic" }, + /* SOF Uplink */ + {SOF_DMA_UL4, NULL, "O034"}, + {SOF_DMA_UL4, NULL, "O035"}, + {SOF_DMA_UL5, NULL, "O036"}, + {SOF_DMA_UL5, NULL, "O037"}, + /* SOF Downlink */ + {"I070", NULL, SOF_DMA_DL2}, + {"I071", NULL, SOF_DMA_DL2}, + {"I020", NULL, SOF_DMA_DL3}, + {"I021", NULL, SOF_DMA_DL3}, }; static const struct snd_kcontrol_new mt8195_mt6359_rt1019_rt5682_controls[] = { @@ -562,8 +591,17 @@ enum { DAI_LINK_PCM1_BE, DAI_LINK_UL_SRC1_BE, DAI_LINK_UL_SRC2_BE, + DAI_LINK_REGULAR_LAST = DAI_LINK_UL_SRC2_BE, + DAI_LINK_SOF_START, + DAI_LINK_SOF_DL2_BE = DAI_LINK_SOF_START, + DAI_LINK_SOF_DL3_BE, + DAI_LINK_SOF_UL4_BE, + DAI_LINK_SOF_UL5_BE, + DAI_LINK_SOF_END = DAI_LINK_SOF_UL5_BE, }; +#define DAI_LINK_REGULAR_NUM (DAI_LINK_REGULAR_LAST + 1) + /* FE */ SND_SOC_DAILINK_DEFS(DL2_FE, DAILINK_COMP_ARRAY(COMP_CPU("DL2")), @@ -702,6 +740,154 @@ SND_SOC_DAILINK_DEFS(UL_SRC2_BE, "mt6359-snd-codec-aif2")), DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(AFE_SOF_DL2, + DAILINK_COMP_ARRAY(COMP_CPU("SOF_DL2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(AFE_SOF_DL3, + DAILINK_COMP_ARRAY(COMP_CPU("SOF_DL3")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(AFE_SOF_UL4, + DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL4")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(AFE_SOF_UL5, + DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL5")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +static const struct sof_conn_stream g_sof_conn_streams[] = { + { "ETDM2_OUT_BE", "AFE_SOF_DL2", SOF_DMA_DL2, SNDRV_PCM_STREAM_PLAYBACK}, + { "ETDM1_OUT_BE", "AFE_SOF_DL3", SOF_DMA_DL3, SNDRV_PCM_STREAM_PLAYBACK}, + { "UL_SRC1_BE", "AFE_SOF_UL4", SOF_DMA_UL4, SNDRV_PCM_STREAM_CAPTURE}, + { "ETDM2_IN_BE", "AFE_SOF_UL5", SOF_DMA_UL5, SNDRV_PCM_STREAM_CAPTURE}, +}; + +/* fixup the BE DAI link to match any values from topology */ +static int mt8195_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_card *card = rtd->card; + struct snd_soc_dai_link *sof_dai_link = NULL; + struct snd_soc_pcm_runtime *runtime; + struct snd_soc_dai *cpu_dai; + int i, j, ret = 0; + + for (i = 0; i < ARRAY_SIZE(g_sof_conn_streams); i++) { + const struct sof_conn_stream *conn = &g_sof_conn_streams[i]; + + if (strcmp(rtd->dai_link->name, conn->normal_link)) + continue; + + for_each_card_rtds(card, runtime) { + if (strcmp(runtime->dai_link->name, conn->sof_link)) + continue; + + for_each_rtd_cpu_dais(runtime, j, cpu_dai) { + if (cpu_dai->stream_active[conn->stream_dir] > 0) { + sof_dai_link = runtime->dai_link; + break; + } + } + break; + } + + if (sof_dai_link && sof_dai_link->be_hw_params_fixup) + ret = sof_dai_link->be_hw_params_fixup(runtime, params); + + break; + } + + if (!strcmp(rtd->dai_link->name, "ETDM2_IN_BE") || + !strcmp(rtd->dai_link->name, "ETDM1_OUT_BE")) { + mt8195_etdm_hw_params_fixup(runtime, params); + } + + return ret; +} + +static int mt8195_mt6359_rt1019_rt5682_card_late_probe(struct snd_soc_card *card) +{ + struct snd_soc_pcm_runtime *runtime; + struct snd_soc_component *sof_comp; + int i; + + /* 1. find sof component */ + for_each_card_rtds(card, runtime) { + for (i = 0; i < runtime->num_components; i++) { + if (!runtime->components[i]->driver->name) + continue; + if (!strcmp(runtime->components[i]->driver->name, "sof-audio-component")) { + sof_comp = runtime->components[i]; + break; + } + } + } + + if (!sof_comp) { + dev_info(card->dev, " probe without component\n"); + return 0; + } + /* 2. add route path and fixup callback */ + for (i = 0; i < ARRAY_SIZE(g_sof_conn_streams); i++) { + const struct sof_conn_stream *conn = &g_sof_conn_streams[i]; + struct snd_soc_pcm_runtime *sof_rtd = NULL; + struct snd_soc_pcm_runtime *normal_rtd = NULL; + struct snd_soc_pcm_runtime *rtd = NULL; + + for_each_card_rtds(card, rtd) { + if (!strcmp(rtd->dai_link->name, conn->sof_link)) { + sof_rtd = rtd; + continue; + } + if (!strcmp(rtd->dai_link->name, conn->normal_link)) { + normal_rtd = rtd; + continue; + } + if (normal_rtd && sof_rtd) + break; + } + if (normal_rtd && sof_rtd) { + int j; + struct snd_soc_dai *cpu_dai; + + for_each_rtd_cpu_dais(sof_rtd, j, cpu_dai) { + struct snd_soc_dapm_route route; + struct snd_soc_dapm_path *p = NULL; + struct snd_soc_dapm_widget *play_widget = + cpu_dai->playback_widget; + struct snd_soc_dapm_widget *cap_widget = + cpu_dai->capture_widget; + memset(&route, 0, sizeof(route)); + if (conn->stream_dir == SNDRV_PCM_STREAM_CAPTURE && + cap_widget) { + snd_soc_dapm_widget_for_each_sink_path(cap_widget, p) { + route.source = conn->sof_dma; + route.sink = p->sink->name; + snd_soc_dapm_add_routes(&card->dapm, &route, 1); + } + } else if (conn->stream_dir == SNDRV_PCM_STREAM_PLAYBACK && + play_widget){ + snd_soc_dapm_widget_for_each_source_path(play_widget, p) { + route.source = p->source->name; + route.sink = conn->sof_dma; + snd_soc_dapm_add_routes(&card->dapm, &route, 1); + } + } else { + dev_err(cpu_dai->dev, "stream dir and widget not pair\n"); + } + } + normal_rtd->dai_link->be_hw_params_fixup = mt8195_dai_link_fixup; + } + } + + return 0; +} + static struct snd_soc_dai_link mt8195_mt6359_rt1019_rt5682_dai_links[] = { /* FE */ [DAI_LINK_DL2_FE] = { @@ -896,7 +1082,6 @@ static struct snd_soc_dai_link mt8195_mt6359_rt1019_rt5682_dai_links[] = { /* BE */ [DAI_LINK_DL_SRC_BE] = { .name = "DL_SRC_BE", - .init = mt8195_mt6359_init, .no_pcm = 1, .dpcm_playback = 1, SND_SOC_DAILINK_REG(DL_SRC_BE), @@ -980,6 +1165,31 @@ static struct snd_soc_dai_link mt8195_mt6359_rt1019_rt5682_dai_links[] = { .dpcm_capture = 1, SND_SOC_DAILINK_REG(UL_SRC2_BE), }, + /* SOF BE */ + [DAI_LINK_SOF_DL2_BE] = { + .name = "AFE_SOF_DL2", + .no_pcm = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(AFE_SOF_DL2), + }, + [DAI_LINK_SOF_DL3_BE] = { + .name = "AFE_SOF_DL3", + .no_pcm = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(AFE_SOF_DL3), + }, + [DAI_LINK_SOF_UL4_BE] = { + .name = "AFE_SOF_UL4", + .no_pcm = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(AFE_SOF_UL4), + }, + [DAI_LINK_SOF_UL5_BE] = { + .name = "AFE_SOF_UL5", + .no_pcm = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(AFE_SOF_UL5), + }, }; static struct snd_soc_card mt8195_mt6359_rt1019_rt5682_soc_card = { @@ -995,12 +1205,61 @@ static struct snd_soc_card mt8195_mt6359_rt1019_rt5682_soc_card = { .num_dapm_routes = ARRAY_SIZE(mt8195_mt6359_rt1019_rt5682_routes), }; +static int mt8195_dailink_parse_of(struct snd_soc_card *card, struct device_node *np, + const char *propname) +{ + struct device *dev = card->dev; + struct snd_soc_dai_link *link; + const char *dai_name = NULL; + int i, j, ret, num_links; + + num_links = of_property_count_strings(np, "mediatek,dai-link"); + + if (num_links < 0 || num_links > ARRAY_SIZE(mt8195_mt6359_rt1019_rt5682_dai_links)) { + dev_dbg(dev, "number of dai-link is invalid\n"); + return -EINVAL; + } + + card->dai_link = devm_kcalloc(dev, num_links, sizeof(*link), GFP_KERNEL); + if (!card->dai_link) + return -ENOMEM; + + card->num_links = 0; + link = card->dai_link; + + for (i = 0; i < num_links; i++) { + ret = of_property_read_string_index(np, propname, i, &dai_name); + if (ret) { + dev_dbg(dev, "ASoC: Property '%s' index %d could not be read: %d\n", + propname, i, ret); + return -EINVAL; + } + + for (j = 0; j < ARRAY_SIZE(mt8195_mt6359_rt1019_rt5682_dai_links); j++) { + if (!strcmp(dai_name, mt8195_mt6359_rt1019_rt5682_dai_links[j].name)) { + memcpy(link, &mt8195_mt6359_rt1019_rt5682_dai_links[j], + sizeof(struct snd_soc_dai_link)); + link++; + card->num_links++; + break; + } + } + } + + if (card->num_links != num_links) + return -EINVAL; + + return 0; +} + static int mt8195_mt6359_rt1019_rt5682_dev_probe(struct platform_device *pdev) { struct snd_soc_card *card = &mt8195_mt6359_rt1019_rt5682_soc_card; struct snd_soc_dai_link *dai_link; struct mt8195_mt6359_rt1019_rt5682_priv *priv; int is5682s = 0; + int init6359 = 0; + int sof_on = 0; int ret, i; card->dev = &pdev->dev; @@ -1026,15 +1285,36 @@ static int mt8195_mt6359_rt1019_rt5682_dev_probe(struct platform_device *pdev) return -EINVAL; } + /* dai link */ + priv->adsp_node = of_parse_phandle(pdev->dev.of_node, + "mediatek,adsp", 0); + if (priv->adsp_node) + sof_on = 1; + + if (of_property_read_bool(pdev->dev.of_node, "mediatek,dai-link")) { + ret = mt8195_dailink_parse_of(card, pdev->dev.of_node, + "mediatek,dai-link"); + if (ret) { + dev_dbg(&pdev->dev, "Parse dai-link fail\n"); + return -EINVAL; + } + } else { + if (!sof_on) + card->num_links = DAI_LINK_REGULAR_NUM; + } + for_each_card_prelinks(card, i, dai_link) { - if (!dai_link->platforms->name) - dai_link->platforms->of_node = priv->platform_node; + if (!dai_link->platforms->name) { + if (!strncmp(dai_link->name, "AFE_SOF", strlen("AFE_SOF")) && sof_on) + dai_link->platforms->of_node = priv->adsp_node; + else + dai_link->platforms->of_node = priv->platform_node; + } if (strcmp(dai_link->name, "DPTX_BE") == 0) { priv->dp_node = of_parse_phandle(pdev->dev.of_node, "mediatek,dptx-codec", 0); - if (!priv->dp_node) { dev_dbg(&pdev->dev, "No property 'dptx-codec'\n"); } else { @@ -1061,9 +1341,19 @@ static int mt8195_mt6359_rt1019_rt5682_dev_probe(struct platform_device *pdev) is5682s ? RT5682S_DEV0_NAME : RT5682_DEV0_NAME; dai_link->codecs->dai_name = is5682s ? RT5682S_CODEC_DAI : RT5682_CODEC_DAI; + } else if (strcmp(dai_link->name, "DL_SRC_BE") == 0 || + strcmp(dai_link->name, "UL_SRC1_BE") == 0 || + strcmp(dai_link->name, "UL_SRC2_BE") == 0) { + if (!init6359) { + dai_link->init = mt8195_mt6359_init; + init6359 = 1; + } } } + if (sof_on) + card->late_probe = mt8195_mt6359_rt1019_rt5682_card_late_probe; + snd_soc_card_set_drvdata(card, priv); ret = devm_snd_soc_register_card(&pdev->dev, card); @@ -1073,6 +1363,7 @@ static int mt8195_mt6359_rt1019_rt5682_dev_probe(struct platform_device *pdev) of_node_put(priv->hdmi_node); of_node_put(priv->dp_node); of_node_put(priv->platform_node); + of_node_put(priv->adsp_node); } return ret; @@ -1087,6 +1378,7 @@ static int mt8195_mt6359_rt1019_rt5682_dev_remove(struct platform_device *pdev) of_node_put(priv->hdmi_node); of_node_put(priv->dp_node); of_node_put(priv->platform_node); + of_node_put(priv->adsp_node); return 0; } @@ -1120,5 +1412,6 @@ module_platform_driver(mt8195_mt6359_rt1019_rt5682_driver); /* Module information */ MODULE_DESCRIPTION("MT8195-MT6359-RT1019-RT5682 ALSA SoC machine driver"); MODULE_AUTHOR("Trevor Wu "); -MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("YC Hung "); +MODULE_LICENSE("GPL"); MODULE_ALIAS("mt8195_mt6359_rt1019_rt5682 soc card"); From 6182ec4616d6ffc046bea798c683a0dee11ded67 Mon Sep 17 00:00:00 2001 From: Trevor Wu Date: Mon, 29 Nov 2021 22:10:57 +0800 Subject: [PATCH 152/327] ASoC: mediatek: mt8195: add adsp and dai-link property 1. adsp phandle can be assigned to the machine driver if adsp is enabled. 2. dai-link supported in the sound card can be specified from DTS. Signed-off-by: Trevor Wu Link: https://lore.kernel.org/r/20211129141057.12422-5-trevor.wu@mediatek.com Signed-off-by: Mark Brown --- .../bindings/sound/mt8195-mt6359-rt1019-rt5682.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/mt8195-mt6359-rt1019-rt5682.yaml b/Documentation/devicetree/bindings/sound/mt8195-mt6359-rt1019-rt5682.yaml index e6786dece9a34..8f177e02ad357 100644 --- a/Documentation/devicetree/bindings/sound/mt8195-mt6359-rt1019-rt5682.yaml +++ b/Documentation/devicetree/bindings/sound/mt8195-mt6359-rt1019-rt5682.yaml @@ -32,6 +32,16 @@ properties: $ref: "/schemas/types.yaml#/definitions/phandle" description: The phandle of MT8195 HDMI codec node. + mediatek,adsp: + $ref: "/schemas/types.yaml#/definitions/phandle" + description: The phandle of MT8195 ADSP platform. + + mediatek,dai-link: + $ref: /schemas/types.yaml#/definitions/string-array + description: + A list of the desired dai-links in the sound card. Each entry is a + name defined in the machine driver. + additionalProperties: false required: From 2da636247bb6f4fc3a9842ade04757790753fd2c Mon Sep 17 00:00:00 2001 From: Trevor Wu Date: Tue, 30 Nov 2021 13:39:05 +0800 Subject: [PATCH 153/327] ASoC: mediatek: mt8195: add memory-region property Add a required property "memory-region", which is used to specify memory for DMA usage. Signed-off-by: Trevor Wu Link: https://lore.kernel.org/r/20211130053905.28470-3-trevor.wu@mediatek.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/mt8195-afe-pcm.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/mt8195-afe-pcm.yaml b/Documentation/devicetree/bindings/sound/mt8195-afe-pcm.yaml index dcf790b053d23..6d0975b33d156 100644 --- a/Documentation/devicetree/bindings/sound/mt8195-afe-pcm.yaml +++ b/Documentation/devicetree/bindings/sound/mt8195-afe-pcm.yaml @@ -19,6 +19,12 @@ properties: interrupts: maxItems: 1 + memory-region: + maxItems: 1 + description: | + Shared memory region for AFE memif. A "shared-dma-pool". + See ../reserved-memory/reserved-memory.txt for details. + mediatek,topckgen: $ref: "/schemas/types.yaml#/definitions/phandle" description: The phandle of the mediatek topckgen controller @@ -125,6 +131,7 @@ required: - power-domains - clocks - clock-names + - memory-region additionalProperties: false @@ -139,6 +146,7 @@ examples: interrupts = ; mediatek,topckgen = <&topckgen>; power-domains = <&spm 7>; //MT8195_POWER_DOMAIN_AUDIO + memory-region = <&snd_dma_mem_reserved>; clocks = <&clk26m>, <&topckgen 163>, //CLK_TOP_APLL1 <&topckgen 166>, //CLK_TOP_APLL2 From 639cd58be7a4bfdf3514877b064b3308bb7800ba Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 7 Dec 2021 15:17:00 -0600 Subject: [PATCH 154/327] ASoC: Intel: boards: add 'static' qualifiers for max98390 routes Sparse warnings: sound/soc/intel/boards/sof_maxim_common.c:140:33: error: symbol 'max_98390_dapm_routes' was not declared. Should it be static? sound/soc/intel/boards/sof_maxim_common.c:156:33: error: symbol 'max_98390_tt_dapm_routes' was not declared. Should it be static? Fixes: f316c9d9ba8ea ('ASoC: Intel: boards: add max98390 2/4 speakers support') Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20211207211700.115319-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_maxim_common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/sof_maxim_common.c b/sound/soc/intel/boards/sof_maxim_common.c index 9171d9cd179ea..112e89951da08 100644 --- a/sound/soc/intel/boards/sof_maxim_common.c +++ b/sound/soc/intel/boards/sof_maxim_common.c @@ -137,7 +137,7 @@ EXPORT_SYMBOL_NS(max_98373_set_codec_conf, SND_SOC_INTEL_SOF_MAXIM_COMMON); /* * Maxim MAX98390 */ -const struct snd_soc_dapm_route max_98390_dapm_routes[] = { +static const struct snd_soc_dapm_route max_98390_dapm_routes[] = { /* speaker */ { "Left Spk", NULL, "Left BE_OUT" }, { "Right Spk", NULL, "Right BE_OUT" }, @@ -153,7 +153,7 @@ static const struct snd_soc_dapm_widget max_98390_tt_dapm_widgets[] = { SND_SOC_DAPM_SPK("TR Spk", NULL), }; -const struct snd_soc_dapm_route max_98390_tt_dapm_routes[] = { +static const struct snd_soc_dapm_route max_98390_tt_dapm_routes[] = { /* Tweeter speaker */ { "TL Spk", NULL, "Tweeter Left BE_OUT" }, { "TR Spk", NULL, "Tweeter Right BE_OUT" }, From 7cfa3d00730a4c0694b55fb1974823baeab8815b Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Wed, 8 Dec 2021 18:17:18 +0800 Subject: [PATCH 155/327] ASoC: rt5682s: add delay time to fix pop sound issue There is a pop noise at the beginning of the capture data. This patch adds the delay time before stereo1 ADC unmute to fix the pop sound issue. Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20211208101718.28945-1-shumingf@realtek.com Signed-off-by: Mark Brown --- include/sound/rt5682s.h | 1 + sound/soc/codecs/rt5682s.c | 34 +++++++++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/include/sound/rt5682s.h b/include/sound/rt5682s.h index accfbc2dcdd2c..f18d91308b9a0 100644 --- a/include/sound/rt5682s.h +++ b/include/sound/rt5682s.h @@ -40,6 +40,7 @@ struct rt5682s_platform_data { enum rt5682s_jd_src jd_src; unsigned int dmic_clk_rate; unsigned int dmic_delay; + unsigned int amic_delay; bool dmic_clk_driving_high; const char *dai_clk_names[RT5682S_DAI_NUM_CLKS]; diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c index d49a4f68566d2..efa1016831dd2 100644 --- a/sound/soc/codecs/rt5682s.c +++ b/sound/soc/codecs/rt5682s.c @@ -1367,6 +1367,31 @@ static int rt5682s_hp_amp_event(struct snd_soc_dapm_widget *w, return 0; } +static int rt5682s_stereo1_adc_mixl_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + unsigned int delay = 0; + + if (rt5682s->pdata.amic_delay) + delay = rt5682s->pdata.amic_delay; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + msleep(delay); + snd_soc_component_update_bits(component, RT5682S_STO1_ADC_DIG_VOL, + RT5682S_L_MUTE, 0); + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_component_update_bits(component, RT5682S_STO1_ADC_DIG_VOL, + RT5682S_L_MUTE, RT5682S_L_MUTE); + break; + } + + return 0; +} + static int sar_power_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -1680,9 +1705,10 @@ static const struct snd_soc_dapm_widget rt5682s_dapm_widgets[] = { /* ADC Mixer */ SND_SOC_DAPM_SUPPLY("ADC Stereo1 Filter", RT5682S_PWR_DIG_2, RT5682S_PWR_ADC_S1F_BIT, 0, set_filter_clk, SND_SOC_DAPM_PRE_PMU), - SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", RT5682S_STO1_ADC_DIG_VOL, - RT5682S_L_MUTE_SFT, 1, rt5682s_sto1_adc_l_mix, - ARRAY_SIZE(rt5682s_sto1_adc_l_mix)), + SND_SOC_DAPM_MIXER_E("Stereo1 ADC MIXL", SND_SOC_NOPM, 0, 0, + rt5682s_sto1_adc_l_mix, ARRAY_SIZE(rt5682s_sto1_adc_l_mix), + rt5682s_stereo1_adc_mixl_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", RT5682S_STO1_ADC_DIG_VOL, RT5682S_R_MUTE_SFT, 1, rt5682s_sto1_adc_r_mix, ARRAY_SIZE(rt5682s_sto1_adc_r_mix)), @@ -2885,6 +2911,8 @@ static int rt5682s_parse_dt(struct rt5682s_priv *rt5682s, struct device *dev) &rt5682s->pdata.dmic_clk_rate); device_property_read_u32(dev, "realtek,dmic-delay-ms", &rt5682s->pdata.dmic_delay); + device_property_read_u32(dev, "realtek,amic-delay-ms", + &rt5682s->pdata.amic_delay); rt5682s->pdata.ldo1_en = of_get_named_gpio(dev->of_node, "realtek,ldo1-en-gpios", 0); From 77659872be233e56019041d05b44d134022296b7 Mon Sep 17 00:00:00 2001 From: Yong Zhi Date: Tue, 7 Dec 2021 13:24:58 -0600 Subject: [PATCH 156/327] ASoC: Intel: sof_rt5682: Move rt1015 speaker amp to common file Move rt1015 driver code to common file to be consistent with rt1011 and rt1015p. No functional change. Reviewed-by: Bard Liao Signed-off-by: Yong Zhi Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20211207192458.44007-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_realtek_common.c | 119 +++++++++++++++++++- sound/soc/intel/boards/sof_realtek_common.h | 7 ++ sound/soc/intel/boards/sof_rt5682.c | 107 +----------------- 3 files changed, 127 insertions(+), 106 deletions(-) diff --git a/sound/soc/intel/boards/sof_realtek_common.c b/sound/soc/intel/boards/sof_realtek_common.c index 2ec34f8df9e15..4cf131310ad3c 100644 --- a/sound/soc/intel/boards/sof_realtek_common.c +++ b/sound/soc/intel/boards/sof_realtek_common.c @@ -12,12 +12,13 @@ #include #include #include "../../codecs/rt1011.h" +#include "../../codecs/rt1015.h" #include "sof_realtek_common.h" /* * Current only 2-amp configuration is supported for rt1011 */ -static const struct snd_soc_dapm_route rt1011_dapm_routes[] = { +static const struct snd_soc_dapm_route speaker_map_lr[] = { /* speaker */ { "Left Spk", NULL, "Left SPO" }, { "Right Spk", NULL, "Right SPO" }, @@ -117,8 +118,8 @@ static int rt1011_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_card *card = rtd->card; int ret; - ret = snd_soc_dapm_add_routes(&card->dapm, rt1011_dapm_routes, - ARRAY_SIZE(rt1011_dapm_routes)); + ret = snd_soc_dapm_add_routes(&card->dapm, speaker_map_lr, + ARRAY_SIZE(speaker_map_lr)); if (ret) dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret); return ret; @@ -241,3 +242,115 @@ void sof_rt1015p_codec_conf(struct snd_soc_card *card) card->codec_conf = rt1015p_codec_confs; card->num_configs = ARRAY_SIZE(rt1015p_codec_confs); } + +/* + * RT1015 audio amplifier + */ + +static int rt1015_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai; + int i, fs = 64, ret; + + for_each_rtd_codec_dais(rtd, i, codec_dai) { + ret = snd_soc_dai_set_pll(codec_dai, 0, RT1015_PLL_S_BCLK, + params_rate(params) * fs, + params_rate(params) * 256); + if (ret) + return ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, RT1015_SCLK_S_PLL, + params_rate(params) * 256, + SND_SOC_CLOCK_IN); + if (ret) + return ret; + } + + return 0; +} + +static int rt1015_hw_params_pll_and_tdm(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai; + int i, fs = 100, ret; + + for_each_rtd_codec_dais(rtd, i, codec_dai) { + ret = snd_soc_dai_set_pll(codec_dai, 0, RT1015_PLL_S_BCLK, + params_rate(params) * fs, + params_rate(params) * 256); + if (ret) + return ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, RT1015_SCLK_S_PLL, + params_rate(params) * 256, + SND_SOC_CLOCK_IN); + if (ret) + return ret; + } + /* rx slot 1 for RT1015_DEV0_NAME */ + ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(rtd, 0), + 0x0, 0x1, 4, 24); + if (ret) + return ret; + + /* rx slot 2 for RT1015_DEV1_NAME */ + ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(rtd, 1), + 0x0, 0x2, 4, 24); + if (ret) + return ret; + + return 0; +} + +static struct snd_soc_ops rt1015_ops = { + .hw_params = rt1015_hw_params, +}; + +static struct snd_soc_codec_conf rt1015_amp_conf[] = { + { + .dlc = COMP_CODEC_CONF(RT1015_DEV0_NAME), + .name_prefix = "Left", + }, + { + .dlc = COMP_CODEC_CONF(RT1015_DEV1_NAME), + .name_prefix = "Right", + }, +}; + +static struct snd_soc_dai_link_component rt1015_components[] = { + { + .name = RT1015_DEV0_NAME, + .dai_name = RT1015_CODEC_DAI, + }, + { + .name = RT1015_DEV1_NAME, + .dai_name = RT1015_CODEC_DAI, + }, +}; + +static int speaker_codec_init_lr(struct snd_soc_pcm_runtime *rtd) +{ + return snd_soc_dapm_add_routes(&rtd->card->dapm, speaker_map_lr, + ARRAY_SIZE(speaker_map_lr)); +} + +void sof_rt1015_codec_conf(struct snd_soc_card *card) +{ + card->codec_conf = rt1015_amp_conf; + card->num_configs = ARRAY_SIZE(rt1015_amp_conf); +} + +void sof_rt1015_dai_link(struct snd_soc_dai_link *link, unsigned int fs) +{ + link->codecs = rt1015_components; + link->num_codecs = ARRAY_SIZE(rt1015_components); + link->init = speaker_codec_init_lr; + link->ops = &rt1015_ops; + + if (fs == 100) + rt1015_ops.hw_params = rt1015_hw_params_pll_and_tdm; +} diff --git a/sound/soc/intel/boards/sof_realtek_common.h b/sound/soc/intel/boards/sof_realtek_common.h index cb0b49b2855c1..228ac9c08430c 100644 --- a/sound/soc/intel/boards/sof_realtek_common.h +++ b/sound/soc/intel/boards/sof_realtek_common.h @@ -28,4 +28,11 @@ void sof_rt1011_codec_conf(struct snd_soc_card *card); void sof_rt1015p_dai_link(struct snd_soc_dai_link *link); void sof_rt1015p_codec_conf(struct snd_soc_card *card); +#define RT1015_CODEC_DAI "rt1015-aif" +#define RT1015_DEV0_NAME "i2c-10EC1015:00" +#define RT1015_DEV1_NAME "i2c-10EC1015:01" + +void sof_rt1015_dai_link(struct snd_soc_dai_link *link, unsigned int fs); +void sof_rt1015_codec_conf(struct snd_soc_card *card); + #endif /* __SOF_REALTEK_COMMON_H */ diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 6cadb5fb72e0c..bd6d2e7dea533 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -20,7 +20,6 @@ #include #include #include -#include "../../codecs/rt1015.h" #include "../../codecs/rt5682.h" #include "../../codecs/rt5682s.h" #include "../../codecs/hdac_hdmi.h" @@ -400,67 +399,6 @@ static struct snd_soc_ops sof_rt5682_ops = { .hw_params = sof_rt5682_hw_params, }; -static int sof_rt1015_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_card *card = rtd->card; - struct snd_soc_dai *codec_dai; - int i, fs, ret; - - if (!snd_soc_card_get_codec_dai(card, "rt1015-aif")) - return 0; - - if (sof_rt5682_quirk & SOF_RT1015_SPEAKER_AMP_100FS) - fs = 100; - else - fs = 64; - - for_each_rtd_codec_dais(rtd, i, codec_dai) { - ret = snd_soc_dai_set_pll(codec_dai, 0, RT1015_PLL_S_BCLK, - params_rate(params) * fs, - params_rate(params) * 256); - if (ret < 0) { - dev_err(card->dev, "failed to set pll\n"); - return ret; - } - /* Configure sysclk for codec */ - ret = snd_soc_dai_set_sysclk(codec_dai, RT1015_SCLK_S_PLL, - params_rate(params) * 256, - SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(card->dev, "failed to set sysclk\n"); - return ret; - } - - if (sof_rt5682_quirk & SOF_RT1015_SPEAKER_AMP_100FS) { - if (!strcmp(codec_dai->component->name, "i2c-10EC1015:00")) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, - 0x0, 0x1, 4, 24); - if (ret < 0) { - dev_err(card->dev, "failed to set tdm slot\n"); - return ret; - } - } - - if (!strcmp(codec_dai->component->name, "i2c-10EC1015:01")) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, - 0x0, 0x2, 4, 24); - if (ret < 0) { - dev_err(card->dev, "failed to set tdm slot\n"); - return ret; - } - } - } - } - - return 0; -} - -static struct snd_soc_ops sof_rt1015_ops = { - .hw_params = sof_rt1015_hw_params, -}; - static struct snd_soc_dai_link_component platform_component[] = { { /* name might be overridden during probe */ @@ -551,22 +489,11 @@ static const struct snd_soc_dapm_route sof_map[] = { { "IN1P", NULL, "Headset Mic" }, }; -static const struct snd_soc_dapm_route speaker_map_lr[] = { - { "Left Spk", NULL, "Left SPO" }, - { "Right Spk", NULL, "Right SPO" }, -}; - static const struct snd_soc_dapm_route dmic_map[] = { /* digital mics */ {"DMic", NULL, "SoC DMIC"}, }; -static int speaker_codec_init_lr(struct snd_soc_pcm_runtime *rtd) -{ - return snd_soc_dapm_add_routes(&rtd->card->dapm, speaker_map_lr, - ARRAY_SIZE(speaker_map_lr)); -} - static int dmic_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; @@ -589,17 +516,6 @@ static int dmic_init(struct snd_soc_pcm_runtime *rtd) return ret; } -static struct snd_soc_codec_conf rt1015_amp_conf[] = { - { - .dlc = COMP_CODEC_CONF("i2c-10EC1015:00"), - .name_prefix = "Left", - }, - { - .dlc = COMP_CODEC_CONF("i2c-10EC1015:01"), - .name_prefix = "Right", - }, -}; - /* sof audio machine driver for rt5682 codec */ static struct snd_soc_card sof_audio_card_rt5682 = { .name = "rt5682", /* the sof- prefix is added by the core */ @@ -635,17 +551,6 @@ static struct snd_soc_dai_link_component dmic_component[] = { } }; -static struct snd_soc_dai_link_component rt1015_components[] = { - { - .name = "i2c-10EC1015:00", - .dai_name = "rt1015-aif", - }, - { - .name = "i2c-10EC1015:01", - .dai_name = "rt1015-aif", - }, -}; - static struct snd_soc_dai_link_component dummy_component[] = { { .name = "snd-soc-dummy", @@ -798,10 +703,8 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].id = id; if (sof_rt5682_quirk & SOF_RT1015_SPEAKER_AMP_PRESENT) { - links[id].codecs = rt1015_components; - links[id].num_codecs = ARRAY_SIZE(rt1015_components); - links[id].init = speaker_codec_init_lr; - links[id].ops = &sof_rt1015_ops; + sof_rt1015_dai_link(&links[id], (sof_rt5682_quirk & + SOF_RT1015_SPEAKER_AMP_100FS) ? 100 : 64); } else if (sof_rt5682_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT) { sof_rt1015p_dai_link(&links[id]); } else if (sof_rt5682_quirk & @@ -995,10 +898,8 @@ static int sof_audio_probe(struct platform_device *pdev) sof_audio_card_rt5682.dai_link = dai_links; - if (sof_rt5682_quirk & SOF_RT1015_SPEAKER_AMP_PRESENT) { - sof_audio_card_rt5682.codec_conf = rt1015_amp_conf; - sof_audio_card_rt5682.num_configs = ARRAY_SIZE(rt1015_amp_conf); - } + if (sof_rt5682_quirk & SOF_RT1015_SPEAKER_AMP_PRESENT) + sof_rt1015_codec_conf(&sof_audio_card_rt5682); INIT_LIST_HEAD(&ctx->hdmi_pcm_list); From 6c7ac18cd82108a0cd58e21b9814503e631dbb5d Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Wed, 8 Dec 2021 18:16:54 +0800 Subject: [PATCH 157/327] ASoC: dt-bindings: rt5682s: add AMIC delay time property Add the AMIC delay time to control how much delay time (ms) to unmute the stereo1 ADC. Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20211208101654.28925-1-shumingf@realtek.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/realtek,rt5682s.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/realtek,rt5682s.yaml b/Documentation/devicetree/bindings/sound/realtek,rt5682s.yaml index 2b8b7b51fe550..d65c0ed5060cc 100644 --- a/Documentation/devicetree/bindings/sound/realtek,rt5682s.yaml +++ b/Documentation/devicetree/bindings/sound/realtek,rt5682s.yaml @@ -61,6 +61,10 @@ properties: description: | Set the delay time (ms) for the requirement of the particular DMIC. + realtek,amic-delay-ms: + description: | + Set the delay time (ms) for the requirement of the particular platform or AMIC. + realtek,dmic-clk-driving-high: type: boolean description: | From d9b994cd7641ad8eda97aa8633f4e2f35d7d0a79 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 7 Dec 2021 13:23:09 -0600 Subject: [PATCH 158/327] ASoC: AMD: acp-config: fix missing dependency on SND_SOC_ACPI With a custom .config, the following error is thrown: ERROR: modpost: "snd_soc_acpi_codec_list" [sound/soc/amd/snd-acp-config.ko] undefined! Fix by adding a clear dependency on SND_SOC_ACPI Reported-by: kernel test robot Signed-off-by: Pierre-Louis Bossart Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211207192309.43883-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/amd/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig index 8961b8fd23eb6..bcfeb3fc2592b 100644 --- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -98,6 +98,7 @@ config SND_SOC_AMD_YC_MACH config SND_AMD_ACP_CONFIG tristate "AMD ACP configuration selection" + depends on SND_SOC_ACPI help This option adds an auto detection to determine which ACP driver modules to use From 9abc21c966619d6ead27fd48481966014fdc680f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 8 Dec 2021 18:11:45 +0300 Subject: [PATCH 159/327] ASoC: mediatek: mt8195: silence uninitialized variable warning Smatch complains that we might hit the continue path on every iteration through the loop. sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c:831 mt8195_mt6359_rt1019_rt5682_card_late_probe() error: uninitialized symbol 'sof_comp'. Initialize "sof_comp" to NULL to silence this warning. Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/20211208151145.GA29257@kili Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c index b240610dcef09..11a185da0d964 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c @@ -813,7 +813,7 @@ static int mt8195_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, static int mt8195_mt6359_rt1019_rt5682_card_late_probe(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *runtime; - struct snd_soc_component *sof_comp; + struct snd_soc_component *sof_comp = NULL; int i; /* 1. find sof component */ From 62df22396bea321435153cdba37585ad8ff9c567 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 15 Sep 2021 19:09:57 +0100 Subject: [PATCH 160/327] ASoC: amd: Convert to new style DAI format definitions Convert the AMD machine drivers to use the new style defines for clocking in DAI formats. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20210915180957.39996-1-broonie@kernel.org Signed-off-by: Mark Brown --- sound/soc/amd/acp-da7219-max98357a.c | 20 ++++++++++---------- sound/soc/amd/acp-rt5645.c | 4 ++-- sound/soc/amd/acp3x-rt5682-max9836.c | 8 ++++---- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c index b2065f3fe42c3..3bf86c2424ae9 100644 --- a/sound/soc/amd/acp-da7219-max98357a.c +++ b/sound/soc/amd/acp-da7219-max98357a.c @@ -522,7 +522,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = { .name = "amd-da7219-play", .stream_name = "Playback", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, .init = cz_da7219_init, .dpcm_playback = 1, .stop_dma_first = 1, @@ -533,7 +533,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = { .name = "amd-da7219-cap", .stream_name = "Capture", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, .dpcm_capture = 1, .stop_dma_first = 1, .ops = &cz_da7219_cap_ops, @@ -543,7 +543,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = { .name = "amd-max98357-play", .stream_name = "HiFi Playback", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, .dpcm_playback = 1, .stop_dma_first = 1, .ops = &cz_max_play_ops, @@ -554,7 +554,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = { .name = "dmic0", .stream_name = "DMIC0 Capture", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, .dpcm_capture = 1, .stop_dma_first = 1, .ops = &cz_dmic0_cap_ops, @@ -565,7 +565,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = { .name = "dmic1", .stream_name = "DMIC1 Capture", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, .dpcm_capture = 1, .stop_dma_first = 1, .ops = &cz_dmic1_cap_ops, @@ -578,7 +578,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = { .name = "amd-rt5682-play", .stream_name = "Playback", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, .init = cz_rt5682_init, .dpcm_playback = 1, .stop_dma_first = 1, @@ -589,7 +589,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = { .name = "amd-rt5682-cap", .stream_name = "Capture", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, .dpcm_capture = 1, .stop_dma_first = 1, .ops = &cz_rt5682_cap_ops, @@ -599,7 +599,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = { .name = "amd-max98357-play", .stream_name = "HiFi Playback", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, .dpcm_playback = 1, .stop_dma_first = 1, .ops = &cz_rt5682_max_play_ops, @@ -610,7 +610,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = { .name = "dmic0", .stream_name = "DMIC0 Capture", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, .dpcm_capture = 1, .stop_dma_first = 1, .ops = &cz_rt5682_dmic0_cap_ops, @@ -621,7 +621,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = { .name = "dmic1", .stream_name = "DMIC1 Capture", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, .dpcm_capture = 1, .stop_dma_first = 1, .ops = &cz_rt5682_dmic1_cap_ops, diff --git a/sound/soc/amd/acp-rt5645.c b/sound/soc/amd/acp-rt5645.c index 6d5c547a32de9..a79a46646d501 100644 --- a/sound/soc/amd/acp-rt5645.c +++ b/sound/soc/amd/acp-rt5645.c @@ -111,7 +111,7 @@ static struct snd_soc_dai_link cz_dai_rt5650[] = { .name = "amd-rt5645-play", .stream_name = "RT5645_AIF1", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, .init = cz_init, .ops = &cz_aif1_ops, SND_SOC_DAILINK_REG(designware1, codec, platform), @@ -120,7 +120,7 @@ static struct snd_soc_dai_link cz_dai_rt5650[] = { .name = "amd-rt5645-cap", .stream_name = "RT5645_AIF1", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, .ops = &cz_aif1_ops, SND_SOC_DAILINK_REG(designware2, codec, platform), }, diff --git a/sound/soc/amd/acp3x-rt5682-max9836.c b/sound/soc/amd/acp3x-rt5682-max9836.c index e561464f7d603..dad70436d063b 100644 --- a/sound/soc/amd/acp3x-rt5682-max9836.c +++ b/sound/soc/amd/acp3x-rt5682-max9836.c @@ -51,7 +51,7 @@ static int acp3x_5682_init(struct snd_soc_pcm_runtime *rtd) /* set rt5682 dai fmt */ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM); + | SND_SOC_DAIFMT_CBP_CFP); if (ret < 0) { dev_err(rtd->card->dev, "Failed to set rt5682 dai fmt: %d\n", ret); @@ -302,7 +302,7 @@ static struct snd_soc_dai_link acp3x_dai[] = { .name = "acp3x-5682-play", .stream_name = "Playback", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, .init = acp3x_5682_init, .dpcm_playback = 1, .dpcm_capture = 1, @@ -313,7 +313,7 @@ static struct snd_soc_dai_link acp3x_dai[] = { .name = "acp3x-max98357-play", .stream_name = "HiFi Playback", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBS_CFS, + | SND_SOC_DAIFMT_CBC_CFC, .dpcm_playback = 1, .ops = &acp3x_max_play_ops, .cpus = acp3x_bt, @@ -325,7 +325,7 @@ static struct snd_soc_dai_link acp3x_dai[] = { .name = "acp3x-ec-dmic0-capture", .stream_name = "Capture DMIC0", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBS_CFS, + | SND_SOC_DAIFMT_CBC_CFC, .dpcm_capture = 1, .ops = &acp3x_ec_cap0_ops, SND_SOC_DAILINK_REG(acp3x_bt, cros_ec, platform), From 5f9155a7d2dc067d72a95b42168f944c7710c0d5 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 6 Dec 2021 16:46:24 +0100 Subject: [PATCH 161/327] ASoC: dt-bindings: tegra: Document interconnects property Add the interconnects and interconnect-names properties to the bindings for the sound card on various NVIDIA Tegra based boards. These are used to describe the device's memory paths to and from memory. Signed-off-by: Thierry Reding Acked-by: Rob Herring Link: https://lore.kernel.org/r/20211206154624.229018-1-thierry.reding@gmail.com Signed-off-by: Mark Brown --- .../bindings/sound/nvidia,tegra-audio-graph-card.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-graph-card.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-graph-card.yaml index 5bdd30a8a404e..b4bee466d67a2 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-graph-card.yaml +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-graph-card.yaml @@ -44,6 +44,16 @@ properties: minItems: 1 maxItems: 3 + interconnects: + items: + - description: APE read memory client + - description: APE write memory client + + interconnect-names: + items: + - const: dma-mem # read + - const: write + iommus: maxItems: 1 From befe304536eeef71f8529ff877444ae2b72a37db Mon Sep 17 00:00:00 2001 From: Ameer Hamza Date: Tue, 7 Dec 2021 19:23:09 +0500 Subject: [PATCH 162/327] ASoC: test-component: fix null pointer dereference. Dereferncing of_id pointer will result in exception in current implementation since of_match_device() will assign it to NULL. Adding NULL check for protection. Signed-off-by: Ameer Hamza Link: https://lore.kernel.org/r/20211207142309.222820-1-amhamza.mgc@gmail.com Signed-off-by: Mark Brown --- sound/soc/generic/test-component.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/sound/soc/generic/test-component.c b/sound/soc/generic/test-component.c index 8fc97d3ff0110..5da4725d9e16c 100644 --- a/sound/soc/generic/test-component.c +++ b/sound/soc/generic/test-component.c @@ -531,17 +531,13 @@ static int test_driver_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; struct device_node *ep; - const struct of_device_id *of_id = of_match_device(test_of_match, &pdev->dev); - const struct test_adata *adata; + const struct test_adata *adata = of_device_get_match_data(&pdev->dev); struct snd_soc_component_driver *cdriv; struct snd_soc_dai_driver *ddriv; struct test_dai_name *dname; struct test_priv *priv; int num, ret, i; - if (!of_id) - return -EINVAL; - adata = of_id->data; num = of_graph_get_endpoint_count(node); if (!num) { dev_err(dev, "no port exits\n"); @@ -552,7 +548,7 @@ static int test_driver_probe(struct platform_device *pdev) cdriv = devm_kzalloc(dev, sizeof(*cdriv), GFP_KERNEL); ddriv = devm_kzalloc(dev, sizeof(*ddriv) * num, GFP_KERNEL); dname = devm_kzalloc(dev, sizeof(*dname) * num, GFP_KERNEL); - if (!priv || !cdriv || !ddriv || !dname) + if (!priv || !cdriv || !ddriv || !dname || !adata) return -EINVAL; priv->dev = dev; From c697ef868f596aba7a5e90be8eb10bf4d4a98990 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 7 Dec 2021 13:39:41 -0600 Subject: [PATCH 163/327] ASoC: SOF: Intel: ICL: move ICL-specific ops to icl.c Move the ICL specific ops to icl.c. Also introduce a macro ICL_DSP_HPRO_CORE_ID to define the core that should be powered up when HPRO is enabled. Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20211207193947.71080-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-loader.c | 64 ------------------------------ sound/soc/sof/intel/hda.h | 2 - sound/soc/sof/intel/icl.c | 67 +++++++++++++++++++++++++++++++- 3 files changed, 65 insertions(+), 68 deletions(-) diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 40201e5ac201e..bfb0e374ebab6 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -481,49 +481,6 @@ int hda_dsp_post_fw_run(struct snd_sof_dev *sdev) return hda_dsp_ctrl_clock_power_gating(sdev, true); } -/* - * post fw run operations for ICL, - * Core 3 will be powered up and in stall when HPRO is enabled - */ -int hda_dsp_post_fw_run_icl(struct snd_sof_dev *sdev) -{ - struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; - int ret; - - if (sdev->first_boot) { - ret = hda_sdw_startup(sdev); - if (ret < 0) { - dev_err(sdev->dev, - "error: could not startup SoundWire links\n"); - return ret; - } - } - - hda_sdw_int_enable(sdev, true); - - /* - * The recommended HW programming sequence for ICL is to - * power up core 3 and keep it in stall if HPRO is enabled. - * Major difference between ICL and TGL, on ICL core 3 is managed by - * the host whereas on TGL it is handled by the firmware. - */ - if (!hda->clk_config_lpro) { - ret = hda_dsp_enable_core(sdev, BIT(3)); - if (ret < 0) { - dev_err(sdev->dev, "error: dsp core power up failed on core 3\n"); - return ret; - } - - sdev->enabled_cores_mask |= BIT(3); - sdev->dsp_core_ref_count[3]++; - - snd_sof_dsp_stall(sdev, BIT(3)); - } - - /* re-enable clock gating and power gating */ - return hda_dsp_ctrl_clock_power_gating(sdev, true); -} - int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev, const struct sof_ext_man_elem_header *hdr) { @@ -561,24 +518,3 @@ int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev, return 0; } - -int hda_dsp_core_stall_icl(struct snd_sof_dev *sdev, unsigned int core_mask) -{ - struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; - const struct sof_intel_dsp_desc *chip = hda->desc; - - /* make sure core_mask in host managed cores */ - core_mask &= chip->host_managed_cores_mask; - if (!core_mask) { - dev_err(sdev->dev, "error: core_mask is not in host managed cores\n"); - return -EINVAL; - } - - /* stall core */ - snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, - HDA_DSP_REG_ADSPCS, - HDA_DSP_ADSPCS_CSTALL_MASK(core_mask), - HDA_DSP_ADSPCS_CSTALL_MASK(core_mask)); - - return 0; -} diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 72e78c449aa82..e2055b6c81398 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -618,8 +618,6 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev); /* pre and post fw run ops */ int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev); int hda_dsp_post_fw_run(struct snd_sof_dev *sdev); -int hda_dsp_post_fw_run_icl(struct snd_sof_dev *sdev); -int hda_dsp_core_stall_icl(struct snd_sof_dev *sdev, unsigned int core_mask); /* parse platform specific ext manifest ops */ int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c index 343c1af7c4532..f75e3983969f2 100644 --- a/sound/soc/sof/intel/icl.c +++ b/sound/soc/sof/intel/icl.c @@ -18,12 +18,75 @@ #include "hda-ipc.h" #include "../sof-audio.h" +#define ICL_DSP_HPRO_CORE_ID 3 + static const struct snd_sof_debugfs_map icl_dsp_debugfs[] = { {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS}, {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS}, {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS}, }; +static int icl_dsp_core_stall(struct snd_sof_dev *sdev, unsigned int core_mask) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; + + /* make sure core_mask in host managed cores */ + core_mask &= chip->host_managed_cores_mask; + if (!core_mask) { + dev_err(sdev->dev, "error: core_mask is not in host managed cores\n"); + return -EINVAL; + } + + /* stall core */ + snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS, + HDA_DSP_ADSPCS_CSTALL_MASK(core_mask), + HDA_DSP_ADSPCS_CSTALL_MASK(core_mask)); + + return 0; +} + +/* + * post fw run operation for ICL. + * Core 3 will be powered up and in stall when HPRO is enabled + */ +static int icl_dsp_post_fw_run(struct snd_sof_dev *sdev) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + int ret; + + if (sdev->first_boot) { + ret = hda_sdw_startup(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: could not startup SoundWire links\n"); + return ret; + } + } + + hda_sdw_int_enable(sdev, true); + + /* + * The recommended HW programming sequence for ICL is to + * power up core 3 and keep it in stall if HPRO is enabled. + */ + if (!hda->clk_config_lpro) { + ret = hda_dsp_enable_core(sdev, BIT(ICL_DSP_HPRO_CORE_ID)); + if (ret < 0) { + dev_err(sdev->dev, "error: dsp core power up failed on core %d\n", + ICL_DSP_HPRO_CORE_ID); + return ret; + } + + sdev->enabled_cores_mask |= BIT(ICL_DSP_HPRO_CORE_ID); + sdev->dsp_core_ref_count[ICL_DSP_HPRO_CORE_ID]++; + + snd_sof_dsp_stall(sdev, BIT(ICL_DSP_HPRO_CORE_ID)); + } + + /* re-enable clock gating and power gating */ + return hda_dsp_ctrl_clock_power_gating(sdev, true); +} + /* Icelake ops */ const struct snd_sof_dsp_ops sof_icl_ops = { /* probe/remove/shutdown */ @@ -93,7 +156,7 @@ const struct snd_sof_dsp_ops sof_icl_ops = { /* pre/post fw run */ .pre_fw_run = hda_dsp_pre_fw_run, - .post_fw_run = hda_dsp_post_fw_run_icl, + .post_fw_run = icl_dsp_post_fw_run, /* parse platform specific extended manifest */ .parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data, @@ -103,7 +166,7 @@ const struct snd_sof_dsp_ops sof_icl_ops = { /* firmware run */ .run = hda_dsp_cl_boot_firmware_iccmax, - .stall = hda_dsp_core_stall_icl, + .stall = icl_dsp_core_stall, /* trace callback */ .trace_init = hda_dsp_trace_init, From a792bfc1c2bc4b5e2311edc62e0efe5adec5d079 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 7 Dec 2021 13:39:42 -0600 Subject: [PATCH 164/327] ASoC: SOF: Intel: hda-stream: limit PROCEN workaround MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The work-around enabled in hda-stream.c is only required on earlier versions of SOCs/PCH (Skylake, KabyLake, ApolloLake, GeminiLake). Before setting the format on the host DMA, it is required to couple the host and link DMA - which as a consequence shall use the same format. This patch introduces a quirk field in the platform descriptor and makes the work-around conditional. Newer platforms have no limitations on the use of host and link DMA, which can use different formats. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Péter Ujfalusi Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20211207193947.71080-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/apl.c | 1 + sound/soc/sof/intel/hda-stream.c | 18 ++++++++++++------ sound/soc/sof/intel/shim.h | 4 ++++ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 8778f46f1d37f..810b8b6748a0e 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -147,5 +147,6 @@ const struct sof_intel_dsp_desc apl_chip_info = { .rom_init_timeout = 150, .ssp_count = APL_SSP_COUNT, .ssp_base_offset = APL_SSP_BASE_OFFSET, + .quirks = SOF_INTEL_PROCEN_FMT_QUIRK, }; EXPORT_SYMBOL_NS(apl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 440827ce390dc..5f9eb5bdcdba2 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -472,6 +472,7 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, struct snd_pcm_hw_params *params) { + const struct sof_intel_dsp_desc *chip = get_chip_info(sdev->pdata); struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_stream *hstream = &stream->hstream; int sd_offset = SOF_STREAM_SD_OFFSET(hstream); @@ -584,6 +585,7 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, /* * Recommended hardware programming sequence for HDAudio DMA format + * on earlier platforms - this is not needed on newer platforms * * 1. Put DMA into coupled mode by clearing PPCTL.PROCEN bit * for corresponding stream index before the time of writing @@ -593,9 +595,11 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, * enable decoupled mode */ - /* couple host and link DMA, disable DSP features */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, - mask, 0); + if (chip->quirks & SOF_INTEL_PROCEN_FMT_QUIRK) { + /* couple host and link DMA, disable DSP features */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, + mask, 0); + } /* program stream format */ snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, @@ -603,9 +607,11 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, SOF_HDA_ADSP_REG_CL_SD_FORMAT, 0xffff, hstream->format_val); - /* decouple host and link DMA, enable DSP features */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, - mask, mask); + if (chip->quirks & SOF_INTEL_PROCEN_FMT_QUIRK) { + /* decouple host and link DMA, enable DSP features */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, + mask, mask); + } /* program last valid index */ snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h index 08c53cb41ea7d..f36cd9d5eb946 100644 --- a/sound/soc/sof/intel/shim.h +++ b/sound/soc/sof/intel/shim.h @@ -151,6 +151,9 @@ #define PCI_PMCS 0x84 #define PCI_PMCS_PS_MASK 0x3 +/* Intel quirks */ +#define SOF_INTEL_PROCEN_FMT_QUIRK BIT(0) + /* DSP hardware descriptor */ struct sof_intel_dsp_desc { int cores_num; @@ -166,6 +169,7 @@ struct sof_intel_dsp_desc { int ssp_base_offset; /* base address of the SSPs */ u32 sdw_shim_base; u32 sdw_alh_base; + u32 quirks; bool (*check_sdw_irq)(struct snd_sof_dev *sdev); }; From 12ce213821b77242b2217d08850ff972e1fb50bb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 7 Dec 2021 13:39:43 -0600 Subject: [PATCH 165/327] ASoC: SOF: Intel: hda-ctrl: apply symmetry for DPIB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit we use 'bus->use_posbuf && bus->posbuf.addr' in hda_dsp_ctrl_init_chip(), use the same for hda_dsp_ctrl_stop_chip() Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Péter Ujfalusi Link: https://lore.kernel.org/r/20211207193947.71080-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-ctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index fa5f0a7189017..0c29bb196e593 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -353,7 +353,7 @@ void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev) snd_hdac_bus_stop_cmd_io(bus); #endif /* disable position buffer */ - if (bus->posbuf.addr) { + if (bus->use_posbuf && bus->posbuf.addr) { snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPLBASE, 0); snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, From ae81d8fd57ff7d2b421c80f0f9426d9e775023b5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 7 Dec 2021 13:39:44 -0600 Subject: [PATCH 166/327] ASoC: SOF: hda-stream: only enable DPIB if needed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The existing code is inconsistent, we should only enable DPIB if the 'use_posbuf' field is true. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Péter Ujfalusi Link: https://lore.kernel.org/r/20211207193947.71080-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-stream.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 5f9eb5bdcdba2..e910f68706d9a 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -626,9 +626,10 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, upper_32_bits(hstream->bdl.addr)); - /* enable position buffer */ - if (!(snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPLBASE) - & SOF_HDA_ADSP_DPLBASE_ENABLE)) { + /* enable position buffer, if needed */ + if (bus->use_posbuf && bus->posbuf.addr && + !(snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPLBASE) + & SOF_HDA_ADSP_DPLBASE_ENABLE)) { snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPUBASE, upper_32_bits(bus->posbuf.addr)); snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPLBASE, From 288fad2f71fa0b989c075d4984879c26d47cfb06 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 7 Dec 2021 13:39:45 -0600 Subject: [PATCH 167/327] ASoC: SOF: Intel: hda: add quirks for HDAudio DMA position information MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code inherited from the Skylake driver does not seem to follow any known hardware recommendations. The only two recommended options are a) use DPIB registers if VC1 traffic is not allowed b) use DPIB DDR update if VC1 traffic is used In all of SOF-based updated, VC1 is not supported so we can 'safely' move to using DPIB registers only. This patch keeps the legacy code, in case there was an undocumented issue lost to history, and adds the DPIB DDR update for additional debug. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Péter Ujfalusi Link: https://lore.kernel.org/r/20211207193947.71080-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-pcm.c | 86 +++++++++++++++++++++++++---------- sound/soc/sof/intel/hda.c | 9 +++- sound/soc/sof/intel/hda.h | 6 +++ 3 files changed, 75 insertions(+), 26 deletions(-) diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index 974383cd04407..d78aa5d8552d5 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -202,38 +202,74 @@ snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev, goto found; } - /* - * DPIB/posbuf position mode: - * For Playback, Use DPIB register from HDA space which - * reflects the actual data transferred. - * For Capture, Use the position buffer for pointer, as DPIB - * is not accurate enough, its update may be completed - * earlier than the data written to DDR. - */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + switch (sof_hda_position_quirk) { + case SOF_HDA_POSITION_QUIRK_USE_SKYLAKE_LEGACY: + /* + * This legacy code, inherited from the Skylake driver, + * mixes DPIB registers and DPIB DDR updates and + * does not seem to follow any known hardware recommendations. + * It's not clear e.g. why there is a different flow + * for capture and playback, the only information that matters is + * what traffic class is used, and on all SOF-enabled platforms + * only VC0 is supported so the work-around was likely not necessary + * and quite possibly wrong. + */ + + /* DPIB/posbuf position mode: + * For Playback, Use DPIB register from HDA space which + * reflects the actual data transferred. + * For Capture, Use the position buffer for pointer, as DPIB + * is not accurate enough, its update may be completed + * earlier than the data written to DDR. + */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + pos = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, + AZX_REG_VS_SDXDPIB_XBASE + + (AZX_REG_VS_SDXDPIB_XINTERVAL * + hstream->index)); + } else { + /* + * For capture stream, we need more workaround to fix the + * position incorrect issue: + * + * 1. Wait at least 20us before reading position buffer after + * the interrupt generated(IOC), to make sure position update + * happens on frame boundary i.e. 20.833uSec for 48KHz. + * 2. Perform a dummy Read to DPIB register to flush DMA + * position value. + * 3. Read the DMA Position from posbuf. Now the readback + * value should be >= period boundary. + */ + usleep_range(20, 21); + snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, + AZX_REG_VS_SDXDPIB_XBASE + + (AZX_REG_VS_SDXDPIB_XINTERVAL * + hstream->index)); + pos = snd_hdac_stream_get_pos_posbuf(hstream); + } + break; + case SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS: + /* + * In case VC1 traffic is disabled this is the recommended option + */ pos = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, AZX_REG_VS_SDXDPIB_XBASE + (AZX_REG_VS_SDXDPIB_XINTERVAL * hstream->index)); - } else { + break; + case SOF_HDA_POSITION_QUIRK_USE_DPIB_DDR_UPDATE: /* - * For capture stream, we need more workaround to fix the - * position incorrect issue: - * - * 1. Wait at least 20us before reading position buffer after - * the interrupt generated(IOC), to make sure position update - * happens on frame boundary i.e. 20.833uSec for 48KHz. - * 2. Perform a dummy Read to DPIB register to flush DMA - * position value. - * 3. Read the DMA Position from posbuf. Now the readback - * value should be >= period boundary. + * This is the recommended option when VC1 is enabled. + * While this isn't needed for SOF platforms it's added for + * consistency and debug. */ - usleep_range(20, 21); - snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, - AZX_REG_VS_SDXDPIB_XBASE + - (AZX_REG_VS_SDXDPIB_XINTERVAL * - hstream->index)); pos = snd_hdac_stream_get_pos_posbuf(hstream); + break; + default: + dev_err_once(sdev->dev, "hda_position_quirk value %d not supported\n", + sof_hda_position_quirk); + pos = 0; + break; } if (pos >= hstream->bufsize) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index cfe026dbf1242..dabbd5d908f64 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -432,6 +432,10 @@ MODULE_PARM_DESC(use_msi, "SOF HDA use PCI MSI mode"); #define hda_use_msi (1) #endif +int sof_hda_position_quirk = SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS; +module_param_named(position_quirk, sof_hda_position_quirk, int, 0444); +MODULE_PARM_DESC(position_quirk, "SOF HDaudio position quirk"); + static char *hda_model; module_param(hda_model, charp, 0444); MODULE_PARM_DESC(hda_model, "Use the given HDA board model."); @@ -610,7 +614,10 @@ static int hda_init(struct snd_sof_dev *sdev) /* HDA bus init */ sof_hda_bus_init(bus, &pci->dev); - bus->use_posbuf = 1; + if (sof_hda_position_quirk == SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS) + bus->use_posbuf = 0; + else + bus->use_posbuf = 1; bus->bdl_pos_adj = 0; bus->sync_write = 1; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index e2055b6c81398..cb71d9d5cf6c4 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -740,4 +740,10 @@ struct sof_ipc_dai_config; int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w, unsigned int quirk_flags); int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w, unsigned int quirk_flags); +#define SOF_HDA_POSITION_QUIRK_USE_SKYLAKE_LEGACY (0) /* previous implementation */ +#define SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS (1) /* recommended if VC0 only */ +#define SOF_HDA_POSITION_QUIRK_USE_DPIB_DDR_UPDATE (2) /* recommended with VC0 or VC1 */ + +extern int sof_hda_position_quirk; + #endif From 924631df4134d62b51a9442d97355eeba7ff613c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 7 Dec 2021 13:39:46 -0600 Subject: [PATCH 168/327] ASoC: SOF: Intel: hda-dai: remove unused fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The existing code does not use the 'host_dma_id', 'link_dma_id', 'host_bps' fields remove them. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Kai Vehmanen Reviewed-by: Péter Ujfalusi Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20211207193947.71080-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dai.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 8c1d7ddb00e2e..35ffb71116c69 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -21,8 +21,6 @@ #endif struct hda_pipe_params { - u8 host_dma_id; - u8 link_dma_id; u32 ch; u32 s_freq; u32 s_fmt; @@ -30,7 +28,6 @@ struct hda_pipe_params { snd_pcm_format_t format; int link_index; int stream; - unsigned int host_bps; unsigned int link_bps; }; @@ -256,7 +253,6 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream, p_params.ch = params_channels(params); p_params.s_freq = params_rate(params); p_params.stream = substream->stream; - p_params.link_dma_id = stream_tag - 1; p_params.link_index = link->index; p_params.format = params_format(params); From 290a7c5509b6f14c28e959392f3cbc4d5b2c9318 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 7 Dec 2021 13:39:47 -0600 Subject: [PATCH 169/327] ASoC: SOF: Intel: add comment on JasperLake support Explain why JasperLake is exposed in cnl.c instead of icl.c No functionality change. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Kai Vehmanen Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20211207193947.71080-8-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/cnl.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 04daaa6100f12..3da158d08980a 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -358,6 +358,13 @@ const struct sof_intel_dsp_desc cnl_chip_info = { }; EXPORT_SYMBOL_NS(cnl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); +/* + * JasperLake is technically derived from IceLake, and should be in + * described in icl.c. However since JasperLake was designed with + * two cores, it cannot support the IceLake-specific power-up sequences + * which rely on core3. To simplify, JasperLake uses the CannonLake ops and + * is described in cnl.c + */ const struct sof_intel_dsp_desc jsl_chip_info = { /* Jasperlake */ .cores_num = 2, From c55676ec292e0ff83261eb61efaf99a91079a3b8 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Thu, 2 Dec 2021 15:55:01 +0100 Subject: [PATCH 170/327] ASoC: dt-bindings: qcom: sm8250: Drop redundant MultiMedia routes The MultiMedia audio routes can be deduced from other parts of the device tree (e.g. the definitions of the MultiMedia DAIs) and therefore specifying them again in "audio-routing" is redundant and prone to mistakes. This is no longer necessary since commit 6fd8d2d275f7 ("ASoC: qcom: qdsp6: Move frontend AIFs to q6asm-dai"). Let's drop them from the example in the DT schema as well to avoid confusion. Cc: Srinivas Kandagatla Signed-off-by: Stephan Gerhold Acked-by: Rob Herring Link: https://lore.kernel.org/r/20211202145505.58852-2-stephan@gerhold.net Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/qcom,sm8250.yaml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index 7d57eb91657a7..a0f1d7340eb53 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -86,10 +86,7 @@ examples: audio-routing = "SpkrLeft IN", "WSA_SPK1 OUT", "SpkrRight IN", "WSA_SPK2 OUT", "VA DMIC0", "vdd-micb", - "VA DMIC1", "vdd-micb", - "MM_DL1", "MultiMedia1 Playback", - "MM_DL2", "MultiMedia2 Playback", - "MultiMedia3 Capture", "MM_UL3"; + "VA DMIC1", "vdd-micb"; mm1-dai-link { link-name = "MultiMedia0"; From 1875ae76f82c5c9acd7b7f44bd9226fbcbe858b7 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Thu, 2 Dec 2021 15:55:02 +0100 Subject: [PATCH 171/327] ASoC: dt-bindings: qcom: sm8250: Document "aux-devs" The sm8250 audio driver uses the common Qualcomm device tree parser and therefore already supports the "aux-devs" property that allows adding additional auxiliary devices to the sound card (e.g. analog speaker amplifiers that can be connected using "audio-routing"). Document the property in the DT schema for sm8250 as well. The description is taken from simple-card.yaml which has a very similar property. Cc: Srinivas Kandagatla Signed-off-by: Stephan Gerhold Acked-by: Rob Herring Link: https://lore.kernel.org/r/20211202145505.58852-3-stephan@gerhold.net Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/qcom,sm8250.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index a0f1d7340eb53..3123382297b8b 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -27,6 +27,12 @@ properties: being the connection's source. Valid names could be power supplies, MicBias of codec and the jacks on the board. + aux-devs: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: | + List of phandles pointing to auxiliary devices, such + as amplifiers, to be added to the sound card. + model: $ref: /schemas/types.yaml#/definitions/string description: User visible long sound card name From b7875d88bf70100d2fe0dc08072018f994ccd6c4 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Thu, 2 Dec 2021 15:55:03 +0100 Subject: [PATCH 172/327] ASoC: dt-bindings: qcom: apq8016-sbc: Move to qcom,sm8250 DT schema All the Qualcomm sound card drivers use the same common device tree parsing code, so the allowed device tree nodes are almost the same for all of them. Convert the qcom,apq8016-sbc-sndcard documentation to a DT schema by adding it to the existing qcom,sm8250 schema. The only speciality of qcom,apq8016-sbc-sndcard is that it has memory resources for setting up an I/O mux. This can be handled using a conditional if statement that only requires it for the apq8016-sbc compatible. Cc: Srinivas Kandagatla Signed-off-by: Stephan Gerhold Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20211202145505.58852-4-stephan@gerhold.net Signed-off-by: Mark Brown --- .../bindings/sound/qcom,apq8016-sbc.txt | 96 ------------------- .../bindings/sound/qcom,sm8250.yaml | 83 +++++++++++++++- 2 files changed, 81 insertions(+), 98 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt diff --git a/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt b/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt deleted file mode 100644 index 23998262a0a7c..0000000000000 --- a/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt +++ /dev/null @@ -1,96 +0,0 @@ -* Qualcomm Technologies APQ8016 SBC ASoC machine driver - -This node models the Qualcomm Technologies APQ8016 SBC ASoC machine driver - -Required properties: - -- compatible : "qcom,apq8016-sbc-sndcard" - -- pinctrl-N : One property must exist for each entry in - pinctrl-names. See ../pinctrl/pinctrl-bindings.txt - for details of the property values. -- pinctrl-names : Must contain a "default" entry. -- reg : Must contain an address for each entry in reg-names. -- reg-names : A list which must include the following entries: - * "mic-iomux" - * "spkr-iomux" -- qcom,model : Name of the sound card. - -- qcom,audio-routing : A list of the connections between audio components. - Each entry is a pair of strings, the first being the - connection's sink, the second being the connection's - source. Valid names could be power supplies, MicBias - of msm8x16_wcd codec and the jacks on the board: - - Power supplies: - * MIC BIAS External1 - * MIC BIAS External2 - * MIC BIAS Internal1 - * MIC BIAS Internal2 - - Board connectors: - * Headset Mic - * Secondary Mic - * DMIC - * Ext Spk - -Optional properties: - -- aux-devs : A list of phandles for auxiliary devices (e.g. analog - amplifiers) that do not appear directly within the DAI - links. Should be connected to another audio component - using "qcom,audio-routing". - -Dai-link subnode properties and subnodes: - -Required dai-link subnodes: - -- cpu : CPU sub-node -- codec : CODEC sub-node - -Required CPU/CODEC subnodes properties: - --link-name : Name of the dai link. --sound-dai : phandle/s and port of CPU/CODEC - -Example: - -sound: sound { - compatible = "qcom,apq8016-sbc-sndcard"; - reg = <0x07702000 0x4>, <0x07702004 0x4>; - reg-names = "mic-iomux", "spkr-iomux"; - qcom,model = "DB410c"; - - qcom,audio-routing = - "MIC BIAS External1", "Handset Mic", - "MIC BIAS Internal2", "Headset Mic", - "MIC BIAS External1", "Secondary Mic", - "AMIC1", "MIC BIAS External1", - "AMIC2", "MIC BIAS Internal2", - "AMIC3", "MIC BIAS External1", - "DMIC1", "MIC BIAS Internal1", - "MIC BIAS Internal1", "Digital Mic1", - "DMIC2", "MIC BIAS Internal1", - "MIC BIAS Internal1", "Digital Mic2"; - - /* I2S - Internal codec */ - internal-dai-link@0 { - cpu { /* PRIMARY */ - sound-dai = <&lpass MI2S_PRIMARY>; - }; - codec { - sound-dai = <&lpass_codec 0>, <&wcd_codec 0>; - }; - }; - - /* External Primary or External Secondary -ADV7533 HDMI */ - external-dai-link@0 { - link-name = "ADV7533"; - cpu { /* QUAT */ - sound-dai = <&lpass MI2S_QUATERNARY>; - }; - codec { - sound-dai = <&adv_bridge 0>; - }; - }; -}; diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index 3123382297b8b..97f13a0a71a9b 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -4,18 +4,19 @@ $id: http://devicetree.org/schemas/sound/qcom,sm8250.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Qualcomm Technologies Inc. SM8250 ASoC sound card driver +title: Qualcomm Technologies Inc. ASoC sound card drivers maintainers: - Srinivas Kandagatla description: - This bindings describes SC8250 SoC based sound cards + This bindings describes Qualcomm SoC based sound cards which uses LPASS internal codec for audio. properties: compatible: enum: + - qcom,apq8016-sbc-sndcard - qcom,sm8250-sndcard - qcom,qrb5165-rb5-sndcard @@ -37,6 +38,10 @@ properties: $ref: /schemas/types.yaml#/definitions/string description: User visible long sound card name + # Only valid for some compatibles (see allOf if below) + reg: true + reg-names: true + patternProperties: ".*-dai-link$": description: @@ -79,6 +84,33 @@ required: - compatible - model +allOf: + - if: + properties: + compatible: + contains: + enum: + - qcom,apq8016-sbc-sndcard + then: + properties: + reg: + items: + - description: Microphone I/O mux register address + - description: Speaker I/O mux register address + reg-names: + items: + - const: mic-iomux + - const: spkr-iomux + required: + - compatible + - model + - reg + - reg-names + else: + properties: + reg: false + reg-names: false + additionalProperties: false examples: @@ -160,3 +192,50 @@ examples: }; }; }; + + - | + #include + sound@7702000 { + compatible = "qcom,apq8016-sbc-sndcard"; + reg = <0x07702000 0x4>, <0x07702004 0x4>; + reg-names = "mic-iomux", "spkr-iomux"; + + model = "DB410c"; + audio-routing = + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS External1"; + + pinctrl-0 = <&cdc_pdm_lines_act &ext_sec_tlmm_lines_act &ext_mclk_tlmm_lines_act>; + pinctrl-1 = <&cdc_pdm_lines_sus &ext_sec_tlmm_lines_sus &ext_mclk_tlmm_lines_sus>; + pinctrl-names = "default", "sleep"; + + quaternary-dai-link { + link-name = "ADV7533"; + cpu { + sound-dai = <&lpass MI2S_QUATERNARY>; + }; + codec { + sound-dai = <&adv_bridge 0>; + }; + }; + + primary-dai-link { + link-name = "WCD"; + cpu { + sound-dai = <&lpass MI2S_PRIMARY>; + }; + codec { + sound-dai = <&lpass_codec 0>, <&wcd_codec 0>; + }; + }; + + tertiary-dai-link { + link-name = "WCD-Capture"; + cpu { + sound-dai = <&lpass MI2S_TERTIARY>; + }; + codec { + sound-dai = <&lpass_codec 1>, <&wcd_codec 1>; + }; + }; + }; From 38192dc36f1fe1615b7a12cc78b9354d6b4ba8b7 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Thu, 2 Dec 2021 15:55:04 +0100 Subject: [PATCH 173/327] ASoC: dt-bindings: qcom: Document qcom,msm8916-qdsp6-sndcard compatible There are two possible audio setups on MSM8916/APQ8016: Normally the audio is routed through the audio/modem DSP (covered by the qdsp6 driver). During upstreaming for the DragonBoard 410c it was decided to bypass it and instead talk directly to the audio controller using the "lpass" driver. Bypassing the DSP gives more control about the audio configuration but limits the functionality: For example, routing audio through the audio/modem DSP is strictly required for voice call audio. Also, without the special changes in the DB410c firmware other MSM8916 devices can only use the bypass as long as the modem DSP is not started. Otherwise, the firmware will assume control of the LPASS hardware block and audio is no longer functional. Add support for using the DSP audio setup instead using a new "qcom,msm8916-qdsp6-sndcard" compatible. It is basically a mixture of the apq8016-sbc-sndcard and the newer sm8250-sndcard, which uses indirect QDSP6 DAI links instead of the direct LPASS DAI links. Cc: Srinivas Kandagatla Signed-off-by: Stephan Gerhold Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20211202145505.58852-5-stephan@gerhold.net Signed-off-by: Mark Brown --- .../bindings/sound/qcom,sm8250.yaml | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index 97f13a0a71a9b..e50964c54bb91 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -17,6 +17,7 @@ properties: compatible: enum: - qcom,apq8016-sbc-sndcard + - qcom,msm8916-qdsp6-sndcard - qcom,sm8250-sndcard - qcom,qrb5165-rb5-sndcard @@ -91,6 +92,7 @@ allOf: contains: enum: - qcom,apq8016-sbc-sndcard + - qcom,msm8916-qdsp6-sndcard then: properties: reg: @@ -239,3 +241,43 @@ examples: }; }; }; + + - | + #include + #include + sound@7702000 { + compatible = "qcom,msm8916-qdsp6-sndcard"; + reg = <0x07702000 0x4>, <0x07702004 0x4>; + reg-names = "mic-iomux", "spkr-iomux"; + + model = "msm8916"; + audio-routing = + "AMIC1", "MIC BIAS Internal1", + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS Internal3"; + aux-devs = <&speaker_amp>; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&cdc_pdm_lines_act>; + pinctrl-1 = <&cdc_pdm_lines_sus>; + + mm1-dai-link { + link-name = "MultiMedia1"; + cpu { + sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA1>; + }; + }; + + primary-dai-link { + link-name = "Primary MI2S"; + cpu { + sound-dai = <&q6afedai PRIMARY_MI2S_RX>; + }; + platform { + sound-dai = <&q6routing>; + }; + codec { + sound-dai = <&lpass_codec 0>, <&wcd_codec 0>; + }; + }; + }; From a78a42fb48b8f261ab122c929f78c272ffc26d1b Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Thu, 2 Dec 2021 15:55:05 +0100 Subject: [PATCH 174/327] ASoC: qcom: apq8016_sbc: Allow routing audio through QDSP6 The apq8016-sbc-sndcard is designed to be used with the LPASS drivers (bypassing the combined audio/modem DSP in MSM8916/APQ8016). Make it possible to use QDSP6 audio instead for the msm8916-qdsp6-sndcard. This only requires adding some additional hooks that set up the DPCM backends correctly. Similar code is already used in drivers for newer SoCs such as apq8096.c, sdm845.c and sm8250.c. A slightly different initialization sequence is used for the apq8016-sbc and msm8916-qdsp6 sound card by defining the apq8016_sbc_add_ops() function as device match data. Cc: Srinivas Kandagatla Signed-off-by: Stephan Gerhold Reviewed-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20211202145505.58852-6-stephan@gerhold.net Signed-off-by: Mark Brown --- sound/soc/qcom/apq8016_sbc.c | 134 +++++++++++++++++++++++++++++++++-- 1 file changed, 129 insertions(+), 5 deletions(-) diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c index ba2a98268ee4f..f9d69375320e7 100644 --- a/sound/soc/qcom/apq8016_sbc.c +++ b/sound/soc/qcom/apq8016_sbc.c @@ -17,6 +17,9 @@ #include #include #include "common.h" +#include "qdsp6/q6afe.h" + +#define MI2S_COUNT (MI2S_QUATERNARY + 1) struct apq8016_sbc_data { struct snd_soc_card card; @@ -24,6 +27,7 @@ struct apq8016_sbc_data { void __iomem *spkr_iomux; struct snd_soc_jack jack; bool jack_setup; + int mi2s_clk_count[MI2S_COUNT]; }; #define MIC_CTRL_TER_WS_SLAVE_SEL BIT(21) @@ -38,10 +42,10 @@ struct apq8016_sbc_data { #define SPKR_CTL_TLMM_WS_EN_SEL_MASK GENMASK(19, 18) #define SPKR_CTL_TLMM_WS_EN_SEL_SEC BIT(18) #define DEFAULT_MCLK_RATE 9600000 +#define MI2S_BCLK_RATE 1536000 -static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd) +static int apq8016_dai_init(struct snd_soc_pcm_runtime *rtd, int mi2s) { - struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); struct snd_soc_dai *codec_dai; struct snd_soc_component *component; struct snd_soc_card *card = rtd->card; @@ -49,7 +53,7 @@ static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd) int i, rval; u32 value; - switch (cpu_dai->id) { + switch (mi2s) { case MI2S_PRIMARY: writel(readl(pdata->spkr_iomux) | SPKR_CTL_PRI_WS_SLAVE_SEL_11, pdata->spkr_iomux); @@ -128,6 +132,13 @@ static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd) return 0; } +static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + + return apq8016_dai_init(rtd, cpu_dai->id); +} + static void apq8016_sbc_add_ops(struct snd_soc_card *card) { struct snd_soc_dai_link *link; @@ -137,6 +148,113 @@ static void apq8016_sbc_add_ops(struct snd_soc_card *card) link->init = apq8016_sbc_dai_init; } +static int qdsp6_dai_get_lpass_id(struct snd_soc_dai *cpu_dai) +{ + switch (cpu_dai->id) { + case PRIMARY_MI2S_RX: + case PRIMARY_MI2S_TX: + return MI2S_PRIMARY; + case SECONDARY_MI2S_RX: + case SECONDARY_MI2S_TX: + return MI2S_SECONDARY; + case TERTIARY_MI2S_RX: + case TERTIARY_MI2S_TX: + return MI2S_TERTIARY; + case QUATERNARY_MI2S_RX: + case QUATERNARY_MI2S_TX: + return MI2S_QUATERNARY; + default: + return -EINVAL; + } +} + +static int msm8916_qdsp6_dai_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + + snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS); + return apq8016_dai_init(rtd, qdsp6_dai_get_lpass_id(cpu_dai)); +} + +static int msm8916_qdsp6_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct apq8016_sbc_data *data = snd_soc_card_get_drvdata(card); + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + int mi2s, ret; + + mi2s = qdsp6_dai_get_lpass_id(cpu_dai); + if (mi2s < 0) + return mi2s; + + if (++data->mi2s_clk_count[mi2s] > 1) + return 0; + + ret = snd_soc_dai_set_sysclk(cpu_dai, LPAIF_BIT_CLK, MI2S_BCLK_RATE, 0); + if (ret) + dev_err(card->dev, "Failed to enable LPAIF bit clk: %d\n", ret); + return ret; +} + +static void msm8916_qdsp6_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct apq8016_sbc_data *data = snd_soc_card_get_drvdata(card); + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + int mi2s, ret; + + mi2s = qdsp6_dai_get_lpass_id(cpu_dai); + if (mi2s < 0) + return; + + if (--data->mi2s_clk_count[mi2s] > 0) + return; + + ret = snd_soc_dai_set_sysclk(cpu_dai, LPAIF_BIT_CLK, 0, 0); + if (ret) + dev_err(card->dev, "Failed to disable LPAIF bit clk: %d\n", ret); +} + +static const struct snd_soc_ops msm8916_qdsp6_be_ops = { + .startup = msm8916_qdsp6_startup, + .shutdown = msm8916_qdsp6_shutdown, +}; + +static int msm8916_qdsp6_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); + + return 0; +} + +static void msm8916_qdsp6_add_ops(struct snd_soc_card *card) +{ + struct snd_soc_dai_link *link; + int i; + + /* Make it obvious to userspace that QDSP6 is used */ + card->components = "qdsp6"; + + for_each_card_prelinks(card, i, link) { + if (link->no_pcm) { + link->init = msm8916_qdsp6_dai_init; + link->ops = &msm8916_qdsp6_be_ops; + link->be_hw_params_fixup = msm8916_qdsp6_be_hw_params_fixup; + } + } +} + static const struct snd_soc_dapm_widget apq8016_sbc_dapm_widgets[] = { SND_SOC_DAPM_MIC("Handset Mic", NULL), @@ -148,11 +266,16 @@ static const struct snd_soc_dapm_widget apq8016_sbc_dapm_widgets[] = { static int apq8016_sbc_platform_probe(struct platform_device *pdev) { + void (*add_ops)(struct snd_soc_card *card); struct device *dev = &pdev->dev; struct snd_soc_card *card; struct apq8016_sbc_data *data; int ret; + add_ops = device_get_match_data(&pdev->dev); + if (!add_ops) + return -EINVAL; + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -177,12 +300,13 @@ static int apq8016_sbc_platform_probe(struct platform_device *pdev) snd_soc_card_set_drvdata(card, data); - apq8016_sbc_add_ops(card); + add_ops(card); return devm_snd_soc_register_card(&pdev->dev, card); } static const struct of_device_id apq8016_sbc_device_id[] __maybe_unused = { - { .compatible = "qcom,apq8016-sbc-sndcard" }, + { .compatible = "qcom,apq8016-sbc-sndcard", .data = apq8016_sbc_add_ops }, + { .compatible = "qcom,msm8916-qdsp6-sndcard", .data = msm8916_qdsp6_add_ops }, {}, }; MODULE_DEVICE_TABLE(of, apq8016_sbc_device_id); From 475b17b4a875ef31246c6a038ee60d5ca4982ea5 Mon Sep 17 00:00:00 2001 From: Allen-KH Cheng Date: Thu, 9 Dec 2021 22:08:30 +0200 Subject: [PATCH 175/327] ASoC: SOF: Remove pm_runtime_put_autosuspend() for SOF OF device In SOF OF device, pm_runtime_put_autosuspend() is not matching any pm_runtime_get_sync(). This is imbalanced for PM runtime. Also, for consistency we call pm_runtime_mark_last_busy() before enabling PM runtime. 1. Remove pm_runtime_put_autosuspend() in probe_complete 2. Reorder PM runtime calls int probe_complete Signed-off-by: Allen-KH Cheng Reviewed-by: Daniel Baluta Reviewed-by: Paul Olaru Reviewed-by: Pierre-Louis Bossart Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20211209200830.145005-1-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-of-dev.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/sof/sof-of-dev.c b/sound/soc/sof/sof-of-dev.c index 412cbb824b844..b0089698eecbe 100644 --- a/sound/soc/sof/sof-of-dev.c +++ b/sound/soc/sof/sof-of-dev.c @@ -74,11 +74,9 @@ static void sof_of_probe_complete(struct device *dev) /* allow runtime_pm */ pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS); pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); - - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); } static int sof_of_probe(struct platform_device *pdev) From ec247fea7380244626d7095dfc1a0bb6c1f84f29 Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Sat, 4 Dec 2021 21:32:20 +0100 Subject: [PATCH 176/327] ASoC: SOF: sof-probes: Constify sof_probe_compr_ops The only usage of sof_probe_compr_ops is to assign its address to the cops field in the snd_soc_dai_driver struct (in sound/soc/sof/intel/hda-dai.c). Make it const to allow the compiler to put it in read-only memory. Signed-off-by: Rikard Falkeborn Link: https://lore.kernel.org/r/20211204203220.54712-1-rikard.falkeborn@gmail.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-probes.c | 2 +- sound/soc/sof/sof-probes.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/sof-probes.c b/sound/soc/sof/sof-probes.c index 5586af9f1a251..c79026cdb8c73 100644 --- a/sound/soc/sof/sof-probes.c +++ b/sound/soc/sof/sof-probes.c @@ -321,7 +321,7 @@ static int sof_probe_compr_pointer(struct snd_compr_stream *cstream, return snd_sof_probe_compr_pointer(sdev, cstream, tstamp, dai); } -struct snd_soc_cdai_ops sof_probe_compr_ops = { +const struct snd_soc_cdai_ops sof_probe_compr_ops = { .startup = sof_probe_compr_startup, .shutdown = sof_probe_compr_shutdown, .set_params = sof_probe_compr_set_params, diff --git a/sound/soc/sof/sof-probes.h b/sound/soc/sof/sof-probes.h index 35e1dd8d9e038..4a1ed2942d28f 100644 --- a/sound/soc/sof/sof-probes.h +++ b/sound/soc/sof/sof-probes.h @@ -32,7 +32,7 @@ int sof_ipc_probe_points_add(struct snd_sof_dev *sdev, int sof_ipc_probe_points_remove(struct snd_sof_dev *sdev, unsigned int *buffer_id, size_t num_buffer_id); -extern struct snd_soc_cdai_ops sof_probe_compr_ops; +extern const struct snd_soc_cdai_ops sof_probe_compr_ops; extern const struct snd_compress_ops sof_probe_compressed_ops; #endif From 03c2192ab636987db72e99f319a942cc4f3cb352 Mon Sep 17 00:00:00 2001 From: Jiaxin Yu Date: Thu, 9 Dec 2021 15:32:24 +0800 Subject: [PATCH 177/327] ASoC: mediatek: assign correct type to argument Fix the following sparse warning: (new ones prefixed by >>) >> sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c:370:33: sparse: sparse: incorrect type in argument 3 (different base types) sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c:370:33: sparse: expected unsigned int to sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c:370:33: sparse: got restricted snd_pcm_format_t [usertype] Correct discription of format, use S32_LE and S24_LE to distinguish the different 32bit. Signed-off-by: Jiaxin Yu Reported-by: kernel test robot Reviewed-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20211209073224.21793-1-jiaxin.yu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c | 8 ++++---- .../mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c | 12 ++++++------ .../mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c | 4 ++-- .../mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c | 4 ++-- .../mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c | 4 ++-- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c index a4d26a6fc8492..f8a72a5102ad5 100644 --- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c @@ -155,9 +155,9 @@ static const struct snd_soc_ops mt8183_da7219_rt1015_i2s_ops = { static int mt8183_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { - /* fix BE i2s format to 32bit, clean param mask first */ + /* fix BE i2s format to S32_LE, clean param mask first */ snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), - 0, SNDRV_PCM_FORMAT_LAST); + 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST); params_set_format(params, SNDRV_PCM_FORMAT_S32_LE); @@ -167,9 +167,9 @@ static int mt8183_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, static int mt8183_rt1015_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { - /* fix BE i2s format to 32bit, clean param mask first */ + /* fix BE i2s format to S24_LE, clean param mask first */ snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), - 0, SNDRV_PCM_FORMAT_LAST); + 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST); params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index aeb1af86047ef..d5fc86132b495 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -94,11 +94,11 @@ static const struct snd_soc_ops mt8183_mt6358_rt1015_i2s_ops = { static int mt8183_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { - dev_dbg(rtd->dev, "%s(), fix format to 32bit\n", __func__); + dev_dbg(rtd->dev, "%s(), fix format to S32_LE\n", __func__); - /* fix BE i2s format to 32bit, clean param mask first */ + /* fix BE i2s format to S32_LE, clean param mask first */ snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), - 0, SNDRV_PCM_FORMAT_LAST); + 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST); params_set_format(params, SNDRV_PCM_FORMAT_S32_LE); return 0; @@ -107,11 +107,11 @@ static int mt8183_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, static int mt8183_rt1015_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { - dev_dbg(rtd->dev, "%s(), fix format to 32bit\n", __func__); + dev_dbg(rtd->dev, "%s(), fix format to S24_LE\n", __func__); - /* fix BE i2s format to 32bit, clean param mask first */ + /* fix BE i2s format to S24_LE, clean param mask first */ snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), - 0, SNDRV_PCM_FORMAT_LAST); + 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST); params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); return 0; diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c index a606133951b70..1d16939f80e36 100644 --- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c +++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c @@ -350,9 +350,9 @@ static int mt8192_mt6359_hdmi_init(struct snd_soc_pcm_runtime *rtd) static int mt8192_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { - /* fix BE i2s format to 32bit, clean param mask first */ + /* fix BE i2s format to S24_LE, clean param mask first */ snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), - 0, SNDRV_PCM_FORMAT_LAST); + 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST); params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c index cca1c739e690b..5cdbfaafd479b 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c @@ -359,7 +359,7 @@ static int mt8195_rt5682_init(struct snd_soc_pcm_runtime *rtd) static int mt8195_etdm_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { - /* fix BE i2s format to 32bit, clean param mask first */ + /* fix BE i2s format to S24_LE, clean param mask first */ snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST); @@ -464,7 +464,7 @@ static int mt8195_dptx_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { - /* fix BE i2s format to 32bit, clean param mask first */ + /* fix BE i2s format to S24_LE, clean param mask first */ snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST); diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c index 11a185da0d964..fa50a31e9718a 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c @@ -355,7 +355,7 @@ static int mt8195_rt5682_init(struct snd_soc_pcm_runtime *rtd) static int mt8195_etdm_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { - /* fix BE i2s format to 32bit, clean param mask first */ + /* fix BE i2s format to S24_LE, clean param mask first */ snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST); @@ -463,7 +463,7 @@ static int mt8195_dptx_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { - /* fix BE i2s format to 32bit, clean param mask first */ + /* fix BE i2s format to S24_LE, clean param mask first */ snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST); From d8a9c6e1f6766a16cf02b4e99a629f3c5512c183 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 7 Dec 2021 11:37:40 -0600 Subject: [PATCH 178/327] ASoC: soc-pcm: use GFP_ATOMIC for dpcm structure We allocate a structure in dpcm_be_connect(), which may be called in atomic context. Using GFP_KERNEL is not quite right, we have to use GFP_ATOMIC to prevent the allocator from sleeping. Suggested-by: Guennadi Liakhovetski Signed-off-by: Pierre-Louis Bossart Reviewed-by: Kai Vehmanen Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20211207173745.15850-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 3b44121833447..f66808dfb5083 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1113,7 +1113,7 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe, return 0; } - dpcm = kzalloc(sizeof(struct snd_soc_dpcm), GFP_KERNEL); + dpcm = kzalloc(sizeof(struct snd_soc_dpcm), GFP_ATOMIC); if (!dpcm) return -ENOMEM; From bbf7d3b1c4f40eb02dd1dffb500ba00b0bff0303 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 7 Dec 2021 11:37:41 -0600 Subject: [PATCH 179/327] ASoC: soc-pcm: align BE 'atomicity' with that of the FE Since the flow for DPCM is based on taking a lock for the FE first, we need to make sure during the connection between a BE and an FE that they both use the same 'atomicity', otherwise we may sleep in atomic context. If the FE is nonatomic, this patch forces the BE to be nonatomic as well. That should have no negative impact since the BE 'inherits' the FE properties. However, if the FE is atomic and the BE is not, then the configuration is flagged as invalid. Signed-off-by: Pierre-Louis Bossart [ removed FE stream lock by tiwai ] Signed-off-by: Takashi Iwai Reviewed-by: Kai Vehmanen Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20211207173745.15850-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index f66808dfb5083..3a34b71fd3c1f 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1104,6 +1104,8 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe, struct snd_soc_pcm_runtime *be, int stream) { + struct snd_pcm_substream *fe_substream; + struct snd_pcm_substream *be_substream; struct snd_soc_dpcm *dpcm; unsigned long flags; @@ -1113,6 +1115,20 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe, return 0; } + 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) { + dev_warn(be->dev, "%s: FE is nonatomic but BE is not, forcing BE as nonatomic\n", + __func__); + be_substream->pcm->nonatomic = 1; + } + dpcm = kzalloc(sizeof(struct snd_soc_dpcm), GFP_ATOMIC); if (!dpcm) return -ENOMEM; From b7898396f4bbe160f546d0c5e9fa17cca9a7d153 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 7 Dec 2021 11:37:42 -0600 Subject: [PATCH 180/327] ASoC: soc-pcm: Fix and cleanup DPCM locking The existing locking for DPCM has several issues a) a confusing mix of card->mutex and card->pcm_mutex. b) a dpcm_lock spinlock added inconsistently and on paths that could be recursively taken. The use of irqsave/irqrestore was also overkill. The suggested model is: 1) The pcm_mutex is the top-most protection of BE links in the FE. The pcm_mutex is applied always on either the top PCM callbacks or the external call from DAPM, not taken in the internal functions. 2) the FE stream lock is taken in higher levels before invoking dpcm_be_dai_trigger() 3) when adding and deleting a BE, both the pcm_mutex and FE stream lock are taken. Signed-off-by: Takashi Iwai [clarification of commit message by plbossart] Signed-off-by: Pierre-Louis Bossart Reviewed-by: Kai Vehmanen Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20211207173745.15850-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/sound/soc.h | 2 - sound/soc/soc-core.c | 1 - sound/soc/soc-pcm.c | 229 ++++++++++++++++++++++++++++--------------- 3 files changed, 152 insertions(+), 80 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 8e6dd8a257c56..5872a8864f3b6 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -893,8 +893,6 @@ struct snd_soc_card { struct mutex pcm_mutex; enum snd_soc_pcm_subclass pcm_subclass; - spinlock_t dpcm_lock; - int (*probe)(struct snd_soc_card *card); int (*late_probe)(struct snd_soc_card *card); int (*remove)(struct snd_soc_card *card); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index dcf6be4c4aaad..1d62160f96b11 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2315,7 +2315,6 @@ int snd_soc_register_card(struct snd_soc_card *card) mutex_init(&card->mutex); mutex_init(&card->dapm_mutex); mutex_init(&card->pcm_mutex); - spin_lock_init(&card->dpcm_lock); return snd_soc_bind_card(card); } diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 3a34b71fd3c1f..2e282c42bac23 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -27,6 +27,31 @@ #include #include +static inline void snd_soc_dpcm_mutex_lock(struct snd_soc_pcm_runtime *rtd) +{ + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); +} + +static inline void snd_soc_dpcm_mutex_unlock(struct snd_soc_pcm_runtime *rtd) +{ + mutex_unlock(&rtd->card->pcm_mutex); +} + +#define snd_soc_dpcm_mutex_assert_held(rtd) \ + lockdep_assert_held(&(rtd)->card->pcm_mutex) + +static inline void snd_soc_dpcm_stream_lock_irq(struct snd_soc_pcm_runtime *rtd, + int stream) +{ + snd_pcm_stream_lock_irq(snd_soc_dpcm_get_substream(rtd, stream)); +} + +static inline void snd_soc_dpcm_stream_unlock_irq(struct snd_soc_pcm_runtime *rtd, + int stream) +{ + snd_pcm_stream_unlock_irq(snd_soc_dpcm_get_substream(rtd, stream)); +} + #define DPCM_MAX_BE_USERS 8 static inline const char *soc_cpu_dai_name(struct snd_soc_pcm_runtime *rtd) @@ -73,7 +98,6 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe, struct snd_pcm_hw_params *params = &fe->dpcm[stream].hw_params; struct snd_soc_dpcm *dpcm; ssize_t offset = 0; - unsigned long flags; /* FE state */ offset += scnprintf(buf + offset, size - offset, @@ -101,7 +125,6 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe, goto out; } - spin_lock_irqsave(&fe->card->dpcm_lock, flags); for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; params = &dpcm->hw_params; @@ -122,7 +145,6 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe, params_channels(params), params_rate(params)); } - spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); out: return offset; } @@ -145,11 +167,13 @@ static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf, if (!buf) return -ENOMEM; + snd_soc_dpcm_mutex_lock(fe); for_each_pcm_streams(stream) if (snd_soc_dai_stream_valid(asoc_rtd_to_cpu(fe, 0), stream)) offset += dpcm_show_state(fe, stream, buf + offset, out_count - offset); + snd_soc_dpcm_mutex_unlock(fe); ret = simple_read_from_buffer(user_buf, count, ppos, buf, offset); @@ -221,14 +245,14 @@ static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe, struct snd_pcm_substream *substream = snd_soc_dpcm_get_substream(fe, stream); - snd_pcm_stream_lock_irq(substream); + snd_soc_dpcm_stream_lock_irq(fe, stream); if (state == SND_SOC_DPCM_UPDATE_NO && fe->dpcm[stream].trigger_pending) { dpcm_fe_dai_do_trigger(substream, fe->dpcm[stream].trigger_pending - 1); fe->dpcm[stream].trigger_pending = 0; } fe->dpcm[stream].runtime_update = state; - snd_pcm_stream_unlock_irq(substream); + snd_soc_dpcm_stream_unlock_irq(fe, stream); } static void dpcm_set_be_update_state(struct snd_soc_pcm_runtime *be, @@ -256,7 +280,7 @@ void snd_soc_runtime_action(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai; int i; - lockdep_assert_held(&rtd->card->pcm_mutex); + snd_soc_dpcm_mutex_assert_held(rtd); for_each_rtd_dais(rtd, i, dai) snd_soc_dai_action(dai, stream, action); @@ -309,6 +333,8 @@ int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, { struct snd_soc_dpcm *dpcm; + snd_soc_dpcm_mutex_assert_held(fe); + for_each_dpcm_be(fe, dir, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; @@ -646,14 +672,14 @@ static int soc_pcm_components_close(struct snd_pcm_substream *substream, return ret; } -static int soc_pcm_clean(struct snd_pcm_substream *substream, int rollback) +static int soc_pcm_clean(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_substream *substream, int rollback) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_component *component; struct snd_soc_dai *dai; int i; - mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); + snd_soc_dpcm_mutex_assert_held(rtd); if (!rollback) snd_soc_runtime_deactivate(rtd, substream->stream); @@ -665,9 +691,6 @@ static int soc_pcm_clean(struct snd_pcm_substream *substream, int rollback) soc_pcm_components_close(substream, rollback); - - mutex_unlock(&rtd->card->pcm_mutex); - snd_soc_pcm_component_pm_runtime_put(rtd, substream, rollback); for_each_rtd_components(rtd, i, component) @@ -682,9 +705,21 @@ static int soc_pcm_clean(struct snd_pcm_substream *substream, int rollback) * freed here. The cpu DAI, codec DAI, machine and components are also * shutdown. */ +static int __soc_pcm_close(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_substream *substream) +{ + return soc_pcm_clean(rtd, substream, 0); +} + +/* PCM close ops for non-DPCM streams */ static int soc_pcm_close(struct snd_pcm_substream *substream) { - return soc_pcm_clean(substream, 0); + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + + snd_soc_dpcm_mutex_lock(rtd); + soc_pcm_clean(rtd, substream, 0); + snd_soc_dpcm_mutex_unlock(rtd); + return 0; } static int soc_hw_sanity_check(struct snd_pcm_substream *substream) @@ -730,21 +765,21 @@ static int soc_hw_sanity_check(struct snd_pcm_substream *substream) * then initialized and any private data can be allocated. This also calls * startup for the cpu DAI, component, machine and codec DAI. */ -static int soc_pcm_open(struct snd_pcm_substream *substream) +static int __soc_pcm_open(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_component *component; struct snd_soc_dai *dai; int i, ret = 0; + snd_soc_dpcm_mutex_assert_held(rtd); + for_each_rtd_components(rtd, i, component) pinctrl_pm_select_default_state(component->dev); ret = snd_soc_pcm_component_pm_runtime_get(rtd, substream); if (ret < 0) - goto pm_err; - - mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); + goto err; ret = soc_pcm_components_open(substream); if (ret < 0) @@ -791,16 +826,26 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) snd_soc_runtime_activate(rtd, substream->stream); ret = 0; err: - mutex_unlock(&rtd->card->pcm_mutex); -pm_err: if (ret < 0) { - soc_pcm_clean(substream, 1); + soc_pcm_clean(rtd, substream, 1); dev_err(rtd->dev, "%s() failed (%d)", __func__, ret); } return ret; } +/* PCM open ops for non-DPCM streams */ +static int soc_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + int ret; + + snd_soc_dpcm_mutex_lock(rtd); + ret = __soc_pcm_open(rtd, substream); + snd_soc_dpcm_mutex_unlock(rtd); + return ret; +} + static void codec2codec_close_delayed_work(struct snd_soc_pcm_runtime *rtd) { /* @@ -816,13 +861,13 @@ static void codec2codec_close_delayed_work(struct snd_soc_pcm_runtime *rtd) * rate, etc. This function is non atomic and can be called multiple times, * it can refer to the runtime info. */ -static int soc_pcm_prepare(struct snd_pcm_substream *substream) +static int __soc_pcm_prepare(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai *dai; int i, ret = 0; - mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); + snd_soc_dpcm_mutex_assert_held(rtd); ret = snd_soc_link_prepare(substream); if (ret < 0) @@ -850,14 +895,24 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) snd_soc_dai_digital_mute(dai, 0, substream->stream); out: - mutex_unlock(&rtd->card->pcm_mutex); - if (ret < 0) dev_err(rtd->dev, "ASoC: %s() failed (%d)\n", __func__, ret); return ret; } +/* PCM prepare ops for non-DPCM streams */ +static int soc_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + int ret; + + snd_soc_dpcm_mutex_lock(rtd); + ret = __soc_pcm_prepare(rtd, substream); + snd_soc_dpcm_mutex_unlock(rtd); + return ret; +} + static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params, unsigned int mask) { @@ -869,13 +924,13 @@ static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params, interval->max = channels; } -static int soc_pcm_hw_clean(struct snd_pcm_substream *substream, int rollback) +static int soc_pcm_hw_clean(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_substream *substream, int rollback) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai *dai; int i; - mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); + snd_soc_dpcm_mutex_assert_held(rtd); /* clear the corresponding DAIs parameters when going to be inactive */ for_each_rtd_dais(rtd, i, dai) { @@ -900,16 +955,28 @@ static int soc_pcm_hw_clean(struct snd_pcm_substream *substream, int rollback) if (snd_soc_dai_stream_valid(dai, substream->stream)) snd_soc_dai_hw_free(dai, substream, rollback); - mutex_unlock(&rtd->card->pcm_mutex); return 0; } /* * Frees resources allocated by hw_params, can be called multiple times */ +static int __soc_pcm_hw_free(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_substream *substream) +{ + return soc_pcm_hw_clean(rtd, substream, 0); +} + +/* hw_free PCM ops for non-DPCM streams */ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) { - return soc_pcm_hw_clean(substream, 0); + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + int ret; + + snd_soc_dpcm_mutex_lock(rtd); + ret = __soc_pcm_hw_free(rtd, substream); + snd_soc_dpcm_mutex_unlock(rtd); + return ret; } /* @@ -917,15 +984,15 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) * function can also be called multiple times and can allocate buffers * (using snd_pcm_lib_* ). It's non-atomic. */ -static int soc_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int __soc_pcm_hw_params(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai; struct snd_soc_dai *codec_dai; int i, ret = 0; - mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); + snd_soc_dpcm_mutex_assert_held(rtd); ret = soc_pcm_params_symmetry(substream, params); if (ret) @@ -997,16 +1064,27 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, ret = snd_soc_pcm_component_hw_params(substream, params); out: - mutex_unlock(&rtd->card->pcm_mutex); - if (ret < 0) { - soc_pcm_hw_clean(substream, 1); + soc_pcm_hw_clean(rtd, substream, 1); dev_err(rtd->dev, "ASoC: %s() failed (%d)\n", __func__, ret); } return ret; } +/* hw_params PCM ops for non-DPCM streams */ +static int soc_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + int ret; + + snd_soc_dpcm_mutex_lock(rtd); + ret = __soc_pcm_hw_params(rtd, substream, params); + snd_soc_dpcm_mutex_unlock(rtd); + return ret; +} + static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); @@ -1107,7 +1185,8 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe, struct snd_pcm_substream *fe_substream; struct snd_pcm_substream *be_substream; struct snd_soc_dpcm *dpcm; - unsigned long flags; + + snd_soc_dpcm_mutex_assert_held(fe); /* only add new dpcms */ for_each_dpcm_be(fe, stream, dpcm) { @@ -1137,10 +1216,10 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe, dpcm->fe = fe; be->dpcm[stream].runtime = fe->dpcm[stream].runtime; dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW; - spin_lock_irqsave(&fe->card->dpcm_lock, flags); + snd_soc_dpcm_stream_lock_irq(fe, stream); list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients); list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients); - spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); + snd_soc_dpcm_stream_unlock_irq(fe, stream); dev_dbg(fe->dev, "connected new DPCM %s path %s %s %s\n", stream ? "capture" : "playback", fe->dai_link->name, @@ -1183,8 +1262,10 @@ static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe, void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream) { struct snd_soc_dpcm *dpcm, *d; - unsigned long flags; + snd_soc_dpcm_mutex_assert_held(fe); + + snd_soc_dpcm_stream_lock_irq(fe, stream); for_each_dpcm_be_safe(fe, stream, dpcm, d) { dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s\n", stream ? "capture" : "playback", @@ -1202,12 +1283,11 @@ void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream) dpcm_remove_debugfs_state(dpcm); - spin_lock_irqsave(&fe->card->dpcm_lock, flags); list_del(&dpcm->list_be); list_del(&dpcm->list_fe); - spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); kfree(dpcm); } + snd_soc_dpcm_stream_unlock_irq(fe, stream); } /* get BE for DAI widget and stream */ @@ -1431,12 +1511,9 @@ int dpcm_process_paths(struct snd_soc_pcm_runtime *fe, void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream) { struct snd_soc_dpcm *dpcm; - unsigned long flags; - spin_lock_irqsave(&fe->card->dpcm_lock, flags); for_each_dpcm_be(fe, stream, dpcm) dpcm_set_be_update_state(dpcm->be, stream, SND_SOC_DPCM_UPDATE_NO); - spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); } void dpcm_be_dai_stop(struct snd_soc_pcm_runtime *fe, int stream, @@ -1472,12 +1549,12 @@ void dpcm_be_dai_stop(struct snd_soc_pcm_runtime *fe, int stream, continue; if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) { - soc_pcm_hw_free(be_substream); + __soc_pcm_hw_free(be, be_substream); be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE; } } - soc_pcm_close(be_substream); + __soc_pcm_close(be, be_substream); be_substream->runtime = NULL; be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; } @@ -1525,7 +1602,7 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) stream ? "capture" : "playback", be->dai_link->name); be_substream->runtime = be->dpcm[stream].runtime; - err = soc_pcm_open(be_substream); + err = __soc_pcm_open(be, be_substream); if (err < 0) { be->dpcm[stream].users--; if (be->dpcm[stream].users < 0) @@ -1769,7 +1846,7 @@ static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream) dev_dbg(fe->dev, "ASoC: open FE %s\n", fe->dai_link->name); /* start the DAI frontend */ - ret = soc_pcm_open(fe_substream); + ret = __soc_pcm_open(fe, fe_substream); if (ret < 0) goto unwind; @@ -1800,6 +1877,8 @@ static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream); int stream = substream->stream; + snd_soc_dpcm_mutex_assert_held(fe); + dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE); /* shutdown the BEs */ @@ -1808,7 +1887,7 @@ static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream) dev_dbg(fe->dev, "ASoC: close FE %s\n", fe->dai_link->name); /* now shutdown the frontend */ - soc_pcm_close(substream); + __soc_pcm_close(fe, substream); /* run the stream stop event */ dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP); @@ -1853,7 +1932,7 @@ void dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream) dev_dbg(be->dev, "ASoC: hw_free BE %s\n", be->dai_link->name); - soc_pcm_hw_free(be_substream); + __soc_pcm_hw_free(be, be_substream); be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE; } @@ -1864,13 +1943,13 @@ static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream); int stream = substream->stream; - mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); + snd_soc_dpcm_mutex_lock(fe); dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE); dev_dbg(fe->dev, "ASoC: hw_free FE %s\n", fe->dai_link->name); /* call hw_free on the frontend */ - soc_pcm_hw_free(substream); + soc_pcm_hw_clean(fe, substream, 0); /* only hw_params backends that are either sinks or sources * to this frontend DAI */ @@ -1879,7 +1958,7 @@ static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream) fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE; dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); - mutex_unlock(&fe->card->mutex); + snd_soc_dpcm_mutex_unlock(fe); return 0; } @@ -1923,7 +2002,7 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) dev_dbg(be->dev, "ASoC: hw_params BE %s\n", be->dai_link->name); - ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params); + ret = __soc_pcm_hw_params(be, be_substream, &dpcm->hw_params); if (ret < 0) goto unwind; @@ -1953,7 +2032,7 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)) continue; - soc_pcm_hw_free(be_substream); + __soc_pcm_hw_free(be, be_substream); } return ret; @@ -1965,7 +2044,7 @@ static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream); int ret, stream = substream->stream; - mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); + snd_soc_dpcm_mutex_lock(fe); dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE); memcpy(&fe->dpcm[stream].hw_params, params, @@ -1979,7 +2058,7 @@ static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream, params_channels(params), params_format(params)); /* call hw_params on the frontend */ - ret = soc_pcm_hw_params(substream, params); + ret = __soc_pcm_hw_params(fe, substream, params); if (ret < 0) dpcm_be_dai_hw_free(fe, stream); else @@ -1987,7 +2066,7 @@ static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream, out: dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); - mutex_unlock(&fe->card->mutex); + snd_soc_dpcm_mutex_unlock(fe); if (ret < 0) dev_err(fe->dev, "ASoC: %s failed (%d)\n", __func__, ret); @@ -2258,7 +2337,7 @@ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream) dev_dbg(be->dev, "ASoC: prepare BE %s\n", be->dai_link->name); - ret = soc_pcm_prepare(be_substream); + ret = __soc_pcm_prepare(be, be_substream); if (ret < 0) break; @@ -2276,7 +2355,7 @@ static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream); int stream = substream->stream, ret = 0; - mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); + snd_soc_dpcm_mutex_lock(fe); dev_dbg(fe->dev, "ASoC: prepare FE %s\n", fe->dai_link->name); @@ -2295,7 +2374,7 @@ static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream) goto out; /* call prepare on the frontend */ - ret = soc_pcm_prepare(substream); + ret = __soc_pcm_prepare(fe, substream); if (ret < 0) goto out; @@ -2303,7 +2382,7 @@ static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream) out: dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); - mutex_unlock(&fe->card->mutex); + snd_soc_dpcm_mutex_unlock(fe); if (ret < 0) dev_err(fe->dev, "ASoC: %s() failed (%d)\n", __func__, ret); @@ -2354,7 +2433,6 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) struct snd_soc_dpcm *dpcm; enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; int ret = 0; - unsigned long flags; dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n", stream ? "capture" : "playback", fe->dai_link->name); @@ -2423,7 +2501,6 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) dpcm_be_dai_shutdown(fe, stream); disconnect: /* disconnect any pending BEs */ - spin_lock_irqsave(&fe->card->dpcm_lock, flags); for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; @@ -2435,7 +2512,6 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) be->dpcm[stream].state == SND_SOC_DPCM_STATE_NEW) dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; } - spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); if (ret < 0) dev_err(fe->dev, "ASoC: %s() failed (%d)\n", __func__, ret); @@ -2510,7 +2586,7 @@ int snd_soc_dpcm_runtime_update(struct snd_soc_card *card) struct snd_soc_pcm_runtime *fe; int ret = 0; - mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME); + mutex_lock_nested(&card->pcm_mutex, card->pcm_subclass); /* shutdown all old paths first */ for_each_card_rtds(card, fe) { ret = soc_dpcm_fe_runtime_update(fe, 0); @@ -2526,7 +2602,7 @@ int snd_soc_dpcm_runtime_update(struct snd_soc_card *card) } out: - mutex_unlock(&card->mutex); + mutex_unlock(&card->pcm_mutex); return ret; } EXPORT_SYMBOL_GPL(snd_soc_dpcm_runtime_update); @@ -2537,6 +2613,8 @@ static void dpcm_fe_dai_cleanup(struct snd_pcm_substream *fe_substream) struct snd_soc_dpcm *dpcm; int stream = fe_substream->stream; + snd_soc_dpcm_mutex_assert_held(fe); + /* mark FE's links ready to prune */ for_each_dpcm_be(fe, stream, dpcm) dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; @@ -2551,12 +2629,12 @@ static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream) struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream); int ret; - mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); + snd_soc_dpcm_mutex_lock(fe); ret = dpcm_fe_dai_shutdown(fe_substream); dpcm_fe_dai_cleanup(fe_substream); - mutex_unlock(&fe->card->mutex); + snd_soc_dpcm_mutex_unlock(fe); return ret; } @@ -2567,7 +2645,7 @@ static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream) int ret; int stream = fe_substream->stream; - mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); + snd_soc_dpcm_mutex_lock(fe); fe->dpcm[stream].runtime = fe_substream->runtime; ret = dpcm_path_get(fe, stream, &list); @@ -2584,7 +2662,7 @@ static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream) dpcm_clear_pending_state(fe, stream); dpcm_path_put(&list); open_end: - mutex_unlock(&fe->card->mutex); + snd_soc_dpcm_mutex_unlock(fe); return ret; } @@ -2845,10 +2923,8 @@ static int snd_soc_dpcm_check_state(struct snd_soc_pcm_runtime *fe, struct snd_soc_dpcm *dpcm; int state; int ret = 1; - unsigned long flags; int i; - spin_lock_irqsave(&fe->card->dpcm_lock, flags); for_each_dpcm_fe(be, stream, dpcm) { if (dpcm->fe == fe) @@ -2862,7 +2938,6 @@ static int snd_soc_dpcm_check_state(struct snd_soc_pcm_runtime *fe, } } } - spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); /* it's safe to do this BE DAI */ return ret; From b2ae80663008a7662febe7d13f14ea1b2eb0cd51 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 7 Dec 2021 11:37:43 -0600 Subject: [PATCH 181/327] ASoC: soc-pcm: serialize BE triggers When more than one FE is connected to a BE, e.g. in a mixing use case, the BE can be triggered multiple times when the FE are opened/started concurrently. This race condition is problematic in the case of SoundWire BE dailinks, and this is not desirable in a general case. This patch relies on the existing BE PCM lock, which takes atomicity into account. The locking model assumes that all interactions start with the FE, so that there is no deadlock between FE and BE locks. Signed-off-by: Takashi Iwai [test, checkpatch fix and clarification of commit message by plbossart] Signed-off-by: Pierre-Louis Bossart Reviewed-by: Kai Vehmanen Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20211207173745.15850-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 46 ++++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 2e282c42bac23..7043857e30b14 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -46,12 +46,18 @@ static inline void snd_soc_dpcm_stream_lock_irq(struct snd_soc_pcm_runtime *rtd, snd_pcm_stream_lock_irq(snd_soc_dpcm_get_substream(rtd, stream)); } +#define snd_soc_dpcm_stream_lock_irqsave(rtd, stream, flags) \ + snd_pcm_stream_lock_irqsave(snd_soc_dpcm_get_substream(rtd, stream), flags) + static inline void snd_soc_dpcm_stream_unlock_irq(struct snd_soc_pcm_runtime *rtd, int stream) { snd_pcm_stream_unlock_irq(snd_soc_dpcm_get_substream(rtd, stream)); } +#define snd_soc_dpcm_stream_unlock_irqrestore(rtd, stream, flags) \ + snd_pcm_stream_unlock_irqrestore(snd_soc_dpcm_get_substream(rtd, stream), flags) + #define DPCM_MAX_BE_USERS 8 static inline const char *soc_cpu_dai_name(struct snd_soc_pcm_runtime *rtd) @@ -2079,6 +2085,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, { struct snd_soc_pcm_runtime *be; struct snd_soc_dpcm *dpcm; + unsigned long flags; int ret = 0; for_each_dpcm_be(fe, stream, dpcm) { @@ -2087,9 +2094,11 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, be = dpcm->be; be_substream = snd_soc_dpcm_get_substream(be, stream); + snd_soc_dpcm_stream_lock_irqsave(be, stream, flags); + /* is this op for this BE ? */ if (!snd_soc_dpcm_be_can_update(fe, be, stream)) - continue; + goto next; dev_dbg(be->dev, "ASoC: trigger BE %s cmd %d\n", be->dai_link->name, cmd); @@ -2099,77 +2108,80 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) && (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) && (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED)) - continue; + goto next; ret = soc_pcm_trigger(be_substream, cmd); if (ret) - goto end; + goto next; be->dpcm[stream].state = SND_SOC_DPCM_STATE_START; break; case SNDRV_PCM_TRIGGER_RESUME: if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND)) - continue; + goto next; ret = soc_pcm_trigger(be_substream, cmd); if (ret) - goto end; + goto next; be->dpcm[stream].state = SND_SOC_DPCM_STATE_START; break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED)) - continue; + goto next; ret = soc_pcm_trigger(be_substream, cmd); if (ret) - goto end; + goto next; be->dpcm[stream].state = SND_SOC_DPCM_STATE_START; break; case SNDRV_PCM_TRIGGER_STOP: if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) && (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED)) - continue; + goto next; if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) - continue; + goto next; ret = soc_pcm_trigger(be_substream, cmd); if (ret) - goto end; + goto next; be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP; break; case SNDRV_PCM_TRIGGER_SUSPEND: if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) - continue; + goto next; if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) - continue; + goto next; ret = soc_pcm_trigger(be_substream, cmd); if (ret) - goto end; + goto next; be->dpcm[stream].state = SND_SOC_DPCM_STATE_SUSPEND; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) - continue; + goto next; if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) - continue; + goto next; ret = soc_pcm_trigger(be_substream, cmd); if (ret) - goto end; + goto next; be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED; break; } +next: + snd_soc_dpcm_stream_unlock_irqrestore(be, stream, flags); + if (ret) + break; } -end: if (ret < 0) dev_err(fe->dev, "ASoC: %s() failed at %s (%d)\n", __func__, be->dai_link->name, ret); From 848aedfdc6ba25ad5652797db9266007773e44dd Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 7 Dec 2021 11:37:44 -0600 Subject: [PATCH 182/327] ASoC: soc-pcm: test refcount before triggering On start/pause_release/resume, when more than one FE is connected to the same BE, it's possible that the trigger is sent more than once. This is not desirable, we only want to trigger a BE once, which is straightforward to implement with a refcount. For stop/pause/suspend, the problem is more complicated: the check implemented in snd_soc_dpcm_can_be_free_stop() may fail due to a conceptual deadlock when we trigger the BE before the FE. In this case, the FE states have not yet changed, so there are corner cases where the TRIGGER_STOP is never sent - the dual case of start where multiple triggers might be sent. This patch suggests an unconditional trigger in all cases, without checking the FE states, using a refcount protected by the BE PCM stream lock. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Kai Vehmanen Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20211207173745.15850-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/sound/soc-dpcm.h | 2 ++ sound/soc/soc-pcm.c | 53 +++++++++++++++++++++++++++++++--------- 2 files changed, 44 insertions(+), 11 deletions(-) diff --git a/include/sound/soc-dpcm.h b/include/sound/soc-dpcm.h index bc7af90099a8d..75b92d883976b 100644 --- a/include/sound/soc-dpcm.h +++ b/include/sound/soc-dpcm.h @@ -101,6 +101,8 @@ struct snd_soc_dpcm_runtime { enum snd_soc_dpcm_state state; int trigger_pending; /* trigger cmd + 1 if pending, 0 if not */ + + int be_start; /* refcount protected by BE stream pcm lock */ }; #define for_each_dpcm_fe(be, stream, _dpcm) \ diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 7043857e30b14..05a0f52eb11b5 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1619,7 +1619,7 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; goto unwind; } - + be->dpcm[stream].be_start = 0; be->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN; count++; } @@ -2105,14 +2105,21 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, switch (cmd) { case SNDRV_PCM_TRIGGER_START: - if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) && + if (!be->dpcm[stream].be_start && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) && (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) && (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED)) goto next; + be->dpcm[stream].be_start++; + if (be->dpcm[stream].be_start != 1) + goto next; + ret = soc_pcm_trigger(be_substream, cmd); - if (ret) + if (ret) { + be->dpcm[stream].be_start--; goto next; + } be->dpcm[stream].state = SND_SOC_DPCM_STATE_START; break; @@ -2120,9 +2127,15 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND)) goto next; + be->dpcm[stream].be_start++; + if (be->dpcm[stream].be_start != 1) + goto next; + ret = soc_pcm_trigger(be_substream, cmd); - if (ret) + if (ret) { + be->dpcm[stream].be_start--; goto next; + } be->dpcm[stream].state = SND_SOC_DPCM_STATE_START; break; @@ -2130,9 +2143,15 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED)) goto next; + be->dpcm[stream].be_start++; + if (be->dpcm[stream].be_start != 1) + goto next; + ret = soc_pcm_trigger(be_substream, cmd); - if (ret) + if (ret) { + be->dpcm[stream].be_start--; goto next; + } be->dpcm[stream].state = SND_SOC_DPCM_STATE_START; break; @@ -2141,12 +2160,18 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED)) goto next; - if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) + if (be->dpcm[stream].state == SND_SOC_DPCM_STATE_START) + be->dpcm[stream].be_start--; + + if (be->dpcm[stream].be_start != 0) goto next; ret = soc_pcm_trigger(be_substream, cmd); - if (ret) + if (ret) { + if (be->dpcm[stream].state == SND_SOC_DPCM_STATE_START) + be->dpcm[stream].be_start++; goto next; + } be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP; break; @@ -2154,12 +2179,15 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) goto next; - if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) + be->dpcm[stream].be_start--; + if (be->dpcm[stream].be_start != 0) goto next; ret = soc_pcm_trigger(be_substream, cmd); - if (ret) + if (ret) { + be->dpcm[stream].be_start++; goto next; + } be->dpcm[stream].state = SND_SOC_DPCM_STATE_SUSPEND; break; @@ -2167,12 +2195,15 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) goto next; - if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) + be->dpcm[stream].be_start--; + if (be->dpcm[stream].be_start != 0) goto next; ret = soc_pcm_trigger(be_substream, cmd); - if (ret) + if (ret) { + be->dpcm[stream].be_start++; goto next; + } be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED; break; From 3aa1e96a2b95e2ece198f8dd01e96818971b84df Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 7 Dec 2021 11:37:45 -0600 Subject: [PATCH 183/327] ASoC: soc-pcm: fix BE handling of PAUSE_RELEASE A BE connected to more than one FE, e.g. in a mixer case, can go through the following transitions. play FE1 -> BE state is START pause FE1 -> BE state is PAUSED play FE2 -> BE state is START stop FE2 -> BE state is STOP (see note [1] below) release FE1 -> BE state is START stop FE1 -> BE state is STOP play FE1 -> BE state is START pause FE1 -> BE state is PAUSED play FE2 -> BE state is START release FE1 -> BE state is START stop FE2 -> BE state is START stop FE1 -> BE state is STOP play FE1 -> BE state is START play FE2 -> BE state is START (no change) pause FE1 -> BE state is START (no change) pause FE2 -> BE state is PAUSED release FE1 -> BE state is START release FE2 -> BE state is START (no change) stop FE1 -> BE state is START (no change) stop FE2 -> BE state is STOP The existing code for PAUSE_RELEASE only allows for the case where the BE is paused, which clearly would not work in the sequences above. Extend the allowed states to restart the BE when PAUSE_RELEASE is received, and increase the refcount if the BE is already in START. [1] the existing logic does not move the BE state back to PAUSED when the FE2 is stopped. This patch does not change the logic; it would be painful to keep a history of changes on the FE side, the state machine is already rather complicated with transitions based on the last BE state and the trigger type. Reported-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Reviewed-by: Kai Vehmanen Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20211207173745.15850-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 05a0f52eb11b5..7abfc48b26ca5 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2140,7 +2140,10 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, be->dpcm[stream].state = SND_SOC_DPCM_STATE_START; break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED)) + if (!be->dpcm[stream].be_start && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED)) goto next; be->dpcm[stream].be_start++; From 833a94aac572d7f0fe3f51329e0eb9f2884cf665 Mon Sep 17 00:00:00 2001 From: Judy Hsiao Date: Tue, 14 Dec 2021 10:25:09 +0800 Subject: [PATCH 184/327] ASoC: qcom: Distinguish headset codec by codec_dai->name Distinguish which headset codec is on the board by codec_dai->name instead of card->name. It fixes the crash of being unable to handle kernel paging requests at virtual address ADDR by initializing the correct audio codec on the board. Call stack of the crash: ``` Unable to handle kernel paging request at virtual address ... ... Call trace: rt5682_set_component_pll+0xcc/0xb78 [snd_soc_rt5682] snd_soc_component_set_pll+0x90/0x154 snd_soc_dai_set_pll+0xf4/0x1ac sc7180_snd_startup+0x268/0x3c0 [snd_soc_sc7180] snd_soc_link_startup+0xa4/0x180 soc_pcm_open+0x35c/0x15c8 snd_pcm_open_substream+0xa90/0x13b0 snd_pcm_open+0x1a4/0x55c snd_pcm_capture_open+0x7c/0xe8 snd_open+0x2b8/0x2e4 chrdev_open+0x364/0x3d4 do_dentry_open+0x66c/0xc58 vfs_open+0x7c/0x8c path_openat+0x108c/0x2bbc do_filp_open+0x15c/0x258 do_sys_open+0x278/0x62c __arm64_compat_sys_openat+0x9c/0xb0 ... ``` Fixes: 425c5fce8a03 ("ASoC: qcom: Add support for ALC5682I-VS codec") Signed-off-by: Judy Hsiao Link: https://lore.kernel.org/r/20211214022509.1288245-1-judyhsiao@chromium.org Signed-off-by: Mark Brown --- sound/soc/qcom/sc7180.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/qcom/sc7180.c b/sound/soc/qcom/sc7180.c index 2fff764a00a72..37225ef2563ac 100644 --- a/sound/soc/qcom/sc7180.c +++ b/sound/soc/qcom/sc7180.c @@ -131,13 +131,13 @@ static int sc7180_snd_startup(struct snd_pcm_substream *substream) struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); int pll_id, pll_source, pll_in, pll_out, clk_id, ret; - if (!(strcmp(card->name, "sc7180-rt5682-max98357a-1mic"))) { + if (!strcmp(codec_dai->name, "rt5682-aif1")) { pll_source = RT5682_PLL1_S_MCLK; pll_id = 0; clk_id = RT5682_SCLK_S_PLL1; pll_out = RT5682_PLL1_FREQ; pll_in = DEFAULT_MCLK_RATE; - } else if (!(strcmp(card->name, "sc7180-rt5682s-max98357a-1mic"))) { + } else if (!strcmp(codec_dai->name, "rt5682s-aif1")) { pll_source = RT5682S_PLL_S_MCLK; pll_id = RT5682S_PLL2; clk_id = RT5682S_SCLK_S_PLL2; From 59716aa3f9764144cdd558c64f04cb83001b71ac Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Sat, 11 Dec 2021 06:58:29 +0000 Subject: [PATCH 185/327] ASoC: qdsp6: Fix an IS_ERR() vs NULL bug The function gpr_alloc_port return ERR_PTR on errors, it doesn't return null. Signed-off-by: Miaoqian Lin Link: https://lore.kernel.org/r/20211211065840.1221-1-linmq006@gmail.com Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6apm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c index 13598ef5bacbe..3e007d609a9bb 100644 --- a/sound/soc/qcom/qdsp6/q6apm.c +++ b/sound/soc/qcom/qdsp6/q6apm.c @@ -630,9 +630,9 @@ struct q6apm_graph *q6apm_graph_open(struct device *dev, q6apm_cb cb, init_waitqueue_head(&graph->cmd_wait); graph->port = gpr_alloc_port(apm->gdev, dev, graph_callback, graph); - if (!graph->port) { + if (IS_ERR(graph->port)) { kfree(graph); - ret = -ENOMEM; + ret = PTR_ERR(graph->port); goto err; } From 28084f4a0e031a87b624ea121bd8fd782b90ff2a Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 15 Dec 2021 10:57:03 +0200 Subject: [PATCH 186/327] ASoC: SOF: OF: Avoid reverse module dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similar with commit 8a49cd11e68ed0 ("ASoC: SOF: ACPI: avoid reverse module dependency") we will be having hardware specific drivers that link against a common "helper" framework. sof-of-dev.c becomes a library with the interface defined in the newly created file sof-of-dev.h. This is the final step started with Kconfig simplification in commit 7548a391c53ca ("ASoC: SOF: i.MX: simplify Kconfig") Signed-off-by: Daniel Baluta Reviewed-by: Paul Olaru Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20211215085703.137414-1-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/imx/imx-ops.h | 10 ---- sound/soc/sof/imx/imx8.c | 43 ++++++++++++-- sound/soc/sof/imx/imx8m.c | 31 ++++++++++- sound/soc/sof/mediatek/mediatek-ops.h | 8 --- sound/soc/sof/mediatek/mt8195/mt8195.c | 31 ++++++++++- sound/soc/sof/sof-of-dev.c | 77 +++----------------------- sound/soc/sof/sof-of-dev.h | 17 ++++++ 7 files changed, 118 insertions(+), 99 deletions(-) delete mode 100644 sound/soc/sof/imx/imx-ops.h delete mode 100644 sound/soc/sof/mediatek/mediatek-ops.h create mode 100644 sound/soc/sof/sof-of-dev.h diff --git a/sound/soc/sof/imx/imx-ops.h b/sound/soc/sof/imx/imx-ops.h deleted file mode 100644 index 24235ef8c8faf..0000000000000 --- a/sound/soc/sof/imx/imx-ops.h +++ /dev/null @@ -1,10 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ - -#ifndef __IMX_OPS_H__ -#define __IMX_OPS_H__ - -extern struct snd_sof_dsp_ops sof_imx8_ops; -extern struct snd_sof_dsp_ops sof_imx8x_ops; -extern struct snd_sof_dsp_ops sof_imx8m_ops; - -#endif diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c index 00b2bb5fd6ae5..099b4356122cf 100644 --- a/sound/soc/sof/imx/imx8.c +++ b/sound/soc/sof/imx/imx8.c @@ -21,8 +21,8 @@ #include #include #include "../ops.h" +#include "../sof-of-dev.h" #include "imx-common.h" -#include "imx-ops.h" /* DSP memories */ #define IRAM_OFFSET 0x10000 @@ -487,7 +487,7 @@ static int imx8_dsp_set_power_state(struct snd_sof_dev *sdev, } /* i.MX8 ops */ -struct snd_sof_dsp_ops sof_imx8_ops = { +static const struct snd_sof_dsp_ops sof_imx8_ops = { /* probe and remove */ .probe = imx8_probe, .remove = imx8_remove, @@ -548,10 +548,9 @@ struct snd_sof_dsp_ops sof_imx8_ops = { .set_power_state = imx8_dsp_set_power_state, }; -EXPORT_SYMBOL(sof_imx8_ops); /* i.MX8X ops */ -struct snd_sof_dsp_ops sof_imx8x_ops = { +static const struct snd_sof_dsp_ops sof_imx8x_ops = { /* probe and remove */ .probe = imx8_probe, .remove = imx8_remove, @@ -612,7 +611,41 @@ struct snd_sof_dsp_ops sof_imx8x_ops = { SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP }; -EXPORT_SYMBOL(sof_imx8x_ops); + +static struct sof_dev_desc sof_of_imx8qxp_desc = { + .default_fw_path = "imx/sof", + .default_tplg_path = "imx/sof-tplg", + .default_fw_filename = "sof-imx8x.ri", + .nocodec_tplg_filename = "sof-imx8-nocodec.tplg", + .ops = &sof_imx8x_ops, +}; + +static struct sof_dev_desc sof_of_imx8qm_desc = { + .default_fw_path = "imx/sof", + .default_tplg_path = "imx/sof-tplg", + .default_fw_filename = "sof-imx8.ri", + .nocodec_tplg_filename = "sof-imx8-nocodec.tplg", + .ops = &sof_imx8_ops, +}; + +static const struct of_device_id sof_of_imx8_ids[] = { + { .compatible = "fsl,imx8qxp-dsp", .data = &sof_of_imx8qxp_desc}, + { .compatible = "fsl,imx8qm-dsp", .data = &sof_of_imx8qm_desc}, + { } +}; +MODULE_DEVICE_TABLE(of, sof_of_imx8_ids); + +/* DT driver definition */ +static struct platform_driver snd_sof_of_imx8_driver = { + .probe = sof_of_probe, + .remove = sof_of_remove, + .driver = { + .name = "sof-audio-of-imx8", + .pm = &sof_of_pm, + .of_match_table = sof_of_imx8_ids, + }, +}; +module_platform_driver(snd_sof_of_imx8_driver); MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/imx/imx8m.c b/sound/soc/sof/imx/imx8m.c index b7df655c49c97..c026caea4c8b2 100644 --- a/sound/soc/sof/imx/imx8m.c +++ b/sound/soc/sof/imx/imx8m.c @@ -20,8 +20,8 @@ #include #include "../ops.h" +#include "../sof-of-dev.h" #include "imx-common.h" -#include "imx-ops.h" #define MBOX_OFFSET 0x800000 #define MBOX_SIZE 0x1000 @@ -411,7 +411,7 @@ static int imx8m_dsp_suspend(struct snd_sof_dev *sdev, unsigned int target_state } /* i.MX8 ops */ -struct snd_sof_dsp_ops sof_imx8m_ops = { +static const struct snd_sof_dsp_ops sof_imx8m_ops = { /* probe and remove */ .probe = imx8m_probe, .remove = imx8m_remove, @@ -470,7 +470,32 @@ struct snd_sof_dsp_ops sof_imx8m_ops = { SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, }; -EXPORT_SYMBOL(sof_imx8m_ops); + +static struct sof_dev_desc sof_of_imx8mp_desc = { + .default_fw_path = "imx/sof", + .default_tplg_path = "imx/sof-tplg", + .default_fw_filename = "sof-imx8m.ri", + .nocodec_tplg_filename = "sof-imx8-nocodec.tplg", + .ops = &sof_imx8m_ops, +}; + +static const struct of_device_id sof_of_imx8m_ids[] = { + { .compatible = "fsl,imx8mp-dsp", .data = &sof_of_imx8mp_desc}, + { } +}; +MODULE_DEVICE_TABLE(of, sof_of_imx8m_ids); + +/* DT driver definition */ +static struct platform_driver snd_sof_of_imx8m_driver = { + .probe = sof_of_probe, + .remove = sof_of_remove, + .driver = { + .name = "sof-audio-of-imx8m", + .pm = &sof_of_pm, + .of_match_table = sof_of_imx8m_ids, + }, +}; +module_platform_driver(snd_sof_of_imx8m_driver); MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/mediatek/mediatek-ops.h b/sound/soc/sof/mediatek/mediatek-ops.h deleted file mode 100644 index e0ffa69ecb0c6..0000000000000 --- a/sound/soc/sof/mediatek/mediatek-ops.h +++ /dev/null @@ -1,8 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ - -#ifndef __MEDIATEK_OPS_H__ -#define __MEDIATEK_OPS_H__ - -extern const struct snd_sof_dsp_ops sof_mt8195_ops; - -#endif diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index c719ba4706202..3ab12f352935f 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -21,9 +21,9 @@ #include #include #include "../../ops.h" +#include "../../sof-of-dev.h" #include "../../sof-audio.h" #include "../adsp_helper.h" -#include "../mediatek-ops.h" #include "mt8195.h" #include "mt8195-clk.h" @@ -388,7 +388,7 @@ static struct snd_soc_dai_driver mt8195_dai[] = { }; /* mt8195 ops */ -const struct snd_sof_dsp_ops sof_mt8195_ops = { +static const struct snd_sof_dsp_ops sof_mt8195_ops = { /* probe and remove */ .probe = mt8195_dsp_probe, .remove = mt8195_dsp_remove, @@ -432,7 +432,32 @@ const struct snd_sof_dsp_ops sof_mt8195_ops = { SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, }; -EXPORT_SYMBOL(sof_mt8195_ops); + +static const struct sof_dev_desc sof_of_mt8195_desc = { + .default_fw_path = "mediatek/sof", + .default_tplg_path = "mediatek/sof-tplg", + .default_fw_filename = "sof-mt8195.ri", + .nocodec_tplg_filename = "sof-mt8195-nocodec.tplg", + .ops = &sof_mt8195_ops, +}; + +static const struct of_device_id sof_of_mt8195_ids[] = { + { .compatible = "mediatek,mt8195-dsp", .data = &sof_of_mt8195_desc}, + { } +}; +MODULE_DEVICE_TABLE(of, sof_of_mt8195_ids); + +/* DT driver definition */ +static struct platform_driver snd_sof_of_mt8195_driver = { + .probe = sof_of_probe, + .remove = sof_of_remove, + .driver = { + .name = "sof-audio-of-mt8195", + .pm = &sof_of_pm, + .of_match_table = sof_of_mt8195_ids, + }, +}; +module_platform_driver(snd_sof_of_mt8195_driver); MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/sof-of-dev.c b/sound/soc/sof/sof-of-dev.c index b0089698eecbe..e3718638f9ce8 100644 --- a/sound/soc/sof/sof-of-dev.c +++ b/sound/soc/sof/sof-of-dev.c @@ -11,9 +11,8 @@ #include #include +#include "sof-of-dev.h" #include "ops.h" -#include "imx/imx-ops.h" -#include "mediatek/mediatek-ops.h" static char *fw_path; module_param(fw_path, charp, 0444); @@ -23,51 +22,14 @@ static char *tplg_path; module_param(tplg_path, charp, 0444); MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology."); -/* platform specific devices */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8) -static struct sof_dev_desc sof_of_imx8qxp_desc = { - .default_fw_path = "imx/sof", - .default_tplg_path = "imx/sof-tplg", - .default_fw_filename = "sof-imx8x.ri", - .nocodec_tplg_filename = "sof-imx8-nocodec.tplg", - .ops = &sof_imx8x_ops, -}; - -static struct sof_dev_desc sof_of_imx8qm_desc = { - .default_fw_path = "imx/sof", - .default_tplg_path = "imx/sof-tplg", - .default_fw_filename = "sof-imx8.ri", - .nocodec_tplg_filename = "sof-imx8-nocodec.tplg", - .ops = &sof_imx8_ops, -}; -#endif - -#if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8M) -static struct sof_dev_desc sof_of_imx8mp_desc = { - .default_fw_path = "imx/sof", - .default_tplg_path = "imx/sof-tplg", - .default_fw_filename = "sof-imx8m.ri", - .nocodec_tplg_filename = "sof-imx8-nocodec.tplg", - .ops = &sof_imx8m_ops, -}; -#endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_MT8195) -static const struct sof_dev_desc sof_of_mt8195_desc = { - .default_fw_path = "mediatek/sof", - .default_tplg_path = "mediatek/sof-tplg", - .default_fw_filename = "sof-mt8195.ri", - .nocodec_tplg_filename = "sof-mt8195-nocodec.tplg", - .ops = &sof_mt8195_ops, -}; -#endif - -static const struct dev_pm_ops sof_of_pm = { +const struct dev_pm_ops sof_of_pm = { .prepare = snd_sof_prepare, .complete = snd_sof_complete, SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, NULL) }; +EXPORT_SYMBOL(sof_of_pm); static void sof_of_probe_complete(struct device *dev) { @@ -79,7 +41,7 @@ static void sof_of_probe_complete(struct device *dev) pm_runtime_enable(dev); } -static int sof_of_probe(struct platform_device *pdev) +int sof_of_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; const struct sof_dev_desc *desc; @@ -120,8 +82,9 @@ static int sof_of_probe(struct platform_device *pdev) /* call sof helper for DSP hardware probe */ return snd_sof_device_probe(dev, sof_pdata); } +EXPORT_SYMBOL(sof_of_probe); -static int sof_of_remove(struct platform_device *pdev) +int sof_of_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); @@ -130,32 +93,6 @@ static int sof_of_remove(struct platform_device *pdev) return 0; } - -static const struct of_device_id sof_of_ids[] = { -#if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8) - { .compatible = "fsl,imx8qxp-dsp", .data = &sof_of_imx8qxp_desc}, - { .compatible = "fsl,imx8qm-dsp", .data = &sof_of_imx8qm_desc}, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8M) - { .compatible = "fsl,imx8mp-dsp", .data = &sof_of_imx8mp_desc}, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_MT8195) - { .compatible = "mediatek,mt8195-dsp", .data = &sof_of_mt8195_desc}, -#endif - { } -}; -MODULE_DEVICE_TABLE(of, sof_of_ids); - -/* DT driver definition */ -static struct platform_driver snd_sof_of_driver = { - .probe = sof_of_probe, - .remove = sof_of_remove, - .driver = { - .name = "sof-audio-of", - .pm = &sof_of_pm, - .of_match_table = sof_of_ids, - }, -}; -module_platform_driver(snd_sof_of_driver); +EXPORT_SYMBOL(sof_of_remove); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/sof-of-dev.h b/sound/soc/sof/sof-of-dev.h new file mode 100644 index 0000000000000..4e0f6588dad99 --- /dev/null +++ b/sound/soc/sof/sof-of-dev.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright 2021 NXP + */ + +#ifndef __SOUND_SOC_SOF_OF_H +#define __SOUND_SOC_SOF_OF_H + +extern const struct dev_pm_ops sof_of_pm; + +int sof_of_probe(struct platform_device *pdev); +int sof_of_remove(struct platform_device *pdev); + +#endif From 2167c0b205960607fb136b4bb3c556a62be1569a Mon Sep 17 00:00:00 2001 From: Jiasheng Jiang Date: Wed, 15 Dec 2021 11:15:50 +0800 Subject: [PATCH 187/327] ASoC: rt5663: Handle device_property_read_u32_array error codes The return value of device_property_read_u32_array() is not always 0. To catch the exception in case that devm_kzalloc failed and the rt5663->imp_table was NULL, which caused the failure of device_property_read_u32_array. Fixes: 450f0f6a8fb4 ("ASoC: rt5663: Add the manual offset field to compensate the DC offset") Signed-off-by: Jiasheng Jiang Link: https://lore.kernel.org/r/20211215031550.70702-1-jiasheng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/rt5663.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 0389b2bb360e2..2138f62e6af5d 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -3461,6 +3461,7 @@ static void rt5663_calibrate(struct rt5663_priv *rt5663) static int rt5663_parse_dp(struct rt5663_priv *rt5663, struct device *dev) { int table_size; + int ret; device_property_read_u32(dev, "realtek,dc_offset_l_manual", &rt5663->pdata.dc_offset_l_manual); @@ -3477,9 +3478,11 @@ static int rt5663_parse_dp(struct rt5663_priv *rt5663, struct device *dev) table_size = sizeof(struct impedance_mapping_table) * rt5663->pdata.impedance_sensing_num; rt5663->imp_table = devm_kzalloc(dev, table_size, GFP_KERNEL); - device_property_read_u32_array(dev, + ret = device_property_read_u32_array(dev, "realtek,impedance_sensing_table", (u32 *)rt5663->imp_table, table_size); + if (ret) + return ret; } return 0; @@ -3504,8 +3507,11 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, if (pdata) rt5663->pdata = *pdata; - else - rt5663_parse_dp(rt5663, &i2c->dev); + else { + ret = rt5663_parse_dp(rt5663, &i2c->dev); + if (ret) + return ret; + } for (i = 0; i < ARRAY_SIZE(rt5663->supplies); i++) rt5663->supplies[i].supply = rt5663_supply_names[i]; From 9d562fdcd52b1bb1a13cd5078ffc06dd3eff3aef Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 15 Dec 2021 10:03:57 -0800 Subject: [PATCH 188/327] ASoC: SOF: ipc: Rename send parameter in snd_sof_ipc_set_get_comp_data() Rename the send parameter to set in snd_sof_ipc_set_get_comp_data() and sof_set_get_large_ctrl_data() to be more aligned with the function name. No functional change. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20211215180404.53254-2-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc.c | 17 ++++++++--------- sound/soc/sof/sof-audio.h | 3 +-- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 6771b444065de..670d780241a3c 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -745,7 +745,7 @@ static int sof_get_ctrl_copy_params(enum sof_ipc_ctrl_type ctrl_type, static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev, struct sof_ipc_ctrl_data *cdata, struct sof_ipc_ctrl_data_params *sparams, - bool send) + bool set) { struct sof_ipc_ctrl_data *partdata; size_t send_bytes; @@ -760,7 +760,7 @@ static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev, if (!partdata) return -ENOMEM; - if (send) + if (set) err = sof_get_ctrl_copy_params(cdata->type, cdata, partdata, sparams); else @@ -789,7 +789,7 @@ static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev, msg_bytes -= send_bytes; partdata->elems_remaining = msg_bytes; - if (send) + if (set) memcpy(sparams->dst, sparams->src + offset, send_bytes); err = sof_ipc_tx_message_unlocked(sdev->ipc, @@ -801,7 +801,7 @@ static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev, if (err < 0) break; - if (!send) + if (!set) memcpy(sparams->dst + offset, sparams->src, send_bytes); offset += pl_size; @@ -819,8 +819,7 @@ static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev, int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, u32 ipc_cmd, enum sof_ipc_ctrl_type ctrl_type, - enum sof_ipc_ctrl_cmd ctrl_cmd, - bool send) + enum sof_ipc_ctrl_cmd ctrl_cmd, bool set) { struct snd_soc_component *scomp = scontrol->scomp; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; @@ -858,7 +857,7 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, /* write/read value header via mmaped region */ send_bytes = sizeof(struct sof_ipc_ctrl_value_chan) * cdata->num_elems; - if (send) + if (set) err = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_IRAM, scontrol->readback_offset, cdata->chanv, send_bytes); @@ -870,7 +869,7 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, if (err) dev_err_once(sdev->dev, "error: %s TYPE_IRAM failed\n", - send ? "write to" : "read from"); + set ? "write to" : "read from"); return err; } @@ -934,7 +933,7 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, return -EINVAL; } - err = sof_set_get_large_ctrl_data(sdev, cdata, &sparams, send); + err = sof_set_get_large_ctrl_data(sdev, cdata, &sparams, set); if (err < 0) dev_err(sdev->dev, "error: set/get large ctrl ipc comp %d\n", diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index e419e7082c28f..1c1d68e220d56 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -242,8 +242,7 @@ static inline void snd_sof_compr_init_elapsed_work(struct work_struct *work) { } int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, u32 ipc_cmd, enum sof_ipc_ctrl_type ctrl_type, - enum sof_ipc_ctrl_cmd ctrl_cmd, - bool send); + enum sof_ipc_ctrl_cmd ctrl_cmd, bool set); /* DAI link fixup */ int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params); From d4a06c4334aed1fe76ae2b7aaae6ee8b72f30a8e Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 15 Dec 2021 10:03:58 -0800 Subject: [PATCH 189/327] ASoC: SOF: Drop ipc_cmd parameter for snd_sof_ipc_set_get_comp_data() The correct ipc_cmd can be selected based on the `ctrl_cmd` and the `set` parameters: if the ctrl_cmd is SOF_CTRL_CMD_BINARY then SOF_IPC_COMP_*_DATA otherwise SOF_IPC_COMP_*_VALUE. The SET or GET direction can be selected with the use of `set` parameter. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20211215180404.53254-3-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/control.c | 15 ++------------- sound/soc/sof/ipc.c | 8 +++++++- sound/soc/sof/sof-audio.c | 6 ++---- sound/soc/sof/sof-audio.h | 1 - 4 files changed, 11 insertions(+), 19 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index bb1dfe4f6d401..299ee466625e2 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -69,7 +69,6 @@ static void snd_sof_refresh_control(struct snd_sof_control *scontrol) { struct sof_ipc_ctrl_data *cdata = scontrol->control_data; struct snd_soc_component *scomp = scontrol->scomp; - u32 ipc_cmd; int ret; if (!scontrol->comp_data_dirty) @@ -78,18 +77,13 @@ static void snd_sof_refresh_control(struct snd_sof_control *scontrol) if (!pm_runtime_active(scomp->dev)) return; - if (scontrol->cmd == SOF_CTRL_CMD_BINARY) - ipc_cmd = SOF_IPC_COMP_GET_DATA; - else - ipc_cmd = SOF_IPC_COMP_GET_VALUE; - /* set the ABI header values */ cdata->data->magic = SOF_ABI_MAGIC; cdata->data->abi = SOF_ABI_VERSION; /* refresh the component data from DSP */ scontrol->comp_data_dirty = false; - ret = snd_sof_ipc_set_get_comp_data(scontrol, ipc_cmd, + ret = snd_sof_ipc_set_get_comp_data(scontrol, SOF_CTRL_TYPE_VALUE_CHAN_GET, scontrol->cmd, false); if (ret < 0) { @@ -143,7 +137,6 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, /* notify DSP of mixer updates */ if (pm_runtime_active(scomp->dev)) snd_sof_ipc_set_get_comp_data(scontrol, - SOF_IPC_COMP_SET_VALUE, SOF_CTRL_TYPE_VALUE_CHAN_SET, SOF_CTRL_CMD_VOLUME, true); @@ -216,7 +209,6 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, /* notify DSP of mixer updates */ if (pm_runtime_active(scomp->dev)) snd_sof_ipc_set_get_comp_data(scontrol, - SOF_IPC_COMP_SET_VALUE, SOF_CTRL_TYPE_VALUE_CHAN_SET, SOF_CTRL_CMD_SWITCH, true); @@ -265,7 +257,6 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, /* notify DSP of enum updates */ if (pm_runtime_active(scomp->dev)) snd_sof_ipc_set_get_comp_data(scontrol, - SOF_IPC_COMP_SET_VALUE, SOF_CTRL_TYPE_VALUE_CHAN_SET, SOF_CTRL_CMD_ENUM, true); @@ -343,7 +334,6 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, /* notify DSP of byte control updates */ if (pm_runtime_active(scomp->dev)) snd_sof_ipc_set_get_comp_data(scontrol, - SOF_IPC_COMP_SET_DATA, SOF_CTRL_TYPE_DATA_SET, scontrol->cmd, true); @@ -423,7 +413,6 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, /* notify DSP of byte control updates */ if (pm_runtime_active(scomp->dev)) snd_sof_ipc_set_get_comp_data(scontrol, - SOF_IPC_COMP_SET_DATA, SOF_CTRL_TYPE_DATA_SET, scontrol->cmd, true); @@ -463,7 +452,7 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _ cdata->data->magic = SOF_ABI_MAGIC; cdata->data->abi = SOF_ABI_VERSION; /* get all the component data from DSP */ - ret = snd_sof_ipc_set_get_comp_data(scontrol, SOF_IPC_COMP_GET_DATA, SOF_CTRL_TYPE_DATA_GET, + ret = snd_sof_ipc_set_get_comp_data(scontrol, SOF_CTRL_TYPE_DATA_GET, scontrol->cmd, false); if (ret < 0) goto out; diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 670d780241a3c..bcfe7edee05e4 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -817,7 +817,6 @@ static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev, * IPC get()/set() for kcontrols. */ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, - u32 ipc_cmd, enum sof_ipc_ctrl_type ctrl_type, enum sof_ipc_ctrl_cmd ctrl_cmd, bool set) { @@ -830,6 +829,7 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, struct snd_sof_widget *swidget; bool widget_found = false; size_t send_bytes; + u32 ipc_cmd; int err; list_for_each_entry(swidget, &sdev->widget_list, list) { @@ -873,6 +873,12 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, return err; } + /* Select the IPC cmd based on the ctrl_cmd and the direction */ + if (ctrl_cmd == SOF_CTRL_CMD_BINARY) + ipc_cmd = set ? SOF_IPC_COMP_SET_DATA : SOF_IPC_COMP_GET_DATA; + else + ipc_cmd = set ? SOF_IPC_COMP_SET_VALUE : SOF_IPC_COMP_GET_VALUE; + cdata->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | ipc_cmd; cdata->cmd = ctrl_cmd; cdata->type = ctrl_type; diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 58a62bfb16ab7..dacc0122c3b46 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -14,7 +14,7 @@ static int sof_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) { - int ipc_cmd, ctrl_type; + enum sof_ipc_ctrl_type ctrl_type; int ret; /* reset readback offset for scontrol */ @@ -25,18 +25,16 @@ static int sof_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_control * case SOF_CTRL_CMD_VOLUME: case SOF_CTRL_CMD_ENUM: case SOF_CTRL_CMD_SWITCH: - ipc_cmd = SOF_IPC_COMP_SET_VALUE; ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_SET; break; case SOF_CTRL_CMD_BINARY: - ipc_cmd = SOF_IPC_COMP_SET_DATA; ctrl_type = SOF_CTRL_TYPE_DATA_SET; break; default: return 0; } - ret = snd_sof_ipc_set_get_comp_data(scontrol, ipc_cmd, ctrl_type, scontrol->cmd, true); + ret = snd_sof_ipc_set_get_comp_data(scontrol, ctrl_type, scontrol->cmd, true); if (ret < 0) dev_err(sdev->dev, "error: failed kcontrol value set for widget: %d\n", scontrol->comp_id); diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 1c1d68e220d56..f4316cd742a7f 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -240,7 +240,6 @@ static inline void snd_sof_compr_init_elapsed_work(struct work_struct *work) { } * Mixer IPC */ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, - u32 ipc_cmd, enum sof_ipc_ctrl_type ctrl_type, enum sof_ipc_ctrl_cmd ctrl_cmd, bool set); From 8af783723f41d3b3d4f7f8452f190405e7059472 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 15 Dec 2021 10:03:59 -0800 Subject: [PATCH 190/327] ASoC: SOF: topology: Set control_data->cmd alongside scontrol->cmd Set the scontrol->control_data->cmd early to the same as scontrol->cmd. This is a preparatory patch to remove the ctrl_cmd parameter for the snd_sof_ipc_set_get_comp_data() function. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20211215180404.53254-4-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/topology.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index b3ad3a6049189..c440e1c53ca5f 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1091,10 +1091,12 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, /* set cmd for mixer control */ if (le32_to_cpu(mc->max) == 1) { scontrol->cmd = SOF_CTRL_CMD_SWITCH; + scontrol->control_data->cmd = scontrol->cmd; goto skip; } scontrol->cmd = SOF_CTRL_CMD_VOLUME; + scontrol->control_data->cmd = scontrol->cmd; /* extract tlv data */ if (!kc->tlv.p || get_tlv_data(kc->tlv.p, tlv) < 0) { @@ -1166,6 +1168,7 @@ static int sof_control_load_enum(struct snd_soc_component *scomp, scontrol->num_channels = le32_to_cpu(ec->num_channels); scontrol->control_data->index = kc->index; scontrol->cmd = SOF_CTRL_CMD_ENUM; + scontrol->control_data->cmd = scontrol->cmd; dev_dbg(scomp->dev, "tplg: load kcontrol index %d chans %d comp_id %d\n", scontrol->comp_id, scontrol->num_channels, scontrol->comp_id); @@ -1212,6 +1215,7 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, scontrol->comp_id = sdev->next_comp_id; scontrol->cmd = SOF_CTRL_CMD_BINARY; + scontrol->control_data->cmd = scontrol->cmd; scontrol->control_data->index = kc->index; dev_dbg(scomp->dev, "tplg: load kcontrol index %d chans %d\n", From 9182f3c40b52ebd91d4796d96186ba10b720b4ba Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 15 Dec 2021 10:04:00 -0800 Subject: [PATCH 191/327] ASoC: SOF: Drop ctrl_cmd parameter for snd_sof_ipc_set_get_comp_data() The scontrol->control_data->cmd has been configured during initialization to the correct sof_ipc_ctrl_cmd. No need to pass duplicated information, let's use the already available one via scontrol. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20211215180404.53254-5-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/control.c | 26 +++++++------------------- sound/soc/sof/ipc.c | 6 ++---- sound/soc/sof/sof-audio.c | 2 +- sound/soc/sof/sof-audio.h | 3 +-- 4 files changed, 11 insertions(+), 26 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 299ee466625e2..23a916ea93f89 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -84,8 +84,7 @@ static void snd_sof_refresh_control(struct snd_sof_control *scontrol) /* refresh the component data from DSP */ scontrol->comp_data_dirty = false; ret = snd_sof_ipc_set_get_comp_data(scontrol, - SOF_CTRL_TYPE_VALUE_CHAN_GET, - scontrol->cmd, false); + SOF_CTRL_TYPE_VALUE_CHAN_GET, false); if (ret < 0) { dev_err(scomp->dev, "error: failed to get control data: %d\n", ret); /* Set the flag to re-try next time to get the data */ @@ -137,9 +136,7 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, /* notify DSP of mixer updates */ if (pm_runtime_active(scomp->dev)) snd_sof_ipc_set_get_comp_data(scontrol, - SOF_CTRL_TYPE_VALUE_CHAN_SET, - SOF_CTRL_CMD_VOLUME, - true); + SOF_CTRL_TYPE_VALUE_CHAN_SET, true); return change; } @@ -209,9 +206,7 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, /* notify DSP of mixer updates */ if (pm_runtime_active(scomp->dev)) snd_sof_ipc_set_get_comp_data(scontrol, - SOF_CTRL_TYPE_VALUE_CHAN_SET, - SOF_CTRL_CMD_SWITCH, - true); + SOF_CTRL_TYPE_VALUE_CHAN_SET, true); return change; } @@ -257,9 +252,7 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, /* notify DSP of enum updates */ if (pm_runtime_active(scomp->dev)) snd_sof_ipc_set_get_comp_data(scontrol, - SOF_CTRL_TYPE_VALUE_CHAN_SET, - SOF_CTRL_CMD_ENUM, - true); + SOF_CTRL_TYPE_VALUE_CHAN_SET, true); return change; } @@ -334,9 +327,7 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, /* notify DSP of byte control updates */ if (pm_runtime_active(scomp->dev)) snd_sof_ipc_set_get_comp_data(scontrol, - SOF_CTRL_TYPE_DATA_SET, - scontrol->cmd, - true); + SOF_CTRL_TYPE_DATA_SET, true); return 0; } @@ -413,9 +404,7 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, /* notify DSP of byte control updates */ if (pm_runtime_active(scomp->dev)) snd_sof_ipc_set_get_comp_data(scontrol, - SOF_CTRL_TYPE_DATA_SET, - scontrol->cmd, - true); + SOF_CTRL_TYPE_DATA_SET, true); return 0; } @@ -452,8 +441,7 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _ cdata->data->magic = SOF_ABI_MAGIC; cdata->data->abi = SOF_ABI_VERSION; /* get all the component data from DSP */ - ret = snd_sof_ipc_set_get_comp_data(scontrol, SOF_CTRL_TYPE_DATA_GET, - scontrol->cmd, false); + ret = snd_sof_ipc_set_get_comp_data(scontrol, SOF_CTRL_TYPE_DATA_GET, false); if (ret < 0) goto out; diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index bcfe7edee05e4..69c8a9964960f 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -817,8 +817,7 @@ static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev, * IPC get()/set() for kcontrols. */ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, - enum sof_ipc_ctrl_type ctrl_type, - enum sof_ipc_ctrl_cmd ctrl_cmd, bool set) + enum sof_ipc_ctrl_type ctrl_type, bool set) { struct snd_soc_component *scomp = scontrol->scomp; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; @@ -874,13 +873,12 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, } /* Select the IPC cmd based on the ctrl_cmd and the direction */ - if (ctrl_cmd == SOF_CTRL_CMD_BINARY) + if (cdata->cmd == SOF_CTRL_CMD_BINARY) ipc_cmd = set ? SOF_IPC_COMP_SET_DATA : SOF_IPC_COMP_GET_DATA; else ipc_cmd = set ? SOF_IPC_COMP_SET_VALUE : SOF_IPC_COMP_GET_VALUE; cdata->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | ipc_cmd; - cdata->cmd = ctrl_cmd; cdata->type = ctrl_type; cdata->comp_id = scontrol->comp_id; cdata->msg_index = 0; diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index dacc0122c3b46..269eca26eab93 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -34,7 +34,7 @@ static int sof_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_control * return 0; } - ret = snd_sof_ipc_set_get_comp_data(scontrol, ctrl_type, scontrol->cmd, true); + ret = snd_sof_ipc_set_get_comp_data(scontrol, ctrl_type, true); if (ret < 0) dev_err(sdev->dev, "error: failed kcontrol value set for widget: %d\n", scontrol->comp_id); diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index f4316cd742a7f..5bcc842e47924 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -240,8 +240,7 @@ static inline void snd_sof_compr_init_elapsed_work(struct work_struct *work) { } * Mixer IPC */ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, - enum sof_ipc_ctrl_type ctrl_type, - enum sof_ipc_ctrl_cmd ctrl_cmd, bool set); + enum sof_ipc_ctrl_type ctrl_type, bool set); /* DAI link fixup */ int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params); From dd2fef982ff75fbae618cc274fda09bd40582acd Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 15 Dec 2021 10:04:01 -0800 Subject: [PATCH 192/327] ASoC: SOF: sof-audio: Drop the `cmd` member from struct snd_sof_control There is no need to use two variables to store and check the same information, the scontrol->cmd is the same as scontrol->control_data->cmd. Drop the former one and when it is needed, access the cmd from the control_data. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20211215180404.53254-6-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/control.c | 6 +++--- sound/soc/sof/sof-audio.c | 2 +- sound/soc/sof/sof-audio.h | 1 - sound/soc/sof/topology.c | 14 +++++--------- 4 files changed, 9 insertions(+), 14 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 23a916ea93f89..9297b29d65cdb 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -372,7 +372,7 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, } /* Check that header id matches the command */ - if (header.numid != scontrol->cmd) { + if (header.numid != cdata->cmd) { dev_err_ratelimited(scomp->dev, "error: incorrect numid %d\n", header.numid); @@ -462,7 +462,7 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _ goto out; } - header.numid = scontrol->cmd; + header.numid = cdata->cmd; header.length = data_size; if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv))) { ret = -EFAULT; @@ -522,7 +522,7 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, if (data_size > size) return -ENOSPC; - header.numid = scontrol->cmd; + header.numid = cdata->cmd; header.length = data_size; if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv))) return -EFAULT; diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 269eca26eab93..4530c6ed34e06 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -21,7 +21,7 @@ static int sof_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_control * scontrol->readback_offset = 0; /* notify DSP of kcontrol values */ - switch (scontrol->cmd) { + switch (scontrol->control_data->cmd) { case SOF_CTRL_CMD_VOLUME: case SOF_CTRL_CMD_ENUM: case SOF_CTRL_CMD_SWITCH: diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 5bcc842e47924..84a8ebe3b1c33 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -74,7 +74,6 @@ struct snd_sof_control { u32 readback_offset; /* offset to mmapped data if used */ struct sof_ipc_ctrl_data *control_data; u32 size; /* cdata size */ - enum sof_ipc_ctrl_cmd cmd; u32 *volume_table; /* volume table computed from tlv data*/ struct list_head list; /* list in sdev control list */ diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index c440e1c53ca5f..ec59baf32699d 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1090,13 +1090,11 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, /* set cmd for mixer control */ if (le32_to_cpu(mc->max) == 1) { - scontrol->cmd = SOF_CTRL_CMD_SWITCH; - scontrol->control_data->cmd = scontrol->cmd; + scontrol->control_data->cmd = SOF_CTRL_CMD_SWITCH; goto skip; } - scontrol->cmd = SOF_CTRL_CMD_VOLUME; - scontrol->control_data->cmd = scontrol->cmd; + scontrol->control_data->cmd = SOF_CTRL_CMD_VOLUME; /* extract tlv data */ if (!kc->tlv.p || get_tlv_data(kc->tlv.p, tlv) < 0) { @@ -1167,8 +1165,7 @@ static int sof_control_load_enum(struct snd_soc_component *scomp, scontrol->comp_id = sdev->next_comp_id; scontrol->num_channels = le32_to_cpu(ec->num_channels); scontrol->control_data->index = kc->index; - scontrol->cmd = SOF_CTRL_CMD_ENUM; - scontrol->control_data->cmd = scontrol->cmd; + scontrol->control_data->cmd = SOF_CTRL_CMD_ENUM; dev_dbg(scomp->dev, "tplg: load kcontrol index %d chans %d comp_id %d\n", scontrol->comp_id, scontrol->num_channels, scontrol->comp_id); @@ -1214,8 +1211,7 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, } scontrol->comp_id = sdev->next_comp_id; - scontrol->cmd = SOF_CTRL_CMD_BINARY; - scontrol->control_data->cmd = scontrol->cmd; + scontrol->control_data->cmd = SOF_CTRL_CMD_BINARY; scontrol->control_data->index = kc->index; dev_dbg(scomp->dev, "tplg: load kcontrol index %d chans %d\n", @@ -2080,7 +2076,7 @@ static int sof_get_control_data(struct snd_soc_component *scomp, *size += wdata[i].pdata->size; /* get data type */ - switch (wdata[i].control->cmd) { + switch (wdata[i].control->control_data->cmd) { case SOF_CTRL_CMD_VOLUME: case SOF_CTRL_CMD_ENUM: case SOF_CTRL_CMD_SWITCH: From 68be4f0ed40cce833cb313871c52878025e40596 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 15 Dec 2021 10:04:02 -0800 Subject: [PATCH 193/327] ASoC: SOF: control: Do not handle control notification with component type The component type is not used in firmware nor in the kernel currently and it is not even clear how it should be handled. Do not even try to handle it to avoid errors. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20211215180404.53254-7-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/control.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 9297b29d65cdb..dac0b630b6a07 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -577,6 +577,13 @@ void snd_sof_control_notify(struct snd_sof_dev *sdev, bool found = false; int i, type; + if (cdata->type == SOF_CTRL_TYPE_VALUE_COMP_GET || + cdata->type == SOF_CTRL_TYPE_VALUE_COMP_SET) { + dev_err(sdev->dev, + "Component data is not supported in control notification\n"); + return; + } + /* Find the swidget first */ list_for_each_entry(swidget, &sdev->widget_list, list) { if (swidget->comp_id == cdata->comp_id) { @@ -643,11 +650,6 @@ void snd_sof_control_notify(struct snd_sof_dev *sdev, expected_size += cdata->num_elems * sizeof(struct sof_ipc_ctrl_value_chan); break; - case SOF_CTRL_TYPE_VALUE_COMP_GET: - case SOF_CTRL_TYPE_VALUE_COMP_SET: - expected_size += cdata->num_elems * - sizeof(struct sof_ipc_ctrl_value_comp); - break; case SOF_CTRL_TYPE_DATA_GET: case SOF_CTRL_TYPE_DATA_SET: expected_size += cdata->num_elems + sizeof(struct sof_abi_hdr); From 47d7328f8cda15e60422c8ca36d067c4deb19b7e Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 15 Dec 2021 10:04:03 -0800 Subject: [PATCH 194/327] ASoC: SOF: Drop ctrl_type parameter for snd_sof_ipc_set_get_comp_data() The SOF_CTRL_TYPE_VALUE_COMP_* type is not used by the firmware nor in the kernel side. It is also not clear what action should be taken for such type. With this in mind: The correct ipc_cmd can be selected based on the `ctrl_cmd` and the `set` parameters: if the ctrl_cmd is SOF_CTRL_CMD_BINARY then SOF_CTRL_TYPE_DATA_* otherwise SOF_CTRL_TYPE_VALUE_CHAN_*. The SET or GET direction can be selected with the use of `set` parameter. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20211215180404.53254-8-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/control.c | 20 +++++++------------- sound/soc/sof/ipc.c | 30 +++++++++++++----------------- sound/soc/sof/sof-audio.c | 17 +---------------- sound/soc/sof/sof-audio.h | 3 +-- 4 files changed, 22 insertions(+), 48 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index dac0b630b6a07..ef61936dad594 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -83,8 +83,7 @@ static void snd_sof_refresh_control(struct snd_sof_control *scontrol) /* refresh the component data from DSP */ scontrol->comp_data_dirty = false; - ret = snd_sof_ipc_set_get_comp_data(scontrol, - SOF_CTRL_TYPE_VALUE_CHAN_GET, false); + ret = snd_sof_ipc_set_get_comp_data(scontrol, false); if (ret < 0) { dev_err(scomp->dev, "error: failed to get control data: %d\n", ret); /* Set the flag to re-try next time to get the data */ @@ -135,8 +134,7 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, /* notify DSP of mixer updates */ if (pm_runtime_active(scomp->dev)) - snd_sof_ipc_set_get_comp_data(scontrol, - SOF_CTRL_TYPE_VALUE_CHAN_SET, true); + snd_sof_ipc_set_get_comp_data(scontrol, true); return change; } @@ -205,8 +203,7 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, /* notify DSP of mixer updates */ if (pm_runtime_active(scomp->dev)) - snd_sof_ipc_set_get_comp_data(scontrol, - SOF_CTRL_TYPE_VALUE_CHAN_SET, true); + snd_sof_ipc_set_get_comp_data(scontrol, true); return change; } @@ -251,8 +248,7 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, /* notify DSP of enum updates */ if (pm_runtime_active(scomp->dev)) - snd_sof_ipc_set_get_comp_data(scontrol, - SOF_CTRL_TYPE_VALUE_CHAN_SET, true); + snd_sof_ipc_set_get_comp_data(scontrol, true); return change; } @@ -326,8 +322,7 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, /* notify DSP of byte control updates */ if (pm_runtime_active(scomp->dev)) - snd_sof_ipc_set_get_comp_data(scontrol, - SOF_CTRL_TYPE_DATA_SET, true); + snd_sof_ipc_set_get_comp_data(scontrol, true); return 0; } @@ -403,8 +398,7 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, /* notify DSP of byte control updates */ if (pm_runtime_active(scomp->dev)) - snd_sof_ipc_set_get_comp_data(scontrol, - SOF_CTRL_TYPE_DATA_SET, true); + snd_sof_ipc_set_get_comp_data(scontrol, true); return 0; } @@ -441,7 +435,7 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _ cdata->data->magic = SOF_ABI_MAGIC; cdata->data->abi = SOF_ABI_VERSION; /* get all the component data from DSP */ - ret = snd_sof_ipc_set_get_comp_data(scontrol, SOF_CTRL_TYPE_DATA_GET, false); + ret = snd_sof_ipc_set_get_comp_data(scontrol, false); if (ret < 0) goto out; diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 69c8a9964960f..8a1eacc7ec5fd 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -721,11 +721,6 @@ static int sof_get_ctrl_copy_params(enum sof_ipc_ctrl_type ctrl_type, sparams->src = (u8 *)src->chanv; sparams->dst = (u8 *)dst->chanv; break; - case SOF_CTRL_TYPE_VALUE_COMP_GET: - case SOF_CTRL_TYPE_VALUE_COMP_SET: - sparams->src = (u8 *)src->compv; - sparams->dst = (u8 *)dst->compv; - break; case SOF_CTRL_TYPE_DATA_GET: case SOF_CTRL_TYPE_DATA_SET: sparams->src = (u8 *)src->data->data; @@ -816,8 +811,7 @@ static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev, /* * IPC get()/set() for kcontrols. */ -int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, - enum sof_ipc_ctrl_type ctrl_type, bool set) +int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, bool set) { struct snd_soc_component *scomp = scontrol->scomp; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; @@ -825,6 +819,7 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, struct sof_ipc_fw_ready *ready = &sdev->fw_ready; struct sof_ipc_fw_version *v = &ready->version; struct sof_ipc_ctrl_data_params sparams; + enum sof_ipc_ctrl_type ctrl_type; struct snd_sof_widget *swidget; bool widget_found = false; size_t send_bytes; @@ -872,11 +867,19 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, return err; } - /* Select the IPC cmd based on the ctrl_cmd and the direction */ - if (cdata->cmd == SOF_CTRL_CMD_BINARY) + /* + * Select the IPC cmd and the ctrl_type based on the ctrl_cmd and the + * direction + * Note: SOF_CTRL_TYPE_VALUE_COMP_* is not used and supported currently + * for ctrl_type + */ + if (cdata->cmd == SOF_CTRL_CMD_BINARY) { ipc_cmd = set ? SOF_IPC_COMP_SET_DATA : SOF_IPC_COMP_GET_DATA; - else + ctrl_type = set ? SOF_CTRL_TYPE_DATA_SET : SOF_CTRL_TYPE_DATA_GET; + } else { ipc_cmd = set ? SOF_IPC_COMP_SET_VALUE : SOF_IPC_COMP_GET_VALUE; + ctrl_type = set ? SOF_CTRL_TYPE_VALUE_CHAN_SET : SOF_CTRL_TYPE_VALUE_CHAN_GET; + } cdata->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | ipc_cmd; cdata->type = ctrl_type; @@ -892,13 +895,6 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, sparams.hdr_bytes = sizeof(struct sof_ipc_ctrl_data); sparams.elems = scontrol->num_channels; break; - case SOF_CTRL_TYPE_VALUE_COMP_GET: - case SOF_CTRL_TYPE_VALUE_COMP_SET: - sparams.msg_bytes = scontrol->num_channels * - sizeof(struct sof_ipc_ctrl_value_comp); - sparams.hdr_bytes = sizeof(struct sof_ipc_ctrl_data); - sparams.elems = scontrol->num_channels; - break; case SOF_CTRL_TYPE_DATA_GET: case SOF_CTRL_TYPE_DATA_SET: sparams.msg_bytes = cdata->data->size; diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 4530c6ed34e06..735fbc5fe1bd3 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -14,27 +14,12 @@ static int sof_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) { - enum sof_ipc_ctrl_type ctrl_type; int ret; /* reset readback offset for scontrol */ scontrol->readback_offset = 0; - /* notify DSP of kcontrol values */ - switch (scontrol->control_data->cmd) { - case SOF_CTRL_CMD_VOLUME: - case SOF_CTRL_CMD_ENUM: - case SOF_CTRL_CMD_SWITCH: - ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_SET; - break; - case SOF_CTRL_CMD_BINARY: - ctrl_type = SOF_CTRL_TYPE_DATA_SET; - break; - default: - return 0; - } - - ret = snd_sof_ipc_set_get_comp_data(scontrol, ctrl_type, true); + ret = snd_sof_ipc_set_get_comp_data(scontrol, true); if (ret < 0) dev_err(sdev->dev, "error: failed kcontrol value set for widget: %d\n", scontrol->comp_id); diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 84a8ebe3b1c33..f3009e6b91a10 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -238,8 +238,7 @@ static inline void snd_sof_compr_init_elapsed_work(struct work_struct *work) { } /* * Mixer IPC */ -int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, - enum sof_ipc_ctrl_type ctrl_type, bool set); +int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, bool set); /* DAI link fixup */ int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params); From fc5adc2bb13a6988df7ce377320f381add236002 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 15 Dec 2021 10:04:04 -0800 Subject: [PATCH 195/327] ASoC: SOF: topology: read back control data from DSP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Read back the control data from the DSP to initialize the control data size to match that of the data in the DSP. This is particularly useful for volatile read-only kcontrols in static pipelines. Signed-off-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Reviewed-by: Péter Ujfalusi Link: https://lore.kernel.org/r/20211215180404.53254-9-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-audio.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 735fbc5fe1bd3..91e3fa5a73501 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -59,12 +59,26 @@ static int sof_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_wi /* set up all controls for the widget */ list_for_each_entry(scontrol, &sdev->kcontrol_list, list) if (scontrol->comp_id == swidget->comp_id) { + /* set kcontrol data in DSP */ ret = sof_kcontrol_setup(sdev, scontrol); if (ret < 0) { dev_err(sdev->dev, "error: fail to set up kcontrols for widget %s\n", swidget->widget->name); return ret; } + + /* + * Read back the data from the DSP for static widgets. This is particularly + * useful for binary kcontrols associated with static pipeline widgets to + * initialize the data size to match that in the DSP. + */ + if (swidget->dynamic_pipeline_widget) + continue; + + ret = snd_sof_ipc_set_get_comp_data(scontrol, false); + if (ret < 0) + dev_warn(sdev->dev, "Failed kcontrol get for control in widget %s\n", + swidget->widget->name); } return 0; From 88dffe43cbc625eb52a57daa0d1c0fb7037b63d2 Mon Sep 17 00:00:00 2001 From: David Heidelberg Date: Sat, 11 Dec 2021 23:49:44 +0100 Subject: [PATCH 196/327] ASoC: nvidia,tegra-audio: Convert multiple txt bindings to yaml Convert Tegra audio complex with the * ALC5632 * MAX98090 * RT5640 * RT5677 * SGTL5000 * TrimSlice * WM8753 * WM8903 * WM9712 codec to the YAML format. Additional changes: - added missing HPOUTL to the WM9712 codec. - extended rt5677 codec with multiple pins Reviewed-by: Dmitry Osipenko Signed-off-by: David Heidelberg Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20211211224946.79875-1-david@ixit.cz Signed-off-by: Mark Brown --- .../sound/nvidia,tegra-audio-alc5632.txt | 48 -------- .../sound/nvidia,tegra-audio-alc5632.yaml | 74 +++++++++++++ .../sound/nvidia,tegra-audio-common.yaml | 83 ++++++++++++++ .../sound/nvidia,tegra-audio-max98090.txt | 53 --------- .../sound/nvidia,tegra-audio-max98090.yaml | 97 +++++++++++++++++ .../sound/nvidia,tegra-audio-rt5640.txt | 52 --------- .../sound/nvidia,tegra-audio-rt5640.yaml | 85 +++++++++++++++ .../sound/nvidia,tegra-audio-rt5677.txt | 67 ------------ .../sound/nvidia,tegra-audio-rt5677.yaml | 103 ++++++++++++++++++ .../sound/nvidia,tegra-audio-sgtl5000.txt | 42 ------- .../sound/nvidia,tegra-audio-sgtl5000.yaml | 67 ++++++++++++ .../sound/nvidia,tegra-audio-trimslice.txt | 21 ---- .../sound/nvidia,tegra-audio-trimslice.yaml | 33 ++++++ .../sound/nvidia,tegra-audio-wm8753.txt | 40 ------- .../sound/nvidia,tegra-audio-wm8753.yaml | 79 ++++++++++++++ .../sound/nvidia,tegra-audio-wm8903.txt | 62 ----------- .../sound/nvidia,tegra-audio-wm8903.yaml | 93 ++++++++++++++++ .../sound/nvidia,tegra-audio-wm9712.txt | 60 ---------- .../sound/nvidia,tegra-audio-wm9712.yaml | 76 +++++++++++++ 19 files changed, 790 insertions(+), 445 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.txt create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.yaml create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra-audio-common.yaml delete mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.yaml delete mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.txt create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.yaml delete mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5677.txt create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5677.yaml delete mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra-audio-sgtl5000.txt create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra-audio-sgtl5000.yaml delete mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra-audio-trimslice.txt create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra-audio-trimslice.yaml delete mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8753.txt create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8753.yaml delete mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.txt create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.yaml delete mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.txt create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.yaml diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.txt deleted file mode 100644 index 57f40f93453ec..0000000000000 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.txt +++ /dev/null @@ -1,48 +0,0 @@ -NVIDIA Tegra audio complex - -Required properties: -- compatible : "nvidia,tegra-audio-alc5632" -- clocks : Must contain an entry for each entry in clock-names. - See ../clocks/clock-bindings.txt for details. -- clock-names : Must include the following entries: - - pll_a - - pll_a_out0 - - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) -- nvidia,model : The user-visible name of this sound complex. -- nvidia,audio-routing : A list of the connections between audio components. - Each entry is a pair of strings, the first being the connection's sink, - the second being the connection's source. Valid names for sources and - sinks are the ALC5632's pins as documented in the binding for the device - and: - - * Headset Stereophone - * Int Spk - * Headset Mic - * Digital Mic - -- nvidia,i2s-controller : The phandle of the Tegra I2S controller -- nvidia,audio-codec : The phandle of the ALC5632 audio codec - -Example: - -sound { - compatible = "nvidia,tegra-audio-alc5632-paz00", - "nvidia,tegra-audio-alc5632"; - - nvidia,model = "Compal PAZ00"; - - nvidia,audio-routing = - "Int Spk", "SPK_OUTP", - "Int Spk", "SPK_OUTN", - "Headset Mic","MICBIAS1", - "MIC1_N", "Headset Mic", - "MIC1_P", "Headset Mic", - "Headset Stereophone", "HP_OUT_R", - "Headset Stereophone", "HP_OUT_L"; - - nvidia,i2s-controller = <&tegra_i2s1>; - nvidia,audio-codec = <&alc5632>; - - clocks = <&tegra_car 112>, <&tegra_car 113>, <&tegra_car 93>; - clock-names = "pll_a", "pll_a_out0", "mclk"; -}; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.yaml new file mode 100644 index 0000000000000..7ef774910e5cd --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.yaml @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nvidia,tegra-audio-alc5632.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NVIDIA Tegra audio complex with ALC5632 CODEC + +maintainers: + - Jon Hunter + - Thierry Reding + +allOf: + - $ref: nvidia,tegra-audio-common.yaml# + +properties: + compatible: + items: + - pattern: '^[a-z0-9]+,tegra-audio-alc5632(-[a-z0-9]+)+$' + - const: nvidia,tegra-audio-alc5632 + + nvidia,audio-routing: + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + description: | + A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources and + sinks are the pins (documented in the binding document), + and the jacks on the board. + minItems: 2 + items: + enum: + # Board Connectors + - "Headset Stereophone" + - "Int Spk" + - "Headset Mic" + - "Digital Mic" + + # CODEC Pins + - SPKOUT + - SPKOUTN + - MICBIAS1 + - MIC1 + - HPR + - HPL + - DMICDAT + +required: + - nvidia,i2s-controller + +unevaluatedProperties: false + +examples: + - | + sound { + compatible = "nvidia,tegra-audio-alc5632-paz00", + "nvidia,tegra-audio-alc5632"; + + nvidia,model = "Compal PAZ00"; + + nvidia,audio-routing = "Int Spk", "SPKOUT", + "Int Spk", "SPKOUTN", + "Headset Mic", "MICBIAS1", + "MIC1", "Headset Mic", + "Headset Stereophone", "HPR", + "Headset Stereophone", "HPL", + "DMICDAT", "Digital Mic"; + + nvidia,i2s-controller = <&i2s>; + nvidia,audio-codec = <&codec>; + + clocks = <&clk 112>, <&clk 113>, <&clk 93>; + clock-names = "pll_a", "pll_a_out0", "mclk"; + }; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-common.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-common.yaml new file mode 100644 index 0000000000000..82801b4f46dd6 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-common.yaml @@ -0,0 +1,83 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/sound/nvidia,tegra-audio-common.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Common properties for NVIDIA Tegra audio complexes + +maintainers: + - Jon Hunter + - Thierry Reding + +properties: + clocks: + items: + - description: PLL A clock + - description: PLL A OUT0 clock + - description: The Tegra cdev1/extern1 clock, which feeds the card's mclk + + clock-names: + items: + - const: pll_a + - const: pll_a_out0 + - const: mclk + + nvidia,model: + $ref: /schemas/types.yaml#/definitions/string + description: The user-visible name of this sound complex. + + nvidia,audio-routing: + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + description: | + A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources and + sinks are the pins (documented in the binding document), + and the jacks on the board. + + nvidia,ac97-controller: + $ref: /schemas/types.yaml#/definitions/phandle + description: The phandle of the AC97 controller + + nvidia,i2s-controller: + $ref: /schemas/types.yaml#/definitions/phandle + description: The phandle of the Tegra I2S controller + + nvidia,audio-codec: + $ref: /schemas/types.yaml#/definitions/phandle + description: The phandle of audio codec + + nvidia,spkr-en-gpios: + maxItems: 1 + description: The GPIO that enables the speakers + + nvidia,hp-mute-gpios: + maxItems: 1 + description: The GPIO that mutes the headphones + + nvidia,hp-det-gpios: + maxItems: 1 + description: The GPIO that detect headphones are plugged in + + nvidia,mic-det-gpios: + maxItems: 1 + description: The GPIO that detect microphone is plugged in + + nvidia,ear-sel-gpios: + maxItems: 1 + description: The GPIO that switch between the microphones + + nvidia,int-mic-en-gpios: + maxItems: 1 + description: The GPIO that enables the internal microphone + + nvidia,ext-mic-en-gpios: + maxItems: 1 + description: The GPIO that enables the external microphone + + nvidia,headset: + type: boolean + description: The Mic Jack represents state of the headset microphone pin + +additionalProperties: true diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt deleted file mode 100644 index c3495beba3584..0000000000000 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt +++ /dev/null @@ -1,53 +0,0 @@ -NVIDIA Tegra audio complex, with MAX98090 CODEC - -Required properties: -- compatible : "nvidia,tegra-audio-max98090" -- clocks : Must contain an entry for each entry in clock-names. - See ../clocks/clock-bindings.txt for details. -- clock-names : Must include the following entries: - - pll_a - - pll_a_out0 - - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) -- nvidia,model : The user-visible name of this sound complex. -- nvidia,audio-routing : A list of the connections between audio components. - Each entry is a pair of strings, the first being the connection's sink, - the second being the connection's source. Valid names for sources and - sinks are the MAX98090's pins (as documented in its binding), and the jacks - on the board: - - * Headphones - * Speakers - * Mic Jack - * Int Mic - -- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's - connected to the CODEC. -- nvidia,audio-codec : The phandle of the MAX98090 audio codec. - -Optional properties: -- nvidia,hp-det-gpios : The GPIO that detect headphones are plugged in -- nvidia,mic-det-gpios : The GPIO that detect microphones are plugged in - -Example: - -sound { - compatible = "nvidia,tegra-audio-max98090-venice2", - "nvidia,tegra-audio-max98090"; - nvidia,model = "NVIDIA Tegra Venice2"; - - nvidia,audio-routing = - "Headphones", "HPR", - "Headphones", "HPL", - "Speakers", "SPKR", - "Speakers", "SPKL", - "Mic Jack", "MICBIAS", - "IN34", "Mic Jack"; - - nvidia,i2s-controller = <&tegra_i2s1>; - nvidia,audio-codec = <&acodec>; - - clocks = <&tegra_car TEGRA124_CLK_PLL_A>, - <&tegra_car TEGRA124_CLK_PLL_A_OUT0>, - <&tegra_car TEGRA124_CLK_EXTERN1>; - clock-names = "pll_a", "pll_a_out0", "mclk"; -}; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.yaml new file mode 100644 index 0000000000000..ccc2ee77ca306 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.yaml @@ -0,0 +1,97 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nvidia,tegra-audio-max98090.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NVIDIA Tegra audio complex with MAX98090 CODEC + +maintainers: + - Jon Hunter + - Thierry Reding + +allOf: + - $ref: nvidia,tegra-audio-common.yaml# + +properties: + compatible: + oneOf: + - items: + - pattern: '^[a-z0-9]+,tegra-audio-max98090(-[a-z0-9]+)+$' + - const: nvidia,tegra-audio-max98090 + - items: + - enum: + - nvidia,tegra-audio-max98090-nyan-big + - nvidia,tegra-audio-max98090-nyan-blaze + - const: nvidia,tegra-audio-max98090-nyan + - const: nvidia,tegra-audio-max98090 + + nvidia,audio-routing: + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + description: | + A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources and + sinks are the pins (documented in the binding document), + and the jacks on the board. + minItems: 2 + items: + enum: + # Board Connectors + - "Headphones" + - "Speakers" + - "Mic Jack" + - "Int Mic" + + # CODEC Pins + - MIC1 + - MIC2 + - DMICL + - DMICR + - IN1 + - IN2 + - IN3 + - IN4 + - IN5 + - IN6 + - IN12 + - IN34 + - IN56 + - HPL + - HPR + - SPKL + - SPKR + - RCVL + - RCVR + - MICBIAS + +required: + - nvidia,i2s-controller + +unevaluatedProperties: false + +examples: + - | + #include + + sound { + compatible = "nvidia,tegra-audio-max98090-venice2", + "nvidia,tegra-audio-max98090"; + nvidia,model = "NVIDIA Tegra Venice2"; + + nvidia,audio-routing = + "Headphones", "HPR", + "Headphones", "HPL", + "Speakers", "SPKR", + "Speakers", "SPKL", + "Mic Jack", "MICBIAS", + "IN34", "Mic Jack"; + + nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,audio-codec = <&acodec>; + + clocks = <&tegra_car TEGRA124_CLK_PLL_A>, + <&tegra_car TEGRA124_CLK_PLL_A_OUT0>, + <&tegra_car TEGRA124_CLK_EXTERN1>; + clock-names = "pll_a", "pll_a_out0", "mclk"; + }; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.txt deleted file mode 100644 index 7788808dcd0bb..0000000000000 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.txt +++ /dev/null @@ -1,52 +0,0 @@ -NVIDIA Tegra audio complex, with RT5640 CODEC - -Required properties: -- compatible : "nvidia,tegra-audio-rt5640" -- clocks : Must contain an entry for each entry in clock-names. - See ../clocks/clock-bindings.txt for details. -- clock-names : Must include the following entries: - - pll_a - - pll_a_out0 - - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) -- nvidia,model : The user-visible name of this sound complex. -- nvidia,audio-routing : A list of the connections between audio components. - Each entry is a pair of strings, the first being the connection's sink, - the second being the connection's source. Valid names for sources and - sinks are the RT5640's pins (as documented in its binding), and the jacks - on the board: - - * Headphones - * Speakers - * Mic Jack - -- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's - connected to the CODEC. -- nvidia,audio-codec : The phandle of the RT5640 audio codec. This binding - assumes that AIF1 on the CODEC is connected to Tegra. - -Optional properties: -- nvidia,hp-det-gpios : The GPIO that detects headphones are plugged in - -Example: - -sound { - compatible = "nvidia,tegra-audio-rt5640-dalmore", - "nvidia,tegra-audio-rt5640"; - nvidia,model = "NVIDIA Tegra Dalmore"; - - nvidia,audio-routing = - "Headphones", "HPOR", - "Headphones", "HPOL", - "Speakers", "SPORP", - "Speakers", "SPORN", - "Speakers", "SPOLP", - "Speakers", "SPOLN"; - - nvidia,i2s-controller = <&tegra_i2s1>; - nvidia,audio-codec = <&rt5640>; - - nvidia,hp-det-gpios = <&gpio 143 0>; /* GPIO PR7 */ - - clocks = <&tegra_car 216>, <&tegra_car 217>, <&tegra_car 120>; - clock-names = "pll_a", "pll_a_out0", "mclk"; -}; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.yaml new file mode 100644 index 0000000000000..e768fb0e9a596 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.yaml @@ -0,0 +1,85 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nvidia,tegra-audio-rt5640.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NVIDIA Tegra audio complex with RT5639 or RT5640 CODEC + +maintainers: + - Jon Hunter + - Thierry Reding + +allOf: + - $ref: nvidia,tegra-audio-common.yaml# + +properties: + compatible: + items: + - pattern: '^[a-z0-9]+,tegra-audio-rt56(39|40)(-[a-z0-9]+)+$' + - const: nvidia,tegra-audio-rt5640 + + nvidia,audio-routing: + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + description: | + A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources and + sinks are the pins (documented in the binding document), + and the jacks on the board. + minItems: 2 + items: + enum: + # Board Connectors + - "Headphones" + - "Speakers" + - "Mic Jack" + + # CODEC Pins + - DMIC1 + - DMIC2 + - MICBIAS1 + - IN1P + - IN1R + - IN2P + - IN2R + - HPOL + - HPOR + - LOUTL + - LOUTR + - MONOP + - MONON + - SPOLP + - SPOLN + - SPORP + - SPORN + +required: + - nvidia,i2s-controller + +unevaluatedProperties: false + +examples: + - | + sound { + compatible = "nvidia,tegra-audio-rt5640-dalmore", + "nvidia,tegra-audio-rt5640"; + nvidia,model = "NVIDIA Tegra Dalmore"; + + nvidia,audio-routing = + "Headphones", "HPOR", + "Headphones", "HPOL", + "Speakers", "SPORP", + "Speakers", "SPORN", + "Speakers", "SPOLP", + "Speakers", "SPOLN"; + + nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,audio-codec = <&rt5640>; + + nvidia,hp-det-gpios = <&gpio 143 0>; + + clocks = <&clk 216>, <&clk 217>, <&clk 120>; + clock-names = "pll_a", "pll_a_out0", "mclk"; + }; + diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5677.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5677.txt deleted file mode 100644 index a4589cda214ee..0000000000000 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5677.txt +++ /dev/null @@ -1,67 +0,0 @@ -NVIDIA Tegra audio complex, with RT5677 CODEC - -Required properties: -- compatible : "nvidia,tegra-audio-rt5677" -- clocks : Must contain an entry for each entry in clock-names. - See ../clocks/clock-bindings.txt for details. -- clock-names : Must include the following entries: - - pll_a - - pll_a_out0 - - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) -- nvidia,model : The user-visible name of this sound complex. -- nvidia,audio-routing : A list of the connections between audio components. - Each entry is a pair of strings, the first being the connection's sink, - the second being the connection's source. Valid names for sources and - sinks are the RT5677's pins (as documented in its binding), and the jacks - on the board: - - * Headphone - * Speaker - * Headset Mic - * Internal Mic 1 - * Internal Mic 2 - -- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's - connected to the CODEC. -- nvidia,audio-codec : The phandle of the RT5677 audio codec. This binding - assumes that AIF1 on the CODEC is connected to Tegra. - -Optional properties: -- nvidia,hp-det-gpios : The GPIO that detects headphones are plugged in -- nvidia,hp-en-gpios : The GPIO that enables headphone amplifier -- nvidia,mic-present-gpios: The GPIO that mic jack is plugged in -- nvidia,dmic-clk-en-gpios : The GPIO that gates DMIC clock signal - -Example: - -sound { - compatible = "nvidia,tegra-audio-rt5677-ryu", - "nvidia,tegra-audio-rt5677"; - nvidia,model = "NVIDIA Tegra Ryu"; - - nvidia,audio-routing = - "Headphone", "LOUT2", - "Headphone", "LOUT1", - "Headset Mic", "MICBIAS1", - "IN1P", "Headset Mic", - "IN1N", "Headset Mic", - "DMIC L1", "Internal Mic 1", - "DMIC R1", "Internal Mic 1", - "DMIC L2", "Internal Mic 2", - "DMIC R2", "Internal Mic 2", - "Speaker", "PDM1L", - "Speaker", "PDM1R"; - - nvidia,i2s-controller = <&tegra_i2s1>; - nvidia,audio-codec = <&rt5677>; - - nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(R, 7) GPIO_ACTIVE_HIGH>; - nvidia,mic-present-gpios = <&gpio TEGRA_GPIO(O, 5) GPIO_ACTIVE_LOW>; - nvidia,hp-en-gpios = <&rt5677 1 GPIO_ACTIVE_HIGH>; - nvidia,dmic-clk-en-gpios = <&rt5677 2 GPIO_ACTIVE_HIGH>; - - clocks = <&tegra_car TEGRA124_CLK_PLL_A>, - <&tegra_car TEGRA124_CLK_PLL_A_OUT0>, - <&tegra_car TEGRA124_CLK_EXTERN1>; - clock-names = "pll_a", "pll_a_out0", "mclk"; -}; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5677.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5677.yaml new file mode 100644 index 0000000000000..03ff691c26c83 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5677.yaml @@ -0,0 +1,103 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nvidia,tegra-audio-rt5677.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NVIDIA Tegra audio complex with RT5677 CODEC + +maintainers: + - Jon Hunter + - Thierry Reding + +allOf: + - $ref: nvidia,tegra-audio-common.yaml# + +properties: + compatible: + items: + - pattern: '^[a-z0-9]+,tegra-audio-rt5677(-[a-z0-9]+)+$' + - const: nvidia,tegra-audio-rt5677 + + nvidia,audio-routing: + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + description: | + A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources and + sinks are the pins (documented in the binding document), + and the jacks on the board. + minItems: 2 + items: + enum: + # Board Connectors + - "Headphone" + - "Speaker" + - "Headset Mic" + - "Internal Mic 1" + - "Internal Mic 2" + + # CODEC Pins + - IN1P + - IN1N + - IN2P + - IN2N + - MICBIAS1 + - DMIC1 + - DMIC2 + - DMIC3 + - DMIC4 + - "DMIC L1" + - "DMIC L2" + - "DMIC L3" + - "DMIC L4" + - "DMIC R1" + - "DMIC R2" + - "DMIC R3" + - "DMIC R4" + - LOUT1 + - LOUT2 + - LOUT3 + - PDM1L + - PDM1R + - PDM2L + - PDM2R + +required: + - nvidia,i2s-controller + +unevaluatedProperties: false + +examples: + - | + sound { + compatible = "nvidia,tegra-audio-rt5677-ryu", + "nvidia,tegra-audio-rt5677"; + nvidia,model = "NVIDIA Tegra Ryu"; + + nvidia,audio-routing = + "Headphone", "LOUT2", + "Headphone", "LOUT1", + "Headset Mic", "MICBIAS1", + "IN1P", "Headset Mic", + "IN1N", "Headset Mic", + "DMIC L1", "Internal Mic 1", + "DMIC R1", "Internal Mic 1", + "DMIC L2", "Internal Mic 2", + "DMIC R2", "Internal Mic 2", + "Speaker", "PDM1L", + "Speaker", "PDM1R"; + + nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,audio-codec = <&rt5677>; + + nvidia,hp-det-gpios = <&gpio 143 0>; + nvidia,mic-present-gpios = <&gpio 132 1>; + nvidia,hp-en-gpios = <&rt5677 1 0>; + nvidia,dmic-clk-en-gpios = <&rt5677 2 1>; + + clocks = <&clk 216>, + <&clk 217>, + <&clk 121>; + clock-names = "pll_a", "pll_a_out0", "mclk"; + }; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-sgtl5000.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-sgtl5000.txt deleted file mode 100644 index 5da7da4ea07ab..0000000000000 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-sgtl5000.txt +++ /dev/null @@ -1,42 +0,0 @@ -NVIDIA Tegra audio complex, with SGTL5000 CODEC - -Required properties: -- compatible : "nvidia,tegra-audio-sgtl5000" -- clocks : Must contain an entry for each entry in clock-names. - See ../clocks/clock-bindings.txt for details. -- clock-names : Must include the following entries: - - pll_a - - pll_a_out0 - - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) -- nvidia,model : The user-visible name of this sound complex. -- nvidia,audio-routing : A list of the connections between audio components. - Each entry is a pair of strings, the first being the connection's sink, - the second being the connection's source. Valid names for sources and - sinks are the SGTL5000's pins (as documented in its binding), and the jacks - on the board: - - * Headphone Jack - * Line In Jack - * Mic Jack - -- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's - connected to the CODEC. -- nvidia,audio-codec : The phandle of the SGTL5000 audio codec. - -Example: - -sound { - compatible = "toradex,tegra-audio-sgtl5000-apalis_t30", - "nvidia,tegra-audio-sgtl5000"; - nvidia,model = "Toradex Apalis T30"; - nvidia,audio-routing = - "Headphone Jack", "HP_OUT", - "LINE_IN", "Line In Jack", - "MIC_IN", "Mic Jack"; - nvidia,i2s-controller = <&tegra_i2s2>; - nvidia,audio-codec = <&sgtl5000>; - clocks = <&tegra_car TEGRA30_CLK_PLL_A>, - <&tegra_car TEGRA30_CLK_PLL_A_OUT0>, - <&tegra_car TEGRA30_CLK_EXTERN1>; - clock-names = "pll_a", "pll_a_out0", "mclk"; -}; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-sgtl5000.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-sgtl5000.yaml new file mode 100644 index 0000000000000..943e7c01741c7 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-sgtl5000.yaml @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nvidia,tegra-audio-sgtl5000.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NVIDIA Tegra audio complex with SGTL5000 CODEC + +maintainers: + - Jon Hunter + - Thierry Reding + +allOf: + - $ref: nvidia,tegra-audio-common.yaml# + +properties: + compatible: + items: + - pattern: '^[a-z0-9]+,tegra-audio-sgtl5000([-_][a-z0-9]+)+$' + - const: nvidia,tegra-audio-sgtl5000 + + nvidia,audio-routing: + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + description: | + A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources and + sinks are the pins (documented in the binding document), + and the jacks on the board. + minItems: 2 + items: + enum: + # Board Connectors + - "Headphone Jack" + - "Line In Jack" + - "Mic Jack" + + # CODEC Pins + - HP_OUT + - LINE_OUT + - LINE_IN + - MIC_IN + +required: + - nvidia,i2s-controller + +unevaluatedProperties: false + +examples: + - | + #include + + sound { + compatible = "toradex,tegra-audio-sgtl5000-apalis_t30", + "nvidia,tegra-audio-sgtl5000"; + nvidia,model = "Toradex Apalis T30 SGTL5000"; + nvidia,audio-routing = + "Headphone Jack", "HP_OUT", + "LINE_IN", "Line In Jack", + "MIC_IN", "Mic Jack"; + nvidia,i2s-controller = <&tegra_i2s2>; + nvidia,audio-codec = <&codec>; + clocks = <&tegra_car TEGRA30_CLK_PLL_A>, + <&tegra_car TEGRA30_CLK_PLL_A_OUT0>, + <&tegra_car TEGRA30_CLK_EXTERN1>; + clock-names = "pll_a", "pll_a_out0", "mclk"; + }; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-trimslice.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-trimslice.txt deleted file mode 100644 index ef1fe73582791..0000000000000 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-trimslice.txt +++ /dev/null @@ -1,21 +0,0 @@ -NVIDIA Tegra audio complex for TrimSlice - -Required properties: -- compatible : "nvidia,tegra-audio-trimslice" -- clocks : Must contain an entry for each entry in clock-names. -- clock-names : Must include the following entries: - "pll_a" (The Tegra clock of that name), - "pll_a_out0" (The Tegra clock of that name), - "mclk" (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) -- nvidia,i2s-controller : The phandle of the Tegra I2S1 controller -- nvidia,audio-codec : The phandle of the WM8903 audio codec - -Example: - -sound { - compatible = "nvidia,tegra-audio-trimslice"; - nvidia,i2s-controller = <&tegra_i2s1>; - nvidia,audio-codec = <&codec>; - clocks = <&tegra_car 112>, <&tegra_car 113>, <&tegra_car 93>; - clock-names = "pll_a", "pll_a_out0", "mclk"; -}; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-trimslice.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-trimslice.yaml new file mode 100644 index 0000000000000..8c87cd166238f --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-trimslice.yaml @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nvidia,tegra-audio-trimslice.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NVIDIA Tegra audio complex with TrimSlice CODEC + +maintainers: + - Jon Hunter + - Thierry Reding + +allOf: + - $ref: nvidia,tegra-audio-common.yaml# + +properties: + compatible: + const: nvidia,tegra-audio-trimslice + +required: + - nvidia,i2s-controller + +unevaluatedProperties: false + +examples: + - | + sound { + compatible = "nvidia,tegra-audio-trimslice"; + nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,audio-codec = <&codec>; + clocks = <&tegra_car 112>, <&tegra_car 113>, <&tegra_car 93>; + clock-names = "pll_a", "pll_a_out0", "mclk"; + }; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8753.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8753.txt deleted file mode 100644 index 96f6a57dd6b40..0000000000000 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8753.txt +++ /dev/null @@ -1,40 +0,0 @@ -NVIDIA Tegra audio complex - -Required properties: -- compatible : "nvidia,tegra-audio-wm8753" -- clocks : Must contain an entry for each entry in clock-names. - See ../clocks/clock-bindings.txt for details. -- clock-names : Must include the following entries: - - pll_a - - pll_a_out0 - - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) -- nvidia,model : The user-visible name of this sound complex. -- nvidia,audio-routing : A list of the connections between audio components. - Each entry is a pair of strings, the first being the connection's sink, - the second being the connection's source. Valid names for sources and - sinks are the WM8753's pins as documented in the binding for the WM8753, - and the jacks on the board: - - * Headphone Jack - * Mic Jack - -- nvidia,i2s-controller : The phandle of the Tegra I2S1 controller -- nvidia,audio-codec : The phandle of the WM8753 audio codec -Example: - -sound { - compatible = "nvidia,tegra-audio-wm8753-whistler", - "nvidia,tegra-audio-wm8753" - nvidia,model = "tegra-wm8753-harmony"; - - nvidia,audio-routing = - "Headphone Jack", "LOUT1", - "Headphone Jack", "ROUT1"; - - nvidia,i2s-controller = <&i2s1>; - nvidia,audio-codec = <&wm8753>; - - clocks = <&tegra_car 112>, <&tegra_car 113>, <&tegra_car 93>; - clock-names = "pll_a", "pll_a_out0", "mclk"; -}; - diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8753.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8753.yaml new file mode 100644 index 0000000000000..a5b431d7d0c2e --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8753.yaml @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nvidia,tegra-audio-wm8753.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NVIDIA Tegra audio complex with WM8753 CODEC + +maintainers: + - Jon Hunter + - Thierry Reding + +allOf: + - $ref: nvidia,tegra-audio-common.yaml# + +properties: + compatible: + items: + - pattern: '^[a-z0-9]+,tegra-audio-wm8753(-[a-z0-9]+)+$' + - const: nvidia,tegra-audio-wm8753 + + nvidia,audio-routing: + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + description: | + A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources and + sinks are the pins (documented in the binding document), + and the jacks on the board. + minItems: 2 + items: + enum: + # Board Connectors + - "Headphone Jack" + - "Mic Jack" + + # CODEC Pins + - LOUT1 + - LOUT2 + - ROUT1 + - ROUT2 + - MONO1 + - MONO2 + - OUT3 + - OUT4 + - LINE1 + - LINE2 + - RXP + - RXN + - ACIN + - ACOP + - MIC1N + - MIC1 + - MIC2N + - MIC2 + - "Mic Bias" + +required: + - nvidia,i2s-controller + +unevaluatedProperties: false + +examples: + - | + sound { + compatible = "nvidia,tegra-audio-wm8753-whistler", + "nvidia,tegra-audio-wm8753"; + nvidia,model = "tegra-wm8753-harmony"; + + nvidia,audio-routing = + "Headphone Jack", "LOUT1", + "Headphone Jack", "ROUT1"; + + nvidia,i2s-controller = <&i2s1>; + nvidia,audio-codec = <&wm8753>; + + clocks = <&clk 112>, <&clk 113>, <&clk 93>; + clock-names = "pll_a", "pll_a_out0", "mclk"; + }; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.txt deleted file mode 100644 index bbd581a8c5bc2..0000000000000 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.txt +++ /dev/null @@ -1,62 +0,0 @@ -NVIDIA Tegra audio complex - -Required properties: -- compatible : "nvidia,tegra-audio-wm8903" -- clocks : Must contain an entry for each entry in clock-names. - See ../clocks/clock-bindings.txt for details. -- clock-names : Must include the following entries: - - pll_a - - pll_a_out0 - - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) -- nvidia,model : The user-visible name of this sound complex. -- nvidia,audio-routing : A list of the connections between audio components. - Each entry is a pair of strings, the first being the connection's sink, - the second being the connection's source. Valid names for sources and - sinks are the WM8903's pins (documented in the WM8903 binding document), - and the jacks on the board: - - * Headphone Jack - * Int Spk - * Mic Jack - * Int Mic - -- nvidia,i2s-controller : The phandle of the Tegra I2S1 controller -- nvidia,audio-codec : The phandle of the WM8903 audio codec - -Optional properties: -- nvidia,spkr-en-gpios : The GPIO that enables the speakers -- nvidia,hp-mute-gpios : The GPIO that mutes the headphones -- nvidia,hp-det-gpios : The GPIO that detect headphones are plugged in -- nvidia,int-mic-en-gpios : The GPIO that enables the internal microphone -- nvidia,ext-mic-en-gpios : The GPIO that enables the external microphone -- nvidia,headset : The Mic Jack represents state of the headset microphone pin - -Example: - -sound { - compatible = "nvidia,tegra-audio-wm8903-harmony", - "nvidia,tegra-audio-wm8903" - nvidia,model = "tegra-wm8903-harmony"; - - nvidia,audio-routing = - "Headphone Jack", "HPOUTR", - "Headphone Jack", "HPOUTL", - "Int Spk", "ROP", - "Int Spk", "RON", - "Int Spk", "LOP", - "Int Spk", "LON", - "Mic Jack", "MICBIAS", - "IN1L", "Mic Jack"; - - nvidia,i2s-controller = <&i2s1>; - nvidia,audio-codec = <&wm8903>; - - nvidia,spkr-en-gpios = <&codec 2 0>; - nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */ - nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */ - nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */ - - clocks = <&tegra_car 112>, <&tegra_car 113>, <&tegra_car 93>; - clock-names = "pll_a", "pll_a_out0", "mclk"; -}; - diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.yaml new file mode 100644 index 0000000000000..1b836acab9809 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.yaml @@ -0,0 +1,93 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nvidia,tegra-audio-wm8903.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NVIDIA Tegra audio complex with WM8903 CODEC + +maintainers: + - Jon Hunter + - Thierry Reding + +allOf: + - $ref: nvidia,tegra-audio-common.yaml# + +properties: + compatible: + oneOf: + - items: + - pattern: '^[a-z0-9]+,tegra-audio-wm8903(-[a-z0-9]+)+$' + - const: nvidia,tegra-audio-wm8903 + - items: + - pattern: ad,tegra-audio-plutux + - const: nvidia,tegra-audio-wm8903 + + nvidia,audio-routing: + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + description: | + A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources and + sinks are the pins (documented in the binding document), + and the jacks on the board. + minItems: 2 + items: + enum: + # Board Connectors + - "Headphone Jack" + - "Int Spk" + - "Mic Jack" + - "Int Mic" + + # CODEC Pins + - IN1L + - IN1R + - IN2L + - IN2R + - IN3L + - IN3R + - DMICDAT + - HPOUTL + - HPOUTR + - LINEOUTL + - LINEOUTR + - LOP + - LON + - ROP + - RON + - MICBIAS + +required: + - nvidia,i2s-controller + +unevaluatedProperties: false + +examples: + - | + sound { + compatible = "nvidia,tegra-audio-wm8903-harmony", + "nvidia,tegra-audio-wm8903"; + nvidia,model = "tegra-wm8903-harmony"; + + nvidia,audio-routing = + "Headphone Jack", "HPOUTR", + "Headphone Jack", "HPOUTL", + "Int Spk", "ROP", + "Int Spk", "RON", + "Int Spk", "LOP", + "Int Spk", "LON", + "Mic Jack", "MICBIAS", + "IN1L", "Mic Jack"; + + nvidia,i2s-controller = <&i2s1>; + nvidia,audio-codec = <&wm8903>; + + nvidia,spkr-en-gpios = <&codec 2 0>; + nvidia,hp-det-gpios = <&gpio 178 0>; + nvidia,int-mic-en-gpios = <&gpio 184 0>; + nvidia,ext-mic-en-gpios = <&gpio 185 0>; + + clocks = <&clk 112>, <&clk 113>, <&clk 93>; + clock-names = "pll_a", "pll_a_out0", "mclk"; + }; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.txt deleted file mode 100644 index 436f6cd9d07cd..0000000000000 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.txt +++ /dev/null @@ -1,60 +0,0 @@ -NVIDIA Tegra audio complex - -Required properties: -- compatible : "nvidia,tegra-audio-wm9712" -- clocks : Must contain an entry for each entry in clock-names. - See ../clocks/clock-bindings.txt for details. -- clock-names : Must include the following entries: - - pll_a - - pll_a_out0 - - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) -- nvidia,model : The user-visible name of this sound complex. -- nvidia,audio-routing : A list of the connections between audio components. - Each entry is a pair of strings, the first being the connection's sink, - the second being the connection's source. Valid names for sources and - sinks are the WM9712's pins, and the jacks on the board: - - WM9712 pins: - - * MONOOUT - * HPOUTL - * HPOUTR - * LOUT2 - * ROUT2 - * OUT3 - * LINEINL - * LINEINR - * PHONE - * PCBEEP - * MIC1 - * MIC2 - * Mic Bias - - Board connectors: - - * Headphone - * LineIn - * Mic - -- nvidia,ac97-controller : The phandle of the Tegra AC97 controller - - -Example: - -sound { - compatible = "nvidia,tegra-audio-wm9712-colibri_t20", - "nvidia,tegra-audio-wm9712"; - nvidia,model = "Toradex Colibri T20"; - - nvidia,audio-routing = - "Headphone", "HPOUTL", - "Headphone", "HPOUTR", - "LineIn", "LINEINL", - "LineIn", "LINEINR", - "Mic", "MIC1"; - - nvidia,ac97-controller = <&ac97>; - - clocks = <&tegra_car 112>, <&tegra_car 113>, <&tegra_car 93>; - clock-names = "pll_a", "pll_a_out0", "mclk"; -}; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.yaml new file mode 100644 index 0000000000000..a1448283344ba --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.yaml @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nvidia,tegra-audio-wm9712.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NVIDIA Tegra audio complex with WM9712 CODEC + +maintainers: + - Jon Hunter + - Thierry Reding + +allOf: + - $ref: nvidia,tegra-audio-common.yaml# + +properties: + compatible: + items: + - pattern: '^[a-z0-9]+,tegra-audio-wm9712([-_][a-z0-9]+)+$' + - const: nvidia,tegra-audio-wm9712 + + nvidia,audio-routing: + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + description: | + A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources and + sinks are the pins (documented in the binding document), + and the jacks on the board. + minItems: 2 + items: + enum: + # Board Connectors + - "Headphone" + - "LineIn" + - "Mic" + + # CODEC Pins + - MONOOUT + - HPOUTL + - HPOUTR + - LOUT2 + - ROUT2 + - OUT3 + - LINEINL + - LINEINR + - PHONE + - PCBEEP + - MIC1 + - MIC2 + - "Mic Bias" + +required: + - nvidia,ac97-controller + +unevaluatedProperties: false + +examples: + - | + sound { + compatible = "nvidia,tegra-audio-wm9712-colibri_t20", + "nvidia,tegra-audio-wm9712"; + nvidia,model = "Toradex Colibri T20"; + + nvidia,audio-routing = + "Headphone", "HPOUTL", + "Headphone", "HPOUTR", + "LineIn", "LINEINL", + "LineIn", "LINEINR", + "Mic", "MIC1"; + + nvidia,ac97-controller = <&ac97>; + + clocks = <&clk 112>, <&clk 113>, <&clk 93>; + clock-names = "pll_a", "pll_a_out0", "mclk"; + }; From fb6c83cab376c0963341a9521e85c1795acaec9b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 15 Dec 2021 10:35:11 -0600 Subject: [PATCH 197/327] ASoC: AMD: fix depend/select mistake on SND_AMD_ACP_CONFIG on i386 or x86_64: when # CONFIG_ACPI is not set, so SND_SOC_ACPI is not set: WARNING: unmet direct dependencies detected for SND_AMD_ACP_CONFIG Depends on [n]: SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && SND_SOC_ACPI [=n] Selected by [y]: - SND_SOC_AMD_ACP_COMMON [=y] && SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && X86 [=y] && PCI [=y] This problem is due to the unconditional selection of SND_AMD_ACP_CONFIG in other options. Using 'depends on' solved an initial problem but exposed another, let's use select instead. Reported-by: Randy Dunlap Fixes: d9b994cd7641 ('ASoC: AMD: acp-config: fix missing dependency on SND_SOC_ACPI') Signed-off-by: Pierre-Louis Bossart Acked-by: Randy Dunlap # build-tested Reviewed-by: Daniel Baluta Reviewed-by: Ranjani Sridharan Reviewed-by: Ajit Kumar Pandey Link: https://lore.kernel.org/r/20211215163511.151286-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/amd/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig index bcfeb3fc2592b..7a9e45094f37e 100644 --- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -98,7 +98,7 @@ config SND_SOC_AMD_YC_MACH config SND_AMD_ACP_CONFIG tristate "AMD ACP configuration selection" - depends on SND_SOC_ACPI + select SND_SOC_ACPI if ACPI help This option adds an auto detection to determine which ACP driver modules to use From 0725ac9ac4492568514a94971f46dd0546684ff8 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 22 Nov 2021 23:21:53 +0100 Subject: [PATCH 198/327] ASoC: tegra20-spdif: stop setting slave_id The DMA resource is never set up anywhere, and passing this as slave_id has not been the proper procedure in a long time. As a preparation for removing all slave_id references from the ALSA code, remove this one. According to Dmitry Osipenko, this driver has never been used and the mechanism for configuring DMA would not work as it is implemented, so this part will get rewritten when the driver gets put into use again in the future. Signed-off-by: Arnd Bergmann Reviewed-by: Dmitry Osipenko Acked-by: Mark Brown Link: https://lore.kernel.org/r/20211122222203.4103644-2-arnd@kernel.org Signed-off-by: Vinod Koul --- sound/soc/tegra/tegra20_spdif.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index 7751575cd6d6a..57a6c576b91f5 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -290,7 +290,6 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev) spdif->playback_dma_data.addr = mem->start + TEGRA20_SPDIF_DATA_OUT; spdif->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; spdif->playback_dma_data.maxburst = 4; - spdif->playback_dma_data.slave_id = dmareq->start; pm_runtime_enable(&pdev->dev); From d53939dcc4cfbe6de2c42daec90c199825f6a96f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 22 Nov 2021 23:22:02 +0100 Subject: [PATCH 199/327] dmaengine: tegra20-apb: stop checking config->slave_id Nothing sets the slave_id field any more, so stop accessing it to allow the removal of this field. Signed-off-by: Arnd Bergmann Acked-by: Mark Brown Link: https://lore.kernel.org/r/20211122222203.4103644-11-arnd@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/tegra20-apb-dma.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c index b7260749e8eee..eaafcbe4ca941 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c @@ -343,12 +343,6 @@ static int tegra_dma_slave_config(struct dma_chan *dc, } memcpy(&tdc->dma_sconfig, sconfig, sizeof(*sconfig)); - if (tdc->slave_id == TEGRA_APBDMA_SLAVE_ID_INVALID && - sconfig->device_fc) { - if (sconfig->slave_id > TEGRA_APBDMA_CSR_REQ_SEL_MASK) - return -EINVAL; - tdc->slave_id = sconfig->slave_id; - } tdc->config_init = true; return 0; From bdecfceffeeb9000e78b0f613069f5c06974b347 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 22 Nov 2021 23:21:54 +0100 Subject: [PATCH 200/327] ASoC: dai_dma: remove slave_id field This field is no longer set from any driver now, so remove the last references as well. Signed-off-by: Arnd Bergmann Acked-by: Mark Brown Link: https://lore.kernel.org/r/20211122222203.4103644-3-arnd@kernel.org Signed-off-by: Vinod Koul --- include/sound/dmaengine_pcm.h | 2 -- sound/core/pcm_dmaengine.c | 5 ++--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index 96666efddb396..38ea046e653c5 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -60,7 +60,6 @@ struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream) * @maxburst: Maximum number of words(note: words, as in units of the * src_addr_width member, not bytes) that can be send to or received from the * DAI in one burst. - * @slave_id: Slave requester id for the DMA channel. * @filter_data: Custom DMA channel filter data, this will usually be used when * requesting the DMA channel. * @chan_name: Custom channel name to use when requesting DMA channel. @@ -74,7 +73,6 @@ struct snd_dmaengine_dai_dma_data { dma_addr_t addr; enum dma_slave_buswidth addr_width; u32 maxburst; - unsigned int slave_id; void *filter_data; const char *chan_name; unsigned int fifo_size; diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c index 1fc2fa0775744..af6f717e1e7e6 100644 --- a/sound/core/pcm_dmaengine.c +++ b/sound/core/pcm_dmaengine.c @@ -91,8 +91,8 @@ EXPORT_SYMBOL_GPL(snd_hwparams_to_dma_slave_config); * @dma_data: DAI DMA data * @slave_config: DMA slave configuration * - * Initializes the {dst,src}_addr, {dst,src}_maxburst, {dst,src}_addr_width and - * slave_id fields of the DMA slave config from the same fields of the DAI DMA + * Initializes the {dst,src}_addr, {dst,src}_maxburst, {dst,src}_addr_width + * fields of the DMA slave config from the same fields of the DAI DMA * data struct. The src and dst fields will be initialized depending on the * direction of the substream. If the substream is a playback stream the dst * fields will be initialized, if it is a capture stream the src fields will be @@ -124,7 +124,6 @@ void snd_dmaengine_pcm_set_config_from_dai_data( slave_config->src_addr_width = dma_data->addr_width; } - slave_config->slave_id = dma_data->slave_id; slave_config->peripheral_config = dma_data->peripheral_config; slave_config->peripheral_size = dma_data->peripheral_size; } From feaa4a09acc9a33211dbe3930357922f7ad9750c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 22 Nov 2021 23:21:55 +0100 Subject: [PATCH 201/327] spi: pic32: stop setting dma_config->slave_id Setting slave_id makes no sense with DT based probing, and should eventually get removed entirely. Address this driver by no longer setting the field here. I could not find which DMA driver is used on PIC32, if it's in the tree at all, but none of the obvious ones even care about slave_id any more. Acked-by: Mark Brown Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20211122222203.4103644-4-arnd@kernel.org Signed-off-by: Vinod Koul --- drivers/spi/spi-pic32.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/spi/spi-pic32.c b/drivers/spi/spi-pic32.c index 5eb7b61bbb4d8..f86433b29260e 100644 --- a/drivers/spi/spi-pic32.c +++ b/drivers/spi/spi-pic32.c @@ -370,7 +370,6 @@ static int pic32_spi_dma_config(struct pic32_spi *pic32s, u32 dma_width) cfg.src_addr_width = dma_width; cfg.dst_addr_width = dma_width; /* tx channel */ - cfg.slave_id = pic32s->tx_irq; cfg.direction = DMA_MEM_TO_DEV; ret = dmaengine_slave_config(master->dma_tx, &cfg); if (ret) { @@ -378,7 +377,6 @@ static int pic32_spi_dma_config(struct pic32_spi *pic32s, u32 dma_width) return ret; } /* rx channel */ - cfg.slave_id = pic32s->rx_irq; cfg.direction = DMA_DEV_TO_MEM; ret = dmaengine_slave_config(master->dma_rx, &cfg); if (ret) From f59f6aaead975f0ec4d8ff2d59c4ffb8cf0127b2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 22 Nov 2021 23:21:56 +0100 Subject: [PATCH 202/327] mmc: bcm2835: stop setting chan_config->slave_id The field is not interpreted by the DMA engine driver, as all the data is passed from devicetree instead. Remove the assignment so the field can eventually be deleted. Reviewed-by: Nicolas Saenz Julienne Signed-off-by: Arnd Bergmann Acked-by: Ulf Hansson Acked-by: Mark Brown Link: https://lore.kernel.org/r/20211122222203.4103644-5-arnd@kernel.org Signed-off-by: Vinod Koul --- drivers/mmc/host/bcm2835.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/mmc/host/bcm2835.c b/drivers/mmc/host/bcm2835.c index 8c2361e662774..463b707d9e997 100644 --- a/drivers/mmc/host/bcm2835.c +++ b/drivers/mmc/host/bcm2835.c @@ -1293,14 +1293,12 @@ static int bcm2835_add_host(struct bcm2835_host *host) host->dma_cfg_tx.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; host->dma_cfg_tx.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - host->dma_cfg_tx.slave_id = 13; /* DREQ channel */ host->dma_cfg_tx.direction = DMA_MEM_TO_DEV; host->dma_cfg_tx.src_addr = 0; host->dma_cfg_tx.dst_addr = host->phys_addr + SDDATA; host->dma_cfg_rx.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; host->dma_cfg_rx.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - host->dma_cfg_rx.slave_id = 13; /* DREQ channel */ host->dma_cfg_rx.direction = DMA_DEV_TO_MEM; host->dma_cfg_rx.src_addr = host->phys_addr + SDDATA; host->dma_cfg_rx.dst_addr = 0; From 37228af82e5f4d7be64f71c63463112b9dd4fc55 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 22 Nov 2021 23:21:57 +0100 Subject: [PATCH 203/327] dmaengine: shdma: remove legacy slave_id parsing The slave device is picked through either devicetree or a filter function, and any remaining out-of-tree drivers would have warned about this usage since 2015. Stop interpreting the field finally so it can be removed from the interface. Reviewed-by: Laurent Pinchart Signed-off-by: Arnd Bergmann Acked-by: Mark Brown Link: https://lore.kernel.org/r/20211122222203.4103644-6-arnd@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/sh/shdma-base.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/dma/sh/shdma-base.c b/drivers/dma/sh/shdma-base.c index 7f72b3f4cd1ae..41c6bc650fa3e 100644 --- a/drivers/dma/sh/shdma-base.c +++ b/drivers/dma/sh/shdma-base.c @@ -786,14 +786,6 @@ static int shdma_config(struct dma_chan *chan, if (!config) return -EINVAL; - /* - * overriding the slave_id through dma_slave_config is deprecated, - * but possibly some out-of-tree drivers still do it. - */ - if (WARN_ON_ONCE(config->slave_id && - config->slave_id != schan->real_slave_id)) - schan->real_slave_id = config->slave_id; - /* * We could lock this, but you shouldn't be configuring the * channel, while using it... From 134c37fa250a87a7e77c80a7c59ae16c462e46e0 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 22 Nov 2021 23:21:58 +0100 Subject: [PATCH 204/327] dmaengine: pxa/mmp: stop referencing config->slave_id The last driver referencing the slave_id on Marvell PXA and MMP platforms was the SPI driver, but this stopped doing so a long time ago, so the TODO from the earlier patch can no be removed. Fixes: b729bf34535e ("spi/pxa2xx: Don't use slave_id of dma_slave_config") Fixes: 13b3006b8ebd ("dma: mmp_pdma: add filter function") Signed-off-by: Arnd Bergmann Acked-by: Mark Brown Link: https://lore.kernel.org/r/20211122222203.4103644-7-arnd@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/mmp_pdma.c | 6 ------ drivers/dma/pxa_dma.c | 7 ------- 2 files changed, 13 deletions(-) diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c index a23563cd118b7..5a53d7fcef018 100644 --- a/drivers/dma/mmp_pdma.c +++ b/drivers/dma/mmp_pdma.c @@ -727,12 +727,6 @@ static int mmp_pdma_config_write(struct dma_chan *dchan, chan->dir = direction; chan->dev_addr = addr; - /* FIXME: drivers should be ported over to use the filter - * function. Once that's done, the following two lines can - * be removed. - */ - if (cfg->slave_id) - chan->drcmr = cfg->slave_id; return 0; } diff --git a/drivers/dma/pxa_dma.c b/drivers/dma/pxa_dma.c index 52d04641e3611..6078cc81892e4 100644 --- a/drivers/dma/pxa_dma.c +++ b/drivers/dma/pxa_dma.c @@ -909,13 +909,6 @@ static void pxad_get_config(struct pxad_chan *chan, *dcmd |= PXA_DCMD_BURST16; else if (maxburst == 32) *dcmd |= PXA_DCMD_BURST32; - - /* FIXME: drivers should be ported over to use the filter - * function. Once that's done, the following two lines can - * be removed. - */ - if (chan->cfg.slave_id) - chan->drcmr = chan->cfg.slave_id; } static struct dma_async_tx_descriptor * From 722d6d2bdcc2dcff5527c704fb8f2bbcb018a232 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 22 Nov 2021 23:21:59 +0100 Subject: [PATCH 205/327] dmaengine: sprd: stop referencing config->slave_id It appears that the code that reads the slave_id from the channel config was copied incorrectly from other drivers. Nothing ever sets this field on platforms that use this driver, so remove the reference. Reviewed-by: Baolin Wang Signed-off-by: Arnd Bergmann Acked-by: Mark Brown Link: https://lore.kernel.org/r/20211122222203.4103644-8-arnd@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/sprd-dma.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c index 4357d2395e6b7..7f158ef5672d7 100644 --- a/drivers/dma/sprd-dma.c +++ b/drivers/dma/sprd-dma.c @@ -795,9 +795,6 @@ static int sprd_dma_fill_desc(struct dma_chan *chan, return dst_datawidth; } - if (slave_cfg->slave_id) - schan->dev_id = slave_cfg->slave_id; - hw->cfg = SPRD_DMA_DONOT_WAIT_BDONE << SPRD_DMA_WAIT_BDONE_OFFSET; /* From 03de6b273805b3c552ff158f8688555937375926 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 22 Nov 2021 23:22:00 +0100 Subject: [PATCH 206/327] dmaengine: qcom-adm: stop abusing slave_id config The slave_id was previously used to pick one DMA slave instead of another, but this is now done through the DMA descriptors in device tree. For the qcom_adm driver, the configuration is documented in the DT binding to contain a tuple of device identifier and a "crci" field, but the implementation ends up using only a single cell for identifying the slave, with the crci getting passed in nonstandard properties of the device, and passed through the dma driver using the old slave_id field. Part of the problem apparently is that the nand driver ends up using only a single DMA request ID, but requires distinct values for "crci" depending on the type of transfer. Change both the dmaengine driver and the two slave drivers to allow the documented binding to work in addition to the ad-hoc passing of crci values. In order to no longer abuse the slave_id field, pass the data using the "peripheral_config" mechanism instead. Signed-off-by: Arnd Bergmann Acked-by: Mark Brown Link: https://lore.kernel.org/r/20211122222203.4103644-9-arnd@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/qcom/qcom_adm.c | 56 +++++++++++++++++++++++++++---- drivers/mtd/nand/raw/qcom_nandc.c | 14 ++++++-- drivers/tty/serial/msm_serial.c | 15 +++++++-- include/linux/dma/qcom_adm.h | 12 +++++++ 4 files changed, 86 insertions(+), 11 deletions(-) create mode 100644 include/linux/dma/qcom_adm.h diff --git a/drivers/dma/qcom/qcom_adm.c b/drivers/dma/qcom/qcom_adm.c index ee78bed8d60d2..facdacf8aede6 100644 --- a/drivers/dma/qcom/qcom_adm.c +++ b/drivers/dma/qcom/qcom_adm.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -140,6 +141,8 @@ struct adm_chan { struct adm_async_desc *curr_txd; struct dma_slave_config slave; + u32 crci; + u32 mux; struct list_head node; int error; @@ -379,8 +382,8 @@ static struct dma_async_tx_descriptor *adm_prep_slave_sg(struct dma_chan *chan, return ERR_PTR(-EINVAL); } - crci = achan->slave.slave_id & 0xf; - if (!crci || achan->slave.slave_id > 0x1f) { + crci = achan->crci & 0xf; + if (!crci || achan->crci > 0x1f) { dev_err(adev->dev, "invalid crci value\n"); return ERR_PTR(-EINVAL); } @@ -403,9 +406,7 @@ static struct dma_async_tx_descriptor *adm_prep_slave_sg(struct dma_chan *chan, if (!async_desc) return ERR_PTR(-ENOMEM); - if (crci) - async_desc->mux = achan->slave.slave_id & ADM_CRCI_MUX_SEL ? - ADM_CRCI_CTL_MUX_SEL : 0; + async_desc->mux = achan->mux ? ADM_CRCI_CTL_MUX_SEL : 0; async_desc->crci = crci; async_desc->blk_size = blk_size; async_desc->dma_len = single_count * sizeof(struct adm_desc_hw_single) + @@ -488,10 +489,13 @@ static int adm_terminate_all(struct dma_chan *chan) static int adm_slave_config(struct dma_chan *chan, struct dma_slave_config *cfg) { struct adm_chan *achan = to_adm_chan(chan); + struct qcom_adm_peripheral_config *config = cfg->peripheral_config; unsigned long flag; spin_lock_irqsave(&achan->vc.lock, flag); memcpy(&achan->slave, cfg, sizeof(struct dma_slave_config)); + if (cfg->peripheral_size == sizeof(config)) + achan->crci = config->crci; spin_unlock_irqrestore(&achan->vc.lock, flag); return 0; @@ -694,6 +698,45 @@ static void adm_channel_init(struct adm_device *adev, struct adm_chan *achan, achan->vc.desc_free = adm_dma_free_desc; } +/** + * adm_dma_xlate + * @dma_spec: pointer to DMA specifier as found in the device tree + * @ofdma: pointer to DMA controller data + * + * This can use either 1-cell or 2-cell formats, the first cell + * identifies the slave device, while the optional second cell + * contains the crci value. + * + * Returns pointer to appropriate dma channel on success or NULL on error. + */ +static struct dma_chan *adm_dma_xlate(struct of_phandle_args *dma_spec, + struct of_dma *ofdma) +{ + struct dma_device *dev = ofdma->of_dma_data; + struct dma_chan *chan, *candidate = NULL; + struct adm_chan *achan; + + if (!dev || dma_spec->args_count > 2) + return NULL; + + list_for_each_entry(chan, &dev->channels, device_node) + if (chan->chan_id == dma_spec->args[0]) { + candidate = chan; + break; + } + + if (!candidate) + return NULL; + + achan = to_adm_chan(candidate); + if (dma_spec->args_count == 2) + achan->crci = dma_spec->args[1]; + else + achan->crci = 0; + + return dma_get_slave_channel(candidate); +} + static int adm_dma_probe(struct platform_device *pdev) { struct adm_device *adev; @@ -838,8 +881,7 @@ static int adm_dma_probe(struct platform_device *pdev) goto err_disable_clks; } - ret = of_dma_controller_register(pdev->dev.of_node, - of_dma_xlate_by_chan_id, + ret = of_dma_controller_register(pdev->dev.of_node, adm_dma_xlate, &adev->common); if (ret) goto err_unregister_dma; diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index 04e6f7b267064..7c6efa3b62557 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -952,6 +953,7 @@ static int prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read, struct dma_async_tx_descriptor *dma_desc; struct scatterlist *sgl; struct dma_slave_config slave_conf; + struct qcom_adm_peripheral_config periph_conf = {}; enum dma_transfer_direction dir_eng; int ret; @@ -983,11 +985,19 @@ static int prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read, if (read) { slave_conf.src_maxburst = 16; slave_conf.src_addr = nandc->base_dma + reg_off; - slave_conf.slave_id = nandc->data_crci; + if (nandc->data_crci) { + periph_conf.crci = nandc->data_crci; + slave_conf.peripheral_config = &periph_conf; + slave_conf.peripheral_size = sizeof(periph_conf); + } } else { slave_conf.dst_maxburst = 16; slave_conf.dst_addr = nandc->base_dma + reg_off; - slave_conf.slave_id = nandc->cmd_crci; + if (nandc->cmd_crci) { + periph_conf.crci = nandc->cmd_crci; + slave_conf.peripheral_config = &periph_conf; + slave_conf.peripheral_size = sizeof(periph_conf); + } } ret = dmaengine_slave_config(nandc->chan, &slave_conf); diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index fcef7a961430b..c6be09f44dc16 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -290,6 +291,7 @@ static void msm_request_tx_dma(struct msm_port *msm_port, resource_size_t base) { struct device *dev = msm_port->uart.dev; struct dma_slave_config conf; + struct qcom_adm_peripheral_config periph_conf = {}; struct msm_dma *dma; u32 crci = 0; int ret; @@ -308,7 +310,11 @@ static void msm_request_tx_dma(struct msm_port *msm_port, resource_size_t base) conf.device_fc = true; conf.dst_addr = base + UARTDM_TF; conf.dst_maxburst = UARTDM_BURST_SIZE; - conf.slave_id = crci; + if (crci) { + conf.peripheral_config = &periph_conf; + conf.peripheral_size = sizeof(periph_conf); + periph_conf.crci = crci; + } ret = dmaengine_slave_config(dma->chan, &conf); if (ret) @@ -333,6 +339,7 @@ static void msm_request_rx_dma(struct msm_port *msm_port, resource_size_t base) { struct device *dev = msm_port->uart.dev; struct dma_slave_config conf; + struct qcom_adm_peripheral_config periph_conf = {}; struct msm_dma *dma; u32 crci = 0; int ret; @@ -355,7 +362,11 @@ static void msm_request_rx_dma(struct msm_port *msm_port, resource_size_t base) conf.device_fc = true; conf.src_addr = base + UARTDM_RF; conf.src_maxburst = UARTDM_BURST_SIZE; - conf.slave_id = crci; + if (crci) { + conf.peripheral_config = &periph_conf; + conf.peripheral_size = sizeof(periph_conf); + periph_conf.crci = crci; + } ret = dmaengine_slave_config(dma->chan, &conf); if (ret) diff --git a/include/linux/dma/qcom_adm.h b/include/linux/dma/qcom_adm.h new file mode 100644 index 0000000000000..af20df674f0ce --- /dev/null +++ b/include/linux/dma/qcom_adm.h @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-only +#ifndef __LINUX_DMA_QCOM_ADM_H +#define __LINUX_DMA_QCOM_ADM_H + +#include + +struct qcom_adm_peripheral_config { + u32 crci; + u32 mux; +}; + +#endif /* __LINUX_DMA_QCOM_ADM_H */ From 93cdb5b0dc56cc7a8b87a61146495f3bdc93d7ba Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 22 Nov 2021 23:22:01 +0100 Subject: [PATCH 207/327] dmaengine: xilinx_dpdma: stop using slave_id field The display driver wants to pass a custom flag to the DMA engine driver, which it started doing by using the slave_id field that was traditionally used for a different purpose. As there is no longer a correct use for the slave_id field, it should really be removed, and the remaining users changed over to something different. The new mechanism for passing nonstandard settings is using the .peripheral_config field, so use that to pass a newly defined structure here, making it clear that this will not work in portable drivers. Reviewed-by: Laurent Pinchart Signed-off-by: Arnd Bergmann Acked-by: Mark Brown Link: https://lore.kernel.org/r/20211122222203.4103644-10-arnd@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/xilinx/xilinx_dpdma.c | 17 +++++++++++------ drivers/gpu/drm/xlnx/zynqmp_disp.c | 9 +++++++-- include/linux/dma/xilinx_dpdma.h | 11 +++++++++++ 3 files changed, 29 insertions(+), 8 deletions(-) create mode 100644 include/linux/dma/xilinx_dpdma.h diff --git a/drivers/dma/xilinx/xilinx_dpdma.c b/drivers/dma/xilinx/xilinx_dpdma.c index ce5c66e6897d2..b0f4948b00a54 100644 --- a/drivers/dma/xilinx/xilinx_dpdma.c +++ b/drivers/dma/xilinx/xilinx_dpdma.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -1273,6 +1274,7 @@ static int xilinx_dpdma_config(struct dma_chan *dchan, struct dma_slave_config *config) { struct xilinx_dpdma_chan *chan = to_xilinx_chan(dchan); + struct xilinx_dpdma_peripheral_config *pconfig; unsigned long flags; /* @@ -1282,15 +1284,18 @@ static int xilinx_dpdma_config(struct dma_chan *dchan, * fixed both on the DPDMA side and on the DP controller side. */ - spin_lock_irqsave(&chan->lock, flags); - /* - * Abuse the slave_id to indicate that the channel is part of a video - * group. + * Use the peripheral_config to indicate that the channel is part + * of a video group. This requires matching use of the custom + * structure in each driver. */ - if (chan->id <= ZYNQMP_DPDMA_VIDEO2) - chan->video_group = config->slave_id != 0; + pconfig = config->peripheral_config; + if (WARN_ON(pconfig && config->peripheral_size != sizeof(*pconfig))) + return -EINVAL; + spin_lock_irqsave(&chan->lock, flags); + if (chan->id <= ZYNQMP_DPDMA_VIDEO2 && pconfig) + chan->video_group = pconfig->video_group; spin_unlock_irqrestore(&chan->lock, flags); return 0; diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c index ff2b308d86517..11c409cbc88e7 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_disp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -1058,14 +1059,18 @@ static void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer, zynqmp_disp_avbuf_set_format(layer->disp, layer, layer->disp_fmt); /* - * Set slave_id for each DMA channel to indicate they're part of a + * Set pconfig for each DMA channel to indicate they're part of a * video group. */ for (i = 0; i < info->num_planes; i++) { struct zynqmp_disp_layer_dma *dma = &layer->dmas[i]; + struct xilinx_dpdma_peripheral_config pconfig = { + .video_group = true, + }; struct dma_slave_config config = { .direction = DMA_MEM_TO_DEV, - .slave_id = 1, + .peripheral_config = &pconfig, + .peripheral_size = sizeof(pconfig), }; dmaengine_slave_config(dma->chan, &config); diff --git a/include/linux/dma/xilinx_dpdma.h b/include/linux/dma/xilinx_dpdma.h new file mode 100644 index 0000000000000..83a1377f03f8d --- /dev/null +++ b/include/linux/dma/xilinx_dpdma.h @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifndef __LINUX_DMA_XILINX_DPDMA_H +#define __LINUX_DMA_XILINX_DPDMA_H + +#include + +struct xilinx_dpdma_peripheral_config { + bool video_group; +}; + +#endif /* __LINUX_DMA_XILINX_DPDMA_H */ From 3c219644075795a99271d345efdfa8b256e55161 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 22 Nov 2021 23:22:03 +0100 Subject: [PATCH 208/327] dmaengine: remove slave_id config field All references to the slave_id field have been removed, so remove the field as well to prevent new references from creeping in again. Originally this allowed slave DMA drivers to configure which device is accessed with the dmaengine_slave_config() call, but this was inconsistent, as the same information is also passed while requesting a channel, and never changes in practice. In modern kernels, the device is always selected when requesting the channel, so the .slave_id field is no longer useful. Reviewed-by: Laurent Pinchart Signed-off-by: Arnd Bergmann Acked-by: Mark Brown Link: https://lore.kernel.org/r/20211122222203.4103644-12-arnd@kernel.org Signed-off-by: Vinod Koul --- include/linux/dmaengine.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 9000f3ffce8b3..0349b35235e6f 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -418,9 +418,6 @@ enum dma_slave_buswidth { * @device_fc: Flow Controller Settings. Only valid for slave channels. Fill * with 'true' if peripheral should be flow controller. Direction will be * selected at Runtime. - * @slave_id: Slave requester id. Only valid for slave channels. The dma - * slave peripheral will have unique id as dma requester which need to be - * pass as slave config. * @peripheral_config: peripheral configuration for programming peripheral * for dmaengine transfer * @peripheral_size: peripheral configuration buffer size @@ -448,7 +445,6 @@ struct dma_slave_config { u32 src_port_window_size; u32 dst_port_window_size; bool device_fc; - unsigned int slave_id; void *peripheral_config; size_t peripheral_size; }; From eed5391f6747ffa7e3972b53aa721bded8feeff7 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 16 Dec 2021 17:16:26 -0600 Subject: [PATCH 209/327] ASoC: SOF: pcm: remove support for RESUME trigger The SOF driver removed the support for INFO_RESUME in the commit "ASoC: SOF: pcm: do not add SNDRV_PCM_INFO_RESUME to runtime hw info". And resuming is handled by the ALSA core with the .prepare and .trigger_start stages. So, remove handling of RESUME trigger in the component driver trigger op. Reviewed-by: Kai Vehmanen Reviewed-by: Rander Wang Reviewed-by: Bard Liao Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20211216231628.344687-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/pcm.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index e4446defe51e9..37fb8e6cd493f 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -395,26 +395,6 @@ static int sof_pcm_trigger(struct snd_soc_component *component, case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_RELEASE; break; - case SNDRV_PCM_TRIGGER_RESUME: - if (spcm->stream[substream->stream].suspend_ignored) { - /* - * this case will be triggered when INFO_RESUME is - * supported, no need to resume streams that remained - * enabled in D0ix. - */ - spcm->stream[substream->stream].suspend_ignored = false; - return 0; - } - - /* set up hw_params */ - ret = sof_pcm_prepare(component, substream); - if (ret < 0) { - dev_err(component->dev, - "error: failed to set up hw_params upon resume\n"); - return ret; - } - - fallthrough; case SNDRV_PCM_TRIGGER_START: if (spcm->stream[substream->stream].suspend_ignored) { /* From 9b465060d144dd8196729cc8d77e328f1328dcbf Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 16 Dec 2021 17:16:27 -0600 Subject: [PATCH 210/327] ASoC: SOF: Intel: hda: remove support for RESUME trigger The SOF driver removed the support for INFO_RESUME in the commit "ASoC: SOF: pcm: do not add SNDRV_PCM_INFO_RESUME to runtime hw info". And resuming is handled by the ALSA core with the .prepare and .trigger_start stages. So, remove handling of RESUME trigger in the HDA DAI BE trigger op. Reviewed-by: Kai Vehmanen Reviewed-by: Rander Wang Reviewed-by: Bard Liao Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20211216231628.344687-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dai.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 35ffb71116c69..6381f2b227f01 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -342,16 +342,6 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, w = snd_soc_dai_get_widget(dai, substream->stream); switch (cmd) { - case SNDRV_PCM_TRIGGER_RESUME: - /* set up hw_params */ - ret = hda_link_pcm_prepare(substream, dai); - if (ret < 0) { - dev_err(dai->dev, - "error: setting up hw_params during resume\n"); - return ret; - } - - fallthrough; case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: snd_hdac_ext_link_stream_start(link_dev); From 35218cf61869ca4b11c8c0b49a95f75f379e403a Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 16 Dec 2021 17:16:28 -0600 Subject: [PATCH 211/327] ASoC: SOF: Intel: hda: remove support for RESUME in platform trigger The SOF driver removed the support for INFO_RESUME in the commit "ASoC: SOF: pcm: do not add SNDRV_PCM_INFO_RESUME to runtime hw info". And resuming is handled by the ALSA core with the .prepare and .trigger_start stages. So, remove handling of RESUME trigger in the component driver trigger op. So, remove handling the RESUME trigger in the platform trigger op for HDA platforms. Reviewed-by: Kai Vehmanen Reviewed-by: Rander Wang Reviewed-by: Bard Liao Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20211216231628.344687-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-stream.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index e910f68706d9a..ba60807fbd8fb 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -329,7 +329,6 @@ int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, /* cmd must be for audio stream */ switch (cmd) { - case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_START: snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, From cb515f105cab124c5740e70dd0e8c78186ae81b7 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 16 Dec 2021 17:24:20 -0600 Subject: [PATCH 212/327] ASoC: SOF: avoid casting "const" attribute away Casting "const" attribute away is dangerous, obtain a writable pointer instead to avoid that. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20211216232422.345164-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/renoir.c | 7 +++-- sound/soc/sof/intel/atom.c | 13 +++++---- sound/soc/sof/intel/atom.h | 4 +-- sound/soc/sof/intel/bdw.c | 11 +++---- sound/soc/sof/intel/hda.c | 60 ++++++++++++++++++-------------------- sound/soc/sof/intel/hda.h | 4 +-- sound/soc/sof/ops.h | 8 +++-- sound/soc/sof/sof-audio.c | 9 +++--- sound/soc/sof/sof-priv.h | 4 +-- 9 files changed, 62 insertions(+), 58 deletions(-) diff --git a/sound/soc/sof/amd/renoir.c b/sound/soc/sof/amd/renoir.c index 43037109e130c..c3ecb9e9d5ba4 100644 --- a/sound/soc/sof/amd/renoir.c +++ b/sound/soc/sof/amd/renoir.c @@ -104,7 +104,7 @@ static struct snd_soc_dai_driver renoir_sof_dai[] = { }, }; -static void amd_sof_machine_select(struct snd_sof_dev *sdev) +static struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev) { struct snd_sof_pdata *sof_pdata = sdev->pdata; const struct sof_dev_desc *desc = sof_pdata->desc; @@ -113,12 +113,13 @@ static void amd_sof_machine_select(struct snd_sof_dev *sdev) mach = snd_soc_acpi_find_machine(desc->machines); if (!mach) { dev_warn(sdev->dev, "No matching ASoC machine driver found\n"); - return; + return NULL; } sof_pdata->tplg_filename = mach->sof_tplg_filename; sof_pdata->fw_filename = mach->fw_filename; - sof_pdata->machine = mach; + + return mach; } /* AMD Renoir DSP ops */ diff --git a/sound/soc/sof/intel/atom.c b/sound/soc/sof/intel/atom.c index cdc96a7df4937..5aa064b28fcae 100644 --- a/sound/soc/sof/intel/atom.c +++ b/sound/soc/sof/intel/atom.c @@ -293,7 +293,7 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev, return tplg_filename; } -void atom_machine_select(struct snd_sof_dev *sdev) +struct snd_soc_acpi_mach *atom_machine_select(struct snd_sof_dev *sdev) { struct snd_sof_pdata *sof_pdata = sdev->pdata; const struct sof_dev_desc *desc = sof_pdata->desc; @@ -304,7 +304,7 @@ void atom_machine_select(struct snd_sof_dev *sdev) mach = snd_soc_acpi_find_machine(desc->machines); if (!mach) { dev_warn(sdev->dev, "warning: No matching ASoC machine driver found\n"); - return; + return NULL; } pdev = to_platform_device(sdev->dev); @@ -322,12 +322,13 @@ void atom_machine_select(struct snd_sof_dev *sdev) if (!tplg_filename) { dev_dbg(sdev->dev, "error: no topology filename\n"); - return; + return NULL; } sof_pdata->tplg_filename = tplg_filename; mach->mach_params.acpi_ipc_irq_index = desc->irqindex_host_ipc; - sof_pdata->machine = mach; + + return mach; } EXPORT_SYMBOL_NS(atom_machine_select, SND_SOC_SOF_INTEL_ATOM_HIFI_EP); @@ -402,14 +403,14 @@ struct snd_soc_dai_driver atom_dai[] = { }; EXPORT_SYMBOL_NS(atom_dai, SND_SOC_SOF_INTEL_ATOM_HIFI_EP); -void atom_set_mach_params(const struct snd_soc_acpi_mach *mach, +void atom_set_mach_params(struct snd_soc_acpi_mach *mach, struct snd_sof_dev *sdev) { struct snd_sof_pdata *pdata = sdev->pdata; const struct sof_dev_desc *desc = pdata->desc; struct snd_soc_acpi_mach_params *mach_params; - mach_params = (struct snd_soc_acpi_mach_params *)&mach->mach_params; + mach_params = &mach->mach_params; mach_params->platform = dev_name(sdev->dev); mach_params->num_dai_drivers = desc->ops->num_drv; mach_params->dai_drivers = desc->ops->drv; diff --git a/sound/soc/sof/intel/atom.h b/sound/soc/sof/intel/atom.h index 96a462c7a2e55..b965e5e080a67 100644 --- a/sound/soc/sof/intel/atom.h +++ b/sound/soc/sof/intel/atom.h @@ -65,8 +65,8 @@ int atom_run(struct snd_sof_dev *sdev); int atom_reset(struct snd_sof_dev *sdev); void atom_dump(struct snd_sof_dev *sdev, u32 flags); -void atom_machine_select(struct snd_sof_dev *sdev); -void atom_set_mach_params(const struct snd_soc_acpi_mach *mach, +struct snd_soc_acpi_mach *atom_machine_select(struct snd_sof_dev *sdev); +void atom_set_mach_params(struct snd_soc_acpi_mach *mach, struct snd_sof_dev *sdev); extern struct snd_soc_dai_driver atom_dai[]; diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 1a8a39a878fd1..1121711e9029c 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -509,7 +509,7 @@ static int bdw_probe(struct snd_sof_dev *sdev) return ret; } -static void bdw_machine_select(struct snd_sof_dev *sdev) +static struct snd_soc_acpi_mach *bdw_machine_select(struct snd_sof_dev *sdev) { struct snd_sof_pdata *sof_pdata = sdev->pdata; const struct sof_dev_desc *desc = sof_pdata->desc; @@ -518,22 +518,23 @@ static void bdw_machine_select(struct snd_sof_dev *sdev) mach = snd_soc_acpi_find_machine(desc->machines); if (!mach) { dev_warn(sdev->dev, "warning: No matching ASoC machine driver found\n"); - return; + return NULL; } sof_pdata->tplg_filename = mach->sof_tplg_filename; mach->mach_params.acpi_ipc_irq_index = desc->irqindex_host_ipc; - sof_pdata->machine = mach; + + return mach; } -static void bdw_set_mach_params(const struct snd_soc_acpi_mach *mach, +static void bdw_set_mach_params(struct snd_soc_acpi_mach *mach, struct snd_sof_dev *sdev) { struct snd_sof_pdata *pdata = sdev->pdata; const struct sof_dev_desc *desc = pdata->desc; struct snd_soc_acpi_mach_params *mach_params; - mach_params = (struct snd_soc_acpi_mach_params *)&mach->mach_params; + mach_params = &mach->mach_params; mach_params->platform = dev_name(sdev->dev); mach_params->num_dai_drivers = desc->ops->num_drv; mach_params->dai_drivers = desc->ops->drv; diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index dabbd5d908f64..21100d2e6644b 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -1105,7 +1105,8 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) } #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) -static int hda_generic_machine_select(struct snd_sof_dev *sdev) +static void hda_generic_machine_select(struct snd_sof_dev *sdev, + struct snd_soc_acpi_mach **mach) { struct hdac_bus *bus = sof_to_bus(sdev); struct snd_soc_acpi_mach_params *mach_params; @@ -1137,7 +1138,7 @@ static int hda_generic_machine_select(struct snd_sof_dev *sdev) * - one HDMI codec, and/or * - one external HDAudio codec */ - if (!pdata->machine && codec_num <= 2) { + if (!*mach && codec_num <= 2) { hda_mach = snd_soc_acpi_intel_hda_machines; dev_info(bus->dev, "using HDA machine driver %s now\n", @@ -1152,10 +1153,9 @@ static int hda_generic_machine_select(struct snd_sof_dev *sdev) tplg_filename = hda_mach->sof_tplg_filename; ret = dmic_topology_fixup(sdev, &tplg_filename, idisp_str, &dmic_num); if (ret < 0) - return ret; + return; hda_mach->mach_params.dmic_num = dmic_num; - pdata->machine = hda_mach; pdata->tplg_filename = tplg_filename; if (codec_num == 2) { @@ -1165,23 +1165,22 @@ static int hda_generic_machine_select(struct snd_sof_dev *sdev) */ hda_mach->mach_params.link_mask = 0; } + + *mach = hda_mach; } } /* used by hda machine driver to create dai links */ - if (pdata->machine) { - mach_params = (struct snd_soc_acpi_mach_params *) - &pdata->machine->mach_params; + if (*mach) { + mach_params = &(*mach)->mach_params; mach_params->codec_mask = bus->codec_mask; mach_params->common_hdmi_codec_drv = hda_codec_use_common_hdmi; } - - return 0; } #else -static int hda_generic_machine_select(struct snd_sof_dev *sdev) +static void hda_generic_machine_select(struct snd_sof_dev *sdev, + struct snd_soc_acpi_mach **mach) { - return 0; } #endif @@ -1264,7 +1263,7 @@ static bool link_slaves_found(struct snd_sof_dev *sdev, return true; } -static int hda_sdw_machine_select(struct snd_sof_dev *sdev) +static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev) { struct snd_sof_pdata *pdata = sdev->pdata; const struct snd_soc_acpi_link_adr *link; @@ -1282,7 +1281,7 @@ static int hda_sdw_machine_select(struct snd_sof_dev *sdev) * machines, for mixed cases with I2C/I2S the detection relies * on the HID list. */ - if (link_mask && !pdata->machine) { + if (link_mask) { for (mach = pdata->desc->alt_machines; mach && mach->link_mask; mach++) { /* @@ -1317,7 +1316,6 @@ static int hda_sdw_machine_select(struct snd_sof_dev *sdev) if (mach && mach->link_mask) { int dmic_num = 0; - pdata->machine = mach; mach->mach_params.links = mach->links; mach->mach_params.link_mask = mach->link_mask; mach->mach_params.platform = dev_name(sdev->dev); @@ -1339,9 +1337,8 @@ static int hda_sdw_machine_select(struct snd_sof_dev *sdev) int ret; ret = dmic_topology_fixup(sdev, &tplg_filename, "", &dmic_num); - if (ret < 0) - return ret; + return NULL; pdata->tplg_filename = tplg_filename; } @@ -1351,35 +1348,36 @@ static int hda_sdw_machine_select(struct snd_sof_dev *sdev) "SoundWire machine driver %s topology %s\n", mach->drv_name, pdata->tplg_filename); - } else { - dev_info(sdev->dev, - "No SoundWire machine driver found\n"); + + return mach; } + + dev_info(sdev->dev, "No SoundWire machine driver found\n"); } - return 0; + return NULL; } #else -static int hda_sdw_machine_select(struct snd_sof_dev *sdev) +static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev) { - return 0; + return NULL; } #endif -void hda_set_mach_params(const struct snd_soc_acpi_mach *mach, +void hda_set_mach_params(struct snd_soc_acpi_mach *mach, struct snd_sof_dev *sdev) { struct snd_sof_pdata *pdata = sdev->pdata; const struct sof_dev_desc *desc = pdata->desc; struct snd_soc_acpi_mach_params *mach_params; - mach_params = (struct snd_soc_acpi_mach_params *)&mach->mach_params; + mach_params = &mach->mach_params; mach_params->platform = dev_name(sdev->dev); mach_params->num_dai_drivers = desc->ops->num_drv; mach_params->dai_drivers = desc->ops->drv; } -void hda_machine_select(struct snd_sof_dev *sdev) +struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) { struct snd_sof_pdata *sof_pdata = sdev->pdata; const struct sof_dev_desc *desc = sof_pdata->desc; @@ -1394,8 +1392,6 @@ void hda_machine_select(struct snd_sof_dev *sdev) if (!sof_pdata->tplg_filename) sof_pdata->tplg_filename = mach->sof_tplg_filename; - sof_pdata->machine = mach; - if (mach->link_mask) { mach->mach_params.links = mach->links; mach->mach_params.link_mask = mach->link_mask; @@ -1405,16 +1401,18 @@ void hda_machine_select(struct snd_sof_dev *sdev) /* * If I2S fails, try SoundWire */ - hda_sdw_machine_select(sdev); + if (!mach) + mach = hda_sdw_machine_select(sdev); /* * Choose HDA generic machine driver if mach is NULL. * Otherwise, set certain mach params. */ - hda_generic_machine_select(sdev); - - if (!sof_pdata->machine) + hda_generic_machine_select(sdev, &mach); + if (!mach) dev_warn(sdev->dev, "warning: No matching ASoC machine driver found\n"); + + return mach; } int hda_pci_intel_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index cb71d9d5cf6c4..5b4d59647a1d1 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -728,8 +728,8 @@ extern const struct sof_intel_dsp_desc jsl_chip_info; extern const struct sof_intel_dsp_desc adls_chip_info; /* machine driver select */ -void hda_machine_select(struct snd_sof_dev *sdev); -void hda_set_mach_params(const struct snd_soc_acpi_mach *mach, +struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev); +void hda_set_mach_params(struct snd_soc_acpi_mach *mach, struct snd_sof_dev *sdev); /* PCI driver selection and probe */ diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 0226a53148c92..b0ffb2a93bcc2 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -557,15 +557,17 @@ snd_sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata) sof_ops(sdev)->machine_unregister(sdev, pdata); } -static inline void +static inline struct snd_soc_acpi_mach * snd_sof_machine_select(struct snd_sof_dev *sdev) { if (sof_ops(sdev) && sof_ops(sdev)->machine_select) - sof_ops(sdev)->machine_select(sdev); + return sof_ops(sdev)->machine_select(sdev); + + return NULL; } static inline void -snd_sof_set_mach_params(const struct snd_soc_acpi_mach *mach, +snd_sof_set_mach_params(struct snd_soc_acpi_mach *mach, struct snd_sof_dev *sdev) { if (sof_ops(sdev) && sof_ops(sdev)->set_mach_params) diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 91e3fa5a73501..9e76b796502fd 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -1027,9 +1027,10 @@ int sof_machine_check(struct snd_sof_dev *sdev) if (!IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)) { /* find machine */ - snd_sof_machine_select(sdev); - if (sof_pdata->machine) { - snd_sof_set_mach_params(sof_pdata->machine, sdev); + mach = snd_sof_machine_select(sdev); + if (mach) { + sof_pdata->machine = mach; + snd_sof_set_mach_params(mach, sdev); return 0; } @@ -1051,7 +1052,7 @@ int sof_machine_check(struct snd_sof_dev *sdev) sof_pdata->tplg_filename = desc->nocodec_tplg_filename; sof_pdata->machine = mach; - snd_sof_set_mach_params(sof_pdata->machine, sdev); + snd_sof_set_mach_params(mach, sdev); return 0; } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 16caf5c74035d..114882e4370f8 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -293,8 +293,8 @@ struct snd_sof_dsp_ops { void *pdata); /* optional */ void (*machine_unregister)(struct snd_sof_dev *sdev, void *pdata); /* optional */ - void (*machine_select)(struct snd_sof_dev *sdev); /* optional */ - void (*set_mach_params)(const struct snd_soc_acpi_mach *mach, + struct snd_soc_acpi_mach * (*machine_select)(struct snd_sof_dev *sdev); /* optional */ + void (*set_mach_params)(struct snd_soc_acpi_mach *mach, struct snd_sof_dev *sdev); /* optional */ /* DAI ops */ From 182b682b9ab1348e07ea1bf9d8f2505cc67f9237 Mon Sep 17 00:00:00 2001 From: Ajit Kumar Pandey Date: Thu, 16 Dec 2021 17:24:21 -0600 Subject: [PATCH 213/327] ASoC: SOF: ipc: Add null pointer check for substream->runtime When pcm stream is stopped "substream->runtime" pointer will be set to NULL by ALSA core. In case host received an ipc msg from firmware of type IPC_STREAM_POSITION after pcm stream is stopped, there will be kernel NULL pointer exception in ipc_period_elapsed(). This patch fixes it by adding NULL pointer check for "substream->runtime". Reviewed-by: Ranjani Sridharan Signed-off-by: Ajit Kumar Pandey Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20211216232422.345164-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 8a1eacc7ec5fd..12860da1d3730 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -623,7 +623,8 @@ static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id) if (spcm->pcm.compress) snd_sof_compr_fragment_elapsed(stream->cstream); - else if (!stream->substream->runtime->no_period_wakeup) + else if (stream->substream->runtime && + !stream->substream->runtime->no_period_wakeup) /* only inform ALSA for period_wakeup mode */ snd_sof_pcm_period_elapsed(stream->substream); } From 60ded273e4c047aec364f70195aced71a4082f90 Mon Sep 17 00:00:00 2001 From: Karol Trzcinski Date: Thu, 16 Dec 2021 17:24:22 -0600 Subject: [PATCH 214/327] ipc: debug: Add shared memory heap to memory scan Newly added shared heap zones should be taken into account during memory usage scanning. Reviewed-by: Kai Vehmanen Reviewed-by: Liam Girdwood Signed-off-by: Karol Trzcinski Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20211216232422.345164-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/debug.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/sound/sof/debug.h b/include/sound/sof/debug.h index 3ecb5793789dd..38693e3fb5149 100644 --- a/include/sound/sof/debug.h +++ b/include/sound/sof/debug.h @@ -19,6 +19,8 @@ enum sof_ipc_dbg_mem_zone { SOF_IPC_MEM_ZONE_SYS_RUNTIME = 1, /**< System-runtime zone */ SOF_IPC_MEM_ZONE_RUNTIME = 2, /**< Runtime zone */ SOF_IPC_MEM_ZONE_BUFFER = 3, /**< Buffer zone */ + SOF_IPC_MEM_ZONE_RUNTIME_SHARED = 4, /**< System runtime zone */ + SOF_IPC_MEM_ZONE_SYS_SHARED = 5, /**< System shared zone */ }; /** ABI3.18 */ From 9b3c847b5fa0364a00227f13ab8ac0cbaf69be83 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 16 Dec 2021 09:00:18 +0900 Subject: [PATCH 215/327] ASoC: dt-bindings: audio-graph-port: enable both flag/phandle for bitclock/frame-master snd_soc_daifmt_parse_clock_provider_raw() is handling both bitclock/frame-master, and is supporting both flag/phandle. Current DT is assuming it is flag style. This patch allows both case. Signed-off-by: Kuninori Morimoto Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20211216000018.2641925-1-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/audio-graph-port.yaml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/audio-graph-port.yaml b/Documentation/devicetree/bindings/sound/audio-graph-port.yaml index 43e7f86e3b235..476dcb49ece63 100644 --- a/Documentation/devicetree/bindings/sound/audio-graph-port.yaml +++ b/Documentation/devicetree/bindings/sound/audio-graph-port.yaml @@ -42,10 +42,15 @@ patternProperties: $ref: /schemas/types.yaml#/definitions/flag frame-master: description: Indicates dai-link frame master. - $ref: /schemas/types.yaml#/definitions/phandle + oneOf: + - $ref: /schemas/types.yaml#/definitions/flag + - $ref: /schemas/types.yaml#/definitions/phandle bitclock-master: description: Indicates dai-link bit clock master - $ref: /schemas/types.yaml#/definitions/phandle + oneOf: + - $ref: /schemas/types.yaml#/definitions/flag + - $ref: /schemas/types.yaml#/definitions/phandle + dai-format: description: audio format. items: From 4941cd7cc845ae0a5317b1462e1b11bab4c023c0 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 16 Dec 2021 17:03:50 -0600 Subject: [PATCH 216/327] ASoC: SOF: Kconfig: Make the SOF_DEVELOPER_SUPPORT depend on SND_SOC_SOF SND_SOC_SOF_DEVELOPER_SUPPORT contains options affecting how the built SOF driver stack will behave, enables debug options and other features. These options have no meaning if the SND_SOC_SOF is not even enabled. If we have SOF client options under developer_support and debug they can be selected to be built even without the core, but they do need symbols from the core (the sof-client API) which can result build failure. In Kconfig we can have SND_SOC_SOF_TOPLEVEL=y SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST=y for example, which will make the flood client to be built, but the SOF core is not as SND_SOC_SOF is not selected. Reviewed-by: Paul Olaru Reviewed-by: Daniel Baluta Reviewed-by: Ranjani Sridharan Signed-off-by: Peter Ujfalusi Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20211216230350.343857-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index ac34c330cf0c0..1a7d6cefd3b78 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -63,7 +63,7 @@ config SND_SOC_SOF_DEBUG_PROBES config SND_SOC_SOF_DEVELOPER_SUPPORT bool "SOF developer options support" - depends on EXPERT + depends on EXPERT && SND_SOC_SOF help This option unlocks SOF developer options for debug/performance/ code hardening. From 46f016119e2ac38d9efd32e4957bc888dc71fffe Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sat, 4 Dec 2021 17:37:04 +0300 Subject: [PATCH 217/327] ASoC: dt-bindings: Add binding for Tegra20 S/PDIF Add device-tree binding for Tegra20 S/PDIF controller. Reviewed-by: Rob Herring Signed-off-by: Dmitry Osipenko Acked-by: Thierry Reding Link: https://lore.kernel.org/r/20211204143725.31646-2-digetx@gmail.com Signed-off-by: Mark Brown --- .../bindings/sound/nvidia,tegra20-spdif.yaml | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra20-spdif.yaml diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra20-spdif.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra20-spdif.yaml new file mode 100644 index 0000000000000..60a368a132b8a --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra20-spdif.yaml @@ -0,0 +1,85 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nvidia,tegra20-spdif.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NVIDIA Tegra20 S/PDIF Controller + +description: | + The S/PDIF controller supports both input and output in serial audio + digital interface format. The input controller can digitally recover + a clock from the received stream. The S/PDIF controller is also used + to generate the embedded audio for HDMI output channel. + +maintainers: + - Thierry Reding + - Jon Hunter + +properties: + compatible: + const: nvidia,tegra20-spdif + + reg: + maxItems: 1 + + resets: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + minItems: 2 + + clock-names: + items: + - const: out + - const: in + + dmas: + minItems: 2 + + dma-names: + items: + - const: rx + - const: tx + + "#sound-dai-cells": + const: 0 + + nvidia,fixed-parent-rate: + description: | + Specifies whether board prefers parent clock to stay at a fixed rate. + This allows multiple Tegra20 audio components work simultaneously by + limiting number of supportable audio rates. + type: boolean + +required: + - compatible + - reg + - resets + - interrupts + - clocks + - clock-names + - dmas + - dma-names + - "#sound-dai-cells" + +additionalProperties: false + +examples: + - | + spdif@70002400 { + compatible = "nvidia,tegra20-spdif"; + reg = <0x70002400 0x200>; + interrupts = <77>; + clocks = <&clk 99>, <&clk 98>; + clock-names = "out", "in"; + resets = <&rst 10>; + dmas = <&apbdma 3>, <&apbdma 3>; + dma-names = "rx", "tx"; + #sound-dai-cells = <0>; + }; + +... From 80c3d0a97abfd2a678b6077236a77ccb8c4747fa Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sat, 4 Dec 2021 17:37:05 +0300 Subject: [PATCH 218/327] ASoC: dt-bindings: tegra20-i2s: Convert to schema Convert NVIDIA Tegra20 I2S binding to schema. Reviewed-by: Rob Herring Signed-off-by: Dmitry Osipenko Acked-by: Thierry Reding Link: https://lore.kernel.org/r/20211204143725.31646-3-digetx@gmail.com Signed-off-by: Mark Brown --- .../bindings/sound/nvidia,tegra20-i2s.txt | 30 -------- .../bindings/sound/nvidia,tegra20-i2s.yaml | 70 +++++++++++++++++++ 2 files changed, 70 insertions(+), 30 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.yaml diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt deleted file mode 100644 index dc30c6bfbe95f..0000000000000 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt +++ /dev/null @@ -1,30 +0,0 @@ -NVIDIA Tegra 20 I2S controller - -Required properties: -- compatible : "nvidia,tegra20-i2s" -- reg : Should contain I2S registers location and length -- interrupts : Should contain I2S interrupt -- resets : Must contain an entry for each entry in reset-names. - See ../reset/reset.txt for details. -- reset-names : Must include the following entries: - - i2s -- dmas : Must contain an entry for each entry in clock-names. - See ../dma/dma.txt for details. -- dma-names : Must include the following entries: - - rx - - tx -- clocks : Must contain one entry, for the module clock. - See ../clocks/clock-bindings.txt for details. - -Example: - -i2s@70002800 { - compatible = "nvidia,tegra20-i2s"; - reg = <0x70002800 0x200>; - interrupts = < 45 >; - clocks = <&tegra_car 11>; - resets = <&tegra_car 11>; - reset-names = "i2s"; - dmas = <&apbdma 21>, <&apbdma 21>; - dma-names = "rx", "tx"; -}; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.yaml new file mode 100644 index 0000000000000..ad43b237d9aff --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.yaml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nvidia,tegra20-i2s.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NVIDIA Tegra20 I2S Controller + +description: | + The I2S Controller streams synchronous serial audio data between system + memory and an external audio device. The controller supports the I2S Left + Justified Mode, Right Justified Mode, and DSP mode formats. + +maintainers: + - Thierry Reding + - Jon Hunter + +properties: + compatible: + const: nvidia,tegra20-i2s + + reg: + maxItems: 1 + + resets: + maxItems: 1 + + reset-names: + const: i2s + + interrupts: + maxItems: 1 + + clocks: + minItems: 1 + + dmas: + minItems: 2 + + dma-names: + items: + - const: rx + - const: tx + +required: + - compatible + - reg + - resets + - reset-names + - interrupts + - clocks + - dmas + - dma-names + +additionalProperties: false + +examples: + - | + i2s@70002800 { + compatible = "nvidia,tegra20-i2s"; + reg = <0x70002800 0x200>; + interrupts = <45>; + clocks = <&tegra_car 11>; + resets = <&tegra_car 11>; + reset-names = "i2s"; + dmas = <&apbdma 21>, <&apbdma 21>; + dma-names = "rx", "tx"; + }; + +... From 549818e5c85a6d806cdef146d0203df2689d4e2f Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sat, 4 Dec 2021 17:37:06 +0300 Subject: [PATCH 219/327] ASoC: dt-bindings: tegra20-i2s: Document new nvidia,fixed-parent-rate property Document new nvidia,fixed-parent-rate property which instructs that this board wants parent clock to stay at a fixed rate. It allows to prevent conflicts between audio components that share same parent PLL. For instance, this property allows to have HDMI audio, speaker and headphones in the system playing audio simultaneously, which is a common pattern for consumer devices. Reviewed-by: Rob Herring Signed-off-by: Dmitry Osipenko Link: https://lore.kernel.org/r/20211204143725.31646-4-digetx@gmail.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/nvidia,tegra20-i2s.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.yaml index ad43b237d9aff..68ae124eaf804 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.yaml +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.yaml @@ -42,6 +42,13 @@ properties: - const: rx - const: tx + nvidia,fixed-parent-rate: + description: | + Specifies whether board prefers parent clock to stay at a fixed rate. + This allows multiple Tegra20 audio components work simultaneously by + limiting number of supportable audio rates. + type: boolean + required: - compatible - reg From 16736a0221db6d6f3fe130750c6dc5bbf5417da4 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sat, 4 Dec 2021 17:37:08 +0300 Subject: [PATCH 220/327] ASoC: tegra20: spdif: Set FIFO trigger level FIFO trigger level must be not less than the size of DMA burst, otherwise audio will be played x4 faster that it should be because part of the DMA data will be dropped on FIFO input buffer overflow. Signed-off-by: Dmitry Osipenko Acked-by: Thierry Reding Link: https://lore.kernel.org/r/20211204143725.31646-6-digetx@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_spdif.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index 57a6c576b91f5..e45e371edc427 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -69,6 +69,14 @@ static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream, regmap_update_bits(spdif->regmap, TEGRA20_SPDIF_CTRL, mask, val); + /* + * FIFO trigger level must be bigger than DMA burst or equal to it, + * otherwise data is discarded on overflow. + */ + regmap_update_bits(spdif->regmap, TEGRA20_SPDIF_DATA_FIFO_CSR, + TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_MASK, + TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU4_WORD_FULL); + switch (params_rate(params)) { case 32000: spdifclock = 4096000; From c0000fc618cdbe190274cf37040033dfa23c159d Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sat, 4 Dec 2021 17:37:10 +0300 Subject: [PATCH 221/327] ASoC: tegra20: spdif: Support device-tree Tegra20 S/PDIF driver was added in a pre-DT era and was never used since that time. Revive driver by adding device-tree support. Signed-off-by: Dmitry Osipenko Acked-by: Thierry Reding Link: https://lore.kernel.org/r/20211204143725.31646-8-digetx@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_spdif.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index e45e371edc427..801784915004d 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -270,7 +271,7 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, spdif); - spdif->clk_spdif_out = devm_clk_get(&pdev->dev, "spdif_out"); + spdif->clk_spdif_out = devm_clk_get(&pdev->dev, "out"); if (IS_ERR(spdif->clk_spdif_out)) { pr_err("Can't retrieve spdif clock\n"); ret = PTR_ERR(spdif->clk_spdif_out); @@ -340,10 +341,17 @@ static const struct dev_pm_ops tegra20_spdif_pm_ops = { tegra20_spdif_runtime_resume, NULL) }; +static const struct of_device_id tegra20_spdif_of_match[] = { + { .compatible = "nvidia,tegra20-spdif", }, + {}, +}; +MODULE_DEVICE_TABLE(of, tegra20_spdif_of_match); + static struct platform_driver tegra20_spdif_driver = { .driver = { .name = DRV_NAME, .pm = &tegra20_spdif_pm_ops, + .of_match_table = tegra20_spdif_of_match, }, .probe = tegra20_spdif_platform_probe, .remove = tegra20_spdif_platform_remove, @@ -354,4 +362,3 @@ module_platform_driver(tegra20_spdif_driver); MODULE_AUTHOR("Stephen Warren "); MODULE_DESCRIPTION("Tegra20 SPDIF ASoC driver"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRV_NAME); From 117aeed43974e500dcbd106e51218a83ae2c9977 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sat, 4 Dec 2021 17:37:11 +0300 Subject: [PATCH 222/327] ASoC: tegra20: spdif: Improve driver's code - Clean up whitespaces, defines and variables. - Remove obsolete code. - Adhere to upstream coding style. - Don't override returned error code. - Replace pr_err with dev_err. No functional changes are made by this patch. This is a minor code's refactoring that will ease further maintenance of the driver. Signed-off-by: Dmitry Osipenko Acked-by: Thierry Reding Link: https://lore.kernel.org/r/20211204143725.31646-9-digetx@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_spdif.c | 49 ++++++++++++--------------------- 1 file changed, 18 insertions(+), 31 deletions(-) diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index 801784915004d..d5c618611dbb3 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -23,8 +23,6 @@ #include "tegra20_spdif.h" -#define DRV_NAME "tegra20-spdif" - static __maybe_unused int tegra20_spdif_runtime_suspend(struct device *dev) { struct tegra20_spdif *spdif = dev_get_drvdata(dev); @@ -49,11 +47,10 @@ static __maybe_unused int tegra20_spdif_runtime_resume(struct device *dev) } static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { - struct device *dev = dai->dev; - struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai); + struct tegra20_spdif *spdif = dev_get_drvdata(dai->dev); unsigned int mask = 0, val = 0; int ret, spdifclock; @@ -106,7 +103,7 @@ static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream, ret = clk_set_rate(spdif->clk_spdif_out, spdifclock); if (ret) { - dev_err(dev, "Can't set SPDIF clock rate: %d\n", ret); + dev_err(dai->dev, "Can't set SPDIF clock rate: %d\n", ret); return ret; } @@ -127,9 +124,9 @@ static void tegra20_spdif_stop_playback(struct tegra20_spdif *spdif) } static int tegra20_spdif_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) + struct snd_soc_dai *dai) { - struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai); + struct tegra20_spdif *spdif = dev_get_drvdata(dai->dev); switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -151,7 +148,7 @@ static int tegra20_spdif_trigger(struct snd_pcm_substream *substream, int cmd, static int tegra20_spdif_probe(struct snd_soc_dai *dai) { - struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai); + struct tegra20_spdif *spdif = dev_get_drvdata(dai->dev); dai->capture_dma_data = NULL; dai->playback_dma_data = &spdif->playback_dma_data; @@ -160,26 +157,26 @@ static int tegra20_spdif_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops tegra20_spdif_dai_ops = { - .hw_params = tegra20_spdif_hw_params, - .trigger = tegra20_spdif_trigger, + .hw_params = tegra20_spdif_hw_params, + .trigger = tegra20_spdif_trigger, }; static struct snd_soc_dai_driver tegra20_spdif_dai = { - .name = DRV_NAME, + .name = "tegra20-spdif", .probe = tegra20_spdif_probe, .playback = { .stream_name = "Playback", .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000, + SNDRV_PCM_RATE_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .ops = &tegra20_spdif_dai_ops, }; static const struct snd_soc_component_driver tegra20_spdif_component = { - .name = DRV_NAME, + .name = "tegra20-spdif", }; static bool tegra20_spdif_wr_rd_reg(struct device *dev, unsigned int reg) @@ -260,7 +257,7 @@ static const struct regmap_config tegra20_spdif_regmap_config = { static int tegra20_spdif_platform_probe(struct platform_device *pdev) { struct tegra20_spdif *spdif; - struct resource *mem, *dmareq; + struct resource *mem; void __iomem *regs; int ret; @@ -273,27 +270,19 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev) spdif->clk_spdif_out = devm_clk_get(&pdev->dev, "out"); if (IS_ERR(spdif->clk_spdif_out)) { - pr_err("Can't retrieve spdif clock\n"); - ret = PTR_ERR(spdif->clk_spdif_out); - return ret; + dev_err(&pdev->dev, "Could not retrieve spdif clock\n"); + return PTR_ERR(spdif->clk_spdif_out); } regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); if (IS_ERR(regs)) return PTR_ERR(regs); - dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!dmareq) { - dev_err(&pdev->dev, "No DMA resource\n"); - return -ENODEV; - } - spdif->regmap = devm_regmap_init_mmio(&pdev->dev, regs, - &tegra20_spdif_regmap_config); + &tegra20_spdif_regmap_config); if (IS_ERR(spdif->regmap)) { dev_err(&pdev->dev, "regmap init failed\n"); - ret = PTR_ERR(spdif->regmap); - return ret; + return PTR_ERR(spdif->regmap); } spdif->playback_dma_data.addr = mem->start + TEGRA20_SPDIF_DATA_OUT; @@ -306,7 +295,6 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev) &tegra20_spdif_dai, 1); if (ret) { dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); - ret = -ENOMEM; goto err_pm_disable; } @@ -349,14 +337,13 @@ MODULE_DEVICE_TABLE(of, tegra20_spdif_of_match); static struct platform_driver tegra20_spdif_driver = { .driver = { - .name = DRV_NAME, + .name = "tegra20-spdif", .pm = &tegra20_spdif_pm_ops, .of_match_table = tegra20_spdif_of_match, }, .probe = tegra20_spdif_platform_probe, .remove = tegra20_spdif_platform_remove, }; - module_platform_driver(tegra20_spdif_driver); MODULE_AUTHOR("Stephen Warren "); From 150f4d573fe19a77864f6dec31aa444332f9fc9e Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sat, 4 Dec 2021 17:37:12 +0300 Subject: [PATCH 223/327] ASoC: tegra20: spdif: Use more resource-managed helpers Use resource-managed helpers to make code cleaner. Driver's remove callback isn't needed anymore since driver is completely resource-managed now. Signed-off-by: Dmitry Osipenko Acked-by: Thierry Reding Link: https://lore.kernel.org/r/20211204143725.31646-10-digetx@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_spdif.c | 33 +++++++++------------------------ sound/soc/tegra/tegra_pcm.c | 6 ++++++ sound/soc/tegra/tegra_pcm.h | 1 + 3 files changed, 16 insertions(+), 24 deletions(-) diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index d5c618611dbb3..7dd263721c2c0 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -289,38 +289,24 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev) spdif->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; spdif->playback_dma_data.maxburst = 4; - pm_runtime_enable(&pdev->dev); + ret = devm_pm_runtime_enable(&pdev->dev); + if (ret) + return ret; - ret = snd_soc_register_component(&pdev->dev, &tegra20_spdif_component, - &tegra20_spdif_dai, 1); + ret = devm_snd_soc_register_component(&pdev->dev, + &tegra20_spdif_component, + &tegra20_spdif_dai, 1); if (ret) { dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); - goto err_pm_disable; + return ret; } - ret = tegra_pcm_platform_register(&pdev->dev); + ret = devm_tegra_pcm_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); - goto err_unregister_component; + return ret; } - return 0; - -err_unregister_component: - snd_soc_unregister_component(&pdev->dev); -err_pm_disable: - pm_runtime_disable(&pdev->dev); - - return ret; -} - -static int tegra20_spdif_platform_remove(struct platform_device *pdev) -{ - tegra_pcm_platform_unregister(&pdev->dev); - snd_soc_unregister_component(&pdev->dev); - - pm_runtime_disable(&pdev->dev); - return 0; } @@ -342,7 +328,6 @@ static struct platform_driver tegra20_spdif_driver = { .of_match_table = tegra20_spdif_of_match, }, .probe = tegra20_spdif_platform_probe, - .remove = tegra20_spdif_platform_remove, }; module_platform_driver(tegra20_spdif_driver); diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index ef1e74d952369..468c8e77de217 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c @@ -48,6 +48,12 @@ int tegra_pcm_platform_register(struct device *dev) } EXPORT_SYMBOL_GPL(tegra_pcm_platform_register); +int devm_tegra_pcm_platform_register(struct device *dev) +{ + return devm_snd_dmaengine_pcm_register(dev, &tegra_dmaengine_pcm_config, 0); +} +EXPORT_SYMBOL_GPL(devm_tegra_pcm_platform_register); + int tegra_pcm_platform_register_with_chan_names(struct device *dev, struct snd_dmaengine_pcm_config *config, char *txdmachan, char *rxdmachan) diff --git a/sound/soc/tegra/tegra_pcm.h b/sound/soc/tegra/tegra_pcm.h index d602126c65b7b..2a36eea1740dd 100644 --- a/sound/soc/tegra/tegra_pcm.h +++ b/sound/soc/tegra/tegra_pcm.h @@ -32,6 +32,7 @@ int tegra_pcm_hw_params(struct snd_soc_component *component, snd_pcm_uframes_t tegra_pcm_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream); int tegra_pcm_platform_register(struct device *dev); +int devm_tegra_pcm_platform_register(struct device *dev); int tegra_pcm_platform_register_with_chan_names(struct device *dev, struct snd_dmaengine_pcm_config *config, char *txdmachan, char *rxdmachan); From ec1b4545d75575118e01a5e95699cff5010b4e19 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sat, 4 Dec 2021 17:37:13 +0300 Subject: [PATCH 224/327] ASoC: tegra20: spdif: Reset hardware Reset S/PDIF controller on runtime PM suspend/resume to ensure that we always have a consistent hardware state. Signed-off-by: Dmitry Osipenko Acked-by: Thierry Reding Link: https://lore.kernel.org/r/20211204143725.31646-11-digetx@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_spdif.c | 32 ++++++++++++++++++++++++++++++++ sound/soc/tegra/tegra20_spdif.h | 1 + 2 files changed, 33 insertions(+) diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index 7dd263721c2c0..bc45a0a8afab8 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -14,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +29,8 @@ static __maybe_unused int tegra20_spdif_runtime_suspend(struct device *dev) { struct tegra20_spdif *spdif = dev_get_drvdata(dev); + regcache_cache_only(spdif->regmap, true); + clk_disable_unprepare(spdif->clk_spdif_out); return 0; @@ -37,13 +41,35 @@ static __maybe_unused int tegra20_spdif_runtime_resume(struct device *dev) struct tegra20_spdif *spdif = dev_get_drvdata(dev); int ret; + ret = reset_control_assert(spdif->reset); + if (ret) + return ret; + ret = clk_prepare_enable(spdif->clk_spdif_out); if (ret) { dev_err(dev, "clk_enable failed: %d\n", ret); return ret; } + usleep_range(10, 100); + + ret = reset_control_deassert(spdif->reset); + if (ret) + goto disable_clocks; + + regcache_cache_only(spdif->regmap, false); + regcache_mark_dirty(spdif->regmap); + + ret = regcache_sync(spdif->regmap); + if (ret) + goto disable_clocks; + return 0; + +disable_clocks: + clk_disable_unprepare(spdif->clk_spdif_out); + + return ret; } static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream, @@ -268,6 +294,12 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, spdif); + spdif->reset = devm_reset_control_get_exclusive(&pdev->dev, NULL); + if (IS_ERR(spdif->reset)) { + dev_err(&pdev->dev, "Can't retrieve spdif reset\n"); + return PTR_ERR(spdif->reset); + } + spdif->clk_spdif_out = devm_clk_get(&pdev->dev, "out"); if (IS_ERR(spdif->clk_spdif_out)) { dev_err(&pdev->dev, "Could not retrieve spdif clock\n"); diff --git a/sound/soc/tegra/tegra20_spdif.h b/sound/soc/tegra/tegra20_spdif.h index 1973ffc2d5c7e..ff4b79e2052fc 100644 --- a/sound/soc/tegra/tegra20_spdif.h +++ b/sound/soc/tegra/tegra20_spdif.h @@ -451,6 +451,7 @@ struct tegra20_spdif { struct snd_dmaengine_dai_dma_data capture_dma_data; struct snd_dmaengine_dai_dma_data playback_dma_data; struct regmap *regmap; + struct reset_control *reset; }; #endif From d51693092ecc732fca3f49549cde1c5206331b09 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sat, 4 Dec 2021 17:37:14 +0300 Subject: [PATCH 225/327] ASoC: tegra20: spdif: Support system suspend Support system suspend by enforcing runtime PM suspend/resume. Now there is no doubt that h/w is indeed stopped during suspend and that h/w state will be properly restored after resume. Signed-off-by: Dmitry Osipenko Acked-by: Thierry Reding Link: https://lore.kernel.org/r/20211204143725.31646-12-digetx@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_spdif.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index bc45a0a8afab8..a4aa5614aef40 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -345,6 +345,8 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev) static const struct dev_pm_ops tegra20_spdif_pm_ops = { SET_RUNTIME_PM_OPS(tegra20_spdif_runtime_suspend, tegra20_spdif_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; static const struct of_device_id tegra20_spdif_of_match[] = { From 9d8f51cd1fa993939db02a014d4f4b6e252c2a18 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sat, 4 Dec 2021 17:37:15 +0300 Subject: [PATCH 226/327] ASoC: tegra20: spdif: Filter out unsupported rates SPDIF and other SoC components share audio PLL on Tegra, thus only one component may set the desired base clock rate. This creates problem for HDMI audio because it uses SPDIF and audio may not work if SPDIF's clock doesn't exactly match standard audio rate since some receivers may reject audio in that case. Filter out audio rates which SPDIF output can't support, assuming that other components won't change rate at runtime. Signed-off-by: Dmitry Osipenko Acked-by: Thierry Reding Link: https://lore.kernel.org/r/20211204143725.31646-13-digetx@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_spdif.c | 61 +++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index a4aa5614aef40..d09cd7ee6879d 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -79,6 +79,7 @@ static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream, struct tegra20_spdif *spdif = dev_get_drvdata(dai->dev); unsigned int mask = 0, val = 0; int ret, spdifclock; + long rate; mask |= TEGRA20_SPDIF_CTRL_PACK | TEGRA20_SPDIF_CTRL_BIT_MODE_MASK; @@ -133,6 +134,12 @@ static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream, return ret; } + rate = clk_get_rate(spdif->clk_spdif_out); + if (rate != spdifclock) + dev_warn_once(dai->dev, + "SPDIF clock rate %d doesn't match requested rate %lu\n", + spdifclock, rate); + return 0; } @@ -172,6 +179,59 @@ static int tegra20_spdif_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } +static int tegra20_spdif_filter_rates(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_interval *r = hw_param_interval(params, rule->var); + struct snd_soc_dai *dai = rule->private; + struct tegra20_spdif *spdif = dev_get_drvdata(dai->dev); + struct clk *parent = clk_get_parent(spdif->clk_spdif_out); + const unsigned int rates[] = { 32000, 44100, 48000 }; + long i, parent_rate, valid_rates = 0; + + parent_rate = clk_get_rate(parent); + if (parent_rate <= 0) { + dev_err(dai->dev, "Can't get parent clock rate: %ld\n", + parent_rate); + return parent_rate ?: -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(rates); i++) { + if (parent_rate % (rates[i] * 128) == 0) + valid_rates |= BIT(i); + } + + /* + * At least one rate must be valid, otherwise the parent clock isn't + * audio PLL. Nothing should be filtered in this case. + */ + if (!valid_rates) + valid_rates = BIT(ARRAY_SIZE(rates)) - 1; + + return snd_interval_list(r, ARRAY_SIZE(rates), rates, valid_rates); +} + +static int tegra20_spdif_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + if (!device_property_read_bool(dai->dev, "nvidia,fixed-parent-rate")) + return 0; + + /* + * SPDIF and I2S share audio PLL. HDMI takes audio packets from SPDIF + * and audio may not work on some TVs if clock rate isn't precise. + * + * PLL rate is controlled by I2S side. Filter out audio rates that + * don't match PLL rate at the start of stream to allow both SPDIF + * and I2S work simultaneously, assuming that PLL rate won't be + * changed later on. + */ + return snd_pcm_hw_rule_add(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + tegra20_spdif_filter_rates, dai, + SNDRV_PCM_HW_PARAM_RATE, -1); +} + static int tegra20_spdif_probe(struct snd_soc_dai *dai) { struct tegra20_spdif *spdif = dev_get_drvdata(dai->dev); @@ -185,6 +245,7 @@ static int tegra20_spdif_probe(struct snd_soc_dai *dai) static const struct snd_soc_dai_ops tegra20_spdif_dai_ops = { .hw_params = tegra20_spdif_hw_params, .trigger = tegra20_spdif_trigger, + .startup = tegra20_spdif_startup, }; static struct snd_soc_dai_driver tegra20_spdif_dai = { From bfa4671db1effe315cade5bddd6cf025e1c403d0 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sat, 4 Dec 2021 17:37:16 +0300 Subject: [PATCH 227/327] ASoC: tegra20: i2s: Filter out unsupported rates Support new nvidia,fixed-parent-rate device-tree property which instructs I2S that board wants parent clock rate to stay at a fixed rate. This allows to play audio over S/PDIF and I2S simultaneously. The root of the problem is that audio components on Tegra share the same audio PLL, and thus, only a subset of rates can be supported if we want to play audio simultaneously. Filter out audio rates that don't match parent clock rate if device-tree has the nvidia,fixed-parent-rate property. Signed-off-by: Dmitry Osipenko Acked-by: Thierry Reding Link: https://lore.kernel.org/r/20211204143725.31646-14-digetx@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_i2s.c | 49 +++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c index 266d2cab9f495..27365a877e471 100644 --- a/sound/soc/tegra/tegra20_i2s.c +++ b/sound/soc/tegra/tegra20_i2s.c @@ -262,10 +262,59 @@ static int tegra20_i2s_probe(struct snd_soc_dai *dai) return 0; } +static const unsigned int tegra20_i2s_rates[] = { + 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 96000 +}; + +static int tegra20_i2s_filter_rates(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_interval *r = hw_param_interval(params, rule->var); + struct snd_soc_dai *dai = rule->private; + struct tegra20_i2s *i2s = dev_get_drvdata(dai->dev); + struct clk *parent = clk_get_parent(i2s->clk_i2s); + long i, parent_rate, valid_rates = 0; + + parent_rate = clk_get_rate(parent); + if (parent_rate <= 0) { + dev_err(dai->dev, "Can't get parent clock rate: %ld\n", + parent_rate); + return parent_rate ?: -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(tegra20_i2s_rates); i++) { + if (parent_rate % (tegra20_i2s_rates[i] * 128) == 0) + valid_rates |= BIT(i); + } + + /* + * At least one rate must be valid, otherwise the parent clock isn't + * audio PLL. Nothing should be filtered in this case. + */ + if (!valid_rates) + valid_rates = BIT(ARRAY_SIZE(tegra20_i2s_rates)) - 1; + + return snd_interval_list(r, ARRAY_SIZE(tegra20_i2s_rates), + tegra20_i2s_rates, valid_rates); +} + +static int tegra20_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + if (!device_property_read_bool(dai->dev, "nvidia,fixed-parent-rate")) + return 0; + + return snd_pcm_hw_rule_add(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + tegra20_i2s_filter_rates, dai, + SNDRV_PCM_HW_PARAM_RATE, -1); +} + static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = { .set_fmt = tegra20_i2s_set_fmt, .hw_params = tegra20_i2s_hw_params, .trigger = tegra20_i2s_trigger, + .startup = tegra20_i2s_startup, }; static const struct snd_soc_dai_driver tegra20_i2s_dai_template = { From 2a9a72e290d4a4741e673f86b9fba9bfb319786d Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Thu, 16 Dec 2021 12:57:39 +0100 Subject: [PATCH 228/327] ASoC: Intel: catpt: Test dmaengine_submit() result before moving on After calling dmaengine_submit(), the submitted transfer descriptor belongs to the DMA engine. Pointer to that descriptor may no longer be valid after the call and should be tested before awaiting transfer completion. Reported-by: Kevin Tian Suggested-by: Dave Jiang Fixes: 4fac9b31d0b9 ("ASoC: Intel: Add catpt base members") Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20211216115743.2130622-2-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/catpt/dsp.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/catpt/dsp.c b/sound/soc/intel/catpt/dsp.c index 9c5fd18f2600f..346bec0003066 100644 --- a/sound/soc/intel/catpt/dsp.c +++ b/sound/soc/intel/catpt/dsp.c @@ -65,6 +65,7 @@ static int catpt_dma_memcpy(struct catpt_dev *cdev, struct dma_chan *chan, { struct dma_async_tx_descriptor *desc; enum dma_status status; + int ret; desc = dmaengine_prep_dma_memcpy(chan, dst_addr, src_addr, size, DMA_CTRL_ACK); @@ -77,13 +78,22 @@ static int catpt_dma_memcpy(struct catpt_dev *cdev, struct dma_chan *chan, catpt_updatel_shim(cdev, HMDC, CATPT_HMDC_HDDA(CATPT_DMA_DEVID, chan->chan_id), CATPT_HMDC_HDDA(CATPT_DMA_DEVID, chan->chan_id)); - dmaengine_submit(desc); + + ret = dma_submit_error(dmaengine_submit(desc)); + if (ret) { + dev_err(cdev->dev, "submit tx failed: %d\n", ret); + goto clear_hdda; + } + status = dma_wait_for_async_tx(desc); + ret = (status == DMA_COMPLETE) ? 0 : -EPROTO; + +clear_hdda: /* regardless of status, disable access to HOST memory in demand mode */ catpt_updatel_shim(cdev, HMDC, CATPT_HMDC_HDDA(CATPT_DMA_DEVID, chan->chan_id), 0); - return (status == DMA_COMPLETE) ? 0 : -EPROTO; + return ret; } int catpt_dma_memcpy_todsp(struct catpt_dev *cdev, struct dma_chan *chan, From dad492cfd24caf1b62d598555cde279bcca4755e Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Thu, 16 Dec 2021 12:57:40 +0100 Subject: [PATCH 229/327] ASoC: Intel: catpt: Reduce size of catpt_component_open() With some improved if-logy, function's size can be reduced slightly. Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20211216115743.2130622-3-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/catpt/pcm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c index ebb27daeb1c77..16146c693c082 100644 --- a/sound/soc/intel/catpt/pcm.c +++ b/sound/soc/intel/catpt/pcm.c @@ -595,9 +595,8 @@ static int catpt_component_open(struct snd_soc_component *component, { struct snd_soc_pcm_runtime *rtm = substream->private_data; - if (rtm->dai_link->no_pcm) - return 0; - snd_soc_set_runtime_hwparams(substream, &catpt_pcm_hardware); + if (!rtm->dai_link->no_pcm) + snd_soc_set_runtime_hwparams(substream, &catpt_pcm_hardware); return 0; } From a62a02986d3990f4b55c2d75610f8fb2074b0870 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Thu, 16 Dec 2021 12:57:41 +0100 Subject: [PATCH 230/327] ASoC: Intel: catpt: Streamline locals declaration for PCM-functions Group all the catpt_xxx structs together in PCM related functions so they look more cohesive. Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20211216115743.2130622-4-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/catpt/pcm.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c index 16146c693c082..939a9b801dece 100644 --- a/sound/soc/intel/catpt/pcm.c +++ b/sound/soc/intel/catpt/pcm.c @@ -259,9 +259,9 @@ static enum catpt_channel_config catpt_get_channel_config(u32 num_channels) static int catpt_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct catpt_dev *cdev = dev_get_drvdata(dai->dev); struct catpt_stream_template *template; struct catpt_stream_runtime *stream; + struct catpt_dev *cdev = dev_get_drvdata(dai->dev); struct resource *res; int ret; @@ -306,8 +306,8 @@ static int catpt_dai_startup(struct snd_pcm_substream *substream, static void catpt_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct catpt_dev *cdev = dev_get_drvdata(dai->dev); struct catpt_stream_runtime *stream; + struct catpt_dev *cdev = dev_get_drvdata(dai->dev); stream = snd_soc_dai_get_dma_data(dai, substream); @@ -329,9 +329,9 @@ static int catpt_set_dspvol(struct catpt_dev *cdev, u8 stream_id, long *ctlvol); static int catpt_dai_apply_usettings(struct snd_soc_dai *dai, struct catpt_stream_runtime *stream) { - struct catpt_dev *cdev = dev_get_drvdata(dai->dev); struct snd_soc_component *component = dai->component; struct snd_kcontrol *pos; + struct catpt_dev *cdev = dev_get_drvdata(dai->dev); const char *name; int ret; u32 id = stream->info.stream_hw_id; @@ -374,12 +374,12 @@ static int catpt_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct catpt_dev *cdev = dev_get_drvdata(dai->dev); + struct snd_pcm_runtime *rtm = substream->runtime; + struct snd_dma_buffer *dmab; struct catpt_stream_runtime *stream; struct catpt_audio_format afmt; struct catpt_ring_info rinfo; - struct snd_pcm_runtime *rtm = substream->runtime; - struct snd_dma_buffer *dmab; + struct catpt_dev *cdev = dev_get_drvdata(dai->dev); int ret; stream = snd_soc_dai_get_dma_data(dai, substream); @@ -427,8 +427,8 @@ static int catpt_dai_hw_params(struct snd_pcm_substream *substream, static int catpt_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct catpt_dev *cdev = dev_get_drvdata(dai->dev); struct catpt_stream_runtime *stream; + struct catpt_dev *cdev = dev_get_drvdata(dai->dev); stream = snd_soc_dai_get_dma_data(dai, substream); if (!stream->allocated) @@ -444,8 +444,8 @@ static int catpt_dai_hw_free(struct snd_pcm_substream *substream, static int catpt_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct catpt_dev *cdev = dev_get_drvdata(dai->dev); struct catpt_stream_runtime *stream; + struct catpt_dev *cdev = dev_get_drvdata(dai->dev); int ret; stream = snd_soc_dai_get_dma_data(dai, substream); @@ -467,9 +467,9 @@ static int catpt_dai_prepare(struct snd_pcm_substream *substream, static int catpt_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { - struct catpt_dev *cdev = dev_get_drvdata(dai->dev); - struct catpt_stream_runtime *stream; struct snd_pcm_runtime *runtime = substream->runtime; + struct catpt_stream_runtime *stream; + struct catpt_dev *cdev = dev_get_drvdata(dai->dev); snd_pcm_uframes_t pos; int ret; @@ -604,10 +604,10 @@ static snd_pcm_uframes_t catpt_component_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct catpt_dev *cdev = dev_get_drvdata(component->dev); - struct catpt_stream_runtime *stream; struct snd_soc_pcm_runtime *rtm = substream->private_data; struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtm, 0); + struct catpt_stream_runtime *stream; + struct catpt_dev *cdev = dev_get_drvdata(component->dev); u32 pos; if (rtm->dai_link->no_pcm) @@ -632,8 +632,8 @@ static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtm, struct snd_soc_dai *dai) { struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtm, 0); - struct catpt_dev *cdev = dev_get_drvdata(dai->dev); struct catpt_ssp_device_format devfmt; + struct catpt_dev *cdev = dev_get_drvdata(dai->dev); int ret; devfmt.iface = dai->driver->id; @@ -893,8 +893,8 @@ static int catpt_stream_volume_get(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); - struct catpt_dev *cdev = dev_get_drvdata(component->dev); struct catpt_stream_runtime *stream; + struct catpt_dev *cdev = dev_get_drvdata(component->dev); long *ctlvol = (long *)kcontrol->private_value; u32 dspvol; int i; @@ -925,8 +925,8 @@ static int catpt_stream_volume_put(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); - struct catpt_dev *cdev = dev_get_drvdata(component->dev); struct catpt_stream_runtime *stream; + struct catpt_dev *cdev = dev_get_drvdata(component->dev); long *ctlvol = (long *)kcontrol->private_value; int ret, i; @@ -1001,8 +1001,8 @@ static int catpt_loopback_switch_put(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); - struct catpt_dev *cdev = dev_get_drvdata(component->dev); struct catpt_stream_runtime *stream; + struct catpt_dev *cdev = dev_get_drvdata(component->dev); bool mute; int ret; From f04b4fb47d83b110a5b007fb2eddea862cfeb151 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 17 Dec 2021 10:22:31 +0100 Subject: [PATCH 231/327] ASoC: sh: rz-ssi: Check return value of pm_runtime_resume_and_get() The return value of pm_runtime_resume_and_get() needs to be checked to avoid a usage count imbalance in the error case. This fix is basically the same as 92c959bae2e5 ("reset: renesas: Fix Runtime PM usage"), and the last step before pm_runtime_resume_and_get() can be annotated as __must_check. Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/9fed506d-b780-55cd-45a4-9bd2407c910f@gmail.com Signed-off-by: Mark Brown --- sound/soc/sh/rz-ssi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/sh/rz-ssi.c b/sound/soc/sh/rz-ssi.c index fa0cc08f70ec4..e8d98b362f9db 100644 --- a/sound/soc/sh/rz-ssi.c +++ b/sound/soc/sh/rz-ssi.c @@ -1020,7 +1020,12 @@ static int rz_ssi_probe(struct platform_device *pdev) reset_control_deassert(ssi->rstc); pm_runtime_enable(&pdev->dev); - pm_runtime_resume_and_get(&pdev->dev); + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret < 0) { + pm_runtime_disable(ssi->dev); + reset_control_assert(ssi->rstc); + return dev_err_probe(ssi->dev, ret, "pm_runtime_resume_and_get failed\n"); + } spin_lock_init(&ssi->lock); dev_set_drvdata(&pdev->dev, ssi); From 30e693ee82d20361f2caacca3b68c79e1a7cb16c Mon Sep 17 00:00:00 2001 From: Trevor Wu Date: Thu, 16 Dec 2021 10:24:24 +0800 Subject: [PATCH 232/327] ASoC: mediatek: mt8195: correct default value mt8195_cg_patch is used to reset the default value of audio cg, so the register value could be consistent with CCF reference count. Nevertheless, AUDIO_TOP_CON1[1:0] is used to control an internal mux, and it's expected to keep the default value 0. This patch corrects the default value in case an unexpected behavior happens in the future. Fixes: 6746cc8582599 ("ASoC: mediatek: mt8195: add platform driver") Signed-off-by: Trevor Wu Link: https://lore.kernel.org/r/20211216022424.28470-1-trevor.wu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8195/mt8195-afe-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c b/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c index 2bb05a828e8d2..15b4cae2524c1 100644 --- a/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c +++ b/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c @@ -3028,7 +3028,7 @@ static const struct reg_sequence mt8195_afe_reg_defaults[] = { static const struct reg_sequence mt8195_cg_patch[] = { { AUDIO_TOP_CON0, 0xfffffffb }, - { AUDIO_TOP_CON1, 0xfffffffa }, + { AUDIO_TOP_CON1, 0xfffffff8 }, }; static int mt8195_afe_init_registers(struct mtk_base_afe *afe) From 5ea4e76b73cd6f2cf29b02a57040c1a11fa8c3f0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 14 Dec 2021 11:08:22 +0900 Subject: [PATCH 233/327] ASoC: codecs: ak4118: Use dev_err_probe() helper Use the dev_err_probe() helper, instead of open-coding the same operation. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/20211214020843.2225831-2-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/ak4118.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/ak4118.c b/sound/soc/codecs/ak4118.c index e0a6451851e8c..2e6bafd2a8213 100644 --- a/sound/soc/codecs/ak4118.c +++ b/sound/soc/codecs/ak4118.c @@ -374,20 +374,14 @@ static int ak4118_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, ak4118); ak4118->reset = devm_gpiod_get(&i2c->dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(ak4118->reset)) { - ret = PTR_ERR(ak4118->reset); - if (ret != -EPROBE_DEFER) - dev_err(&i2c->dev, "Failed to get reset: %d\n", ret); - return ret; - } + if (IS_ERR(ak4118->reset)) + return dev_err_probe(&i2c->dev, PTR_ERR(ak4118->reset), + "Failed to get reset\n"); ak4118->irq = devm_gpiod_get(&i2c->dev, "irq", GPIOD_IN); - if (IS_ERR(ak4118->irq)) { - ret = PTR_ERR(ak4118->irq); - if (ret != -EPROBE_DEFER) - dev_err(&i2c->dev, "Failed to get IRQ: %d\n", ret); - return ret; - } + if (IS_ERR(ak4118->irq)) + return dev_err_probe(&i2c->dev, PTR_ERR(ak4118->irq), + "Failed to get IRQ\n"); ret = devm_request_threaded_irq(&i2c->dev, gpiod_to_irq(ak4118->irq), NULL, ak4118_irq_handler, From 900b4b911aca2270ae3f966df5f31081a086c3cf Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 14 Dec 2021 11:08:23 +0900 Subject: [PATCH 234/327] ASoC: codecs: es7241: Use dev_err_probe() helper Use the dev_err_probe() helper, instead of open-coding the same operation. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/20211214020843.2225831-3-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/es7241.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/sound/soc/codecs/es7241.c b/sound/soc/codecs/es7241.c index 2344a0b035181..9f20bfb855b3e 100644 --- a/sound/soc/codecs/es7241.c +++ b/sound/soc/codecs/es7241.c @@ -255,7 +255,6 @@ static int es7241_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct es7241_data *priv; - int err; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -271,28 +270,19 @@ static int es7241_probe(struct platform_device *pdev) es7241_parse_fmt(dev, priv); priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(priv->reset)) { - err = PTR_ERR(priv->reset); - if (err != -EPROBE_DEFER) - dev_err(dev, "Failed to get 'reset' gpio: %d", err); - return err; - } + if (IS_ERR(priv->reset)) + return dev_err_probe(dev, PTR_ERR(priv->reset), + "Failed to get 'reset' gpio"); priv->m0 = devm_gpiod_get_optional(dev, "m0", GPIOD_OUT_LOW); - if (IS_ERR(priv->m0)) { - err = PTR_ERR(priv->m0); - if (err != -EPROBE_DEFER) - dev_err(dev, "Failed to get 'm0' gpio: %d", err); - return err; - } + if (IS_ERR(priv->m0)) + return dev_err_probe(dev, PTR_ERR(priv->m0), + "Failed to get 'm0' gpio"); priv->m1 = devm_gpiod_get_optional(dev, "m1", GPIOD_OUT_LOW); - if (IS_ERR(priv->m1)) { - err = PTR_ERR(priv->m1); - if (err != -EPROBE_DEFER) - dev_err(dev, "Failed to get 'm1' gpio: %d", err); - return err; - } + if (IS_ERR(priv->m1)) + return dev_err_probe(dev, PTR_ERR(priv->m1), + "Failed to get 'm1' gpio"); return devm_snd_soc_register_component(&pdev->dev, &es7241_component_driver, From 6df96c8f5b50574c196607f036a09b5626124a24 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 14 Dec 2021 11:08:24 +0900 Subject: [PATCH 235/327] ASoC: codecs: max9759: Use dev_err_probe() helper Use the dev_err_probe() helper, instead of open-coding the same operation. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/20211214020843.2225831-4-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/max9759.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/sound/soc/codecs/max9759.c b/sound/soc/codecs/max9759.c index 00e9d4fd1651f..d75fd61b90321 100644 --- a/sound/soc/codecs/max9759.c +++ b/sound/soc/codecs/max9759.c @@ -140,7 +140,6 @@ static int max9759_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct max9759 *priv; - int err; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -149,29 +148,20 @@ static int max9759_probe(struct platform_device *pdev) platform_set_drvdata(pdev, priv); priv->gpiod_shutdown = devm_gpiod_get(dev, "shutdown", GPIOD_OUT_HIGH); - if (IS_ERR(priv->gpiod_shutdown)) { - err = PTR_ERR(priv->gpiod_shutdown); - if (err != -EPROBE_DEFER) - dev_err(dev, "Failed to get 'shutdown' gpio: %d", err); - return err; - } + if (IS_ERR(priv->gpiod_shutdown)) + return dev_err_probe(dev, PTR_ERR(priv->gpiod_shutdown), + "Failed to get 'shutdown' gpio"); priv->gpiod_mute = devm_gpiod_get(dev, "mute", GPIOD_OUT_HIGH); - if (IS_ERR(priv->gpiod_mute)) { - err = PTR_ERR(priv->gpiod_mute); - if (err != -EPROBE_DEFER) - dev_err(dev, "Failed to get 'mute' gpio: %d", err); - return err; - } + if (IS_ERR(priv->gpiod_mute)) + return dev_err_probe(dev, PTR_ERR(priv->gpiod_mute), + "Failed to get 'mute' gpio"); priv->is_mute = true; priv->gpiod_gain = devm_gpiod_get_array(dev, "gain", GPIOD_OUT_HIGH); - if (IS_ERR(priv->gpiod_gain)) { - err = PTR_ERR(priv->gpiod_gain); - if (err != -EPROBE_DEFER) - dev_err(dev, "Failed to get 'gain' gpios: %d", err); - return err; - } + if (IS_ERR(priv->gpiod_gain)) + return dev_err_probe(dev, PTR_ERR(priv->gpiod_gain), + "Failed to get 'gain' gpios"); priv->gain = 0; if (priv->gpiod_gain->ndescs != 2) { From edfe9f451a8c6174fad43689fb5af5c096940e13 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 14 Dec 2021 11:08:25 +0900 Subject: [PATCH 236/327] ASoC: codecs: max9860: Use dev_err_probe() helper Use the dev_err_probe() helper, instead of open-coding the same operation. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/20211214020843.2225831-5-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/max9860.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/max9860.c b/sound/soc/codecs/max9860.c index dd29b183ecd6c..7c9686be59d99 100644 --- a/sound/soc/codecs/max9860.c +++ b/sound/soc/codecs/max9860.c @@ -606,12 +606,9 @@ static int max9860_probe(struct i2c_client *i2c) return -ENOMEM; max9860->dvddio = devm_regulator_get(dev, "DVDDIO"); - if (IS_ERR(max9860->dvddio)) { - ret = PTR_ERR(max9860->dvddio); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to get DVDDIO supply: %d\n", ret); - return ret; - } + if (IS_ERR(max9860->dvddio)) + return dev_err_probe(dev, PTR_ERR(max9860->dvddio), + "Failed to get DVDDIO supply\n"); max9860->dvddio_nb.notifier_call = max9860_dvddio_event; @@ -643,8 +640,7 @@ static int max9860_probe(struct i2c_client *i2c) if (IS_ERR(mclk)) { ret = PTR_ERR(mclk); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to get MCLK: %d\n", ret); + dev_err_probe(dev, ret, "Failed to get MCLK\n"); goto err_regulator; } From 526f6ca95a9d0c85ccb0a83ed48936394e4185e6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 14 Dec 2021 11:08:26 +0900 Subject: [PATCH 237/327] ASoC: codecs: pcm3168a: Use dev_err_probe() helper Use the dev_err_probe() helper, instead of open-coding the same operation. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/20211214020843.2225831-6-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3168a.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index b6fd412441a11..fdf92c8b28e14 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -751,21 +751,14 @@ int pcm3168a_probe(struct device *dev, struct regmap *regmap) pcm3168a->gpio_rst = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE); - if (IS_ERR(pcm3168a->gpio_rst)) { - ret = PTR_ERR(pcm3168a->gpio_rst); - if (ret != -EPROBE_DEFER ) - dev_err(dev, "failed to acquire RST gpio: %d\n", ret); - - return ret; - } + if (IS_ERR(pcm3168a->gpio_rst)) + return dev_err_probe(dev, PTR_ERR(pcm3168a->gpio_rst), + "failed to acquire RST gpio\n"); pcm3168a->scki = devm_clk_get(dev, "scki"); - if (IS_ERR(pcm3168a->scki)) { - ret = PTR_ERR(pcm3168a->scki); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to acquire clock 'scki': %d\n", ret); - return ret; - } + if (IS_ERR(pcm3168a->scki)) + return dev_err_probe(dev, PTR_ERR(pcm3168a->scki), + "failed to acquire clock 'scki'\n"); ret = clk_prepare_enable(pcm3168a->scki); if (ret) { @@ -781,8 +774,7 @@ int pcm3168a_probe(struct device *dev, struct regmap *regmap) ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(pcm3168a->supplies), pcm3168a->supplies); if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to request supplies: %d\n", ret); + dev_err_probe(dev, ret, "failed to request supplies\n"); goto err_clk; } From ec1e0e72a8d4180c65aee01e9563ddfb47f87709 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 14 Dec 2021 11:08:27 +0900 Subject: [PATCH 238/327] ASoC: codecs: sgtl5000: Use dev_err_probe() helper Use the dev_err_probe() helper, instead of open-coding the same operation. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/20211214020843.2225831-7-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/sgtl5000.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 97bf1f222805e..8eebf27d0ea24 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -1612,9 +1612,8 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, if (ret == -ENOENT) ret = -EPROBE_DEFER; - if (ret != -EPROBE_DEFER) - dev_err(&client->dev, "Failed to get mclock: %d\n", - ret); + dev_err_probe(&client->dev, ret, "Failed to get mclock\n"); + goto disable_regs; } From 2c16636a8bbd85573376363420c8e9f6006d3753 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 14 Dec 2021 11:08:28 +0900 Subject: [PATCH 239/327] ASoC: codecs: simple-amplifier: Use dev_err_probe() helper Use the dev_err_probe() helper, instead of open-coding the same operation. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/20211214020843.2225831-8-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/simple-amplifier.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/simple-amplifier.c b/sound/soc/codecs/simple-amplifier.c index b30fc1f894e1b..d306c585b52b0 100644 --- a/sound/soc/codecs/simple-amplifier.c +++ b/sound/soc/codecs/simple-amplifier.c @@ -69,7 +69,6 @@ static int simple_amp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct simple_amp *priv; - int err; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (priv == NULL) @@ -78,12 +77,9 @@ static int simple_amp_probe(struct platform_device *pdev) priv->gpiod_enable = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW); - if (IS_ERR(priv->gpiod_enable)) { - err = PTR_ERR(priv->gpiod_enable); - if (err != -EPROBE_DEFER) - dev_err(dev, "Failed to get 'enable' gpio: %d", err); - return err; - } + if (IS_ERR(priv->gpiod_enable)) + return dev_err_probe(dev, PTR_ERR(priv->gpiod_enable), + "Failed to get 'enable' gpio"); return devm_snd_soc_register_component(dev, &simple_amp_component_driver, From 17d7044715c5b1e0321f8e56060260e39bba54b7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 14 Dec 2021 11:08:29 +0900 Subject: [PATCH 240/327] ASoC: codecs: simple-mux: Use dev_err_probe() helper Use the dev_err_probe() helper, instead of open-coding the same operation. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/20211214020843.2225831-9-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/simple-mux.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/simple-mux.c b/sound/soc/codecs/simple-mux.c index e0a09dadfa7cf..d30c0d24d90a6 100644 --- a/sound/soc/codecs/simple-mux.c +++ b/sound/soc/codecs/simple-mux.c @@ -82,7 +82,6 @@ static int simple_mux_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct simple_mux *priv; - int err; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -91,12 +90,9 @@ static int simple_mux_probe(struct platform_device *pdev) dev_set_drvdata(dev, priv); priv->gpiod_mux = devm_gpiod_get(dev, "mux", GPIOD_OUT_LOW); - if (IS_ERR(priv->gpiod_mux)) { - err = PTR_ERR(priv->gpiod_mux); - if (err != -EPROBE_DEFER) - dev_err(dev, "Failed to get 'mux' gpio: %d", err); - return err; - } + if (IS_ERR(priv->gpiod_mux)) + return dev_err_probe(dev, PTR_ERR(priv->gpiod_mux), + "Failed to get 'mux' gpio"); return devm_snd_soc_register_component(dev, &simple_mux_component_driver, NULL, 0); } From 382ae995597fbe214596f794ee5a38b4b64195be Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 14 Dec 2021 11:08:30 +0900 Subject: [PATCH 241/327] ASoC: codecs: ssm2305: Use dev_err_probe() helper Use the dev_err_probe() helper, instead of open-coding the same operation. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/20211214020843.2225831-10-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/ssm2305.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/ssm2305.c b/sound/soc/codecs/ssm2305.c index 2968959c4b759..1d022643c307f 100644 --- a/sound/soc/codecs/ssm2305.c +++ b/sound/soc/codecs/ssm2305.c @@ -57,7 +57,6 @@ static int ssm2305_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct ssm2305 *priv; - int err; /* Allocate the private data */ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -69,13 +68,9 @@ static int ssm2305_probe(struct platform_device *pdev) /* Get shutdown gpio */ priv->gpiod_shutdown = devm_gpiod_get(dev, "shutdown", GPIOD_OUT_LOW); - if (IS_ERR(priv->gpiod_shutdown)) { - err = PTR_ERR(priv->gpiod_shutdown); - if (err != -EPROBE_DEFER) - dev_err(dev, "Failed to get 'shutdown' gpio: %d\n", - err); - return err; - } + if (IS_ERR(priv->gpiod_shutdown)) + return dev_err_probe(dev, PTR_ERR(priv->gpiod_shutdown), + "Failed to get 'shutdown' gpio\n"); return devm_snd_soc_register_component(dev, &ssm2305_component_driver, NULL, 0); From 7ff27faec8cccbbf499d0b4cd8ef951f1d5f5d05 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 14 Dec 2021 11:08:31 +0900 Subject: [PATCH 242/327] ASoC: codecs: tlv320aic31xx: Use dev_err_probe() helper Use the dev_err_probe() helper, instead of open-coding the same operation. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/20211214020843.2225831-11-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 4224b4b3cae62..e77342aff46d0 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1680,11 +1680,9 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, aic31xx->gpio_reset = devm_gpiod_get_optional(aic31xx->dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(aic31xx->gpio_reset)) { - if (PTR_ERR(aic31xx->gpio_reset) != -EPROBE_DEFER) - dev_err(aic31xx->dev, "not able to acquire gpio\n"); - return PTR_ERR(aic31xx->gpio_reset); - } + if (IS_ERR(aic31xx->gpio_reset)) + return dev_err_probe(aic31xx->dev, PTR_ERR(aic31xx->gpio_reset), + "not able to acquire gpio\n"); for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) aic31xx->supplies[i].supply = aic31xx_supply_names[i]; @@ -1692,12 +1690,8 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, ret = devm_regulator_bulk_get(aic31xx->dev, ARRAY_SIZE(aic31xx->supplies), aic31xx->supplies); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(aic31xx->dev, - "Failed to request supplies: %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(aic31xx->dev, ret, "Failed to request supplies\n"); aic31xx_configure_ocmv(aic31xx); From 0624dafa6a85be94e98822075c08006b5b528e2d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 14 Dec 2021 11:08:32 +0900 Subject: [PATCH 243/327] ASoC: ateml: Use dev_err_probe() helper Use the dev_err_probe() helper, instead of open-coding the same operation. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/20211214020843.2225831-12-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/atmel/mikroe-proto.c | 6 +++--- sound/soc/atmel/tse850-pcm5142.c | 32 ++++++++++++-------------------- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/sound/soc/atmel/mikroe-proto.c b/sound/soc/atmel/mikroe-proto.c index f9331f7e80fe4..627564c18c270 100644 --- a/sound/soc/atmel/mikroe-proto.c +++ b/sound/soc/atmel/mikroe-proto.c @@ -144,9 +144,9 @@ static int snd_proto_probe(struct platform_device *pdev) of_node_put(cpu_np); ret = snd_soc_register_card(&snd_proto); - if (ret && ret != -EPROBE_DEFER) - dev_err(&pdev->dev, - "snd_soc_register_card() failed: %d\n", ret); + if (ret) + dev_err_probe(&pdev->dev, ret, + "snd_soc_register_card() failed\n"); return ret; } diff --git a/sound/soc/atmel/tse850-pcm5142.c b/sound/soc/atmel/tse850-pcm5142.c index 1b3a31296c9b4..ef537de7719c7 100644 --- a/sound/soc/atmel/tse850-pcm5142.c +++ b/sound/soc/atmel/tse850-pcm5142.c @@ -371,35 +371,27 @@ static int tse850_probe(struct platform_device *pdev) } tse850->add = devm_gpiod_get(dev, "axentia,add", GPIOD_OUT_HIGH); - if (IS_ERR(tse850->add)) { - if (PTR_ERR(tse850->add) != -EPROBE_DEFER) - dev_err(dev, "failed to get 'add' gpio\n"); - return PTR_ERR(tse850->add); - } + if (IS_ERR(tse850->add)) + return dev_err_probe(dev, PTR_ERR(tse850->add), + "failed to get 'add' gpio\n"); tse850->add_cache = 1; tse850->loop1 = devm_gpiod_get(dev, "axentia,loop1", GPIOD_OUT_HIGH); - if (IS_ERR(tse850->loop1)) { - if (PTR_ERR(tse850->loop1) != -EPROBE_DEFER) - dev_err(dev, "failed to get 'loop1' gpio\n"); - return PTR_ERR(tse850->loop1); - } + if (IS_ERR(tse850->loop1)) + return dev_err_probe(dev, PTR_ERR(tse850->loop1), + "failed to get 'loop1' gpio\n"); tse850->loop1_cache = 1; tse850->loop2 = devm_gpiod_get(dev, "axentia,loop2", GPIOD_OUT_HIGH); - if (IS_ERR(tse850->loop2)) { - if (PTR_ERR(tse850->loop2) != -EPROBE_DEFER) - dev_err(dev, "failed to get 'loop2' gpio\n"); - return PTR_ERR(tse850->loop2); - } + if (IS_ERR(tse850->loop2)) + return dev_err_probe(dev, PTR_ERR(tse850->loop2), + "failed to get 'loop2' gpio\n"); tse850->loop2_cache = 1; tse850->ana = devm_regulator_get(dev, "axentia,ana"); - if (IS_ERR(tse850->ana)) { - if (PTR_ERR(tse850->ana) != -EPROBE_DEFER) - dev_err(dev, "failed to get 'ana' regulator\n"); - return PTR_ERR(tse850->ana); - } + if (IS_ERR(tse850->ana)) + return dev_err_probe(dev, PTR_ERR(tse850->ana), + "failed to get 'ana' regulator\n"); ret = regulator_enable(tse850->ana); if (ret < 0) { From 88fb6da3f4313feb885f432cfc3051b33fdb2df7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 14 Dec 2021 11:08:33 +0900 Subject: [PATCH 244/327] ASoC: ti: Use dev_err_probe() helper Use the dev_err_probe() helper, instead of open-coding the same operation. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/20211214020843.2225831-13-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/ti/davinci-mcasp.c | 10 +++------- sound/soc/ti/j721e-evm.c | 10 +++------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index 3e105caac95ee..2c146b91fca32 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -2024,13 +2024,9 @@ static int davinci_mcasp_get_dma_type(struct davinci_mcasp *mcasp) tmp = mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data; chan = dma_request_chan(mcasp->dev, tmp); - if (IS_ERR(chan)) { - if (PTR_ERR(chan) != -EPROBE_DEFER) - dev_err(mcasp->dev, - "Can't verify DMA configuration (%ld)\n", - PTR_ERR(chan)); - return PTR_ERR(chan); - } + if (IS_ERR(chan)) + return dev_err_probe(mcasp->dev, PTR_ERR(chan), + "Can't verify DMA configuration\n"); if (WARN_ON(!chan->device || !chan->device->dev)) { dma_release_channel(chan); return -EINVAL; diff --git a/sound/soc/ti/j721e-evm.c b/sound/soc/ti/j721e-evm.c index 9347f982c3e10..4077e15ec48b7 100644 --- a/sound/soc/ti/j721e-evm.c +++ b/sound/soc/ti/j721e-evm.c @@ -464,13 +464,9 @@ static int j721e_get_clocks(struct device *dev, int ret; clocks->target = devm_clk_get(dev, prefix); - if (IS_ERR(clocks->target)) { - ret = PTR_ERR(clocks->target); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to acquire %s: %d\n", - prefix, ret); - return ret; - } + if (IS_ERR(clocks->target)) + return dev_err_probe(dev, PTR_ERR(clocks->target), + "failed to acquire %s\n", prefix); clk_name = kasprintf(GFP_KERNEL, "%s-48000", prefix); if (clk_name) { From 2e6f557ca35aa330dbf31c5e1cc8119eff1526fa Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 14 Dec 2021 11:08:34 +0900 Subject: [PATCH 245/327] ASoC: fsl: Use dev_err_probe() helper Use the dev_err_probe() helper, instead of open-coding the same operation. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/20211214020843.2225831-14-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl-asoc-card.c | 3 +-- sound/soc/fsl/imx-card.c | 17 ++++++----------- sound/soc/fsl/imx-sgtl5000.c | 4 +--- sound/soc/fsl/imx-spdif.c | 4 ++-- 4 files changed, 10 insertions(+), 18 deletions(-) diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 90cbed496f98f..5ee9455052813 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -853,8 +853,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) ret = devm_snd_soc_register_card(&pdev->dev, &priv->card); if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); + dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed\n"); goto asrc_fail; } diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c index 6f06afd23b16a..e758c4f1b0bc7 100644 --- a/sound/soc/fsl/imx-card.c +++ b/sound/soc/fsl/imx-card.c @@ -563,9 +563,8 @@ static int imx_card_parse_of(struct imx_card_data *data) ret = snd_soc_of_get_dai_name(cpu, &link->cpus->dai_name); if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(card->dev, "%s: error getting cpu dai name: %d\n", - link->name, ret); + dev_err_probe(card->dev, ret, + "%s: error getting cpu dai name\n", link->name); goto err; } @@ -573,9 +572,8 @@ static int imx_card_parse_of(struct imx_card_data *data) if (codec) { ret = snd_soc_of_get_dai_link_codecs(dev, codec, link); if (ret < 0) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "%s: codec dai not found: %d\n", - link->name, ret); + dev_err_probe(dev, ret, "%s: codec dai not found\n", + link->name); goto err; } @@ -814,11 +812,8 @@ static int imx_card_probe(struct platform_device *pdev) } ret = devm_snd_soc_register_card(&pdev->dev, &data->card); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed\n"); return 0; } diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index 2f1acd0110426..8daced42d55e4 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c @@ -173,9 +173,7 @@ static int imx_sgtl5000_probe(struct platform_device *pdev) ret = devm_snd_soc_register_card(&pdev->dev, &data->card); if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", - ret); + dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed\n"); goto fail; } diff --git a/sound/soc/fsl/imx-spdif.c b/sound/soc/fsl/imx-spdif.c index 6c4dadf603551..4446fba755b9a 100644 --- a/sound/soc/fsl/imx-spdif.c +++ b/sound/soc/fsl/imx-spdif.c @@ -70,8 +70,8 @@ static int imx_spdif_audio_probe(struct platform_device *pdev) goto end; ret = devm_snd_soc_register_card(&pdev->dev, &data->card); - if (ret && ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "snd_soc_register_card failed: %d\n", ret); + if (ret) + dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed\n"); end: of_node_put(spdif_np); From 7a0299e13bc740caebbbba24b3df85fc9ffa7759 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 14 Dec 2021 11:08:35 +0900 Subject: [PATCH 246/327] ASoC: generic: Use dev_err_probe() helper Use the dev_err_probe() helper, instead of open-coding the same operation. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/20211214020843.2225831-15-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 5 +---- sound/soc/generic/audio-graph-card2.c | 4 ++-- sound/soc/generic/simple-card.c | 3 +-- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 7eb0272383278..2b598af8feef8 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -593,10 +593,7 @@ int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev) err: asoc_simple_clean_reference(card); - if (ret != -EPROBE_DEFER) - dev_err(dev, "parse error %d\n", ret); - - return ret; + return dev_err_probe(dev, ret, "parse error\n"); } EXPORT_SYMBOL_GPL(audio_graph_parse_of); diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index b6049bcfb771e..c3947347dda35 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -1238,8 +1238,8 @@ int audio_graph2_parse_of(struct asoc_simple_priv *priv, struct device *dev, err: devm_kfree(dev, li); - if ((ret < 0) && (ret != -EPROBE_DEFER)) - dev_err(dev, "parse error %d\n", ret); + if (ret < 0) + dev_err_probe(dev, ret, "parse error\n"); return ret; } diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index a3a7990b5cb66..a89d1cfdda327 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -642,8 +642,7 @@ static int asoc_simple_probe(struct platform_device *pdev) ret = simple_parse_of(priv, li); if (ret < 0) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "parse error %d\n", ret); + dev_err_probe(dev, ret, "parse error\n"); goto err; } From ef12f373f21d66e9d14eeace517c05fc2c9cf258 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 14 Dec 2021 11:08:36 +0900 Subject: [PATCH 247/327] ASoC: img: Use dev_err_probe() helper Use the dev_err_probe() helper, instead of open-coding the same operation. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/20211214020843.2225831-16-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/img/img-i2s-in.c | 8 +++----- sound/soc/img/img-i2s-out.c | 24 +++++++++--------------- sound/soc/img/img-parallel-out.c | 24 +++++++++--------------- sound/soc/img/img-spdif-in.c | 8 +++----- sound/soc/img/img-spdif-out.c | 24 +++++++++--------------- sound/soc/img/pistachio-internal-dac.c | 9 +++------ 6 files changed, 36 insertions(+), 61 deletions(-) diff --git a/sound/soc/img/img-i2s-in.c b/sound/soc/img/img-i2s-in.c index 1bf5d6edbd323..f1f36f15a503e 100644 --- a/sound/soc/img/img-i2s-in.c +++ b/sound/soc/img/img-i2s-in.c @@ -451,11 +451,9 @@ static int img_i2s_in_probe(struct platform_device *pdev) i2s->channel_base = base + (max_i2s_chan_pow_2 * 0x20); i2s->clk_sys = devm_clk_get(dev, "sys"); - if (IS_ERR(i2s->clk_sys)) { - if (PTR_ERR(i2s->clk_sys) != -EPROBE_DEFER) - dev_err(dev, "Failed to acquire clock 'sys'\n"); - return PTR_ERR(i2s->clk_sys); - } + if (IS_ERR(i2s->clk_sys)) + return dev_err_probe(dev, PTR_ERR(i2s->clk_sys), + "Failed to acquire clock 'sys'\n"); pm_runtime_enable(&pdev->dev); if (!pm_runtime_enabled(&pdev->dev)) { diff --git a/sound/soc/img/img-i2s-out.c b/sound/soc/img/img-i2s-out.c index 4f90d36dc7dfd..28f48ca1508a6 100644 --- a/sound/soc/img/img-i2s-out.c +++ b/sound/soc/img/img-i2s-out.c @@ -457,25 +457,19 @@ static int img_i2s_out_probe(struct platform_device *pdev) i2s->channel_base = base + (max_i2s_chan_pow_2 * 0x20); i2s->rst = devm_reset_control_get_exclusive(&pdev->dev, "rst"); - if (IS_ERR(i2s->rst)) { - if (PTR_ERR(i2s->rst) != -EPROBE_DEFER) - dev_err(&pdev->dev, "No top level reset found\n"); - return PTR_ERR(i2s->rst); - } + if (IS_ERR(i2s->rst)) + return dev_err_probe(&pdev->dev, PTR_ERR(i2s->rst), + "No top level reset found\n"); i2s->clk_sys = devm_clk_get(&pdev->dev, "sys"); - if (IS_ERR(i2s->clk_sys)) { - if (PTR_ERR(i2s->clk_sys) != -EPROBE_DEFER) - dev_err(dev, "Failed to acquire clock 'sys'\n"); - return PTR_ERR(i2s->clk_sys); - } + if (IS_ERR(i2s->clk_sys)) + return dev_err_probe(dev, PTR_ERR(i2s->clk_sys), + "Failed to acquire clock 'sys'\n"); i2s->clk_ref = devm_clk_get(&pdev->dev, "ref"); - if (IS_ERR(i2s->clk_ref)) { - if (PTR_ERR(i2s->clk_ref) != -EPROBE_DEFER) - dev_err(dev, "Failed to acquire clock 'ref'\n"); - return PTR_ERR(i2s->clk_ref); - } + if (IS_ERR(i2s->clk_ref)) + return dev_err_probe(dev, PTR_ERR(i2s->clk_ref), + "Failed to acquire clock 'ref'\n"); i2s->suspend_ch_ctl = devm_kcalloc(dev, i2s->max_i2s_chan, sizeof(*i2s->suspend_ch_ctl), GFP_KERNEL); diff --git a/sound/soc/img/img-parallel-out.c b/sound/soc/img/img-parallel-out.c index ce0f08d3777c6..800f247283cd8 100644 --- a/sound/soc/img/img-parallel-out.c +++ b/sound/soc/img/img-parallel-out.c @@ -229,25 +229,19 @@ static int img_prl_out_probe(struct platform_device *pdev) prl->base = base; prl->rst = devm_reset_control_get_exclusive(&pdev->dev, "rst"); - if (IS_ERR(prl->rst)) { - if (PTR_ERR(prl->rst) != -EPROBE_DEFER) - dev_err(&pdev->dev, "No top level reset found\n"); - return PTR_ERR(prl->rst); - } + if (IS_ERR(prl->rst)) + return dev_err_probe(&pdev->dev, PTR_ERR(prl->rst), + "No top level reset found\n"); prl->clk_sys = devm_clk_get(&pdev->dev, "sys"); - if (IS_ERR(prl->clk_sys)) { - if (PTR_ERR(prl->clk_sys) != -EPROBE_DEFER) - dev_err(dev, "Failed to acquire clock 'sys'\n"); - return PTR_ERR(prl->clk_sys); - } + if (IS_ERR(prl->clk_sys)) + return dev_err_probe(dev, PTR_ERR(prl->clk_sys), + "Failed to acquire clock 'sys'\n"); prl->clk_ref = devm_clk_get(&pdev->dev, "ref"); - if (IS_ERR(prl->clk_ref)) { - if (PTR_ERR(prl->clk_ref) != -EPROBE_DEFER) - dev_err(dev, "Failed to acquire clock 'ref'\n"); - return PTR_ERR(prl->clk_ref); - } + if (IS_ERR(prl->clk_ref)) + return dev_err_probe(dev, PTR_ERR(prl->clk_ref), + "Failed to acquire clock 'ref'\n"); ret = clk_prepare_enable(prl->clk_sys); if (ret) diff --git a/sound/soc/img/img-spdif-in.c b/sound/soc/img/img-spdif-in.c index 6364eb742f6d8..95914d0612fe7 100644 --- a/sound/soc/img/img-spdif-in.c +++ b/sound/soc/img/img-spdif-in.c @@ -739,11 +739,9 @@ static int img_spdif_in_probe(struct platform_device *pdev) spdif->base = base; spdif->clk_sys = devm_clk_get(dev, "sys"); - if (IS_ERR(spdif->clk_sys)) { - if (PTR_ERR(spdif->clk_sys) != -EPROBE_DEFER) - dev_err(dev, "Failed to acquire clock 'sys'\n"); - return PTR_ERR(spdif->clk_sys); - } + if (IS_ERR(spdif->clk_sys)) + return dev_err_probe(dev, PTR_ERR(spdif->clk_sys), + "Failed to acquire clock 'sys'\n"); pm_runtime_enable(&pdev->dev); if (!pm_runtime_enabled(&pdev->dev)) { diff --git a/sound/soc/img/img-spdif-out.c b/sound/soc/img/img-spdif-out.c index 858e1b8538209..c3189d9ff72f4 100644 --- a/sound/soc/img/img-spdif-out.c +++ b/sound/soc/img/img-spdif-out.c @@ -342,25 +342,19 @@ static int img_spdif_out_probe(struct platform_device *pdev) spdif->base = base; spdif->rst = devm_reset_control_get_exclusive(&pdev->dev, "rst"); - if (IS_ERR(spdif->rst)) { - if (PTR_ERR(spdif->rst) != -EPROBE_DEFER) - dev_err(&pdev->dev, "No top level reset found\n"); - return PTR_ERR(spdif->rst); - } + if (IS_ERR(spdif->rst)) + return dev_err_probe(&pdev->dev, PTR_ERR(spdif->rst), + "No top level reset found\n"); spdif->clk_sys = devm_clk_get(&pdev->dev, "sys"); - if (IS_ERR(spdif->clk_sys)) { - if (PTR_ERR(spdif->clk_sys) != -EPROBE_DEFER) - dev_err(dev, "Failed to acquire clock 'sys'\n"); - return PTR_ERR(spdif->clk_sys); - } + if (IS_ERR(spdif->clk_sys)) + return dev_err_probe(dev, PTR_ERR(spdif->clk_sys), + "Failed to acquire clock 'sys'\n"); spdif->clk_ref = devm_clk_get(&pdev->dev, "ref"); - if (IS_ERR(spdif->clk_ref)) { - if (PTR_ERR(spdif->clk_ref) != -EPROBE_DEFER) - dev_err(dev, "Failed to acquire clock 'ref'\n"); - return PTR_ERR(spdif->clk_ref); - } + if (IS_ERR(spdif->clk_ref)) + return dev_err_probe(dev, PTR_ERR(spdif->clk_ref), + "Failed to acquire clock 'ref'\n"); pm_runtime_enable(&pdev->dev); if (!pm_runtime_enabled(&pdev->dev)) { diff --git a/sound/soc/img/pistachio-internal-dac.c b/sound/soc/img/pistachio-internal-dac.c index fe181c2e51d65..802c0ee63aa26 100644 --- a/sound/soc/img/pistachio-internal-dac.c +++ b/sound/soc/img/pistachio-internal-dac.c @@ -161,12 +161,9 @@ static int pistachio_internal_dac_probe(struct platform_device *pdev) return PTR_ERR(dac->regmap); dac->supply = devm_regulator_get(dev, "VDD"); - if (IS_ERR(dac->supply)) { - ret = PTR_ERR(dac->supply); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to acquire supply 'VDD-supply': %d\n", ret); - return ret; - } + if (IS_ERR(dac->supply)) + return dev_err_probe(dev, PTR_ERR(dac->supply), + "failed to acquire supply 'VDD-supply'\n"); ret = regulator_enable(dac->supply); if (ret) { From 2ff4e003e8e105fb65c682c876a5cb0e00f854bf Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 14 Dec 2021 11:08:37 +0900 Subject: [PATCH 248/327] ASoC: meson: Use dev_err_probe() helper Use the dev_err_probe() helper, instead of open-coding the same operation. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/20211214020843.2225831-17-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/meson/aiu.c | 36 +++++++-------------- sound/soc/meson/axg-fifo.c | 16 +++------ sound/soc/meson/axg-pdm.c | 25 ++++----------- sound/soc/meson/axg-spdifin.c | 17 +++------- sound/soc/meson/axg-spdifout.c | 17 +++------- sound/soc/meson/axg-tdm-formatter.c | 50 ++++++++--------------------- sound/soc/meson/axg-tdm-interface.c | 25 ++++----------- sound/soc/meson/meson-card-utils.c | 8 ++--- sound/soc/meson/t9015.c | 14 +++----- 9 files changed, 56 insertions(+), 152 deletions(-) diff --git a/sound/soc/meson/aiu.c b/sound/soc/meson/aiu.c index ba15d5762b0bf..d299a70db7e59 100644 --- a/sound/soc/meson/aiu.c +++ b/sound/soc/meson/aiu.c @@ -218,34 +218,23 @@ static int aiu_clk_get(struct device *dev) int ret; aiu->pclk = devm_clk_get(dev, "pclk"); - if (IS_ERR(aiu->pclk)) { - if (PTR_ERR(aiu->pclk) != -EPROBE_DEFER) - dev_err(dev, "Can't get the aiu pclk\n"); - return PTR_ERR(aiu->pclk); - } + if (IS_ERR(aiu->pclk)) + return dev_err_probe(dev, PTR_ERR(aiu->pclk), "Can't get the aiu pclk\n"); aiu->spdif_mclk = devm_clk_get(dev, "spdif_mclk"); - if (IS_ERR(aiu->spdif_mclk)) { - if (PTR_ERR(aiu->spdif_mclk) != -EPROBE_DEFER) - dev_err(dev, "Can't get the aiu spdif master clock\n"); - return PTR_ERR(aiu->spdif_mclk); - } + if (IS_ERR(aiu->spdif_mclk)) + return dev_err_probe(dev, PTR_ERR(aiu->spdif_mclk), + "Can't get the aiu spdif master clock\n"); ret = aiu_clk_bulk_get(dev, aiu_i2s_ids, ARRAY_SIZE(aiu_i2s_ids), &aiu->i2s); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "Can't get the i2s clocks\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Can't get the i2s clocks\n"); ret = aiu_clk_bulk_get(dev, aiu_spdif_ids, ARRAY_SIZE(aiu_spdif_ids), &aiu->spdif); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "Can't get the spdif clocks\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Can't get the spdif clocks\n"); ret = clk_prepare_enable(aiu->pclk); if (ret) { @@ -281,11 +270,8 @@ static int aiu_probe(struct platform_device *pdev) platform_set_drvdata(pdev, aiu); ret = device_reset(dev); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to reset device\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Failed to reset device\n"); regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) diff --git a/sound/soc/meson/axg-fifo.c b/sound/soc/meson/axg-fifo.c index b9af2d513e096..bccfb770b3391 100644 --- a/sound/soc/meson/axg-fifo.c +++ b/sound/soc/meson/axg-fifo.c @@ -351,20 +351,12 @@ int axg_fifo_probe(struct platform_device *pdev) } fifo->pclk = devm_clk_get(dev, NULL); - if (IS_ERR(fifo->pclk)) { - if (PTR_ERR(fifo->pclk) != -EPROBE_DEFER) - dev_err(dev, "failed to get pclk: %ld\n", - PTR_ERR(fifo->pclk)); - return PTR_ERR(fifo->pclk); - } + if (IS_ERR(fifo->pclk)) + return dev_err_probe(dev, PTR_ERR(fifo->pclk), "failed to get pclk\n"); fifo->arb = devm_reset_control_get_exclusive(dev, NULL); - if (IS_ERR(fifo->arb)) { - if (PTR_ERR(fifo->arb) != -EPROBE_DEFER) - dev_err(dev, "failed to get arb reset: %ld\n", - PTR_ERR(fifo->arb)); - return PTR_ERR(fifo->arb); - } + if (IS_ERR(fifo->arb)) + return dev_err_probe(dev, PTR_ERR(fifo->arb), "failed to get arb reset\n"); fifo->irq = of_irq_get(dev->of_node, 0); if (fifo->irq <= 0) { diff --git a/sound/soc/meson/axg-pdm.c b/sound/soc/meson/axg-pdm.c index bfd37d49a73ef..672e43a9729dc 100644 --- a/sound/soc/meson/axg-pdm.c +++ b/sound/soc/meson/axg-pdm.c @@ -586,7 +586,6 @@ static int axg_pdm_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct axg_pdm *priv; void __iomem *regs; - int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -611,28 +610,16 @@ static int axg_pdm_probe(struct platform_device *pdev) } priv->pclk = devm_clk_get(dev, "pclk"); - if (IS_ERR(priv->pclk)) { - ret = PTR_ERR(priv->pclk); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get pclk: %d\n", ret); - return ret; - } + if (IS_ERR(priv->pclk)) + return dev_err_probe(dev, PTR_ERR(priv->pclk), "failed to get pclk\n"); priv->dclk = devm_clk_get(dev, "dclk"); - if (IS_ERR(priv->dclk)) { - ret = PTR_ERR(priv->dclk); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get dclk: %d\n", ret); - return ret; - } + if (IS_ERR(priv->dclk)) + return dev_err_probe(dev, PTR_ERR(priv->dclk), "failed to get dclk\n"); priv->sysclk = devm_clk_get(dev, "sysclk"); - if (IS_ERR(priv->sysclk)) { - ret = PTR_ERR(priv->sysclk); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get dclk: %d\n", ret); - return ret; - } + if (IS_ERR(priv->sysclk)) + return dev_err_probe(dev, PTR_ERR(priv->sysclk), "failed to get dclk\n"); return devm_snd_soc_register_component(dev, &axg_pdm_component_drv, &axg_pdm_dai_drv, 1); diff --git a/sound/soc/meson/axg-spdifin.c b/sound/soc/meson/axg-spdifin.c index d0d09f945b489..4ba44e0d65d9f 100644 --- a/sound/soc/meson/axg-spdifin.c +++ b/sound/soc/meson/axg-spdifin.c @@ -454,7 +454,6 @@ static int axg_spdifin_probe(struct platform_device *pdev) struct axg_spdifin *priv; struct snd_soc_dai_driver *dai_drv; void __iomem *regs; - int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -479,20 +478,12 @@ static int axg_spdifin_probe(struct platform_device *pdev) } priv->pclk = devm_clk_get(dev, "pclk"); - if (IS_ERR(priv->pclk)) { - ret = PTR_ERR(priv->pclk); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get pclk: %d\n", ret); - return ret; - } + if (IS_ERR(priv->pclk)) + return dev_err_probe(dev, PTR_ERR(priv->pclk), "failed to get pclk\n"); priv->refclk = devm_clk_get(dev, "refclk"); - if (IS_ERR(priv->refclk)) { - ret = PTR_ERR(priv->refclk); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get mclk: %d\n", ret); - return ret; - } + if (IS_ERR(priv->refclk)) + return dev_err_probe(dev, PTR_ERR(priv->refclk), "failed to get mclk\n"); dai_drv = axg_spdifin_get_dai_drv(dev, priv); if (IS_ERR(dai_drv)) { diff --git a/sound/soc/meson/axg-spdifout.c b/sound/soc/meson/axg-spdifout.c index e769a5ee6e27e..3960d082e1436 100644 --- a/sound/soc/meson/axg-spdifout.c +++ b/sound/soc/meson/axg-spdifout.c @@ -403,7 +403,6 @@ static int axg_spdifout_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct axg_spdifout *priv; void __iomem *regs; - int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -422,20 +421,12 @@ static int axg_spdifout_probe(struct platform_device *pdev) } priv->pclk = devm_clk_get(dev, "pclk"); - if (IS_ERR(priv->pclk)) { - ret = PTR_ERR(priv->pclk); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get pclk: %d\n", ret); - return ret; - } + if (IS_ERR(priv->pclk)) + return dev_err_probe(dev, PTR_ERR(priv->pclk), "failed to get pclk\n"); priv->mclk = devm_clk_get(dev, "mclk"); - if (IS_ERR(priv->mclk)) { - ret = PTR_ERR(priv->mclk); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get mclk: %d\n", ret); - return ret; - } + if (IS_ERR(priv->mclk)) + return dev_err_probe(dev, PTR_ERR(priv->mclk), "failed to get mclk\n"); return devm_snd_soc_register_component(dev, &axg_spdifout_component_drv, axg_spdifout_dai_drv, ARRAY_SIZE(axg_spdifout_dai_drv)); diff --git a/sound/soc/meson/axg-tdm-formatter.c b/sound/soc/meson/axg-tdm-formatter.c index cab7fa2851aa8..9883dc777f630 100644 --- a/sound/soc/meson/axg-tdm-formatter.c +++ b/sound/soc/meson/axg-tdm-formatter.c @@ -255,7 +255,6 @@ int axg_tdm_formatter_probe(struct platform_device *pdev) const struct axg_tdm_formatter_driver *drv; struct axg_tdm_formatter *formatter; void __iomem *regs; - int ret; drv = of_device_get_match_data(dev); if (!drv) { @@ -282,57 +281,34 @@ int axg_tdm_formatter_probe(struct platform_device *pdev) /* Peripharal clock */ formatter->pclk = devm_clk_get(dev, "pclk"); - if (IS_ERR(formatter->pclk)) { - ret = PTR_ERR(formatter->pclk); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get pclk: %d\n", ret); - return ret; - } + if (IS_ERR(formatter->pclk)) + return dev_err_probe(dev, PTR_ERR(formatter->pclk), "failed to get pclk\n"); /* Formatter bit clock */ formatter->sclk = devm_clk_get(dev, "sclk"); - if (IS_ERR(formatter->sclk)) { - ret = PTR_ERR(formatter->sclk); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get sclk: %d\n", ret); - return ret; - } + if (IS_ERR(formatter->sclk)) + return dev_err_probe(dev, PTR_ERR(formatter->sclk), "failed to get sclk\n"); /* Formatter sample clock */ formatter->lrclk = devm_clk_get(dev, "lrclk"); - if (IS_ERR(formatter->lrclk)) { - ret = PTR_ERR(formatter->lrclk); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get lrclk: %d\n", ret); - return ret; - } + if (IS_ERR(formatter->lrclk)) + return dev_err_probe(dev, PTR_ERR(formatter->lrclk), "failed to get lrclk\n"); /* Formatter bit clock input multiplexer */ formatter->sclk_sel = devm_clk_get(dev, "sclk_sel"); - if (IS_ERR(formatter->sclk_sel)) { - ret = PTR_ERR(formatter->sclk_sel); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get sclk_sel: %d\n", ret); - return ret; - } + if (IS_ERR(formatter->sclk_sel)) + return dev_err_probe(dev, PTR_ERR(formatter->sclk_sel), "failed to get sclk_sel\n"); /* Formatter sample clock input multiplexer */ formatter->lrclk_sel = devm_clk_get(dev, "lrclk_sel"); - if (IS_ERR(formatter->lrclk_sel)) { - ret = PTR_ERR(formatter->lrclk_sel); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get lrclk_sel: %d\n", ret); - return ret; - } + if (IS_ERR(formatter->lrclk_sel)) + return dev_err_probe(dev, PTR_ERR(formatter->lrclk_sel), + "failed to get lrclk_sel\n"); /* Formatter dedicated reset line */ formatter->reset = devm_reset_control_get_optional_exclusive(dev, NULL); - if (IS_ERR(formatter->reset)) { - ret = PTR_ERR(formatter->reset); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get reset: %d\n", ret); - return ret; - } + if (IS_ERR(formatter->reset)) + return dev_err_probe(dev, PTR_ERR(formatter->reset), "failed to get reset\n"); return devm_snd_soc_register_component(dev, drv->component_drv, NULL, 0); diff --git a/sound/soc/meson/axg-tdm-interface.c b/sound/soc/meson/axg-tdm-interface.c index db077773af7aa..0c31934a96301 100644 --- a/sound/soc/meson/axg-tdm-interface.c +++ b/sound/soc/meson/axg-tdm-interface.c @@ -533,21 +533,13 @@ static int axg_tdm_iface_probe(struct platform_device *pdev) /* Bit clock provided on the pad */ iface->sclk = devm_clk_get(dev, "sclk"); - if (IS_ERR(iface->sclk)) { - ret = PTR_ERR(iface->sclk); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get sclk: %d\n", ret); - return ret; - } + if (IS_ERR(iface->sclk)) + return dev_err_probe(dev, PTR_ERR(iface->sclk), "failed to get sclk\n"); /* Sample clock provided on the pad */ iface->lrclk = devm_clk_get(dev, "lrclk"); - if (IS_ERR(iface->lrclk)) { - ret = PTR_ERR(iface->lrclk); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get lrclk: %d\n", ret); - return ret; - } + if (IS_ERR(iface->lrclk)) + return dev_err_probe(dev, PTR_ERR(iface->lrclk), "failed to get lrclk\n"); /* * mclk maybe be missing when the cpu dai is in slave mode and @@ -558,13 +550,10 @@ static int axg_tdm_iface_probe(struct platform_device *pdev) iface->mclk = devm_clk_get(dev, "mclk"); if (IS_ERR(iface->mclk)) { ret = PTR_ERR(iface->mclk); - if (ret == -ENOENT) { + if (ret == -ENOENT) iface->mclk = NULL; - } else { - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get mclk: %d\n", ret); - return ret; - } + else + return dev_err_probe(dev, ret, "failed to get mclk\n"); } return devm_snd_soc_register_component(dev, diff --git a/sound/soc/meson/meson-card-utils.c b/sound/soc/meson/meson-card-utils.c index 29b0174f4b5c9..2d8d5717fd8bf 100644 --- a/sound/soc/meson/meson-card-utils.c +++ b/sound/soc/meson/meson-card-utils.c @@ -85,11 +85,9 @@ int meson_card_parse_dai(struct snd_soc_card *card, ret = of_parse_phandle_with_args(node, "sound-dai", "#sound-dai-cells", 0, &args); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(card->dev, "can't parse dai %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(card->dev, ret, "can't parse dai\n"); + *dai_of_node = args.np; return snd_soc_get_dai_name(&args, dai_name); diff --git a/sound/soc/meson/t9015.c b/sound/soc/meson/t9015.c index 4c1349dd1e06a..a9b8c4e77d405 100644 --- a/sound/soc/meson/t9015.c +++ b/sound/soc/meson/t9015.c @@ -258,18 +258,12 @@ static int t9015_probe(struct platform_device *pdev) platform_set_drvdata(pdev, priv); priv->pclk = devm_clk_get(dev, "pclk"); - if (IS_ERR(priv->pclk)) { - if (PTR_ERR(priv->pclk) != -EPROBE_DEFER) - dev_err(dev, "failed to get core clock\n"); - return PTR_ERR(priv->pclk); - } + if (IS_ERR(priv->pclk)) + return dev_err_probe(dev, PTR_ERR(priv->pclk), "failed to get core clock\n"); priv->avdd = devm_regulator_get(dev, "AVDD"); - if (IS_ERR(priv->avdd)) { - if (PTR_ERR(priv->avdd) != -EPROBE_DEFER) - dev_err(dev, "failed to AVDD\n"); - return PTR_ERR(priv->avdd); - } + if (IS_ERR(priv->avdd)) + return dev_err_probe(dev, PTR_ERR(priv->avdd), "failed to AVDD\n"); ret = clk_prepare_enable(priv->pclk); if (ret) { From 7a17f6a95a6136cb0a5c41be2b0ac131f9238ae8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 14 Dec 2021 11:08:38 +0900 Subject: [PATCH 249/327] ASoC: mxs: Use dev_err_probe() helper Use the dev_err_probe() helper, instead of open-coding the same operation. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/20211214020843.2225831-18-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/mxs/mxs-sgtl5000.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c index a6407f4388de7..2412dc7e65d44 100644 --- a/sound/soc/mxs/mxs-sgtl5000.c +++ b/sound/soc/mxs/mxs-sgtl5000.c @@ -160,12 +160,8 @@ static int mxs_sgtl5000_probe(struct platform_device *pdev) } ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", - ret); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed\n"); return 0; } From ab6c3e68ab6e3c545b044a00814946e2998c8c53 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 14 Dec 2021 11:08:39 +0900 Subject: [PATCH 250/327] ASoC: qcom: Use dev_err_probe() helper Use the dev_err_probe() helper, instead of open-coding the same operation. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/20211214020843.2225831-19-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/qcom/common.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c index 2e1c618f75297..e1bf04d006259 100644 --- a/sound/soc/qcom/common.c +++ b/sound/soc/qcom/common.c @@ -94,9 +94,8 @@ int qcom_snd_parse_of(struct snd_soc_card *card) ret = snd_soc_of_get_dai_name(cpu, &link->cpus->dai_name); if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(card->dev, "%s: error getting cpu dai name: %d\n", - link->name, ret); + dev_err_probe(card->dev, ret, + "%s: error getting cpu dai name\n", link->name); goto err; } @@ -116,9 +115,8 @@ int qcom_snd_parse_of(struct snd_soc_card *card) if (codec) { ret = snd_soc_of_get_dai_link_codecs(dev, codec, link); if (ret < 0) { - if (ret != -EPROBE_DEFER) - dev_err(card->dev, "%s: codec dai not found: %d\n", - link->name, ret); + dev_err_probe(card->dev, ret, + "%s: codec dai not found\n", link->name); goto err; } From b3a66d22a2fd5435bf4d0a357e220cfca88ae5e2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 14 Dec 2021 11:08:40 +0900 Subject: [PATCH 251/327] ASoC: rockchip: Use dev_err_probe() helper Use the dev_err_probe() helper, instead of open-coding the same operation. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/20211214020843.2225831-20-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/rockchip/rk3288_hdmi_analog.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/sound/soc/rockchip/rk3288_hdmi_analog.c b/sound/soc/rockchip/rk3288_hdmi_analog.c index 33a00774746d6..b052642ea620b 100644 --- a/sound/soc/rockchip/rk3288_hdmi_analog.c +++ b/sound/soc/rockchip/rk3288_hdmi_analog.c @@ -249,13 +249,9 @@ static int snd_rk_mc_probe(struct platform_device *pdev) snd_soc_card_set_drvdata(card, machine); ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret == -EPROBE_DEFER) - return -EPROBE_DEFER; - if (ret) { - dev_err(&pdev->dev, - "Soc register card failed %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Soc register card failed\n"); return ret; } From 27c6eaebcf75e4fac145d17c7fa76bc64b60d24c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 14 Dec 2021 11:08:41 +0900 Subject: [PATCH 252/327] ASoC: samsung: Use dev_err_probe() helper Use the dev_err_probe() helper, instead of open-coding the same operation. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/20211214020843.2225831-21-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/samsung/aries_wm8994.c | 17 +++++++---------- sound/soc/samsung/arndale.c | 5 ++--- sound/soc/samsung/littlemill.c | 5 ++--- sound/soc/samsung/lowland.c | 5 ++--- sound/soc/samsung/odroid.c | 4 +--- sound/soc/samsung/smdk_wm8994.c | 4 ++-- sound/soc/samsung/smdk_wm8994pcm.c | 4 ++-- sound/soc/samsung/snow.c | 9 +++------ sound/soc/samsung/speyside.c | 5 ++--- sound/soc/samsung/tm2_wm5110.c | 3 +-- sound/soc/samsung/tobermory.c | 5 ++--- 11 files changed, 26 insertions(+), 40 deletions(-) diff --git a/sound/soc/samsung/aries_wm8994.c b/sound/soc/samsung/aries_wm8994.c index 313ab650f8d9f..5265e546b124c 100644 --- a/sound/soc/samsung/aries_wm8994.c +++ b/sound/soc/samsung/aries_wm8994.c @@ -585,19 +585,16 @@ static int aries_audio_probe(struct platform_device *pdev) extcon_np = of_parse_phandle(np, "extcon", 0); priv->usb_extcon = extcon_find_edev_by_node(extcon_np); - if (IS_ERR(priv->usb_extcon)) { - if (PTR_ERR(priv->usb_extcon) != -EPROBE_DEFER) - dev_err(dev, "Failed to get extcon device"); - return PTR_ERR(priv->usb_extcon); - } + if (IS_ERR(priv->usb_extcon)) + return dev_err_probe(dev, PTR_ERR(priv->usb_extcon), + "Failed to get extcon device"); of_node_put(extcon_np); priv->adc = devm_iio_channel_get(dev, "headset-detect"); - if (IS_ERR(priv->adc)) { - if (PTR_ERR(priv->adc) != -EPROBE_DEFER) - dev_err(dev, "Failed to get ADC channel"); - return PTR_ERR(priv->adc); - } + if (IS_ERR(priv->adc)) + return dev_err_probe(dev, PTR_ERR(priv->adc), + "Failed to get ADC channel"); + if (priv->adc->channel->type != IIO_VOLTAGE) return -EINVAL; diff --git a/sound/soc/samsung/arndale.c b/sound/soc/samsung/arndale.c index 606ac5e33a8e9..a5dc640d0d768 100644 --- a/sound/soc/samsung/arndale.c +++ b/sound/soc/samsung/arndale.c @@ -174,9 +174,8 @@ static int arndale_audio_probe(struct platform_device *pdev) ret = devm_snd_soc_register_card(card->dev, card); if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, - "snd_soc_register_card() failed: %d\n", ret); + dev_err_probe(&pdev->dev, ret, + "snd_soc_register_card() failed\n"); goto err_put_of_nodes; } return 0; diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c index 390f2dd735ad2..34067cc314ff0 100644 --- a/sound/soc/samsung/littlemill.c +++ b/sound/soc/samsung/littlemill.c @@ -325,9 +325,8 @@ static int littlemill_probe(struct platform_device *pdev) card->dev = &pdev->dev; ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret && ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", - ret); + if (ret) + dev_err_probe(&pdev->dev, ret, "snd_soc_register_card() failed\n"); return ret; } diff --git a/sound/soc/samsung/lowland.c b/sound/soc/samsung/lowland.c index 998d10cf8c947..7b12ccd2a9b22 100644 --- a/sound/soc/samsung/lowland.c +++ b/sound/soc/samsung/lowland.c @@ -183,9 +183,8 @@ static int lowland_probe(struct platform_device *pdev) card->dev = &pdev->dev; ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret && ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", - ret); + if (ret) + dev_err_probe(&pdev->dev, ret, "snd_soc_register_card() failed\n"); return ret; } diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c index ca643a488c3ca..4ff12e2e704fe 100644 --- a/sound/soc/samsung/odroid.c +++ b/sound/soc/samsung/odroid.c @@ -311,9 +311,7 @@ static int odroid_audio_probe(struct platform_device *pdev) ret = devm_snd_soc_register_card(dev, card); if (ret < 0) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "snd_soc_register_card() failed: %d\n", - ret); + dev_err_probe(dev, ret, "snd_soc_register_card() failed\n"); goto err_put_clk_i2s; } diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c index 7661b637946d1..821ad1eb1b79f 100644 --- a/sound/soc/samsung/smdk_wm8994.c +++ b/sound/soc/samsung/smdk_wm8994.c @@ -179,8 +179,8 @@ static int smdk_audio_probe(struct platform_device *pdev) ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret && ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret); + if (ret) + dev_err_probe(&pdev->dev, ret, "snd_soc_register_card() failed\n"); return ret; } diff --git a/sound/soc/samsung/smdk_wm8994pcm.c b/sound/soc/samsung/smdk_wm8994pcm.c index 029448f5bedbe..d77dc54cae9c8 100644 --- a/sound/soc/samsung/smdk_wm8994pcm.c +++ b/sound/soc/samsung/smdk_wm8994pcm.c @@ -118,8 +118,8 @@ static int snd_smdk_probe(struct platform_device *pdev) smdk_pcm.dev = &pdev->dev; ret = devm_snd_soc_register_card(&pdev->dev, &smdk_pcm); - if (ret && ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret); + if (ret) + dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed\n"); return ret; } diff --git a/sound/soc/samsung/snow.c b/sound/soc/samsung/snow.c index 6da674e901caf..02372109c251e 100644 --- a/sound/soc/samsung/snow.c +++ b/sound/soc/samsung/snow.c @@ -212,12 +212,9 @@ static int snow_probe(struct platform_device *pdev) snd_soc_card_set_drvdata(card, priv); ret = devm_snd_soc_register_card(dev, card); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, - "snd_soc_register_card failed (%d)\n", ret); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, + "snd_soc_register_card failed\n"); return ret; } diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c index f5f6ba00d0731..37b1f4f60b210 100644 --- a/sound/soc/samsung/speyside.c +++ b/sound/soc/samsung/speyside.c @@ -330,9 +330,8 @@ static int speyside_probe(struct platform_device *pdev) card->dev = &pdev->dev; ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret && ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", - ret); + if (ret) + dev_err_probe(&pdev->dev, ret, "snd_soc_register_card() failed\n"); return ret; } diff --git a/sound/soc/samsung/tm2_wm5110.c b/sound/soc/samsung/tm2_wm5110.c index a2c77e6defec5..d611ec9e5325e 100644 --- a/sound/soc/samsung/tm2_wm5110.c +++ b/sound/soc/samsung/tm2_wm5110.c @@ -612,8 +612,7 @@ static int tm2_probe(struct platform_device *pdev) ret = devm_snd_soc_register_card(dev, card); if (ret < 0) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to register card: %d\n", ret); + dev_err_probe(dev, ret, "Failed to register card\n"); goto dai_node_put; } diff --git a/sound/soc/samsung/tobermory.c b/sound/soc/samsung/tobermory.c index 15223d860cb72..8d3149a47a4c8 100644 --- a/sound/soc/samsung/tobermory.c +++ b/sound/soc/samsung/tobermory.c @@ -229,9 +229,8 @@ static int tobermory_probe(struct platform_device *pdev) card->dev = &pdev->dev; ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret && ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", - ret); + if (ret) + dev_err_probe(&pdev->dev, ret, "snd_soc_register_card() failed\n"); return ret; } From efc162cbd480f1fb47d439c193ec9731bcc6c749 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 14 Dec 2021 11:08:42 +0900 Subject: [PATCH 253/327] ASoC: stm: Use dev_err_probe() helper Use the dev_err_probe() helper, instead of open-coding the same operation. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/20211214020843.2225831-22-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/stm/stm32_i2s.c | 62 ++++++++++++----------------------- sound/soc/stm/stm32_sai.c | 37 ++++++++------------- sound/soc/stm/stm32_sai_sub.c | 25 +++++--------- sound/soc/stm/stm32_spdifrx.c | 44 +++++++++---------------- 4 files changed, 57 insertions(+), 111 deletions(-) diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index 24327cabd32a3..ac5dff4d1677a 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -1045,36 +1045,24 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev, /* Get clocks */ i2s->pclk = devm_clk_get(&pdev->dev, "pclk"); - if (IS_ERR(i2s->pclk)) { - if (PTR_ERR(i2s->pclk) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Could not get pclk: %ld\n", - PTR_ERR(i2s->pclk)); - return PTR_ERR(i2s->pclk); - } + if (IS_ERR(i2s->pclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(i2s->pclk), + "Could not get pclk\n"); i2s->i2sclk = devm_clk_get(&pdev->dev, "i2sclk"); - if (IS_ERR(i2s->i2sclk)) { - if (PTR_ERR(i2s->i2sclk) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Could not get i2sclk: %ld\n", - PTR_ERR(i2s->i2sclk)); - return PTR_ERR(i2s->i2sclk); - } + if (IS_ERR(i2s->i2sclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(i2s->i2sclk), + "Could not get i2sclk\n"); i2s->x8kclk = devm_clk_get(&pdev->dev, "x8k"); - if (IS_ERR(i2s->x8kclk)) { - if (PTR_ERR(i2s->x8kclk) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Could not get x8k parent clock: %ld\n", - PTR_ERR(i2s->x8kclk)); - return PTR_ERR(i2s->x8kclk); - } + if (IS_ERR(i2s->x8kclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(i2s->x8kclk), + "Could not get x8k parent clock\n"); i2s->x11kclk = devm_clk_get(&pdev->dev, "x11k"); - if (IS_ERR(i2s->x11kclk)) { - if (PTR_ERR(i2s->x11kclk) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Could not get x11k parent clock: %ld\n", - PTR_ERR(i2s->x11kclk)); - return PTR_ERR(i2s->x11kclk); - } + if (IS_ERR(i2s->x11kclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(i2s->x11kclk), + "Could not get x11k parent clock\n"); /* Register mclk provider if requested */ if (of_find_property(np, "#clock-cells", NULL)) { @@ -1097,12 +1085,10 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev, /* Reset */ rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); - if (IS_ERR(rst)) { - if (PTR_ERR(rst) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Reset controller error %ld\n", - PTR_ERR(rst)); - return PTR_ERR(rst); - } + if (IS_ERR(rst)) + return dev_err_probe(&pdev->dev, PTR_ERR(rst), + "Reset controller error\n"); + reset_control_assert(rst); udelay(2); reset_control_deassert(rst); @@ -1145,21 +1131,15 @@ static int stm32_i2s_probe(struct platform_device *pdev) i2s->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "pclk", i2s->base, i2s->regmap_conf); - if (IS_ERR(i2s->regmap)) { - if (PTR_ERR(i2s->regmap) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Regmap init error %ld\n", - PTR_ERR(i2s->regmap)); - return PTR_ERR(i2s->regmap); - } + if (IS_ERR(i2s->regmap)) + return dev_err_probe(&pdev->dev, PTR_ERR(i2s->regmap), + "Regmap init error\n"); pm_runtime_enable(&pdev->dev); ret = snd_dmaengine_pcm_register(&pdev->dev, &stm32_i2s_pcm_config, 0); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "PCM DMA register error %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "PCM DMA register error\n"); ret = snd_soc_register_component(&pdev->dev, &stm32_i2s_component, i2s->dai_drv, 1); diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index 058757c721f0a..8e21e6f886fc1 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -173,29 +173,20 @@ static int stm32_sai_probe(struct platform_device *pdev) if (!STM_SAI_IS_F4(sai)) { sai->pclk = devm_clk_get(&pdev->dev, "pclk"); - if (IS_ERR(sai->pclk)) { - if (PTR_ERR(sai->pclk) != -EPROBE_DEFER) - dev_err(&pdev->dev, "missing bus clock pclk: %ld\n", - PTR_ERR(sai->pclk)); - return PTR_ERR(sai->pclk); - } + if (IS_ERR(sai->pclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(sai->pclk), + "missing bus clock pclk\n"); } sai->clk_x8k = devm_clk_get(&pdev->dev, "x8k"); - if (IS_ERR(sai->clk_x8k)) { - if (PTR_ERR(sai->clk_x8k) != -EPROBE_DEFER) - dev_err(&pdev->dev, "missing x8k parent clock: %ld\n", - PTR_ERR(sai->clk_x8k)); - return PTR_ERR(sai->clk_x8k); - } + if (IS_ERR(sai->clk_x8k)) + return dev_err_probe(&pdev->dev, PTR_ERR(sai->clk_x8k), + "missing x8k parent clock\n"); sai->clk_x11k = devm_clk_get(&pdev->dev, "x11k"); - if (IS_ERR(sai->clk_x11k)) { - if (PTR_ERR(sai->clk_x11k) != -EPROBE_DEFER) - dev_err(&pdev->dev, "missing x11k parent clock: %ld\n", - PTR_ERR(sai->clk_x11k)); - return PTR_ERR(sai->clk_x11k); - } + if (IS_ERR(sai->clk_x11k)) + return dev_err_probe(&pdev->dev, PTR_ERR(sai->clk_x11k), + "missing x11k parent clock\n"); /* init irqs */ sai->irq = platform_get_irq(pdev, 0); @@ -204,12 +195,10 @@ static int stm32_sai_probe(struct platform_device *pdev) /* reset */ rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); - if (IS_ERR(rst)) { - if (PTR_ERR(rst) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Reset controller error %ld\n", - PTR_ERR(rst)); - return PTR_ERR(rst); - } + if (IS_ERR(rst)) + return dev_err_probe(&pdev->dev, PTR_ERR(rst), + "Reset controller error\n"); + reset_control_assert(rst); udelay(2); reset_control_deassert(rst); diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 95cd38a502bb4..dd636af81c9bd 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -1379,12 +1379,9 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, */ sai->regmap = devm_regmap_init_mmio(&pdev->dev, base, sai->regmap_config); - if (IS_ERR(sai->regmap)) { - if (PTR_ERR(sai->regmap) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Regmap init error %ld\n", - PTR_ERR(sai->regmap)); - return PTR_ERR(sai->regmap); - } + if (IS_ERR(sai->regmap)) + return dev_err_probe(&pdev->dev, PTR_ERR(sai->regmap), + "Regmap init error\n"); /* Get direction property */ if (of_property_match_string(np, "dma-names", "tx") >= 0) { @@ -1472,12 +1469,9 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, of_node_put(args.np); sai->sai_ck = devm_clk_get(&pdev->dev, "sai_ck"); - if (IS_ERR(sai->sai_ck)) { - if (PTR_ERR(sai->sai_ck) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Missing kernel clock sai_ck: %ld\n", - PTR_ERR(sai->sai_ck)); - return PTR_ERR(sai->sai_ck); - } + if (IS_ERR(sai->sai_ck)) + return dev_err_probe(&pdev->dev, PTR_ERR(sai->sai_ck), + "Missing kernel clock sai_ck\n"); ret = clk_prepare(sai->pdata->pclk); if (ret < 0) @@ -1551,11 +1545,8 @@ static int stm32_sai_sub_probe(struct platform_device *pdev) conf = &stm32_sai_pcm_config_spdif; ret = snd_dmaengine_pcm_register(&pdev->dev, conf, 0); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "Could not register pcm dma\n"); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "Could not register pcm dma\n"); ret = snd_soc_register_component(&pdev->dev, &stm32_component, &sai->cpu_dai_drv, 1); diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c index a9ccdc2c58673..6f7882c4fe6ad 100644 --- a/sound/soc/stm/stm32_spdifrx.c +++ b/sound/soc/stm/stm32_spdifrx.c @@ -406,12 +406,9 @@ static int stm32_spdifrx_dma_ctrl_register(struct device *dev, int ret; spdifrx->ctrl_chan = dma_request_chan(dev, "rx-ctrl"); - if (IS_ERR(spdifrx->ctrl_chan)) { - if (PTR_ERR(spdifrx->ctrl_chan) != -EPROBE_DEFER) - dev_err(dev, "dma_request_slave_channel error %ld\n", - PTR_ERR(spdifrx->ctrl_chan)); - return PTR_ERR(spdifrx->ctrl_chan); - } + if (IS_ERR(spdifrx->ctrl_chan)) + return dev_err_probe(dev, PTR_ERR(spdifrx->ctrl_chan), + "dma_request_slave_channel error\n"); spdifrx->dmab = devm_kzalloc(dev, sizeof(struct snd_dma_buffer), GFP_KERNEL); @@ -930,12 +927,9 @@ static int stm32_spdifrx_parse_of(struct platform_device *pdev, spdifrx->phys_addr = res->start; spdifrx->kclk = devm_clk_get(&pdev->dev, "kclk"); - if (IS_ERR(spdifrx->kclk)) { - if (PTR_ERR(spdifrx->kclk) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Could not get kclk: %ld\n", - PTR_ERR(spdifrx->kclk)); - return PTR_ERR(spdifrx->kclk); - } + if (IS_ERR(spdifrx->kclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(spdifrx->kclk), + "Could not get kclk\n"); spdifrx->irq = platform_get_irq(pdev, 0); if (spdifrx->irq < 0) @@ -987,12 +981,9 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) spdifrx->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "kclk", spdifrx->base, spdifrx->regmap_conf); - if (IS_ERR(spdifrx->regmap)) { - if (PTR_ERR(spdifrx->regmap) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Regmap init error %ld\n", - PTR_ERR(spdifrx->regmap)); - return PTR_ERR(spdifrx->regmap); - } + if (IS_ERR(spdifrx->regmap)) + return dev_err_probe(&pdev->dev, PTR_ERR(spdifrx->regmap), + "Regmap init error\n"); ret = devm_request_irq(&pdev->dev, spdifrx->irq, stm32_spdifrx_isr, 0, dev_name(&pdev->dev), spdifrx); @@ -1002,12 +993,10 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) } rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); - if (IS_ERR(rst)) { - if (PTR_ERR(rst) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Reset controller error %ld\n", - PTR_ERR(rst)); - return PTR_ERR(rst); - } + if (IS_ERR(rst)) + return dev_err_probe(&pdev->dev, PTR_ERR(rst), + "Reset controller error\n"); + reset_control_assert(rst); udelay(2); reset_control_deassert(rst); @@ -1016,11 +1005,8 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) pcm_config = &stm32_spdifrx_pcm_config; ret = snd_dmaengine_pcm_register(&pdev->dev, pcm_config, 0); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "PCM DMA register error %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "PCM DMA register error\n"); ret = snd_soc_register_component(&pdev->dev, &stm32_spdifrx_component, From 11a95c583c1de215d2c338bf5cb9f929312616f8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 14 Dec 2021 11:08:43 +0900 Subject: [PATCH 254/327] ASoC: sunxi: Use dev_err_probe() helper Use the dev_err_probe() helper, instead of open-coding the same operation. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/20211214020843.2225831-23-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index da597e456beb2..60712f24ade59 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -1752,8 +1752,7 @@ static int sun4i_codec_probe(struct platform_device *pdev) GPIOD_OUT_LOW); if (IS_ERR(scodec->gpio_pa)) { ret = PTR_ERR(scodec->gpio_pa); - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "Failed to get pa gpio: %d\n", ret); + dev_err_probe(&pdev->dev, ret, "Failed to get pa gpio\n"); return ret; } From e047d0372689f5d4231eefb731b60ac64720bbf0 Mon Sep 17 00:00:00 2001 From: Ricard Wanderlof Date: Wed, 15 Dec 2021 18:01:24 +0100 Subject: [PATCH 255/327] ASoC: tlv320adc3xxx: New codec bindings DT bindings for Texas Instruments TLV320ADC3001 and TLV320ADC3101 audio ADCs. Signed-off-by: Ricard Wanderlof Link: https://lore.kernel.org/r/alpine.DEB.2.21.2112151759170.27889@lap5cg0092dnk.se.axis.com Signed-off-by: Mark Brown --- .../bindings/sound/ti,tlv320adc3xxx.yaml | 137 ++++++++++++++++++ include/dt-bindings/sound/tlv320adc3xxx.h | 28 ++++ 2 files changed, 165 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/ti,tlv320adc3xxx.yaml create mode 100644 include/dt-bindings/sound/tlv320adc3xxx.h diff --git a/Documentation/devicetree/bindings/sound/ti,tlv320adc3xxx.yaml b/Documentation/devicetree/bindings/sound/ti,tlv320adc3xxx.yaml new file mode 100644 index 0000000000000..83936f594d1ad --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ti,tlv320adc3xxx.yaml @@ -0,0 +1,137 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/ti,tlv320adc3xxx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments TLV320ADC3001/TLV320ADC3101 Stereo ADC + +maintainers: + - Ricard Wanderlof + +description: | + Texas Instruments TLV320ADC3001 and TLV320ADC3101 Stereo ADC + https://www.ti.com/product/TLV320ADC3001 + https://www.ti.com/product/TLV320ADC3101 + +properties: + compatible: + enum: + - ti,tlv320adc3001 + - ti,tlv320adc3101 + + reg: + maxItems: 1 + description: I2C address + + '#sound-dai-cells': + const: 0 + + '#gpio-cells': + const: 2 + + gpio-controller: true + + reset-gpios: + maxItems: 1 + description: GPIO pin used for codec reset (RESET pin) + + clocks: + maxItems: 1 + description: Master clock (MCLK) + + ti,dmdin-gpio1: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # ADC3XXX_GPIO_DISABLED - I/O buffers powered down and not used + - 1 # ADC3XXX_GPIO_INPUT - Various non-GPIO input functions + - 2 # ADC3XXX_GPIO_GPI - General purpose input + - 3 # ADC3XXX_GPIO_GPO - General purpose output + - 4 # ADC3XXX_GPIO_CLKOUT - Clock source set in CLKOUT_MUX reg + - 5 # ADC3XXX_GPIO_INT1 - INT1 output + - 6 # ADC3XXX_GPIO_SECONDARY_BCLK - Codec interface secondary BCLK + - 7 # ADC3XXX_GPIO_SECONDARY_WCLK - Codec interface secondary WCLK + default: 0 + description: | + Configuration for DMDIN/GPIO1 pin. + + When ADC3XXX_GPIO_GPO is configured, this causes corresponding the + ALSA control "GPIOx Output" to appear, as a switch control. + + ti,dmclk-gpio2: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # ADC3XXX_GPIO_DISABLED - I/O buffers powered down and not used + - 1 # ADC3XXX_GPIO_INPUT - Various non-GPIO input functions + - 2 # ADC3XXX_GPIO_GPI - General purpose input + - 3 # ADC3XXX_GPIO_GPO - General purpose output + - 4 # ADC3XXX_GPIO_CLKOUT - Clock source set in CLKOUT_MUX reg + - 5 # ADC3XXX_GPIO_INT1 - INT1 output + - 6 # ADC3XXX_GPIO_SECONDARY_BCLK - Codec interface secondary BCLK + - 7 # ADC3XXX_GPIO_SECONDARY_WCLK - Codec interface secondary WCLK + default: 0 + description: | + Configuration for DMCLK/GPIO2 pin. + + When ADC3XXX_GPIO_GPO is configured, this causes corresponding the + ALSA control "GPIOx Output" to appear, as a switch control. + + Note that there is currently no support for reading the GPIO pins as + inputs. + + ti,micbias1-vg: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # ADC3XXX_MICBIAS_OFF - Mic bias is powered down + - 1 # ADC3XXX_MICBIAS_2_0V - Mic bias is set to 2.0V + - 2 # ADC3XXX_MICBIAS_2_5V - Mic bias is set to 2.5V + - 3 # ADC3XXX_MICBIAS_AVDD - Mic bias is same as AVDD supply + default: 0 + description: | + Mic bias voltage output on MICBIAS1 pin + + ti,micbias2-vg: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # ADC3XXX_MICBIAS_OFF - Mic bias is powered down + - 1 # ADC3XXX_MICBIAS_2_0V - Mic bias is set to 2.0V + - 2 # ADC3XXX_MICBIAS_2_5V - Mic bias is set to 2.5V + - 3 # ADC3XXX_MICBIAS_AVDD - Mic bias is same as AVDD supply + default: 0 + description: | + Mic bias voltage output on MICBIAS2 pin + +required: + - compatible + - reg + - clocks + +additionalProperties: false + +examples: + - | + + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + tlv320adc3101: audio-codec@18 { + compatible = "ti,tlv320adc3101"; + reg = <0x18>; + reset-gpios = <&gpio_pc 3 GPIO_ACTIVE_LOW>; + clocks = <&audio_mclk>; + gpio-controller; + #gpio-cells = <2>; + ti,dmdin-gpio1 = ; + ti,micbias1-vg = ; + }; + }; + + audio_mclk: clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24576000>; + }; +... diff --git a/include/dt-bindings/sound/tlv320adc3xxx.h b/include/dt-bindings/sound/tlv320adc3xxx.h new file mode 100644 index 0000000000000..ec988439da205 --- /dev/null +++ b/include/dt-bindings/sound/tlv320adc3xxx.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Devicetree bindings definitions for tlv320adc3xxx driver. + * + * Copyright (C) 2021 Axis Communications AB + */ +#ifndef __DT_TLV320ADC3XXX_H +#define __DT_TLV320ADC3XXX_H + +#define ADC3XXX_GPIO_DISABLED 0 /* I/O buffers powered down */ +#define ADC3XXX_GPIO_INPUT 1 /* Various non-GPIO inputs */ +#define ADC3XXX_GPIO_GPI 2 /* General purpose input */ +#define ADC3XXX_GPIO_GPO 3 /* General purpose output */ +#define ADC3XXX_GPIO_CLKOUT 4 /* Source set in reg. CLKOUT_MUX */ +#define ADC3XXX_GPIO_INT1 5 /* INT1 output */ +#define ADC3XXX_GPIO_INT2 6 /* INT2 output */ +/* value 7 is reserved */ +#define ADC3XXX_GPIO_SECONDARY_BCLK 8 /* Codec interface secondary BCLK */ +#define ADC3XXX_GPIO_SECONDARY_WCLK 9 /* Codec interface secondary WCLK */ +#define ADC3XXX_GPIO_ADC_MOD_CLK 10 /* Clock output for digital mics */ +/* values 11-15 reserved */ + +#define ADC3XXX_MICBIAS_OFF 0 /* Micbias pin powered off */ +#define ADC3XXX_MICBIAS_2_0V 1 /* Micbias pin set to 2.0V */ +#define ADC3XXX_MICBIAS_2_5V 2 /* Micbias pin set to 2.5V */ +#define ADC3XXX_MICBIAS_AVDD 3 /* Use AVDD voltage for micbias pin */ + +#endif /* __DT_TLV320ADC3XXX_H */ From e9a3b57efd28fe889a98171bdc1e9e0dd7eb9a50 Mon Sep 17 00:00:00 2001 From: Ricard Wanderlof Date: Wed, 15 Dec 2021 18:04:23 +0100 Subject: [PATCH 256/327] ASoC: codec: tlv320adc3xxx: New codec driver New codec driver for Texas Instruments TLV320ADC3001 and TLV320ADC3101 audio ADCs. Signed-off-by: Ricard Wanderlof Link: https://lore.kernel.org/r/alpine.DEB.2.21.2112151801370.27889@lap5cg0092dnk.se.axis.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 8 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tlv320adc3xxx.c | 1311 ++++++++++++++++++++++++++++++ 3 files changed, 1321 insertions(+) create mode 100644 sound/soc/codecs/tlv320adc3xxx.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c033ee7d82e46..22836ca9b4789 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -220,6 +220,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_TDA7419 imply SND_SOC_TFA9879 imply SND_SOC_TFA989X + imply SND_SOC_TLV320ADC3XXX imply SND_SOC_TLV320ADCX140 imply SND_SOC_TLV320AIC23_I2C imply SND_SOC_TLV320AIC23_SPI @@ -1496,6 +1497,13 @@ config SND_SOC_TFA989X Note that the driver currently bypasses the built-in "CoolFlux DSP" and does not support (hardware) volume control. +config SND_SOC_TLV320ADC3XXX + tristate "Texas Instruments TLV320ADC3001/3101 audio ADC" + depends on I2C + help + Enable support for Texas Instruments TLV320ADC3001 and TLV320ADC3101 + ADCs. + config SND_SOC_TLV320AIC23 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 485eee75502b0..24bc6b34ba2f4 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -239,6 +239,7 @@ snd-soc-tda7419-objs := tda7419.o snd-soc-tas2770-objs := tas2770.o snd-soc-tfa9879-objs := tfa9879.o snd-soc-tfa989x-objs := tfa989x.o +snd-soc-tlv320adc3xxx-objs := tlv320adc3xxx.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o @@ -574,6 +575,7 @@ obj-$(CONFIG_SND_SOC_TDA7419) += snd-soc-tda7419.o obj-$(CONFIG_SND_SOC_TAS2770) += snd-soc-tas2770.o obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o obj-$(CONFIG_SND_SOC_TFA989X) += snd-soc-tfa989x.o +obj-$(CONFIG_SND_SOC_TLV320ADC3XXX) += snd-soc-tlv320adc3xxx.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o diff --git a/sound/soc/codecs/tlv320adc3xxx.c b/sound/soc/codecs/tlv320adc3xxx.c new file mode 100644 index 0000000000000..a683bda7eb36e --- /dev/null +++ b/sound/soc/codecs/tlv320adc3xxx.c @@ -0,0 +1,1311 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Based on sound/soc/codecs/tlv320aic3x.c by Vladimir Barinov +// +// Copyright (C) 2010 Mistral Solutions Pvt Ltd. +// Author: Shahina Shaik +// +// Copyright (C) 2014-2018, Ambarella, Inc. +// Author: Dongge wu +// +// Copyright (C) 2021 Axis Communications AB +// Author: Ricard Wanderlof +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * General definitions defining exported functionality. + */ + +#define ADC3XXX_MICBIAS_PINS 2 + +/* Number of GPIO pins exposed via the gpiolib interface */ +#define ADC3XXX_GPIOS_MAX 2 + +#define ADC3XXX_RATES SNDRV_PCM_RATE_8000_96000 +#define ADC3XXX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_3LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +/* + * PLL modes, to be used for clk_id for set_sysclk callback. + * + * The default behavior (AUTO) is to take the first matching entry in the clock + * table, which is intended to be the PLL based one if there is more than one. + * + * Setting the clock source using simple-card (clocks or + * system-clock-frequency property) sets clk_id = 0 = ADC3XXX_PLL_AUTO. + */ +#define ADC3XXX_PLL_AUTO 0 /* Use first available mode */ +#define ADC3XXX_PLL_ENABLE 1 /* Use PLL for clock generation */ +#define ADC3XXX_PLL_BYPASS 2 /* Don't use PLL for clock generation */ + +/* Register definitions. */ + +#define ADC3XXX_PAGE_SIZE 128 +#define ADC3XXX_REG(page, reg) ((page * ADC3XXX_PAGE_SIZE) + reg) + +/* + * Page 0 registers. + */ + +#define ADC3XXX_PAGE_SELECT ADC3XXX_REG(0, 0) +#define ADC3XXX_RESET ADC3XXX_REG(0, 1) + +/* 2-3 Reserved */ + +#define ADC3XXX_CLKGEN_MUX ADC3XXX_REG(0, 4) +#define ADC3XXX_PLL_PROG_PR ADC3XXX_REG(0, 5) +#define ADC3XXX_PLL_PROG_J ADC3XXX_REG(0, 6) +#define ADC3XXX_PLL_PROG_D_MSB ADC3XXX_REG(0, 7) +#define ADC3XXX_PLL_PROG_D_LSB ADC3XXX_REG(0, 8) + +/* 9-17 Reserved */ + +#define ADC3XXX_ADC_NADC ADC3XXX_REG(0, 18) +#define ADC3XXX_ADC_MADC ADC3XXX_REG(0, 19) +#define ADC3XXX_ADC_AOSR ADC3XXX_REG(0, 20) +#define ADC3XXX_ADC_IADC ADC3XXX_REG(0, 21) + +/* 23-24 Reserved */ + +#define ADC3XXX_CLKOUT_MUX ADC3XXX_REG(0, 25) +#define ADC3XXX_CLKOUT_M_DIV ADC3XXX_REG(0, 26) +#define ADC3XXX_INTERFACE_CTRL_1 ADC3XXX_REG(0, 27) +#define ADC3XXX_CH_OFFSET_1 ADC3XXX_REG(0, 28) +#define ADC3XXX_INTERFACE_CTRL_2 ADC3XXX_REG(0, 29) +#define ADC3XXX_BCLK_N_DIV ADC3XXX_REG(0, 30) +#define ADC3XXX_INTERFACE_CTRL_3 ADC3XXX_REG(0, 31) +#define ADC3XXX_INTERFACE_CTRL_4 ADC3XXX_REG(0, 32) +#define ADC3XXX_INTERFACE_CTRL_5 ADC3XXX_REG(0, 33) +#define ADC3XXX_I2S_SYNC ADC3XXX_REG(0, 34) +/* 35 Reserved */ +#define ADC3XXX_ADC_FLAG ADC3XXX_REG(0, 36) +#define ADC3XXX_CH_OFFSET_2 ADC3XXX_REG(0, 37) +#define ADC3XXX_I2S_TDM_CTRL ADC3XXX_REG(0, 38) +/* 39-41 Reserved */ +#define ADC3XXX_INTR_FLAG_1 ADC3XXX_REG(0, 42) +#define ADC3XXX_INTR_FLAG_2 ADC3XXX_REG(0, 43) +/* 44 Reserved */ +#define ADC3XXX_INTR_FLAG_ADC1 ADC3XXX_REG(0, 45) +/* 46 Reserved */ +#define ADC3XXX_INTR_FLAG_ADC2 ADC3XXX_REG(0, 47) +#define ADC3XXX_INT1_CTRL ADC3XXX_REG(0, 48) +#define ADC3XXX_INT2_CTRL ADC3XXX_REG(0, 49) +/* 50 Reserved */ +#define ADC3XXX_GPIO2_CTRL ADC3XXX_REG(0, 51) +#define ADC3XXX_GPIO1_CTRL ADC3XXX_REG(0, 52) +#define ADC3XXX_DOUT_CTRL ADC3XXX_REG(0, 53) +/* 54-56 Reserved */ +#define ADC3XXX_SYNC_CTRL_1 ADC3XXX_REG(0, 57) +#define ADC3XXX_SYNC_CTRL_2 ADC3XXX_REG(0, 58) +#define ADC3XXX_CIC_GAIN_CTRL ADC3XXX_REG(0, 59) +/* 60 Reserved */ +#define ADC3XXX_PRB_SELECT ADC3XXX_REG(0, 61) +#define ADC3XXX_INST_MODE_CTRL ADC3XXX_REG(0, 62) +/* 63-79 Reserved */ +#define ADC3XXX_MIC_POLARITY_CTRL ADC3XXX_REG(0, 80) +#define ADC3XXX_ADC_DIGITAL ADC3XXX_REG(0, 81) +#define ADC3XXX_ADC_FGA ADC3XXX_REG(0, 82) +#define ADC3XXX_LADC_VOL ADC3XXX_REG(0, 83) +#define ADC3XXX_RADC_VOL ADC3XXX_REG(0, 84) +#define ADC3XXX_ADC_PHASE_COMP ADC3XXX_REG(0, 85) +#define ADC3XXX_LEFT_CHN_AGC_1 ADC3XXX_REG(0, 86) +#define ADC3XXX_LEFT_CHN_AGC_2 ADC3XXX_REG(0, 87) +#define ADC3XXX_LEFT_CHN_AGC_3 ADC3XXX_REG(0, 88) +#define ADC3XXX_LEFT_CHN_AGC_4 ADC3XXX_REG(0, 89) +#define ADC3XXX_LEFT_CHN_AGC_5 ADC3XXX_REG(0, 90) +#define ADC3XXX_LEFT_CHN_AGC_6 ADC3XXX_REG(0, 91) +#define ADC3XXX_LEFT_CHN_AGC_7 ADC3XXX_REG(0, 92) +#define ADC3XXX_LEFT_AGC_GAIN ADC3XXX_REG(0, 93) +#define ADC3XXX_RIGHT_CHN_AGC_1 ADC3XXX_REG(0, 94) +#define ADC3XXX_RIGHT_CHN_AGC_2 ADC3XXX_REG(0, 95) +#define ADC3XXX_RIGHT_CHN_AGC_3 ADC3XXX_REG(0, 96) +#define ADC3XXX_RIGHT_CHN_AGC_4 ADC3XXX_REG(0, 97) +#define ADC3XXX_RIGHT_CHN_AGC_5 ADC3XXX_REG(0, 98) +#define ADC3XXX_RIGHT_CHN_AGC_6 ADC3XXX_REG(0, 99) +#define ADC3XXX_RIGHT_CHN_AGC_7 ADC3XXX_REG(0, 100) +#define ADC3XXX_RIGHT_AGC_GAIN ADC3XXX_REG(0, 101) +/* 102-127 Reserved */ + +/* + * Page 1 registers. + */ + +/* 1-25 Reserved */ +#define ADC3XXX_DITHER_CTRL ADC3XXX_REG(1, 26) +/* 27-50 Reserved */ +#define ADC3XXX_MICBIAS_CTRL ADC3XXX_REG(1, 51) +#define ADC3XXX_LEFT_PGA_SEL_1 ADC3XXX_REG(1, 52) +/* 53 Reserved */ +#define ADC3XXX_LEFT_PGA_SEL_2 ADC3XXX_REG(1, 54) +#define ADC3XXX_RIGHT_PGA_SEL_1 ADC3XXX_REG(1, 55) +#define ADC3XXX_RIGHT_PGA_SEL_2 ADC3XXX_REG(1, 57) +#define ADC3XXX_LEFT_APGA_CTRL ADC3XXX_REG(1, 59) +#define ADC3XXX_RIGHT_APGA_CTRL ADC3XXX_REG(1, 60) +#define ADC3XXX_LOW_CURRENT_MODES ADC3XXX_REG(1, 61) +#define ADC3XXX_ANALOG_PGA_FLAGS ADC3XXX_REG(1, 62) +/* 63-127 Reserved */ + +/* + * Register bits. + */ + +/* PLL Enable bits */ +#define ADC3XXX_ENABLE_PLL_SHIFT 7 +#define ADC3XXX_ENABLE_PLL (1 << ADC3XXX_ENABLE_PLL_SHIFT) +#define ADC3XXX_ENABLE_NADC_SHIFT 7 +#define ADC3XXX_ENABLE_NADC (1 << ADC3XXX_ENABLE_NADC_SHIFT) +#define ADC3XXX_ENABLE_MADC_SHIFT 7 +#define ADC3XXX_ENABLE_MADC (1 << ADC3XXX_ENABLE_MADC_SHIFT) +#define ADC3XXX_ENABLE_BCLK_SHIFT 7 +#define ADC3XXX_ENABLE_BCLK (1 << ADC3XXX_ENABLE_BCLK_SHIFT) + +/* Power bits */ +#define ADC3XXX_LADC_PWR_ON 0x80 +#define ADC3XXX_RADC_PWR_ON 0x40 + +#define ADC3XXX_SOFT_RESET 0x01 +#define ADC3XXX_BCLK_MASTER 0x08 +#define ADC3XXX_WCLK_MASTER 0x04 + +/* Interface register masks */ +#define ADC3XXX_FORMAT_MASK 0xc0 +#define ADC3XXX_FORMAT_SHIFT 6 +#define ADC3XXX_WLENGTH_MASK 0x30 +#define ADC3XXX_WLENGTH_SHIFT 4 +#define ADC3XXX_CLKDIR_MASK 0x0c +#define ADC3XXX_CLKDIR_SHIFT 2 + +/* Interface register bit patterns */ +#define ADC3XXX_FORMAT_I2S (0 << ADC3XXX_FORMAT_SHIFT) +#define ADC3XXX_FORMAT_DSP (1 << ADC3XXX_FORMAT_SHIFT) +#define ADC3XXX_FORMAT_RJF (2 << ADC3XXX_FORMAT_SHIFT) +#define ADC3XXX_FORMAT_LJF (3 << ADC3XXX_FORMAT_SHIFT) + +#define ADC3XXX_IFACE_16BITS (0 << ADC3XXX_WLENGTH_SHIFT) +#define ADC3XXX_IFACE_20BITS (1 << ADC3XXX_WLENGTH_SHIFT) +#define ADC3XXX_IFACE_24BITS (2 << ADC3XXX_WLENGTH_SHIFT) +#define ADC3XXX_IFACE_32BITS (3 << ADC3XXX_WLENGTH_SHIFT) + +/* PLL P/R bit offsets */ +#define ADC3XXX_PLLP_SHIFT 4 +#define ADC3XXX_PLLR_SHIFT 0 +#define ADC3XXX_PLL_PR_MASK 0x7f +#define ADC3XXX_PLLJ_MASK 0x3f +#define ADC3XXX_PLLD_MSB_MASK 0x3f +#define ADC3XXX_PLLD_LSB_MASK 0xff +#define ADC3XXX_NADC_MASK 0x7f +#define ADC3XXX_MADC_MASK 0x7f +#define ADC3XXX_AOSR_MASK 0xff +#define ADC3XXX_IADC_MASK 0xff +#define ADC3XXX_BDIV_MASK 0x7f + +/* PLL_CLKIN bits */ +#define ADC3XXX_PLL_CLKIN_SHIFT 2 +#define ADC3XXX_PLL_CLKIN_MCLK 0x0 +#define ADC3XXX_PLL_CLKIN_BCLK 0x1 +#define ADC3XXX_PLL_CLKIN_ZERO 0x3 + +/* CODEC_CLKIN bits */ +#define ADC3XXX_CODEC_CLKIN_SHIFT 0 +#define ADC3XXX_CODEC_CLKIN_MCLK 0x0 +#define ADC3XXX_CODEC_CLKIN_BCLK 0x1 +#define ADC3XXX_CODEC_CLKIN_PLL_CLK 0x3 + +#define ADC3XXX_USE_PLL ((ADC3XXX_PLL_CLKIN_MCLK << ADC3XXX_PLL_CLKIN_SHIFT) | \ + (ADC3XXX_CODEC_CLKIN_PLL_CLK << ADC3XXX_CODEC_CLKIN_SHIFT)) +#define ADC3XXX_NO_PLL ((ADC3XXX_PLL_CLKIN_ZERO << ADC3XXX_PLL_CLKIN_SHIFT) | \ + (ADC3XXX_CODEC_CLKIN_MCLK << ADC3XXX_CODEC_CLKIN_SHIFT)) + +/* Analog PGA control bits */ +#define ADC3XXX_LPGA_MUTE 0x80 +#define ADC3XXX_RPGA_MUTE 0x80 + +#define ADC3XXX_LPGA_GAIN_MASK 0x7f +#define ADC3XXX_RPGA_GAIN_MASK 0x7f + +/* ADC current modes */ +#define ADC3XXX_ADC_LOW_CURR_MODE 0x01 + +/* Left ADC Input selection bits */ +#define ADC3XXX_LCH_SEL1_SHIFT 0 +#define ADC3XXX_LCH_SEL2_SHIFT 2 +#define ADC3XXX_LCH_SEL3_SHIFT 4 +#define ADC3XXX_LCH_SEL4_SHIFT 6 + +#define ADC3XXX_LCH_SEL1X_SHIFT 0 +#define ADC3XXX_LCH_SEL2X_SHIFT 2 +#define ADC3XXX_LCH_SEL3X_SHIFT 4 +#define ADC3XXX_LCH_COMMON_MODE 0x40 +#define ADC3XXX_BYPASS_LPGA 0x80 + +/* Right ADC Input selection bits */ +#define ADC3XXX_RCH_SEL1_SHIFT 0 +#define ADC3XXX_RCH_SEL2_SHIFT 2 +#define ADC3XXX_RCH_SEL3_SHIFT 4 +#define ADC3XXX_RCH_SEL4_SHIFT 6 + +#define ADC3XXX_RCH_SEL1X_SHIFT 0 +#define ADC3XXX_RCH_SEL2X_SHIFT 2 +#define ADC3XXX_RCH_SEL3X_SHIFT 4 +#define ADC3XXX_RCH_COMMON_MODE 0x40 +#define ADC3XXX_BYPASS_RPGA 0x80 + +/* MICBIAS control bits */ +#define ADC3XXX_MICBIAS_MASK 0x2 +#define ADC3XXX_MICBIAS1_SHIFT 5 +#define ADC3XXX_MICBIAS2_SHIFT 3 + +#define ADC3XXX_ADC_MAX_VOLUME 64 +#define ADC3XXX_ADC_POS_VOL 24 + +/* GPIO control bits (GPIO1_CTRL and GPIO2_CTRL) */ +#define ADC3XXX_GPIO_CTRL_CFG_MASK 0x3c +#define ADC3XXX_GPIO_CTRL_CFG_SHIFT 2 +#define ADC3XXX_GPIO_CTRL_OUTPUT_CTRL_MASK 0x01 +#define ADC3XXX_GPIO_CTRL_OUTPUT_CTRL_SHIFT 0 +#define ADC3XXX_GPIO_CTRL_INPUT_VALUE_MASK 0x02 +#define ADC3XXX_GPIO_CTRL_INPUT_VALUE_SHIFT 1 + +enum adc3xxx_type { + ADC3001 = 0, + ADC3101 +}; + +struct adc3xxx { + struct device *dev; + enum adc3xxx_type type; + struct clk *mclk; + struct regmap *regmap; + struct gpio_desc *rst_pin; + unsigned int pll_mode; + unsigned int sysclk; + unsigned int gpio_cfg[ADC3XXX_GPIOS_MAX]; /* value+1 (0 => not set) */ + unsigned int micbias_vg[ADC3XXX_MICBIAS_PINS]; + int master; + u8 page_no; + int use_pll; + struct gpio_chip gpio_chip; +}; + +static const unsigned int adc3xxx_gpio_ctrl_reg[ADC3XXX_GPIOS_MAX] = { + ADC3XXX_GPIO1_CTRL, + ADC3XXX_GPIO2_CTRL +}; + +static const unsigned int adc3xxx_micbias_shift[ADC3XXX_MICBIAS_PINS] = { + ADC3XXX_MICBIAS1_SHIFT, + ADC3XXX_MICBIAS2_SHIFT +}; + +static const struct reg_default adc3xxx_defaults[] = { + /* Page 0 */ + { 0, 0x00 }, { 1, 0x00 }, { 2, 0x00 }, { 3, 0x00 }, + { 4, 0x00 }, { 5, 0x11 }, { 6, 0x04 }, { 7, 0x00 }, + { 8, 0x00 }, { 9, 0x00 }, { 10, 0x00 }, { 11, 0x00 }, + { 12, 0x00 }, { 13, 0x00 }, { 14, 0x00 }, { 15, 0x00 }, + { 16, 0x00 }, { 17, 0x00 }, { 18, 0x01 }, { 19, 0x01 }, + { 20, 0x80 }, { 21, 0x80 }, { 22, 0x04 }, { 23, 0x00 }, + { 24, 0x00 }, { 25, 0x00 }, { 26, 0x01 }, { 27, 0x00 }, + { 28, 0x00 }, { 29, 0x02 }, { 30, 0x01 }, { 31, 0x00 }, + { 32, 0x00 }, { 33, 0x10 }, { 34, 0x00 }, { 35, 0x00 }, + { 36, 0x00 }, { 37, 0x00 }, { 38, 0x02 }, { 39, 0x00 }, + { 40, 0x00 }, { 41, 0x00 }, { 42, 0x00 }, { 43, 0x00 }, + { 44, 0x00 }, { 45, 0x00 }, { 46, 0x00 }, { 47, 0x00 }, + { 48, 0x00 }, { 49, 0x00 }, { 50, 0x00 }, { 51, 0x00 }, + { 52, 0x00 }, { 53, 0x12 }, { 54, 0x00 }, { 55, 0x00 }, + { 56, 0x00 }, { 57, 0x00 }, { 58, 0x00 }, { 59, 0x44 }, + { 60, 0x00 }, { 61, 0x01 }, { 62, 0x00 }, { 63, 0x00 }, + { 64, 0x00 }, { 65, 0x00 }, { 66, 0x00 }, { 67, 0x00 }, + { 68, 0x00 }, { 69, 0x00 }, { 70, 0x00 }, { 71, 0x00 }, + { 72, 0x00 }, { 73, 0x00 }, { 74, 0x00 }, { 75, 0x00 }, + { 76, 0x00 }, { 77, 0x00 }, { 78, 0x00 }, { 79, 0x00 }, + { 80, 0x00 }, { 81, 0x00 }, { 82, 0x88 }, { 83, 0x00 }, + { 84, 0x00 }, { 85, 0x00 }, { 86, 0x00 }, { 87, 0x00 }, + { 88, 0x7f }, { 89, 0x00 }, { 90, 0x00 }, { 91, 0x00 }, + { 92, 0x00 }, { 93, 0x00 }, { 94, 0x00 }, { 95, 0x00 }, + { 96, 0x7f }, { 97, 0x00 }, { 98, 0x00 }, { 99, 0x00 }, + { 100, 0x00 }, { 101, 0x00 }, { 102, 0x00 }, { 103, 0x00 }, + { 104, 0x00 }, { 105, 0x00 }, { 106, 0x00 }, { 107, 0x00 }, + { 108, 0x00 }, { 109, 0x00 }, { 110, 0x00 }, { 111, 0x00 }, + { 112, 0x00 }, { 113, 0x00 }, { 114, 0x00 }, { 115, 0x00 }, + { 116, 0x00 }, { 117, 0x00 }, { 118, 0x00 }, { 119, 0x00 }, + { 120, 0x00 }, { 121, 0x00 }, { 122, 0x00 }, { 123, 0x00 }, + { 124, 0x00 }, { 125, 0x00 }, { 126, 0x00 }, { 127, 0x00 }, + + /* Page 1 */ + { 128, 0x00 }, { 129, 0x00 }, { 130, 0x00 }, { 131, 0x00 }, + { 132, 0x00 }, { 133, 0x00 }, { 134, 0x00 }, { 135, 0x00 }, + { 136, 0x00 }, { 137, 0x00 }, { 138, 0x00 }, { 139, 0x00 }, + { 140, 0x00 }, { 141, 0x00 }, { 142, 0x00 }, { 143, 0x00 }, + { 144, 0x00 }, { 145, 0x00 }, { 146, 0x00 }, { 147, 0x00 }, + { 148, 0x00 }, { 149, 0x00 }, { 150, 0x00 }, { 151, 0x00 }, + { 152, 0x00 }, { 153, 0x00 }, { 154, 0x00 }, { 155, 0x00 }, + { 156, 0x00 }, { 157, 0x00 }, { 158, 0x00 }, { 159, 0x00 }, + { 160, 0x00 }, { 161, 0x00 }, { 162, 0x00 }, { 163, 0x00 }, + { 164, 0x00 }, { 165, 0x00 }, { 166, 0x00 }, { 167, 0x00 }, + { 168, 0x00 }, { 169, 0x00 }, { 170, 0x00 }, { 171, 0x00 }, + { 172, 0x00 }, { 173, 0x00 }, { 174, 0x00 }, { 175, 0x00 }, + { 176, 0x00 }, { 177, 0x00 }, { 178, 0x00 }, { 179, 0x00 }, + { 180, 0xff }, { 181, 0x00 }, { 182, 0x3f }, { 183, 0xff }, + { 184, 0x00 }, { 185, 0x3f }, { 186, 0x00 }, { 187, 0x80 }, + { 188, 0x80 }, { 189, 0x00 }, { 190, 0x00 }, { 191, 0x00 }, +}; + +static bool adc3xxx_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ADC3XXX_RESET: + return true; + default: + return false; + } +} + +static const struct regmap_range_cfg adc3xxx_ranges[] = { + { + .range_min = 0, + .range_max = 2 * ADC3XXX_PAGE_SIZE, + .selector_reg = ADC3XXX_PAGE_SELECT, + .selector_mask = 0xff, + .selector_shift = 0, + .window_start = 0, + .window_len = ADC3XXX_PAGE_SIZE, + } +}; + +static const struct regmap_config adc3xxx_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .reg_defaults = adc3xxx_defaults, + .num_reg_defaults = ARRAY_SIZE(adc3xxx_defaults), + + .volatile_reg = adc3xxx_volatile_reg, + + .cache_type = REGCACHE_RBTREE, + + .ranges = adc3xxx_ranges, + .num_ranges = ARRAY_SIZE(adc3xxx_ranges), + .max_register = 2 * ADC3XXX_PAGE_SIZE, +}; + +struct adc3xxx_rate_divs { + u32 mclk; + u32 rate; + u8 pll_p; + u8 pll_r; + u8 pll_j; + u16 pll_d; + u8 nadc; + u8 madc; + u8 aosr; +}; + +/* + * PLL and Clock settings. + * If p member is 0, PLL is not used. + * The order of the entries in this table have the PLL entries before + * the non-PLL entries, so that the PLL modes are preferred unless + * the PLL mode setting says otherwise. + */ +static const struct adc3xxx_rate_divs adc3xxx_divs[] = { + /* mclk, rate, p, r, j, d, nadc, madc, aosr */ + /* 8k rate */ + { 12000000, 8000, 1, 1, 7, 1680, 42, 2, 128 }, + { 12288000, 8000, 1, 1, 7, 0000, 42, 2, 128 }, + /* 11.025k rate */ + { 12000000, 11025, 1, 1, 6, 8208, 29, 2, 128 }, + /* 16k rate */ + { 12000000, 16000, 1, 1, 7, 1680, 21, 2, 128 }, + { 12288000, 16000, 1, 1, 7, 0000, 21, 2, 128 }, + /* 22.05k rate */ + { 12000000, 22050, 1, 1, 7, 560, 15, 2, 128 }, + /* 32k rate */ + { 12000000, 32000, 1, 1, 8, 1920, 12, 2, 128 }, + { 12288000, 32000, 1, 1, 8, 0000, 12, 2, 128 }, + /* 44.1k rate */ + { 12000000, 44100, 1, 1, 7, 5264, 8, 2, 128 }, + /* 48k rate */ + { 12000000, 48000, 1, 1, 7, 1680, 7, 2, 128 }, + { 12288000, 48000, 1, 1, 7, 0000, 7, 2, 128 }, + { 24576000, 48000, 1, 1, 3, 5000, 7, 2, 128 }, /* With PLL */ + { 24576000, 48000, 0, 0, 0, 0000, 2, 2, 128 }, /* Without PLL */ + /* 88.2k rate */ + { 12000000, 88200, 1, 1, 7, 5264, 4, 4, 64 }, + /* 96k rate */ + { 12000000, 96000, 1, 1, 8, 1920, 4, 4, 64 }, +}; + +static int adc3xxx_get_divs(struct device *dev, int mclk, int rate, int pll_mode) +{ + int i; + + dev_dbg(dev, "mclk = %d, rate = %d, clock mode %u\n", + mclk, rate, pll_mode); + for (i = 0; i < ARRAY_SIZE(adc3xxx_divs); i++) { + const struct adc3xxx_rate_divs *mode = &adc3xxx_divs[i]; + + /* Skip this entry if it doesn't fulfill the intended clock + * mode requirement. We consider anything besides the two + * modes below to be the same as ADC3XXX_PLL_AUTO. + */ + if ((pll_mode == ADC3XXX_PLL_BYPASS && mode->pll_p) || + (pll_mode == ADC3XXX_PLL_ENABLE && !mode->pll_p)) + continue; + + if (mode->rate == rate && mode->mclk == mclk) + return i; + } + + dev_info(dev, "Master clock rate %d and sample rate %d is not supported\n", + mclk, rate); + return -EINVAL; +} + +static int adc3xxx_pll_delay(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + /* 10msec delay needed after PLL power-up to allow + * PLL and dividers to stabilize (datasheet p13). + */ + usleep_range(10000, 20000); + + return 0; +} + +static const char * const adc_softstepping_text[] = { "1 step", "2 step", "off" }; +static SOC_ENUM_SINGLE_DECL(adc_softstepping_enum, ADC3XXX_ADC_DIGITAL, 0, + adc_softstepping_text); + +static const char * const multiplier_text[] = { "1", "2", "4", "8", "16", "32", "64", "128" }; +static SOC_ENUM_SINGLE_DECL(left_agc_attack_mult_enum, + ADC3XXX_LEFT_CHN_AGC_4, 0, multiplier_text); +static SOC_ENUM_SINGLE_DECL(right_agc_attack_mult_enum, + ADC3XXX_RIGHT_CHN_AGC_4, 0, multiplier_text); +static SOC_ENUM_SINGLE_DECL(left_agc_decay_mult_enum, + ADC3XXX_LEFT_CHN_AGC_5, 0, multiplier_text); +static SOC_ENUM_SINGLE_DECL(right_agc_decay_mult_enum, + ADC3XXX_RIGHT_CHN_AGC_5, 0, multiplier_text); + +static const char * const dither_dc_offset_text[] = { + "0mV", "15mV", "30mV", "45mV", "60mV", "75mV", "90mV", "105mV", + "-15mV", "-30mV", "-45mV", "-60mV", "-75mV", "-90mV", "-105mV" +}; +static const unsigned int dither_dc_offset_values[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15 +}; +static SOC_VALUE_ENUM_DOUBLE_DECL(dither_dc_offset_enum, + ADC3XXX_DITHER_CTRL, + 4, 0, 0xf, dither_dc_offset_text, + dither_dc_offset_values); + +static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 50, 0); +static const DECLARE_TLV_DB_SCALE(adc_tlv, -1200, 50, 0); +static const DECLARE_TLV_DB_SCALE(adc_fine_tlv, -40, 10, 0); +/* AGC target: 8 values: -5.5, -8, -10, -12, -14, -17, -20, -24 dB */ +/* It would be nice to declare these in the order above, but empirically + * TLV_DB_SCALE_ITEM doesn't take lightly to the increment (second) parameter + * being negative, despite there being examples to the contrary in other + * drivers. So declare these in the order from lowest to highest, and + * set the invert flag in the SOC_DOUBLE_R_TLV declaration instead. + */ +static const DECLARE_TLV_DB_RANGE(agc_target_tlv, + 0, 0, TLV_DB_SCALE_ITEM(-2400, 0, 0), + 1, 3, TLV_DB_SCALE_ITEM(-2000, 300, 0), + 4, 6, TLV_DB_SCALE_ITEM(-1200, 200, 0), + 7, 7, TLV_DB_SCALE_ITEM(-550, 0, 0)); +/* Since the 'disabled' value (mute) is at the highest value in the dB + * range (i.e. just before -32 dB) rather than the lowest, we need to resort + * to using a TLV_DB_RANGE in order to get the mute value in the right place. + */ +static const DECLARE_TLV_DB_RANGE(agc_thresh_tlv, + 0, 30, TLV_DB_SCALE_ITEM(-9000, 200, 0), + 31, 31, TLV_DB_SCALE_ITEM(0, 0, 1)); /* disabled = mute */ +/* AGC hysteresis: 4 values: 1, 2, 4 dB, disabled (= mute) */ +static const DECLARE_TLV_DB_RANGE(agc_hysteresis_tlv, + 0, 1, TLV_DB_SCALE_ITEM(100, 100, 0), + 2, 2, TLV_DB_SCALE_ITEM(400, 0, 0), + 3, 3, TLV_DB_SCALE_ITEM(0, 0, 1)); /* disabled = mute */ +static const DECLARE_TLV_DB_SCALE(agc_max_tlv, 0, 50, 0); +/* Input attenuation: -6 dB or 0 dB */ +static const DECLARE_TLV_DB_SCALE(input_attenuation_tlv, -600, 600, 0); + +static const struct snd_kcontrol_new adc3xxx_snd_controls[] = { + SOC_DOUBLE_R_TLV("PGA Capture Volume", ADC3XXX_LEFT_APGA_CTRL, + ADC3XXX_RIGHT_APGA_CTRL, 0, 80, 0, pga_tlv), + SOC_DOUBLE("PGA Capture Switch", ADC3XXX_ADC_FGA, 7, 3, 1, 1), + SOC_DOUBLE_R("AGC Capture Switch", ADC3XXX_LEFT_CHN_AGC_1, + ADC3XXX_RIGHT_CHN_AGC_1, 7, 1, 0), + SOC_DOUBLE_R_TLV("AGC Target Level Capture Volume", ADC3XXX_LEFT_CHN_AGC_1, + ADC3XXX_RIGHT_CHN_AGC_2, 4, 0x07, 1, agc_target_tlv), + SOC_DOUBLE_R_TLV("AGC Noise Threshold Capture Volume", ADC3XXX_LEFT_CHN_AGC_2, + ADC3XXX_RIGHT_CHN_AGC_2, 1, 0x1f, 1, agc_thresh_tlv), + SOC_DOUBLE_R_TLV("AGC Hysteresis Capture Volume", ADC3XXX_LEFT_CHN_AGC_2, + ADC3XXX_RIGHT_CHN_AGC_2, 6, 3, 0, agc_hysteresis_tlv), + SOC_DOUBLE_R("AGC Clip Stepping Capture Switch", ADC3XXX_LEFT_CHN_AGC_2, + ADC3XXX_RIGHT_CHN_AGC_2, 0, 1, 0), + /* + * Oddly enough, the data sheet says the default value + * for the left/right AGC maximum gain register field + * (ADC3XXX_LEFT/RIGHT_CHN_AGC_3 bits 0..6) is 0x7f = 127 + * (verified empirically) even though this value (indeed, above + * 0x50) is specified as 'Reserved. Do not use.' in the accompanying + * table in the data sheet. + */ + SOC_DOUBLE_R_TLV("AGC Maximum Capture Volume", ADC3XXX_LEFT_CHN_AGC_3, + ADC3XXX_RIGHT_CHN_AGC_3, 0, 0x50, 0, agc_max_tlv), + SOC_DOUBLE_R("AGC Attack Time", ADC3XXX_LEFT_CHN_AGC_4, + ADC3XXX_RIGHT_CHN_AGC_4, 3, 0x1f, 0), + /* Would like to have the multipliers as LR pairs, but there is + * no SOC_ENUM_foo which accepts two values in separate registers. + */ + SOC_ENUM("AGC Left Attack Time Multiplier", left_agc_attack_mult_enum), + SOC_ENUM("AGC Right Attack Time Multiplier", right_agc_attack_mult_enum), + SOC_DOUBLE_R("AGC Decay Time", ADC3XXX_LEFT_CHN_AGC_5, + ADC3XXX_RIGHT_CHN_AGC_5, 3, 0x1f, 0), + SOC_ENUM("AGC Left Decay Time Multiplier", left_agc_decay_mult_enum), + SOC_ENUM("AGC Right Decay Time Multiplier", right_agc_decay_mult_enum), + SOC_DOUBLE_R("AGC Noise Debounce", ADC3XXX_LEFT_CHN_AGC_6, + ADC3XXX_RIGHT_CHN_AGC_6, 0, 0x1f, 0), + SOC_DOUBLE_R("AGC Signal Debounce", ADC3XXX_LEFT_CHN_AGC_7, + ADC3XXX_RIGHT_CHN_AGC_7, 0, 0x0f, 0), + /* Read only register */ + SOC_DOUBLE_R_S_TLV("AGC Applied Capture Volume", ADC3XXX_LEFT_AGC_GAIN, + ADC3XXX_RIGHT_AGC_GAIN, 0, -24, 40, 6, 0, adc_tlv), + /* ADC soft stepping */ + SOC_ENUM("ADC Soft Stepping", adc_softstepping_enum), + /* Left/Right Input attenuation */ + SOC_SINGLE_TLV("Left Input IN_1L Capture Volume", + ADC3XXX_LEFT_PGA_SEL_1, 0, 1, 1, input_attenuation_tlv), + SOC_SINGLE_TLV("Left Input IN_2L Capture Volume", + ADC3XXX_LEFT_PGA_SEL_1, 2, 1, 1, input_attenuation_tlv), + SOC_SINGLE_TLV("Left Input IN_3L Capture Volume", + ADC3XXX_LEFT_PGA_SEL_1, 4, 1, 1, input_attenuation_tlv), + SOC_SINGLE_TLV("Left Input IN_1R Capture Volume", + ADC3XXX_LEFT_PGA_SEL_2, 0, 1, 1, input_attenuation_tlv), + SOC_SINGLE_TLV("Left Input DIF_2L_3L Capture Volume", + ADC3XXX_LEFT_PGA_SEL_1, 6, 1, 1, input_attenuation_tlv), + SOC_SINGLE_TLV("Left Input DIF_1L_1R Capture Volume", + ADC3XXX_LEFT_PGA_SEL_2, 4, 1, 1, input_attenuation_tlv), + SOC_SINGLE_TLV("Left Input DIF_2R_3R Capture Volume", + ADC3XXX_LEFT_PGA_SEL_2, 2, 1, 1, input_attenuation_tlv), + SOC_SINGLE_TLV("Right Input IN_1R Capture Volume", + ADC3XXX_RIGHT_PGA_SEL_1, 0, 1, 1, input_attenuation_tlv), + SOC_SINGLE_TLV("Right Input IN_2R Capture Volume", + ADC3XXX_RIGHT_PGA_SEL_1, 2, 1, 1, input_attenuation_tlv), + SOC_SINGLE_TLV("Right Input IN_3R Capture Volume", + ADC3XXX_RIGHT_PGA_SEL_1, 4, 1, 1, input_attenuation_tlv), + SOC_SINGLE_TLV("Right Input IN_1L Capture Volume", + ADC3XXX_RIGHT_PGA_SEL_2, 0, 1, 1, input_attenuation_tlv), + SOC_SINGLE_TLV("Right Input DIF_2R_3R Capture Volume", + ADC3XXX_RIGHT_PGA_SEL_1, 6, 1, 1, input_attenuation_tlv), + SOC_SINGLE_TLV("Right Input DIF_1L_1R Capture Volume", + ADC3XXX_RIGHT_PGA_SEL_2, 4, 1, 1, input_attenuation_tlv), + SOC_SINGLE_TLV("Right Input DIF_2L_3L Capture Volume", + ADC3XXX_RIGHT_PGA_SEL_2, 2, 1, 1, input_attenuation_tlv), + SOC_DOUBLE_R_S_TLV("ADC Volume Control Capture Volume", ADC3XXX_LADC_VOL, + ADC3XXX_RADC_VOL, 0, -24, 40, 6, 0, adc_tlv), + /* Empirically, the following doesn't work the way it's supposed + * to. Values 0, -0.1, -0.2 and -0.3 dB result in the same level, and + * -0.4 dB drops about 0.12 dB on a specific chip. + */ + SOC_DOUBLE_TLV("ADC Fine Volume Control Capture Volume", ADC3XXX_ADC_FGA, + 4, 0, 4, 1, adc_fine_tlv), + SOC_SINGLE("Left ADC Unselected CM Bias Capture Switch", + ADC3XXX_LEFT_PGA_SEL_2, 6, 1, 0), + SOC_SINGLE("Right ADC Unselected CM Bias Capture Switch", + ADC3XXX_RIGHT_PGA_SEL_2, 6, 1, 0), + SOC_ENUM("Dither Control DC Offset", dither_dc_offset_enum), +}; + +/* Left input selection, Single Ended inputs and Differential inputs */ +static const struct snd_kcontrol_new left_input_mixer_controls[] = { + SOC_DAPM_SINGLE("IN_1L Capture Switch", + ADC3XXX_LEFT_PGA_SEL_1, 1, 0x1, 1), + SOC_DAPM_SINGLE("IN_2L Capture Switch", + ADC3XXX_LEFT_PGA_SEL_1, 3, 0x1, 1), + SOC_DAPM_SINGLE("IN_3L Capture Switch", + ADC3XXX_LEFT_PGA_SEL_1, 5, 0x1, 1), + SOC_DAPM_SINGLE("DIF_2L_3L Capture Switch", + ADC3XXX_LEFT_PGA_SEL_1, 7, 0x1, 1), + SOC_DAPM_SINGLE("DIF_1L_1R Capture Switch", + ADC3XXX_LEFT_PGA_SEL_2, 5, 0x1, 1), + SOC_DAPM_SINGLE("DIF_2R_3R Capture Switch", + ADC3XXX_LEFT_PGA_SEL_2, 3, 0x1, 1), + SOC_DAPM_SINGLE("IN_1R Capture Switch", + ADC3XXX_LEFT_PGA_SEL_2, 1, 0x1, 1), +}; + +/* Right input selection, Single Ended inputs and Differential inputs */ +static const struct snd_kcontrol_new right_input_mixer_controls[] = { + SOC_DAPM_SINGLE("IN_1R Capture Switch", + ADC3XXX_RIGHT_PGA_SEL_1, 1, 0x1, 1), + SOC_DAPM_SINGLE("IN_2R Capture Switch", + ADC3XXX_RIGHT_PGA_SEL_1, 3, 0x1, 1), + SOC_DAPM_SINGLE("IN_3R Capture Switch", + ADC3XXX_RIGHT_PGA_SEL_1, 5, 0x1, 1), + SOC_DAPM_SINGLE("DIF_2R_3R Capture Switch", + ADC3XXX_RIGHT_PGA_SEL_1, 7, 0x1, 1), + SOC_DAPM_SINGLE("DIF_1L_1R Capture Switch", + ADC3XXX_RIGHT_PGA_SEL_2, 5, 0x1, 1), + SOC_DAPM_SINGLE("DIF_2L_3L Capture Switch", + ADC3XXX_RIGHT_PGA_SEL_2, 3, 0x1, 1), + SOC_DAPM_SINGLE("IN_1L Capture Switch", + ADC3XXX_RIGHT_PGA_SEL_2, 1, 0x1, 1), +}; + +/* Left Digital Mic input for left ADC */ +static const struct snd_kcontrol_new left_input_dmic_controls[] = { + SOC_DAPM_SINGLE("Left ADC Capture Switch", + ADC3XXX_ADC_DIGITAL, 3, 0x1, 0), +}; + +/* Right Digital Mic input for Right ADC */ +static const struct snd_kcontrol_new right_input_dmic_controls[] = { + SOC_DAPM_SINGLE("Right ADC Capture Switch", + ADC3XXX_ADC_DIGITAL, 2, 0x1, 0), +}; + +/* DAPM widgets */ +static const struct snd_soc_dapm_widget adc3xxx_dapm_widgets[] = { + + /* Left Input Selection */ + SND_SOC_DAPM_MIXER("Left Input", SND_SOC_NOPM, 0, 0, + &left_input_mixer_controls[0], + ARRAY_SIZE(left_input_mixer_controls)), + /* Right Input Selection */ + SND_SOC_DAPM_MIXER("Right Input", SND_SOC_NOPM, 0, 0, + &right_input_mixer_controls[0], + ARRAY_SIZE(right_input_mixer_controls)), + /* PGA selection */ + SND_SOC_DAPM_PGA("Left PGA", ADC3XXX_LEFT_APGA_CTRL, 7, 1, NULL, 0), + SND_SOC_DAPM_PGA("Right PGA", ADC3XXX_RIGHT_APGA_CTRL, 7, 1, NULL, 0), + + /* Digital Microphone Input Control for Left/Right ADC */ + SND_SOC_DAPM_MIXER("Left DMic Input", SND_SOC_NOPM, 0, 0, + &left_input_dmic_controls[0], + ARRAY_SIZE(left_input_dmic_controls)), + SND_SOC_DAPM_MIXER("Right DMic Input", SND_SOC_NOPM, 0, 0, + &right_input_dmic_controls[0], + ARRAY_SIZE(right_input_dmic_controls)), + + /* Left/Right ADC */ + SND_SOC_DAPM_ADC("Left ADC", "Left Capture", ADC3XXX_ADC_DIGITAL, 7, 0), + SND_SOC_DAPM_ADC("Right ADC", "Right Capture", ADC3XXX_ADC_DIGITAL, 6, 0), + + /* Inputs */ + SND_SOC_DAPM_INPUT("IN_1L"), + SND_SOC_DAPM_INPUT("IN_1R"), + SND_SOC_DAPM_INPUT("IN_2L"), + SND_SOC_DAPM_INPUT("IN_2R"), + SND_SOC_DAPM_INPUT("IN_3L"), + SND_SOC_DAPM_INPUT("IN_3R"), + SND_SOC_DAPM_INPUT("DIFL_1L_1R"), + SND_SOC_DAPM_INPUT("DIFL_2L_3L"), + SND_SOC_DAPM_INPUT("DIFL_2R_3R"), + SND_SOC_DAPM_INPUT("DIFR_1L_1R"), + SND_SOC_DAPM_INPUT("DIFR_2L_3L"), + SND_SOC_DAPM_INPUT("DIFR_2R_3R"), + SND_SOC_DAPM_INPUT("DMic_L"), + SND_SOC_DAPM_INPUT("DMic_R"), + + /* Digital audio interface output */ + SND_SOC_DAPM_AIF_OUT("AIF_OUT", "Capture", 0, SND_SOC_NOPM, 0, 0), + + /* Clocks */ + SND_SOC_DAPM_SUPPLY("PLL_CLK", ADC3XXX_PLL_PROG_PR, ADC3XXX_ENABLE_PLL_SHIFT, + 0, adc3xxx_pll_delay, SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_SUPPLY("ADC_CLK", ADC3XXX_ADC_NADC, ADC3XXX_ENABLE_NADC_SHIFT, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC_MOD_CLK", ADC3XXX_ADC_MADC, ADC3XXX_ENABLE_MADC_SHIFT, + 0, NULL, 0), + + /* This refers to the generated BCLK in master mode. */ + SND_SOC_DAPM_SUPPLY("BCLK", ADC3XXX_BCLK_N_DIV, ADC3XXX_ENABLE_BCLK_SHIFT, + 0, NULL, 0), +}; + +static const struct snd_soc_dapm_route adc3xxx_intercon[] = { + /* Left input selection from switches */ + { "Left Input", "IN_1L Capture Switch", "IN_1L" }, + { "Left Input", "IN_2L Capture Switch", "IN_2L" }, + { "Left Input", "IN_3L Capture Switch", "IN_3L" }, + { "Left Input", "DIF_2L_3L Capture Switch", "DIFL_2L_3L" }, + { "Left Input", "DIF_1L_1R Capture Switch", "DIFL_1L_1R" }, + { "Left Input", "DIF_2R_3R Capture Switch", "DIFL_2R_3R" }, + { "Left Input", "IN_1R Capture Switch", "IN_1R" }, + + /* Left input selection to left PGA */ + { "Left PGA", NULL, "Left Input" }, + + /* Left PGA to left ADC */ + { "Left ADC", NULL, "Left PGA" }, + + /* Right input selection from switches */ + { "Right Input", "IN_1R Capture Switch", "IN_1R" }, + { "Right Input", "IN_2R Capture Switch", "IN_2R" }, + { "Right Input", "IN_3R Capture Switch", "IN_3R" }, + { "Right Input", "DIF_2R_3R Capture Switch", "DIFR_2R_3R" }, + { "Right Input", "DIF_1L_1R Capture Switch", "DIFR_1L_1R" }, + { "Right Input", "DIF_2L_3L Capture Switch", "DIFR_2L_3L" }, + { "Right Input", "IN_1L Capture Switch", "IN_1L" }, + + /* Right input selection to right PGA */ + { "Right PGA", NULL, "Right Input" }, + + /* Right PGA to right ADC */ + { "Right ADC", NULL, "Right PGA" }, + + /* Left DMic Input selection from switch */ + { "Left DMic Input", "Left ADC Capture Switch", "DMic_L" }, + + /* Left DMic to left ADC */ + { "Left ADC", NULL, "Left DMic Input" }, + + /* Right DMic Input selection from switch */ + { "Right DMic Input", "Right ADC Capture Switch", "DMic_R" }, + + /* Right DMic to right ADC */ + { "Right ADC", NULL, "Right DMic Input" }, + + /* ADC to AIF output */ + { "AIF_OUT", NULL, "Left ADC" }, + { "AIF_OUT", NULL, "Right ADC" }, + + /* Clocking */ + { "ADC_MOD_CLK", NULL, "ADC_CLK" }, + { "Left ADC", NULL, "ADC_MOD_CLK" }, + { "Right ADC", NULL, "ADC_MOD_CLK" }, + + { "BCLK", NULL, "ADC_CLK" }, +}; + +static const struct snd_soc_dapm_route adc3xxx_pll_intercon[] = { + { "ADC_CLK", NULL, "PLL_CLK" }, +}; + +static const struct snd_soc_dapm_route adc3xxx_bclk_out_intercon[] = { + { "AIF_OUT", NULL, "BCLK" } +}; + +static int adc3xxx_gpio_request(struct gpio_chip *chip, unsigned int offset) +{ + struct adc3xxx *adc3xxx = gpiochip_get_data(chip); + + if (offset >= ADC3XXX_GPIOS_MAX) + return -EINVAL; + + /* GPIO1 is offset 0, GPIO2 is offset 1 */ + /* We check here that the GPIO pins are either not configured in the + * DT, or that they purposely are set as outputs. + * (Input mode not yet implemented). + */ + if (adc3xxx->gpio_cfg[offset] != 0 && + adc3xxx->gpio_cfg[offset] != ADC3XXX_GPIO_GPO + 1) + return -EINVAL; + + return 0; +} + +static int adc3xxx_gpio_direction_out(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct adc3xxx *adc3xxx = gpiochip_get_data(chip); + + /* Set GPIO output function. */ + return regmap_update_bits(adc3xxx->regmap, + adc3xxx_gpio_ctrl_reg[offset], + ADC3XXX_GPIO_CTRL_CFG_MASK | + ADC3XXX_GPIO_CTRL_OUTPUT_CTRL_MASK, + ADC3XXX_GPIO_GPO << ADC3XXX_GPIO_CTRL_CFG_SHIFT | + !!value << ADC3XXX_GPIO_CTRL_OUTPUT_CTRL_SHIFT); +} + +/* With only GPIO outputs configured, we never get the .direction_out call, + * so we set the output mode and output value in the same call. Hence + * .set in practice does the same thing as .direction_out . + */ +static void adc3xxx_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + (void) adc3xxx_gpio_direction_out(chip, offset, value); +} + +/* Even though we only support GPIO output for now, some GPIO clients + * want to read the current pin state using the .get callback. + */ +static int adc3xxx_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct adc3xxx *adc3xxx = gpiochip_get_data(chip); + unsigned int regval; + int ret; + + /* We only allow output pins, so just read the value set in the output + * pin register field. + */ + ret = regmap_read(adc3xxx->regmap, adc3xxx_gpio_ctrl_reg[offset], ®val); + if (ret) + return ret; + return !!(regval & ADC3XXX_GPIO_CTRL_OUTPUT_CTRL_MASK); +} + +static const struct gpio_chip adc3xxx_gpio_chip = { + .label = "adc3xxx", + .owner = THIS_MODULE, + .request = adc3xxx_gpio_request, + .direction_output = adc3xxx_gpio_direction_out, + .set = adc3xxx_gpio_set, + .get = adc3xxx_gpio_get, + .can_sleep = 1, +}; + +static void adc3xxx_free_gpio(struct adc3xxx *adc3xxx) +{ + gpiochip_remove(&adc3xxx->gpio_chip); +} + +static void adc3xxx_init_gpio(struct adc3xxx *adc3xxx) +{ + int gpio, micbias; + int ret; + + adc3xxx->gpio_chip = adc3xxx_gpio_chip; + adc3xxx->gpio_chip.ngpio = ADC3XXX_GPIOS_MAX; + adc3xxx->gpio_chip.parent = adc3xxx->dev; + adc3xxx->gpio_chip.base = -1; + + ret = gpiochip_add_data(&adc3xxx->gpio_chip, adc3xxx); + if (ret) + dev_err(adc3xxx->dev, "Failed to add gpios: %d\n", ret); + + /* Set up potential GPIO configuration from the devicetree. + * This allows us to set up things which are not software + * controllable GPIOs, such as PDM microphone I/O, + */ + for (gpio = 0; gpio < ADC3XXX_GPIOS_MAX; gpio++) { + unsigned int cfg = adc3xxx->gpio_cfg[gpio]; + + if (cfg) { + cfg--; /* actual value to use is stored +1 */ + regmap_update_bits(adc3xxx->regmap, + adc3xxx_gpio_ctrl_reg[gpio], + ADC3XXX_GPIO_CTRL_CFG_MASK, + cfg << ADC3XXX_GPIO_CTRL_CFG_SHIFT); + } + } + + /* Set up micbias voltage */ + for (micbias = 0; micbias < ADC3XXX_MICBIAS_PINS; micbias++) { + unsigned int vg = adc3xxx->micbias_vg[micbias]; + + regmap_update_bits(adc3xxx->regmap, + ADC3XXX_MICBIAS_CTRL, + ADC3XXX_MICBIAS_MASK << adc3xxx_micbias_shift[micbias], + vg << adc3xxx_micbias_shift[micbias]); + } +} + +static int adc3xxx_parse_dt_gpio(struct adc3xxx *adc3xxx, + const char *propname, unsigned int *cfg) +{ + struct device *dev = adc3xxx->dev; + struct device_node *np = dev->of_node; + unsigned int val; + + if (!of_property_read_u32(np, propname, &val)) { + if (val & ~15 || val == 7 || val >= 11) { + dev_err(dev, "Invalid property value for '%s'\n", propname); + return -EINVAL; + } + if (val == ADC3XXX_GPIO_GPI) + dev_warn(dev, "GPIO Input read not yet implemented\n"); + *cfg = val + 1; /* 0 => not set up, all others shifted +1 */ + } + return 0; +} + +static int adc3xxx_parse_dt_micbias(struct adc3xxx *adc3xxx, + const char *propname, unsigned int *vg) +{ + struct device *dev = adc3xxx->dev; + struct device_node *np = dev->of_node; + unsigned int val; + + if (!of_property_read_u32(np, propname, &val)) { + if (val >= ADC3XXX_MICBIAS_AVDD) { + dev_err(dev, "Invalid property value for '%s'\n", propname); + return -EINVAL; + } + *vg = val; + } + return 0; +} + +static int adc3xxx_parse_pll_mode(uint32_t val, unsigned int *pll_mode) +{ + if (val != ADC3XXX_PLL_ENABLE && val != ADC3XXX_PLL_BYPASS && + val != ADC3XXX_PLL_AUTO) + return -EINVAL; + + *pll_mode = val; + + return 0; +} + +static void adc3xxx_setup_pll(struct snd_soc_component *component, + int div_entry) +{ + int i = div_entry; + + /* P & R values */ + snd_soc_component_write(component, ADC3XXX_PLL_PROG_PR, + (adc3xxx_divs[i].pll_p << ADC3XXX_PLLP_SHIFT) | + (adc3xxx_divs[i].pll_r << ADC3XXX_PLLR_SHIFT)); + /* J value */ + snd_soc_component_write(component, ADC3XXX_PLL_PROG_J, + adc3xxx_divs[i].pll_j & ADC3XXX_PLLJ_MASK); + /* D value */ + snd_soc_component_write(component, ADC3XXX_PLL_PROG_D_LSB, + adc3xxx_divs[i].pll_d & ADC3XXX_PLLD_LSB_MASK); + snd_soc_component_write(component, ADC3XXX_PLL_PROG_D_MSB, + (adc3xxx_divs[i].pll_d >> 8) & ADC3XXX_PLLD_MSB_MASK); +} + +static int adc3xxx_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(dai->component); + struct adc3xxx *adc3xxx = snd_soc_component_get_drvdata(component); + int i, width = 16; + u8 iface_len, bdiv; + + i = adc3xxx_get_divs(component->dev, adc3xxx->sysclk, + params_rate(params), adc3xxx->pll_mode); + + if (i < 0) + return i; + + /* select data word length */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + iface_len = ADC3XXX_IFACE_16BITS; + width = 16; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + iface_len = ADC3XXX_IFACE_20BITS; + width = 20; + break; + case SNDRV_PCM_FORMAT_S24_LE: + iface_len = ADC3XXX_IFACE_24BITS; + width = 24; + break; + case SNDRV_PCM_FORMAT_S32_LE: + iface_len = ADC3XXX_IFACE_32BITS; + width = 32; + break; + default: + dev_err(component->dev, "Unsupported serial data format\n"); + return -EINVAL; + } + snd_soc_component_update_bits(component, ADC3XXX_INTERFACE_CTRL_1, + ADC3XXX_WLENGTH_MASK, iface_len); + if (adc3xxx_divs[i].pll_p) { /* If PLL used for this mode */ + adc3xxx_setup_pll(component, i); + snd_soc_component_write(component, ADC3XXX_CLKGEN_MUX, ADC3XXX_USE_PLL); + if (!adc3xxx->use_pll) { + snd_soc_dapm_add_routes(dapm, adc3xxx_pll_intercon, + ARRAY_SIZE(adc3xxx_pll_intercon)); + adc3xxx->use_pll = 1; + } + } else { + snd_soc_component_write(component, ADC3XXX_CLKGEN_MUX, ADC3XXX_NO_PLL); + if (adc3xxx->use_pll) { + snd_soc_dapm_del_routes(dapm, adc3xxx_pll_intercon, + ARRAY_SIZE(adc3xxx_pll_intercon)); + adc3xxx->use_pll = 0; + } + } + + /* NADC */ + snd_soc_component_update_bits(component, ADC3XXX_ADC_NADC, + ADC3XXX_NADC_MASK, adc3xxx_divs[i].nadc); + /* MADC */ + snd_soc_component_update_bits(component, ADC3XXX_ADC_MADC, + ADC3XXX_MADC_MASK, adc3xxx_divs[i].madc); + /* AOSR */ + snd_soc_component_update_bits(component, ADC3XXX_ADC_AOSR, + ADC3XXX_AOSR_MASK, adc3xxx_divs[i].aosr); + /* BDIV N Value */ + /* BCLK is (by default) set up to be derived from ADC_CLK */ + bdiv = (adc3xxx_divs[i].aosr * adc3xxx_divs[i].madc) / (2 * width); + snd_soc_component_update_bits(component, ADC3XXX_BCLK_N_DIV, + ADC3XXX_BDIV_MASK, bdiv); + + return 0; +} + +static const char *adc3xxx_pll_mode_text(int pll_mode) +{ + switch (pll_mode) { + case ADC3XXX_PLL_AUTO: + return "PLL auto"; + case ADC3XXX_PLL_ENABLE: + return "PLL enable"; + case ADC3XXX_PLL_BYPASS: + return "PLL bypass"; + default: + break; + } + + return "PLL unknown"; +} + +static int adc3xxx_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_component *component = codec_dai->component; + struct adc3xxx *adc3xxx = snd_soc_component_get_drvdata(component); + int ret; + + ret = adc3xxx_parse_pll_mode(clk_id, &adc3xxx->pll_mode); + if (ret < 0) + return ret; + + adc3xxx->sysclk = freq; + dev_dbg(component->dev, "Set sysclk to %u Hz, %s\n", + freq, adc3xxx_pll_mode_text(adc3xxx->pll_mode)); + return 0; +} + +static int adc3xxx_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_component *component = codec_dai->component; + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct adc3xxx *adc3xxx = snd_soc_component_get_drvdata(component); + u8 clkdir = 0, format = 0; + int master = 0; + + /* set master/slave audio interface */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + master = 1; + clkdir = ADC3XXX_BCLK_MASTER | ADC3XXX_WCLK_MASTER; + break; + case SND_SOC_DAIFMT_CBC_CFC: + master = 0; + break; + default: + dev_err(component->dev, "Invalid DAI clock setup\n"); + return -EINVAL; + } + + /* + * match both interface format and signal polarities since they + * are fixed + */ + switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK)) { + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF: + format = ADC3XXX_FORMAT_I2S; + break; + case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF: + format = ADC3XXX_FORMAT_DSP; + break; + case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF: + format = ADC3XXX_FORMAT_DSP; + break; + case SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_NB_NF: + format = ADC3XXX_FORMAT_RJF; + break; + case SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF: + format = ADC3XXX_FORMAT_LJF; + break; + default: + dev_err(component->dev, "Invalid DAI format\n"); + return -EINVAL; + } + + /* Add/del route enabling BCLK output as applicable */ + if (master && !adc3xxx->master) + snd_soc_dapm_add_routes(dapm, adc3xxx_bclk_out_intercon, + ARRAY_SIZE(adc3xxx_bclk_out_intercon)); + else if (!master && adc3xxx->master) + snd_soc_dapm_del_routes(dapm, adc3xxx_bclk_out_intercon, + ARRAY_SIZE(adc3xxx_bclk_out_intercon)); + adc3xxx->master = master; + + /* set clock direction and format */ + return snd_soc_component_update_bits(component, + ADC3XXX_INTERFACE_CTRL_1, + ADC3XXX_CLKDIR_MASK | ADC3XXX_FORMAT_MASK, + clkdir | format); +} + +static const struct snd_soc_dai_ops adc3xxx_dai_ops = { + .hw_params = adc3xxx_hw_params, + .set_sysclk = adc3xxx_set_dai_sysclk, + .set_fmt = adc3xxx_set_dai_fmt, +}; + +static struct snd_soc_dai_driver adc3xxx_dai = { + .name = "tlv320adc3xxx-hifi", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = ADC3XXX_RATES, + .formats = ADC3XXX_FORMATS, + }, + .ops = &adc3xxx_dai_ops, +}; + +static const struct snd_soc_component_driver soc_component_dev_adc3xxx = { + .controls = adc3xxx_snd_controls, + .num_controls = ARRAY_SIZE(adc3xxx_snd_controls), + .dapm_widgets = adc3xxx_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(adc3xxx_dapm_widgets), + .dapm_routes = adc3xxx_intercon, + .num_dapm_routes = ARRAY_SIZE(adc3xxx_intercon), +}; + +static int adc3xxx_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct device *dev = &i2c->dev; + struct adc3xxx *adc3xxx = NULL; + int ret; + + adc3xxx = devm_kzalloc(dev, sizeof(struct adc3xxx), GFP_KERNEL); + if (!adc3xxx) + return -ENOMEM; + adc3xxx->dev = dev; + + adc3xxx->rst_pin = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(adc3xxx->rst_pin)) { + return dev_err_probe(dev, PTR_ERR(adc3xxx->rst_pin), + "Failed to request rst_pin\n"); + } + + adc3xxx->mclk = devm_clk_get(dev, NULL); + if (IS_ERR(adc3xxx->mclk)) { + /* + * The chip itself supports running off the BCLK either + * directly or via the PLL, but the driver does not (yet), so + * having a specified mclk is required. Otherwise, we could + * use the lack of a clocks property to indicate when BCLK is + * intended as the clock source. + */ + return dev_err_probe(dev, PTR_ERR(adc3xxx->mclk), + "Failed to acquire MCLK\n"); + } else if (adc3xxx->mclk) { + ret = clk_prepare_enable(adc3xxx->mclk); + if (ret < 0) + return ret; + dev_dbg(dev, "Enabled MCLK, freq %lu Hz\n", clk_get_rate(adc3xxx->mclk)); + } + + ret = adc3xxx_parse_dt_gpio(adc3xxx, "ti,dmdin-gpio1", &adc3xxx->gpio_cfg[0]); + if (ret < 0) + return ret; + ret = adc3xxx_parse_dt_gpio(adc3xxx, "ti,dmclk-gpio2", &adc3xxx->gpio_cfg[1]); + if (ret < 0) + return ret; + ret = adc3xxx_parse_dt_micbias(adc3xxx, "ti,micbias1-vg", &adc3xxx->micbias_vg[0]); + if (ret < 0) + return ret; + ret = adc3xxx_parse_dt_micbias(adc3xxx, "ti,micbias2-vg", &adc3xxx->micbias_vg[1]); + if (ret < 0) + return ret; + + adc3xxx->regmap = devm_regmap_init_i2c(i2c, &adc3xxx_regmap); + if (IS_ERR(adc3xxx->regmap)) { + ret = PTR_ERR(adc3xxx->regmap); + return ret; + } + + i2c_set_clientdata(i2c, adc3xxx); + + adc3xxx->type = id->driver_data; + + /* Reset codec chip */ + gpiod_set_value_cansleep(adc3xxx->rst_pin, 1); + usleep_range(2000, 100000); /* Requirement: > 10 ns (datasheet p13) */ + gpiod_set_value_cansleep(adc3xxx->rst_pin, 0); + + /* Potentially set up pins used as GPIOs */ + adc3xxx_init_gpio(adc3xxx); + + ret = snd_soc_register_component(dev, + &soc_component_dev_adc3xxx, &adc3xxx_dai, 1); + if (ret < 0) + dev_err(dev, "Failed to register codec: %d\n", ret); + + return ret; +} + +static int __exit adc3xxx_i2c_remove(struct i2c_client *client) +{ + struct adc3xxx *adc3xxx = i2c_get_clientdata(client); + + if (adc3xxx->mclk) + clk_disable_unprepare(adc3xxx->mclk); + adc3xxx_free_gpio(adc3xxx); + snd_soc_unregister_component(&client->dev); + return 0; +} + +static const struct of_device_id tlv320adc3xxx_of_match[] = { + { .compatible = "ti,tlv320adc3001", }, + { .compatible = "ti,tlv320adc3101", }, + {}, +}; +MODULE_DEVICE_TABLE(of, tlv320adc3xxx_of_match); + +static const struct i2c_device_id adc3xxx_i2c_id[] = { + { "tlv320adc3001", ADC3001 }, + { "tlv320adc3101", ADC3101 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, adc3xxx_i2c_id); + +static struct i2c_driver adc3xxx_i2c_driver = { + .driver = { + .name = "tlv320adc3xxx-codec", + .of_match_table = tlv320adc3xxx_of_match, + }, + .probe = adc3xxx_i2c_probe, + .remove = adc3xxx_i2c_remove, + .id_table = adc3xxx_i2c_id, +}; + +module_i2c_driver(adc3xxx_i2c_driver); + +MODULE_DESCRIPTION("ASoC TLV320ADC3xxx codec driver"); +MODULE_AUTHOR("shahina.s@mistralsolutions.com"); +MODULE_LICENSE("GPL v2"); From 98bf33ca3f00d76659aa1be1586a433efa74d34e Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 20 Dec 2021 17:34:07 +0800 Subject: [PATCH 257/327] ASoC: mediatek: mt8195-mt6359: reduce log verbosity in probe() Eliminates error messages if snd_soc_register_card() failed. Kernel emits messages if device probe error anyway. This is mainly for removing the following error messages during boot. >>> snd_soc_register_card fail -517 Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20211220093408.207206-1-tzungbi@google.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c | 2 -- sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c index 5cdbfaafd479b..9cf907c49ea80 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c @@ -1114,8 +1114,6 @@ static int mt8195_mt6359_rt1011_rt5682_dev_probe(struct platform_device *pdev) ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) { - dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", - __func__, ret); of_node_put(priv->hdmi_node); of_node_put(priv->dp_node); of_node_put(priv->platform_node); diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c index fa50a31e9718a..fdd4441387281 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c @@ -1358,8 +1358,6 @@ static int mt8195_mt6359_rt1019_rt5682_dev_probe(struct platform_device *pdev) ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) { - dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", - __func__, ret); of_node_put(priv->hdmi_node); of_node_put(priv->dp_node); of_node_put(priv->platform_node); From f487201343312faa697ac40124085a834e0e26d8 Mon Sep 17 00:00:00 2001 From: Ajit Kumar Pandey Date: Tue, 21 Dec 2021 21:48:08 +0530 Subject: [PATCH 258/327] ASoC: amd: acp-config: Enable SOF audio for Google chrome boards. We need to support sof audio on different variants of Google boards. Add new entry in dmi table to enable SOF flag on Google chrome boards. Also add newer machines to sof_machines list with codecs and amps acpi id check to register sof sound cards on different variants. Signed-off-by: Ajit Kumar Pandey Reviewed-by: Pierre-Louis Bossart Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211221161814.236318-2-AjitKumar.Pandey@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp-config.c | 53 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c index 1493d52c92907..c0bbcdb1761d1 100644 --- a/sound/soc/amd/acp-config.c +++ b/sound/soc/amd/acp-config.c @@ -35,6 +35,18 @@ static const struct config_entry config_table[] = { {} }, }, + { + .flags = FLAG_AMD_SOF, + .device = ACP_PCI_DEV_ID, + .dmi_table = (const struct dmi_system_id []) { + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + }, + }, + {} + }, + }, }; int snd_amd_acp_find_config(struct pci_dev *pci) @@ -43,6 +55,10 @@ int snd_amd_acp_find_config(struct pci_dev *pci) u16 device = pci->device; int i; + /* Do not enable FLAGS on older platforms with Rev id zero */ + if (!pci->revision) + return 0; + for (i = 0; i < ARRAY_SIZE(config_table); i++, table++) { if (table->device != device) continue; @@ -56,7 +72,44 @@ int snd_amd_acp_find_config(struct pci_dev *pci) } EXPORT_SYMBOL(snd_amd_acp_find_config); +static struct snd_soc_acpi_codecs amp_rt1019 = { + .num_codecs = 1, + .codecs = {"10EC1019"} +}; + +static struct snd_soc_acpi_codecs amp_max = { + .num_codecs = 1, + .codecs = {"MX98360A"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[] = { + { + .id = "10EC5682", + .drv_name = "rt5682-rt1019", + .pdata = (void *)&acp_quirk_data, + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &_rt1019, + .fw_filename = "sof-rn.ri", + .sof_tplg_filename = "sof-acp.tplg", + }, + { + .id = "10EC5682", + .drv_name = "rt5682-max", + .pdata = (void *)&acp_quirk_data, + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &_max, + .fw_filename = "sof-rn.ri", + .sof_tplg_filename = "sof-acp.tplg", + }, + { + .id = "RTL5682", + .drv_name = "rt5682s-max", + .pdata = (void *)&acp_quirk_data, + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &_max, + .fw_filename = "sof-rn.ri", + .sof_tplg_filename = "sof-acp.tplg", + }, { .id = "AMDI1019", .drv_name = "renoir-dsp", From 0082e3299a49286a7761f4d237530b07c00676fb Mon Sep 17 00:00:00 2001 From: Ajit Kumar Pandey Date: Tue, 21 Dec 2021 21:48:09 +0530 Subject: [PATCH 259/327] ASoC: amd: acp-config: Update sof_tplg_filename for SOF machines SOF machines support different codec end points and hence required different topologies configuration. Update tplg filename in machine struct to load different topology files for SOF machines. Signed-off-by: Ajit Kumar Pandey Reviewed-by: Curtis Malainey Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20211221161814.236318-3-AjitKumar.Pandey@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp-config.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c index c0bbcdb1761d1..c9e1c08364f3a 100644 --- a/sound/soc/amd/acp-config.c +++ b/sound/soc/amd/acp-config.c @@ -90,7 +90,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[] = { .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &_rt1019, .fw_filename = "sof-rn.ri", - .sof_tplg_filename = "sof-acp.tplg", + .sof_tplg_filename = "sof-rn-rt5682-rt1019.tplg", }, { .id = "10EC5682", @@ -99,7 +99,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[] = { .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &_max, .fw_filename = "sof-rn.ri", - .sof_tplg_filename = "sof-acp.tplg", + .sof_tplg_filename = "sof-rn-rt5682-max98360.tplg", }, { .id = "RTL5682", @@ -108,7 +108,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[] = { .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &_max, .fw_filename = "sof-rn.ri", - .sof_tplg_filename = "sof-acp.tplg", + .sof_tplg_filename = "sof-rn-rt5682-max98360.tplg", }, { .id = "AMDI1019", From 3bf4fb25d5c2455396a1decd43f5e6b775f0b377 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Thu, 16 Dec 2021 19:02:29 +0300 Subject: [PATCH 260/327] ASoC: tegra-audio-rt5677: Correct example Remove non-existent properties from the example of the binding. These properties were borrower from the old txt binding, but they were never used in practice and aren't documented in the new binding. They aren't reported by the binding checker because dtschema needs extra patch that hasn't been upstreamed yet to make unevaluatedProperties work properly. Signed-off-by: Dmitry Osipenko Acked-by: Rob Herring Link: https://lore.kernel.org/r/20211216160229.17049-1-digetx@gmail.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/nvidia,tegra-audio-rt5677.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5677.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5677.yaml index 03ff691c26c83..a49997d6028bf 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5677.yaml +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5677.yaml @@ -92,9 +92,6 @@ examples: nvidia,audio-codec = <&rt5677>; nvidia,hp-det-gpios = <&gpio 143 0>; - nvidia,mic-present-gpios = <&gpio 132 1>; - nvidia,hp-en-gpios = <&rt5677 1 0>; - nvidia,dmic-clk-en-gpios = <&rt5677 2 1>; clocks = <&clk 216>, <&clk 217>, From 2dc643cd756398c3013fcc2d3c2a07c9c4a0a3bd Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 21 Dec 2021 22:27:57 +0530 Subject: [PATCH 261/327] ASoC: SOF: AMD: simplify return status handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cppcheck warning: sound/soc/sof/amd/acp.c:222:9: warning: Identical condition and return expression 'ret', return value is always 0 [identicalConditionAfterEarlyExit] return ret; ^ sound/soc/sof/amd/acp.c:213:6: note: If condition 'ret' is true, the function will return/exit if (ret) ^ sound/soc/sof/amd/acp.c:222:9: note: Returning identical expression 'ret' return ret; ^ Just return 0; on success. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Péter Ujfalusi Signed-off-by: Ajit Kumar Pandey Link: https://lore.kernel.org/r/20211221165802.236843-1-AjitKumar.Pandey@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 4c5550e8d3649..fe9b7dc5bc866 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -219,7 +219,7 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, return -EINVAL; } - return ret; + return 0; } int acp_dma_status(struct acp_dev_data *adata, unsigned char ch) From ac1e6bc146d45e15f0a5c0908338f918f6261388 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 17 Dec 2021 18:00:07 +0300 Subject: [PATCH 262/327] ASoC: qdsp6: fix a use after free bug in open() This code frees "graph" and then dereferences to save the error code. Save the error code first and then use gotos to unwind the allocation. Fixes: 59716aa3f976 ("ASoC: qdsp6: Fix an IS_ERR() vs NULL bug") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/20211217150007.GB16611@kili Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6apm.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c index 3e007d609a9bb..f424d7aa389a2 100644 --- a/sound/soc/qcom/qdsp6/q6apm.c +++ b/sound/soc/qcom/qdsp6/q6apm.c @@ -615,7 +615,7 @@ struct q6apm_graph *q6apm_graph_open(struct device *dev, q6apm_cb cb, graph = kzalloc(sizeof(*graph), GFP_KERNEL); if (!graph) { ret = -ENOMEM; - goto err; + goto put_ar_graph; } graph->apm = apm; @@ -631,13 +631,15 @@ struct q6apm_graph *q6apm_graph_open(struct device *dev, q6apm_cb cb, graph->port = gpr_alloc_port(apm->gdev, dev, graph_callback, graph); if (IS_ERR(graph->port)) { - kfree(graph); ret = PTR_ERR(graph->port); - goto err; + goto free_graph; } return graph; -err: + +free_graph: + kfree(graph); +put_ar_graph: kref_put(&ar_graph->refcount, q6apm_put_audioreach_graph); return ERR_PTR(ret); } From 15443f6cab25762272312373226d3fd2a742404f Mon Sep 17 00:00:00 2001 From: Ajit Kumar Pandey Date: Tue, 21 Dec 2021 22:49:10 +0530 Subject: [PATCH 263/327] ASoC: amd: acp: Remove duplicate dependency in Kconfig Remove duplicate depends on statement in Kconfig file. Signed-off-by: Ajit Kumar Pandey Link: https://lore.kernel.org/r/20211221171912.237792-1-AjitKumar.Pandey@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/Kconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/amd/acp/Kconfig b/sound/soc/amd/acp/Kconfig index 52a1371f9e617..154be5e70821a 100644 --- a/sound/soc/amd/acp/Kconfig +++ b/sound/soc/amd/acp/Kconfig @@ -46,7 +46,6 @@ config SND_SOC_AMD_LEGACY_MACH tristate "AMD Legacy Machine Driver Support" depends on X86 && PCI && I2C select SND_SOC_AMD_MACH_COMMON - depends on X86 && PCI && I2C help This option enables legacy sound card support for ACP audio. @@ -54,7 +53,6 @@ config SND_SOC_AMD_SOF_MACH tristate "AMD SOF Machine Driver Support" depends on X86 && PCI && I2C select SND_SOC_AMD_MACH_COMMON - depends on X86 && PCI && I2C help This option enables SOF sound card support for ACP audio. From c2efaf8f2d53ffa2ecc487e21c62d13bbb8d88c3 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Tue, 21 Dec 2021 17:00:59 +0000 Subject: [PATCH 264/327] ASoC: xlnx: Use platform_get_irq() to get the interrupt platform_get_resource(pdev, IORESOURCE_IRQ, ..) relies on static allocation of IRQ resources in DT core code, this causes an issue when using hierarchical interrupt domains using "interrupts" property in the node as this bypasses the hierarchical setup and messes up the irq chaining. In preparation for removal of static setup of IRQ resource from DT core code use platform_get_irq(). Signed-off-by: Lad Prabhakar Link: https://lore.kernel.org/r/20211221170100.27423-2-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Mark Brown --- sound/soc/xilinx/xlnx_spdif.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/sound/soc/xilinx/xlnx_spdif.c b/sound/soc/xilinx/xlnx_spdif.c index e2ca087adee67..cba0e868a7d77 100644 --- a/sound/soc/xilinx/xlnx_spdif.c +++ b/sound/soc/xilinx/xlnx_spdif.c @@ -237,7 +237,6 @@ MODULE_DEVICE_TABLE(of, xlnx_spdif_of_match); static int xlnx_spdif_probe(struct platform_device *pdev) { int ret; - struct resource *res; struct snd_soc_dai_driver *dai_drv; struct spdif_dev_data *ctx; @@ -273,13 +272,10 @@ static int xlnx_spdif_probe(struct platform_device *pdev) if (ctx->mode) { dai_drv = &xlnx_spdif_tx_dai; } else { - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(dev, "No IRQ resource found\n"); - ret = -ENODEV; + ret = platform_get_irq(pdev, 0); + if (ret < 0) goto clk_err; - } - ret = devm_request_irq(dev, res->start, + ret = devm_request_irq(dev, ret, xlnx_spdifrx_irq_handler, 0, "XLNX_SPDIF_RX", ctx); if (ret) { From 5de035c270047e7ae754fbfb69031707aa5b54f7 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Tue, 21 Dec 2021 17:01:00 +0000 Subject: [PATCH 265/327] ASoC: bcm: Use platform_get_irq() to get the interrupt platform_get_resource(pdev, IORESOURCE_IRQ, ..) relies on static allocation of IRQ resources in DT core code, this causes an issue when using hierarchical interrupt domains using "interrupts" property in the node as this bypasses the hierarchical setup and messes up the irq chaining. In preparation for removal of static setup of IRQ resource from DT core code use platform_get_irq(). While at it also drop "r_irq" member from struct bcm_i2s_priv as there are no users of it. Signed-off-by: Lad Prabhakar Reviewed-by: Florian Fainelli Link: https://lore.kernel.org/r/20211221170100.27423-3-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Mark Brown --- sound/soc/bcm/bcm63xx-i2s.h | 1 - sound/soc/bcm/bcm63xx-pcm-whistler.c | 13 ++++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/sound/soc/bcm/bcm63xx-i2s.h b/sound/soc/bcm/bcm63xx-i2s.h index edc328ba53d3b..f30556bec89ed 100644 --- a/sound/soc/bcm/bcm63xx-i2s.h +++ b/sound/soc/bcm/bcm63xx-i2s.h @@ -74,7 +74,6 @@ struct bcm_i2s_priv { struct device *dev; - struct resource *r_irq; struct regmap *regmap_i2s; struct clk *i2s_clk; struct snd_pcm_substream *play_substream; diff --git a/sound/soc/bcm/bcm63xx-pcm-whistler.c b/sound/soc/bcm/bcm63xx-pcm-whistler.c index b5096f64c576e..2c600b017524f 100644 --- a/sound/soc/bcm/bcm63xx-pcm-whistler.c +++ b/sound/soc/bcm/bcm63xx-pcm-whistler.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -387,14 +388,12 @@ int bcm63xx_soc_platform_probe(struct platform_device *pdev, { int ret; - i2s_priv->r_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!i2s_priv->r_irq) { - dev_err(&pdev->dev, "Unable to get register irq resource.\n"); - return -ENODEV; - } + ret = platform_get_irq(pdev, 0); + if (ret < 0) + return ret; - ret = devm_request_irq(&pdev->dev, i2s_priv->r_irq->start, i2s_dma_isr, - i2s_priv->r_irq->flags, "i2s_dma", (void *)i2s_priv); + ret = devm_request_irq(&pdev->dev, ret, i2s_dma_isr, + irq_get_trigger_type(ret), "i2s_dma", (void *)i2s_priv); if (ret) { dev_err(&pdev->dev, "i2s_init: failed to request interrupt.ret=%d\n", ret); From 70ba14cf6dfd7ebd1275562bb9637b8d0ddb8f49 Mon Sep 17 00:00:00 2001 From: Vincent Knecht Date: Mon, 20 Dec 2021 20:37:24 +0100 Subject: [PATCH 266/327] ASoC: dt-bindings: codecs: Add bindings for ak4375 AK4375 is an audio DAC with headphones amplifier controlled via I2C. Add simple device tree bindings that describe how to set it up. Reviewed-by: Rob Herring Signed-off-by: Vincent Knecht Link: https://lore.kernel.org/r/20211220193725.2650356-1-vincent.knecht@mailoo.org Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/ak4375.yaml | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/ak4375.yaml diff --git a/Documentation/devicetree/bindings/sound/ak4375.yaml b/Documentation/devicetree/bindings/sound/ak4375.yaml new file mode 100644 index 0000000000000..f1d5074a024d9 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ak4375.yaml @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/ak4375.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: AK4375 DAC and headphones amplifier Device Tree Bindings + +maintainers: + - Vincent Knecht + +properties: + compatible: + const: asahi-kasei,ak4375 + + reg: + maxItems: 1 + + '#sound-dai-cells': + const: 0 + + avdd-supply: + description: regulator phandle for the AVDD power supply. + + tvdd-supply: + description: regulator phandle for the TVDD power supply. + + pdn-gpios: + description: optional GPIO to set the PDN pin. + +required: + - compatible + - reg + - '#sound-dai-cells' + - avdd-supply + - tvdd-supply + +additionalProperties: false + +examples: + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + headphones: audio-codec@10 { + compatible = "asahi-kasei,ak4375"; + reg = <0x10>; + avdd-supply = <®_headphones_avdd>; + tvdd-supply = <&pm8916_l6>; + pdn-gpios = <&msmgpio 114 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&headphones_pdn_default>; + #sound-dai-cells = <0>; + }; + }; From 53778b8292b5492ec3ecf1efb84163eac2a6e422 Mon Sep 17 00:00:00 2001 From: Vincent Knecht Date: Mon, 20 Dec 2021 20:37:25 +0100 Subject: [PATCH 267/327] ASoC: Add AK4375 support AK4375 is a 32-bit stereo DAC with headphones amplifier. There's no documentation for it on akm.com, and only a brief datasheet can be found floating on the internets [1]. Thanks to Oriane BAYERD for finally answering my inquiries through akm.com, if only to tell me that this chip is EOL following AKM factory burning in october 2020 and thus no detailed documentation is available anymore... AK4331 is advertised [2] as pin and register compatible with AK4375 so some scraps of its datasheet were used and this driver might be used as a base for it, but this is totally untested. So this driver is mainly based on downstream code [3] and [4] by Hu Jin from AKM (no known email). Tested on msm8916-alcatel-idol347 and msm8939-alcatel-idol3, which both use PLL driven clock with bypass of SRC (sample rate converter), so only this setup is supported for now. [1] https://datasheetspdf.com/pdf-file/1400317/AKM/AK4375A/1 [2] https://www.akm.com/content/dam/documents/products/audio/audio-dac/ak4331ecb/ak4331ecb-en-datasheet.pdf [3] https://github.com/msm8916-mainline/android_kernel_qcom_msm8916/blob/alcatel-idol347/sound/soc/codecs/idol347/ak4375.c [4] https://github.com/msm8916-mainline/android_kernel_qcom_msm8916/blob/alcatel-idol347/sound/soc/codecs/ak4375.c Signed-off-by: Vincent Knecht Link: https://lore.kernel.org/r/20211220193725.2650356-2-vincent.knecht@mailoo.org Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 11 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/ak4375.c | 619 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 632 insertions(+) create mode 100644 sound/soc/codecs/ak4375.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 22836ca9b4789..5fe9ec9248642 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -41,6 +41,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_ADS117X imply SND_SOC_AK4104 imply SND_SOC_AK4118 + imply SND_SOC_AK4375 imply SND_SOC_AK4458 imply SND_SOC_AK4535 imply SND_SOC_AK4554 @@ -523,6 +524,16 @@ config SND_SOC_AK4118 depends on I2C select REGMAP_I2C +config SND_SOC_AK4375 + tristate "AKM AK4375 CODEC" + depends on I2C + select REGMAP_I2C + help + Enable support for the Asahi-Kasei AK4375 codec. + + To compile this driver as a module, choose M here: the module + will be called snd-soc-ak4375. + config SND_SOC_AK4458 tristate "AKM AK4458 CODEC" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 24bc6b34ba2f4..8dbdf3518bda4 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -34,6 +34,7 @@ snd-soc-adav803-objs := adav803.o snd-soc-ads117x-objs := ads117x.o snd-soc-ak4104-objs := ak4104.o snd-soc-ak4118-objs := ak4118.o +snd-soc-ak4375-objs := ak4375.o snd-soc-ak4458-objs := ak4458.o snd-soc-ak4535-objs := ak4535.o snd-soc-ak4554-objs := ak4554.o @@ -371,6 +372,7 @@ obj-$(CONFIG_SND_SOC_ADAV803) += snd-soc-adav803.o obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o obj-$(CONFIG_SND_SOC_AK4118) += snd-soc-ak4118.o +obj-$(CONFIG_SND_SOC_AK4375) += snd-soc-ak4375.o obj-$(CONFIG_SND_SOC_AK4458) += snd-soc-ak4458.o obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o obj-$(CONFIG_SND_SOC_AK4554) += snd-soc-ak4554.o diff --git a/sound/soc/codecs/ak4375.c b/sound/soc/codecs/ak4375.c new file mode 100644 index 0000000000000..a893aff42a017 --- /dev/null +++ b/sound/soc/codecs/ak4375.c @@ -0,0 +1,619 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Based on code by Hu Jin + * Copyright (C) 2014 Asahi Kasei Microdevices Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Registers and fields */ +#define AK4375_00_POWER_MANAGEMENT1 0x00 +#define PMPLL BIT(0) /* 0: PLL off, 1: PLL on */ +#define AK4375_01_POWER_MANAGEMENT2 0x01 +#define PMCP1 BIT(0) /* Charge Pump 1: LDO1 and DAC */ +#define PMCP2 BIT(1) /* Charge Pump 2: Class-G HP Amp */ +#define PMLDO1P BIT(4) +#define PMLDO1N BIT(5) +#define PMLDO (PMLDO1P | PMLDO1N) +#define AK4375_02_POWER_MANAGEMENT3 0x02 +#define AK4375_03_POWER_MANAGEMENT4 0x03 +#define AK4375_04_OUTPUT_MODE_SETTING 0x04 +#define AK4375_05_CLOCK_MODE_SELECT 0x05 +#define FS_MASK GENMASK(4, 0) +#define FS_8KHZ 0x00 +#define FS_11_025KHZ 0x01 +#define FS_16KHZ 0x04 +#define FS_22_05KHZ 0x05 +#define FS_32KHZ 0x08 +#define FS_44_1KHZ 0x09 +#define FS_48KHZ 0x0a +#define FS_88_2KHZ 0x0d +#define FS_96KHZ 0x0e +#define FS_176_4KHZ 0x11 +#define FS_192KHZ 0x12 +#define CM_MASK GENMASK(6, 5) /* For SRC Bypass mode */ +#define CM_0 (0x0 << 5) +#define CM_1 (0x1 << 5) +#define CM_2 (0x2 << 5) +#define CM_3 (0x3 << 5) +#define AK4375_06_DIGITAL_FILTER_SELECT 0x06 +#define DADFSEL BIT(5) /* 0: in SRC Bypass mode, 1: in SRC mode */ +#define DASL BIT(6) +#define DASD BIT(7) +#define AK4375_07_DAC_MONO_MIXING 0x07 +#define DACMUTE_MASK (GENMASK(5, 4) | GENMASK(1, 0)) /* Clear to mute */ +#define AK4375_08_JITTER_CLEANER_SETTING1 0x08 +#define AK4375_09_JITTER_CLEANER_SETTING2 0x09 +#define AK4375_0A_JITTER_CLEANER_SETTING3 0x0a +#define SELDAIN BIT(1) /* 0: SRC Bypass mode, 1: SRC mode */ +#define XCKSEL BIT(6) /* 0: PLL0, 1: MCKI */ +#define XCKCPSEL BIT(7) /* Should be equal to SELDAIN and XCKSEL */ +#define AK4375_0B_LCH_OUTPUT_VOLUME 0x0b +#define AK4375_0C_RCH_OUTPUT_VOLUME 0x0c +#define AK4375_0D_HP_VOLUME_CONTROL 0x0d +#define AK4375_0E_PLL_CLK_SOURCE_SELECT 0x0e +#define PLS BIT(0) /* 0: MCKI, 1: BCLK */ +#define AK4375_0F_PLL_REF_CLK_DIVIDER1 0x0f /* Reference clock divider [15:8] bits */ +#define AK4375_10_PLL_REF_CLK_DIVIDER2 0x10 /* Reference clock divider [7:0] bis */ +#define AK4375_11_PLL_FB_CLK_DIVIDER1 0x11 /* Feedback clock divider [15:8] bits */ +#define AK4375_12_PLL_FB_CLK_DIVIDER2 0x12 /* Feedback clock divider [7:0] bits */ +#define AK4375_13_SRC_CLK_SOURCE 0x13 /* SRC Bypass: SRCCKS=XCKSEL=SELDAIN=0 */ +#define SRCCKS BIT(0) /* SRC Clock source 0: MCKI, 1: PLL0 */ +#define DIV BIT(4) +#define AK4375_14_DAC_CLK_DIVIDER 0x14 +#define AK4375_15_AUDIO_IF_FORMAT 0x15 +#define DEVICEID_MASK GENMASK(7, 5) +#define AK4375_24_MODE_CONTROL 0x24 + +#define AK4375_PLL_FREQ_OUT_112896000 112896000 /* 44.1 kHz base rate */ +#define AK4375_PLL_FREQ_OUT_122880000 122880000 /* 32 and 48 kHz base rates */ + +#define DEVICEID_AK4375 0x00 +#define DEVICEID_AK4375A 0x01 +#define DEVICEID_AK4376A 0x02 +#define DEVICEID_AK4377 0x03 +#define DEVICEID_AK4331 0x07 + +static const char * const supply_names[] = { + "avdd", "tvdd" +}; + +struct ak4375_drvdata { + struct snd_soc_dai_driver *dai_drv; + const struct snd_soc_component_driver *comp_drv; +}; + +struct ak4375_priv { + struct device *dev; + struct regmap *regmap; + struct gpio_desc *pdn_gpiod; + struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; + unsigned int rate; + unsigned int pld; + u8 mute_save; +}; + +static const struct reg_default ak4375_reg_defaults[] = { + { 0x00, 0x00 }, { 0x01, 0x00 }, { 0x02, 0x00 }, + { 0x03, 0x00 }, { 0x04, 0x00 }, { 0x05, 0x00 }, + { 0x06, 0x00 }, { 0x07, 0x00 }, { 0x08, 0x00 }, + { 0x09, 0x00 }, { 0x0a, 0x00 }, { 0x0b, 0x19 }, + { 0x0c, 0x19 }, { 0x0d, 0x75 }, { 0x0e, 0x01 }, + { 0x0f, 0x00 }, { 0x10, 0x00 }, { 0x11, 0x00 }, + { 0x12, 0x00 }, { 0x13, 0x00 }, { 0x14, 0x00 }, + { 0x15, 0x00 }, { 0x24, 0x00 }, +}; + +/* + * Output Digital volume control: + * from -12.5 to 3 dB in 0.5 dB steps (mute instead of -12.5 dB) + */ +static DECLARE_TLV_DB_SCALE(dac_tlv, -1250, 50, 0); + +/* + * HP-Amp Analog volume control: + * from -4.2 to 6 dB in 2 dB steps (mute instead of -4.2 dB) + */ +static DECLARE_TLV_DB_SCALE(hpg_tlv, -4200, 20, 0); + +static const char * const ak4375_ovolcn_select_texts[] = { "Dependent", "Independent" }; +static const char * const ak4375_mdac_select_texts[] = { "x1", "x1/2" }; +static const char * const ak4375_inv_select_texts[] = { "Normal", "Inverting" }; +static const char * const ak4375_cpmode_select_texts[] = { + "Automatic Switching", + "+-VDD Operation", + "+-1/2VDD Operation" +}; + +/* + * DASD, DASL bits Digital Filter Setting + * 0, 0 : Sharp Roll-Off Filter + * 0, 1 : Slow Roll-Off Filter + * 1, 0 : Short delay Sharp Roll-Off Filter + * 1, 1 : Short delay Slow Roll-Off Filter + */ +static const char * const ak4375_digfil_select_texts[] = { + "Sharp Roll-Off Filter", + "Slow Roll-Off Filter", + "Short delay Sharp Roll-Off Filter", + "Short delay Slow Roll-Off Filter", +}; + +static const struct soc_enum ak4375_ovolcn_enum = + SOC_ENUM_SINGLE(AK4375_0B_LCH_OUTPUT_VOLUME, 7, + ARRAY_SIZE(ak4375_ovolcn_select_texts), ak4375_ovolcn_select_texts); +static const struct soc_enum ak4375_mdacl_enum = + SOC_ENUM_SINGLE(AK4375_07_DAC_MONO_MIXING, 2, + ARRAY_SIZE(ak4375_mdac_select_texts), ak4375_mdac_select_texts); +static const struct soc_enum ak4375_mdacr_enum = + SOC_ENUM_SINGLE(AK4375_07_DAC_MONO_MIXING, 6, + ARRAY_SIZE(ak4375_mdac_select_texts), ak4375_mdac_select_texts); +static const struct soc_enum ak4375_invl_enum = + SOC_ENUM_SINGLE(AK4375_07_DAC_MONO_MIXING, 3, + ARRAY_SIZE(ak4375_inv_select_texts), ak4375_inv_select_texts); +static const struct soc_enum ak4375_invr_enum = + SOC_ENUM_SINGLE(AK4375_07_DAC_MONO_MIXING, 7, + ARRAY_SIZE(ak4375_inv_select_texts), ak4375_inv_select_texts); +static const struct soc_enum ak4375_cpmode_enum = + SOC_ENUM_SINGLE(AK4375_03_POWER_MANAGEMENT4, 2, + ARRAY_SIZE(ak4375_cpmode_select_texts), ak4375_cpmode_select_texts); +static const struct soc_enum ak4375_digfil_enum = + SOC_ENUM_SINGLE(AK4375_06_DIGITAL_FILTER_SELECT, 6, + ARRAY_SIZE(ak4375_digfil_select_texts), ak4375_digfil_select_texts); + +static const struct snd_kcontrol_new ak4375_snd_controls[] = { + SOC_DOUBLE_R_TLV("Digital Output Volume", AK4375_0B_LCH_OUTPUT_VOLUME, + AK4375_0C_RCH_OUTPUT_VOLUME, 0, 0x1f, 0, dac_tlv), + SOC_SINGLE_TLV("HP-Amp Analog Volume", + AK4375_0D_HP_VOLUME_CONTROL, 0, 0x1f, 0, hpg_tlv), + + SOC_ENUM("Digital Volume Control", ak4375_ovolcn_enum), + SOC_ENUM("DACL Signal Level", ak4375_mdacl_enum), + SOC_ENUM("DACR Signal Level", ak4375_mdacr_enum), + SOC_ENUM("DACL Signal Invert", ak4375_invl_enum), + SOC_ENUM("DACR Signal Invert", ak4375_invr_enum), + SOC_ENUM("Charge Pump Mode", ak4375_cpmode_enum), + SOC_ENUM("DAC Digital Filter Mode", ak4375_digfil_enum), +}; + +static const struct snd_kcontrol_new ak4375_hpl_mixer_controls[] = { + SOC_DAPM_SINGLE("LDACL Switch", AK4375_07_DAC_MONO_MIXING, 0, 1, 0), + SOC_DAPM_SINGLE("RDACL Switch", AK4375_07_DAC_MONO_MIXING, 1, 1, 0), +}; + +static const struct snd_kcontrol_new ak4375_hpr_mixer_controls[] = { + SOC_DAPM_SINGLE("LDACR Switch", AK4375_07_DAC_MONO_MIXING, 4, 1, 0), + SOC_DAPM_SINGLE("RDACR Switch", AK4375_07_DAC_MONO_MIXING, 5, 1, 0), +}; + +static int ak4375_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, AK4375_00_POWER_MANAGEMENT1, PMPLL, PMPLL); + snd_soc_component_update_bits(component, AK4375_01_POWER_MANAGEMENT2, PMCP1, PMCP1); + usleep_range(6500, 7000); + snd_soc_component_update_bits(component, AK4375_01_POWER_MANAGEMENT2, PMLDO, PMLDO); + usleep_range(1000, 2000); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_update_bits(component, AK4375_01_POWER_MANAGEMENT2, PMCP2, PMCP2); + usleep_range(4500, 5000); + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_component_update_bits(component, AK4375_01_POWER_MANAGEMENT2, PMCP2, 0x0); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, AK4375_01_POWER_MANAGEMENT2, PMLDO, 0x0); + snd_soc_component_update_bits(component, AK4375_01_POWER_MANAGEMENT2, PMCP1, 0x0); + snd_soc_component_update_bits(component, AK4375_00_POWER_MANAGEMENT1, PMPLL, 0x0); + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget ak4375_dapm_widgets[] = { + SND_SOC_DAPM_DAC_E("DAC", NULL, AK4375_02_POWER_MANAGEMENT3, 0, 0, ak4375_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_AIF_IN("SDTI", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_OUTPUT("HPL"), + SND_SOC_DAPM_OUTPUT("HPR"), + + SND_SOC_DAPM_MIXER("HPR Mixer", AK4375_03_POWER_MANAGEMENT4, 1, 0, + &ak4375_hpr_mixer_controls[0], ARRAY_SIZE(ak4375_hpr_mixer_controls)), + SND_SOC_DAPM_MIXER("HPL Mixer", AK4375_03_POWER_MANAGEMENT4, 0, 0, + &ak4375_hpl_mixer_controls[0], ARRAY_SIZE(ak4375_hpl_mixer_controls)), +}; + +static const struct snd_soc_dapm_route ak4375_intercon[] = { + { "DAC", NULL, "SDTI" }, + + { "HPL Mixer", "LDACL Switch", "DAC" }, + { "HPL Mixer", "RDACL Switch", "DAC" }, + { "HPR Mixer", "LDACR Switch", "DAC" }, + { "HPR Mixer", "RDACR Switch", "DAC" }, + + { "HPL", NULL, "HPL Mixer" }, + { "HPR", NULL, "HPR Mixer" }, +}; + +static int ak4375_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct ak4375_priv *ak4375 = snd_soc_component_get_drvdata(component); + unsigned int freq_in, freq_out; + + ak4375->rate = params_rate(params); + + if (ak4375->rate <= 96000) + ak4375->pld = 0; + else + ak4375->pld = 1; + + freq_in = 32 * ak4375->rate / (ak4375->pld + 1); + + if ((ak4375->rate % 8000) == 0) + freq_out = AK4375_PLL_FREQ_OUT_122880000; + else + freq_out = AK4375_PLL_FREQ_OUT_112896000; + + return snd_soc_dai_set_pll(dai, 0, 0, freq_in, freq_out); +} + +static int ak4375_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source, + unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_component *component = dai->component; + struct ak4375_priv *ak4375 = snd_soc_component_get_drvdata(component); + unsigned int mclk, plm, mdiv, div; + u8 cms, fs, cm; + + cms = snd_soc_component_read(component, AK4375_05_CLOCK_MODE_SELECT); + fs = cms & ~FS_MASK; + cm = cms & ~CM_MASK; + + switch (ak4375->rate) { + case 8000: + fs |= FS_8KHZ; + break; + case 11025: + fs |= FS_11_025KHZ; + break; + case 16000: + fs |= FS_16KHZ; + break; + case 22050: + fs |= FS_22_05KHZ; + break; + case 32000: + fs |= FS_32KHZ; + break; + case 44100: + fs |= FS_44_1KHZ; + break; + case 48000: + fs |= FS_48KHZ; + break; + case 88200: + fs |= FS_88_2KHZ; + break; + case 96000: + fs |= FS_96KHZ; + break; + case 176400: + fs |= FS_176_4KHZ; + break; + case 192000: + fs |= FS_192KHZ; + break; + default: + return -EINVAL; + } + + if (ak4375->rate <= 24000) { + cm |= CM_1; + mclk = 512 * ak4375->rate; + mdiv = freq_out / mclk - 1; + div = 0; + } else if (ak4375->rate <= 96000) { + cm |= CM_0; + mclk = 256 * ak4375->rate; + mdiv = freq_out / mclk - 1; + div = 0; + } else { + cm |= CM_3; + mclk = 128 * ak4375->rate; + mdiv = 4; + div = 1; + } + + /* Writing both fields in one go seems to make playback choppy on start */ + snd_soc_component_update_bits(component, AK4375_05_CLOCK_MODE_SELECT, FS_MASK, fs); + snd_soc_component_update_bits(component, AK4375_05_CLOCK_MODE_SELECT, CM_MASK, cm); + + snd_soc_component_write(component, AK4375_0F_PLL_REF_CLK_DIVIDER1, + (ak4375->pld & 0xff00) >> 8); + snd_soc_component_write(component, AK4375_10_PLL_REF_CLK_DIVIDER2, + ak4375->pld & 0x00ff); + + plm = freq_out / freq_in - 1; + snd_soc_component_write(component, AK4375_11_PLL_FB_CLK_DIVIDER1, (plm & 0xff00) >> 8); + snd_soc_component_write(component, AK4375_12_PLL_FB_CLK_DIVIDER2, plm & 0x00ff); + + snd_soc_component_update_bits(component, AK4375_13_SRC_CLK_SOURCE, DIV, div); + + /* SRCCKS bit: force to 1 for SRC PLL source clock */ + snd_soc_component_update_bits(component, AK4375_13_SRC_CLK_SOURCE, SRCCKS, SRCCKS); + + snd_soc_component_write(component, AK4375_14_DAC_CLK_DIVIDER, mdiv); + + dev_dbg(ak4375->dev, "rate=%d mclk=%d f_in=%d f_out=%d PLD=%d PLM=%d MDIV=%d DIV=%d\n", + ak4375->rate, mclk, freq_in, freq_out, ak4375->pld, plm, mdiv, div); + + return 0; +} + +static int ak4375_mute(struct snd_soc_dai *dai, int mute, int direction) +{ + struct snd_soc_component *component = dai->component; + struct ak4375_priv *ak4375 = snd_soc_component_get_drvdata(component); + u8 val = snd_soc_component_read(component, AK4375_07_DAC_MONO_MIXING); + + dev_dbg(ak4375->dev, "mute=%d val=%d\n", mute, val); + + if (mute) { + ak4375->mute_save = val & DACMUTE_MASK; + val &= ~DACMUTE_MASK; + } else { + val |= ak4375->mute_save; + } + + snd_soc_component_write(component, AK4375_07_DAC_MONO_MIXING, val); + + return 0; +} + +#define AK4375_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000) + +#define AK4375_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static const struct snd_soc_dai_ops ak4375_dai_ops = { + .hw_params = ak4375_hw_params, + .mute_stream = ak4375_mute, + .set_pll = ak4375_dai_set_pll, +}; + +static struct snd_soc_dai_driver ak4375_dai = { + .name = "ak4375-hifi", + .playback = { + .stream_name = "HiFi Playback", + .channels_min = 1, + .channels_max = 2, + .rates = AK4375_RATES, + .rate_min = 8000, + .rate_max = 192000, + .formats = AK4375_FORMATS, + }, + .ops = &ak4375_dai_ops, +}; + +static void ak4375_power_off(struct ak4375_priv *ak4375) +{ + gpiod_set_value_cansleep(ak4375->pdn_gpiod, 0); + usleep_range(1000, 2000); + + regulator_bulk_disable(ARRAY_SIZE(ak4375->supplies), ak4375->supplies); +} + +static int ak4375_power_on(struct ak4375_priv *ak4375) +{ + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(ak4375->supplies), ak4375->supplies); + if (ret < 0) { + dev_err(ak4375->dev, "Failed to enable regulators: %d\n", ret); + return ret; + } + + usleep_range(3000, 4000); + + gpiod_set_value_cansleep(ak4375->pdn_gpiod, 1); + usleep_range(1000, 2000); + + return 0; +} + +#ifdef CONFIG_PM +static int __maybe_unused ak4375_runtime_suspend(struct device *dev) +{ + struct ak4375_priv *ak4375 = dev_get_drvdata(dev); + + regcache_cache_only(ak4375->regmap, true); + ak4375_power_off(ak4375); + + return 0; +} + +static int __maybe_unused ak4375_runtime_resume(struct device *dev) +{ + struct ak4375_priv *ak4375 = dev_get_drvdata(dev); + int ret; + + ret = ak4375_power_on(ak4375); + if (ret < 0) + return ret; + + regcache_cache_only(ak4375->regmap, false); + regcache_mark_dirty(ak4375->regmap); + + return regcache_sync(ak4375->regmap); +} +#endif /* CONFIG_PM */ + +static const struct snd_soc_component_driver soc_codec_dev_ak4375 = { + .controls = ak4375_snd_controls, + .num_controls = ARRAY_SIZE(ak4375_snd_controls), + .dapm_widgets = ak4375_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ak4375_dapm_widgets), + .dapm_routes = ak4375_intercon, + .num_dapm_routes = ARRAY_SIZE(ak4375_intercon), + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + +static const struct regmap_config ak4375_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = AK4375_24_MODE_CONTROL, + .reg_defaults = ak4375_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(ak4375_reg_defaults), + .cache_type = REGCACHE_RBTREE, +}; + +static const struct ak4375_drvdata ak4375_drvdata = { + .dai_drv = &ak4375_dai, + .comp_drv = &soc_codec_dev_ak4375, +}; + +static const struct dev_pm_ops ak4375_pm = { + SET_RUNTIME_PM_OPS(ak4375_runtime_suspend, ak4375_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static int ak4375_i2c_probe(struct i2c_client *i2c) +{ + struct ak4375_priv *ak4375; + const struct ak4375_drvdata *drvdata; + unsigned int deviceid; + int ret, i; + + ak4375 = devm_kzalloc(&i2c->dev, sizeof(*ak4375), GFP_KERNEL); + if (!ak4375) + return -ENOMEM; + + ak4375->regmap = devm_regmap_init_i2c(i2c, &ak4375_regmap); + if (IS_ERR(ak4375->regmap)) + return PTR_ERR(ak4375->regmap); + + i2c_set_clientdata(i2c, ak4375); + ak4375->dev = &i2c->dev; + + drvdata = of_device_get_match_data(&i2c->dev); + + for (i = 0; i < ARRAY_SIZE(supply_names); i++) + ak4375->supplies[i].supply = supply_names[i]; + + ret = devm_regulator_bulk_get(ak4375->dev, ARRAY_SIZE(ak4375->supplies), ak4375->supplies); + if (ret < 0) { + dev_err(ak4375->dev, "Failed to get regulators: %d\n", ret); + return ret; + } + + ak4375->pdn_gpiod = devm_gpiod_get_optional(ak4375->dev, "pdn", GPIOD_OUT_LOW); + if (IS_ERR(ak4375->pdn_gpiod)) + return dev_err_probe(ak4375->dev, PTR_ERR(ak4375->pdn_gpiod), + "failed to get pdn\n"); + + ret = ak4375_power_on(ak4375); + if (ret < 0) + return ret; + + /* Don't read deviceid from cache */ + regcache_cache_bypass(ak4375->regmap, true); + + ret = regmap_read(ak4375->regmap, AK4375_15_AUDIO_IF_FORMAT, &deviceid); + if (ret < 0) { + dev_err(ak4375->dev, "unable to read DEVICEID!\n"); + return ret; + } + + regcache_cache_bypass(ak4375->regmap, false); + + deviceid = (deviceid & DEVICEID_MASK) >> 5; + + switch (deviceid) { + case DEVICEID_AK4331: + dev_err(ak4375->dev, "found untested AK4331\n"); + return -EINVAL; + case DEVICEID_AK4375: + dev_dbg(ak4375->dev, "found AK4375\n"); + break; + case DEVICEID_AK4375A: + dev_dbg(ak4375->dev, "found AK4375A\n"); + break; + case DEVICEID_AK4376A: + dev_err(ak4375->dev, "found unsupported AK4376/A!\n"); + return -EINVAL; + case DEVICEID_AK4377: + dev_err(ak4375->dev, "found unsupported AK4377!\n"); + return -EINVAL; + default: + dev_err(ak4375->dev, "unrecognized DEVICEID!\n"); + return -EINVAL; + } + + pm_runtime_set_active(ak4375->dev); + pm_runtime_enable(ak4375->dev); + + ret = devm_snd_soc_register_component(ak4375->dev, drvdata->comp_drv, + drvdata->dai_drv, 1); + if (ret < 0) { + dev_err(ak4375->dev, "Failed to register CODEC: %d\n", ret); + return ret; + } + + return 0; +} + +static int ak4375_i2c_remove(struct i2c_client *i2c) +{ + pm_runtime_disable(&i2c->dev); + + return 0; +} + +static const struct of_device_id ak4375_of_match[] = { + { .compatible = "asahi-kasei,ak4375", .data = &ak4375_drvdata }, + { }, +}; +MODULE_DEVICE_TABLE(of, ak4375_of_match); + +static struct i2c_driver ak4375_i2c_driver = { + .driver = { + .name = "ak4375", + .pm = &ak4375_pm, + .of_match_table = ak4375_of_match, + }, + .probe_new = ak4375_i2c_probe, + .remove = ak4375_i2c_remove, +}; +module_i2c_driver(ak4375_i2c_driver); + +MODULE_AUTHOR("Vincent Knecht "); +MODULE_DESCRIPTION("ASoC AK4375 DAC driver"); +MODULE_LICENSE("GPL"); From 0d422a466ef7fdbbe402194ac06144d1bbcdc227 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Sat, 18 Dec 2021 15:34:21 +0100 Subject: [PATCH 268/327] ASoC: dt-bindings: Use name-prefix schema name-prefix.txt does not exist anymore, just reference the schema instead. Signed-off-by: Alexander Stein Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20211218143423.18768-1-alexander.stein@mailbox.org Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/simple-audio-amplifier.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/simple-audio-amplifier.yaml b/Documentation/devicetree/bindings/sound/simple-audio-amplifier.yaml index 26379377a7ac3..8327846356d30 100644 --- a/Documentation/devicetree/bindings/sound/simple-audio-amplifier.yaml +++ b/Documentation/devicetree/bindings/sound/simple-audio-amplifier.yaml @@ -9,6 +9,9 @@ title: Simple Audio Amplifier Device Tree Bindings maintainers: - Jerome Brunet +allOf: + - $ref: name-prefix.yaml# + properties: compatible: enum: @@ -22,10 +25,7 @@ properties: description: > power supply for the device - sound-name-prefix: - $ref: /schemas/types.yaml#/definitions/string - description: > - See ./name-prefix.txt + sound-name-prefix: true required: - compatible From 847cbea6459d5beb3f0f960fde4337f28b663eae Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Sat, 18 Dec 2021 15:34:22 +0100 Subject: [PATCH 269/327] ASoC: meson: t9015: add missing sound-name-prefix property This is used in meson-gxl and meson-g12-common .dtsi. Add the property to the binding. This fixes the dtschema warning: audio-controller@32000: 'sound-name-prefix' does not match any of the regexes: 'pinctrl-[0-9]+' Signed-off-by: Alexander Stein Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20211218143423.18768-2-alexander.stein@mailbox.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/amlogic,t9015.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/amlogic,t9015.yaml b/Documentation/devicetree/bindings/sound/amlogic,t9015.yaml index db7b04da0b394..580a3d040abca 100644 --- a/Documentation/devicetree/bindings/sound/amlogic,t9015.yaml +++ b/Documentation/devicetree/bindings/sound/amlogic,t9015.yaml @@ -9,6 +9,9 @@ title: Amlogic T9015 Internal Audio DAC maintainers: - Jerome Brunet +allOf: + - $ref: name-prefix.yaml# + properties: $nodename: pattern: "^audio-controller@.*" @@ -38,6 +41,8 @@ properties: description: Analogue power supply. + sound-name-prefix: true + required: - "#sound-dai-cells" - compatible From 1f6532073e3e9caee1dbc3f9b4be28359a181ea4 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Sat, 18 Dec 2021 15:34:23 +0100 Subject: [PATCH 270/327] ASoC: meson: g12a: add missing sound-name-prefix property This is used in meson-sm1 and meson-g12 .dtsi. Add the property to the binding. This fixes the dtschema warning: audio-controller@740: 'sound-name-prefix' does not match any of the regexes: 'pinctrl-[0-9]+' Signed-off-by: Alexander Stein Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20211218143423.18768-3-alexander.stein@mailbox.org Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/amlogic,g12a-toacodec.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/amlogic,g12a-toacodec.yaml b/Documentation/devicetree/bindings/sound/amlogic,g12a-toacodec.yaml index 3c3891d17238e..77469a45bb7a4 100644 --- a/Documentation/devicetree/bindings/sound/amlogic,g12a-toacodec.yaml +++ b/Documentation/devicetree/bindings/sound/amlogic,g12a-toacodec.yaml @@ -9,6 +9,9 @@ title: Amlogic G12a Internal DAC Control Glue maintainers: - Jerome Brunet +allOf: + - $ref: name-prefix.yaml# + properties: $nodename: pattern: "^audio-controller@.*" @@ -31,6 +34,8 @@ properties: resets: maxItems: 1 + sound-name-prefix: true + required: - "#sound-dai-cells" - compatible From 37daf8d9e0bd85a2859721aec28e1eb6e9973262 Mon Sep 17 00:00:00 2001 From: Vincent Knecht Date: Wed, 22 Dec 2021 14:54:03 +0100 Subject: [PATCH 271/327] ASoC: codecs: ak4375: Change invert controls to a stereo switch Don't use enums for DACL/DACR Signal Invert controls, and change them into a stereo "DAC Signal Invert Switch" control. Signed-off-by: Vincent Knecht Link: https://lore.kernel.org/r/20211222135403.2991657-1-vincent.knecht@mailoo.org Signed-off-by: Mark Brown --- sound/soc/codecs/ak4375.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/ak4375.c b/sound/soc/codecs/ak4375.c index a893aff42a017..22cda06993418 100644 --- a/sound/soc/codecs/ak4375.c +++ b/sound/soc/codecs/ak4375.c @@ -127,7 +127,6 @@ static DECLARE_TLV_DB_SCALE(hpg_tlv, -4200, 20, 0); static const char * const ak4375_ovolcn_select_texts[] = { "Dependent", "Independent" }; static const char * const ak4375_mdac_select_texts[] = { "x1", "x1/2" }; -static const char * const ak4375_inv_select_texts[] = { "Normal", "Inverting" }; static const char * const ak4375_cpmode_select_texts[] = { "Automatic Switching", "+-VDD Operation", @@ -157,12 +156,6 @@ static const struct soc_enum ak4375_mdacl_enum = static const struct soc_enum ak4375_mdacr_enum = SOC_ENUM_SINGLE(AK4375_07_DAC_MONO_MIXING, 6, ARRAY_SIZE(ak4375_mdac_select_texts), ak4375_mdac_select_texts); -static const struct soc_enum ak4375_invl_enum = - SOC_ENUM_SINGLE(AK4375_07_DAC_MONO_MIXING, 3, - ARRAY_SIZE(ak4375_inv_select_texts), ak4375_inv_select_texts); -static const struct soc_enum ak4375_invr_enum = - SOC_ENUM_SINGLE(AK4375_07_DAC_MONO_MIXING, 7, - ARRAY_SIZE(ak4375_inv_select_texts), ak4375_inv_select_texts); static const struct soc_enum ak4375_cpmode_enum = SOC_ENUM_SINGLE(AK4375_03_POWER_MANAGEMENT4, 2, ARRAY_SIZE(ak4375_cpmode_select_texts), ak4375_cpmode_select_texts); @@ -176,11 +169,11 @@ static const struct snd_kcontrol_new ak4375_snd_controls[] = { SOC_SINGLE_TLV("HP-Amp Analog Volume", AK4375_0D_HP_VOLUME_CONTROL, 0, 0x1f, 0, hpg_tlv), + SOC_DOUBLE("DAC Signal Invert Switch", AK4375_07_DAC_MONO_MIXING, 3, 7, 1, 0), + SOC_ENUM("Digital Volume Control", ak4375_ovolcn_enum), SOC_ENUM("DACL Signal Level", ak4375_mdacl_enum), SOC_ENUM("DACR Signal Level", ak4375_mdacr_enum), - SOC_ENUM("DACL Signal Invert", ak4375_invl_enum), - SOC_ENUM("DACR Signal Invert", ak4375_invr_enum), SOC_ENUM("Charge Pump Mode", ak4375_cpmode_enum), SOC_ENUM("DAC Digital Filter Mode", ak4375_digfil_enum), }; From 72b8ed83f7eccf84c54b68a551beae400949cc29 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 23 Dec 2021 13:36:09 +0200 Subject: [PATCH 272/327] ASoC: SOF: ops: Use dev_warn() if the panic offsets differ Catch the cases when the stored sdev->dsp_oops_offset and the offset received via the panic message differs and print a warning, but keep using the dsp_oops_offset for the oops query. Signed-off-by: Peter Ujfalusi Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211223113628.18582-2-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ops.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c index 160b88a2d59f6..1d6a95a00cf59 100644 --- a/sound/soc/sof/ops.c +++ b/sound/soc/sof/ops.c @@ -144,18 +144,23 @@ EXPORT_SYMBOL(snd_sof_dsp_update_bits_forced); void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset) { - dev_err(sdev->dev, "error : DSP panic!\n"); - /* - * check if DSP is not ready and did not set the dsp_oops_offset. - * if the dsp_oops_offset is not set, set it from the panic message. - * Also add a check to memory window setting with panic message. + * if DSP is not ready and the dsp_oops_offset is not yet set, use the + * offset from the panic message. */ if (!sdev->dsp_oops_offset) sdev->dsp_oops_offset = offset; - else - dev_dbg(sdev->dev, "panic: dsp_oops_offset %zu offset %d\n", - sdev->dsp_oops_offset, offset); + + /* + * Print warning if the offset from the panic message differs from + * dsp_oops_offset + */ + if (sdev->dsp_oops_offset != offset) + dev_warn(sdev->dev, + "%s: dsp_oops_offset %zu differs from panic offset %u\n", + __func__, sdev->dsp_oops_offset, offset); + + dev_err(sdev->dev, "DSP panic!\n"); /* We want to see the DSP panic! */ sdev->dbg_dump_printed = false; From b2539ef00e4427350b26896540ccabd98e88c7bb Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 23 Dec 2021 13:36:10 +0200 Subject: [PATCH 273/327] ASoC: SOF: Intel: hda-loader: Avoid re-defining the HDA_FW_BOOT_ATTEMPTS HDA_FW_BOOT_ATTEMPTS is defined in hda.h, do not define it again locally in hda-loader.c At the same time correct the indentation for the define in hda.h Signed-off-by: Peter Ujfalusi Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211223113628.18582-3-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-loader.c | 1 - sound/soc/sof/intel/hda.h | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index bfb0e374ebab6..5f5f396f4fb83 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -23,7 +23,6 @@ #include "../ops.h" #include "hda.h" -#define HDA_FW_BOOT_ATTEMPTS 3 #define HDA_CL_STREAM_FORMAT 0x40 static struct hdac_ext_stream *cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format, diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 5b4d59647a1d1..03a6bb7a165c6 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -273,7 +273,7 @@ #define BXT_D0I3_DELAY 5000 #define FW_CL_STREAM_NUMBER 0x1 -#define HDA_FW_BOOT_ATTEMPTS 3 +#define HDA_FW_BOOT_ATTEMPTS 3 /* ADSPCS - Audio DSP Control & Status */ From f902b21adba98f28eaa1cf5e509d99eaa7b1b36e Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 23 Dec 2021 13:36:11 +0200 Subject: [PATCH 274/327] ASoC: SOF: core: Add simple wrapper to check flags in sof_core_debug The sof_debug_check_flag() can be used to check a flag or a combination of them in sof_core_debug. Signed-off-by: Peter Ujfalusi Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211223113628.18582-4-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/core.c | 16 ++++++++++++++++ sound/soc/sof/sof-priv.h | 1 + 2 files changed, 17 insertions(+) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 40549cdd6d588..1224a7da053a6 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -27,6 +27,22 @@ MODULE_PARM_DESC(sof_debug, "SOF core debug options (0x0 all off)"); #define TIMEOUT_DEFAULT_IPC_MS 500 #define TIMEOUT_DEFAULT_BOOT_MS 2000 +/** + * sof_debug_check_flag - check if a given flag(s) is set in sof_core_debug + * @mask: Flag or combination of flags to check + * + * Returns true if all bits set in mask is also set in sof_core_debug, otherwise + * false + */ +bool sof_debug_check_flag(int mask) +{ + if ((sof_core_debug & mask) == mask) + return true; + + return false; +} +EXPORT_SYMBOL(sof_debug_check_flag); + /* * FW Panic/fault handling. */ diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 114882e4370f8..35c5b2d6930b8 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -43,6 +43,7 @@ /* global debug state set by SOF_DBG_ flags */ extern int sof_core_debug; +bool sof_debug_check_flag(int mask); /* max BARs mmaped devices can use */ #define SND_SOF_BARS 8 From 12b401f4de787627f4a25784a0278bbbf93122b6 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 23 Dec 2021 13:36:12 +0200 Subject: [PATCH 275/327] ASoC: SOF: Use sof_debug_check_flag() instead of sof_core_debug directly The sof_debug_check_flag() is available for checking flags set in sof_core_debug. sof_core_debug can be marked static in core.c Signed-off-by: Peter Ujfalusi Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211223113628.18582-5-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/core.c | 4 ++-- sound/soc/sof/debug.c | 6 +++--- sound/soc/sof/sof-priv.h | 1 - sound/soc/sof/topology.c | 12 ++++++------ 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 1224a7da053a6..00f8ffee2866b 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -19,7 +19,7 @@ #endif /* see SOF_DBG_ flags */ -int sof_core_debug = IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE); +static int sof_core_debug = IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE); module_param_named(sof_debug, sof_core_debug, int, 0444); MODULE_PARM_DESC(sof_debug, "SOF core debug options (0x0 all off)"); @@ -218,7 +218,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) goto fw_run_err; } - if (sof_core_debug & SOF_DBG_ENABLE_TRACE) { + if (sof_debug_check_flag(SOF_DBG_ENABLE_TRACE)) { sdev->dtrace_is_supported = true; /* init DMA trace */ diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 2f8b5ac9b78a2..9e4a128b59184 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -957,7 +957,7 @@ static void snd_sof_dbg_print_fw_state(struct snd_sof_dev *sdev) void snd_sof_dsp_dbg_dump(struct snd_sof_dev *sdev, u32 flags) { - bool print_all = !!(sof_core_debug & SOF_DBG_PRINT_ALL_DUMPS); + bool print_all = sof_debug_check_flag(SOF_DBG_PRINT_ALL_DUMPS); if (flags & SOF_DBG_DUMP_OPTIONAL && !print_all) return; @@ -979,7 +979,7 @@ static void snd_sof_ipc_dump(struct snd_sof_dev *sdev) dev_err(sdev->dev, "------------[ IPC dump start ]------------\n"); sof_ops(sdev)->ipc_dump(sdev); dev_err(sdev->dev, "------------[ IPC dump end ]------------\n"); - if (!(sof_core_debug & SOF_DBG_PRINT_ALL_DUMPS)) + if (!sof_debug_check_flag(SOF_DBG_PRINT_ALL_DUMPS)) sdev->ipc_dump_printed = true; } } @@ -987,7 +987,7 @@ static void snd_sof_ipc_dump(struct snd_sof_dev *sdev) void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev) { if (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_RETAIN_DSP_CONTEXT) || - (sof_core_debug & SOF_DBG_RETAIN_CTX)) { + sof_debug_check_flag(SOF_DBG_RETAIN_CTX)) { /* should we prevent DSP entering D3 ? */ if (!sdev->ipc_dump_printed) dev_info(sdev->dev, diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 35c5b2d6930b8..0f849cdbfbc82 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -42,7 +42,6 @@ #define SOF_DBG_DUMP_OPTIONAL BIT(4) /* only dump if SOF_DBG_PRINT_ALL_DUMPS is set */ /* global debug state set by SOF_DBG_ flags */ -extern int sof_core_debug; bool sof_debug_check_flag(int mask); /* max BARs mmaped devices can use */ diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index ec59baf32699d..e72dcae5e7ee7 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1695,12 +1695,12 @@ static int sof_widget_load_pipeline(struct snd_soc_component *scomp, int index, goto err; } - if (sof_core_debug & SOF_DBG_DISABLE_MULTICORE) + if (sof_debug_check_flag(SOF_DBG_DISABLE_MULTICORE)) pipeline->core = SOF_DSP_PRIMARY_CORE; - if (sof_core_debug & SOF_DBG_DYNAMIC_PIPELINES_OVERRIDE) - swidget->dynamic_pipeline_widget = sof_core_debug & - SOF_DBG_DYNAMIC_PIPELINES_ENABLE; + if (sof_debug_check_flag(SOF_DBG_DYNAMIC_PIPELINES_OVERRIDE)) + swidget->dynamic_pipeline_widget = + sof_debug_check_flag(SOF_DBG_DYNAMIC_PIPELINES_ENABLE); dev_dbg(scomp->dev, "pipeline %s: period %d pri %d mips %d core %d frames %d dynamic %d\n", swidget->widget->name, pipeline->period, pipeline->priority, @@ -2295,7 +2295,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, return ret; } - if (sof_core_debug & SOF_DBG_DISABLE_MULTICORE) + if (sof_debug_check_flag(SOF_DBG_DISABLE_MULTICORE)) comp.core = SOF_DSP_PRIMARY_CORE; swidget->core = comp.core; @@ -3542,7 +3542,7 @@ static int sof_complete(struct snd_soc_component *scomp) } /* verify topology components loading including dynamic pipelines */ - if (sof_core_debug & SOF_DBG_VERIFY_TPLG) { + if (sof_debug_check_flag(SOF_DBG_VERIFY_TPLG)) { ret = sof_set_up_pipelines(sdev, true); if (ret < 0) { dev_err(sdev->dev, "error: topology verification failed %d\n", ret); From b2b10aa79fe2fb3d3393d0e90ffb5c1802992412 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 23 Dec 2021 13:36:13 +0200 Subject: [PATCH 276/327] ASoC: SOF: Add 'non_recoverable' parameter to snd_sof_dsp_panic() Some platforms use retries during firmware boot to overcome DSP startup issues. In these cases we might receive a DSP panic message which should not be treated as fatal if it happens during boot. Pass this information to snd_sof_dsp_panic() and omit the panic print if it is not fatal or the user does not want to see all dumps. Signed-off-by: Peter Ujfalusi Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211223113628.18582-6-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/imx/imx8.c | 2 +- sound/soc/sof/imx/imx8m.c | 2 +- sound/soc/sof/intel/atom.c | 4 ++-- sound/soc/sof/intel/bdw.c | 4 ++-- sound/soc/sof/intel/cnl.c | 21 ++++++++++++++++++--- sound/soc/sof/intel/hda-ipc.c | 19 +++++++++++++++++-- sound/soc/sof/intel/hda-loader.c | 8 ++++++-- sound/soc/sof/ops.c | 24 ++++++++++++++++++------ sound/soc/sof/ops.h | 2 +- 9 files changed, 66 insertions(+), 20 deletions(-) diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c index 099b4356122cf..f6baecbb57fb2 100644 --- a/sound/soc/sof/imx/imx8.c +++ b/sound/soc/sof/imx/imx8.c @@ -97,7 +97,7 @@ static void imx8_dsp_handle_request(struct imx_dsp_ipc *ipc) /* Check to see if the message is a panic code (0x0dead***) */ if ((p & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) - snd_sof_dsp_panic(priv->sdev, p); + snd_sof_dsp_panic(priv->sdev, p, true); else snd_sof_ipc_msgs_rx(priv->sdev); } diff --git a/sound/soc/sof/imx/imx8m.c b/sound/soc/sof/imx/imx8m.c index c026caea4c8b2..788e77bcb6038 100644 --- a/sound/soc/sof/imx/imx8m.c +++ b/sound/soc/sof/imx/imx8m.c @@ -90,7 +90,7 @@ static void imx8m_dsp_handle_request(struct imx_dsp_ipc *ipc) /* Check to see if the message is a panic code (0x0dead***) */ if ((p & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) - snd_sof_dsp_panic(priv->sdev, p); + snd_sof_dsp_panic(priv->sdev, p, true); else snd_sof_ipc_msgs_rx(priv->sdev); } diff --git a/sound/soc/sof/intel/atom.c b/sound/soc/sof/intel/atom.c index 5aa064b28fcae..bcb2eb2acf2e2 100644 --- a/sound/soc/sof/intel/atom.c +++ b/sound/soc/sof/intel/atom.c @@ -165,8 +165,8 @@ irqreturn_t atom_irq_thread(int irq, void *context) /* Handle messages from DSP Core */ if ((ipcd & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { - snd_sof_dsp_panic(sdev, PANIC_OFFSET(ipcd) + - MBOX_OFFSET); + snd_sof_dsp_panic(sdev, PANIC_OFFSET(ipcd) + MBOX_OFFSET, + true); } else { snd_sof_ipc_msgs_rx(sdev); } diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 1121711e9029c..10c9a0b39371b 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -344,8 +344,8 @@ static irqreturn_t bdw_irq_thread(int irq, void *context) /* Handle messages from DSP Core */ if ((ipcd & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { - snd_sof_dsp_panic(sdev, BDW_PANIC_OFFSET(ipcx) + - MBOX_OFFSET); + snd_sof_dsp_panic(sdev, BDW_PANIC_OFFSET(ipcx) + MBOX_OFFSET, + true); } else { snd_sof_ipc_msgs_rx(sdev); } diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 3da158d08980a..e615125d575e2 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -82,9 +82,24 @@ irqreturn_t cnl_ipc_irq_thread(int irq, void *context) msg, msg_ext); /* handle messages from DSP */ - if ((hipctdr & SOF_IPC_PANIC_MAGIC_MASK) == - SOF_IPC_PANIC_MAGIC) { - snd_sof_dsp_panic(sdev, HDA_DSP_PANIC_OFFSET(msg_ext)); + if ((hipctdr & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + bool non_recoverable = true; + + /* + * This is a PANIC message! + * + * If it is arriving during firmware boot and it is not + * the last boot attempt then change the non_recoverable + * to false as the DSP might be able to boot in the next + * iteration(s) + */ + if (sdev->fw_state == SOF_FW_BOOT_IN_PROGRESS && + hda->boot_iteration < HDA_FW_BOOT_ATTEMPTS) + non_recoverable = false; + + snd_sof_dsp_panic(sdev, HDA_DSP_PANIC_OFFSET(msg_ext), + non_recoverable); } else { snd_sof_ipc_msgs_rx(sdev); } diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 2019087a84cec..f0cf8019d72dd 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -173,8 +173,23 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) /* handle messages from DSP */ if ((hipct & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { - /* this is a PANIC message !! */ - snd_sof_dsp_panic(sdev, HDA_DSP_PANIC_OFFSET(msg_ext)); + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + bool non_recoverable = true; + + /* + * This is a PANIC message! + * + * If it is arriving during firmware boot and it is not + * the last boot attempt then change the non_recoverable + * to false as the DSP might be able to boot in the next + * iteration(s) + */ + if (sdev->fw_state == SOF_FW_BOOT_IN_PROGRESS && + hda->boot_iteration < HDA_FW_BOOT_ATTEMPTS) + non_recoverable = false; + + snd_sof_dsp_panic(sdev, HDA_DSP_PANIC_OFFSET(msg_ext), + non_recoverable); } else { /* normal message - process normally */ snd_sof_ipc_msgs_rx(sdev); diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 5f5f396f4fb83..8ef16f1082e35 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -413,9 +413,13 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) hda_sdw_process_wakeen(sdev); /* - * at this point DSP ROM has been initialized and - * should be ready for code loading and firmware boot + * Set the boot_iteration to the last attempt, indicating that the + * DSP ROM has been initialized and from this point there will be no + * retry done to boot. + * + * Continue with code loading and firmware boot */ + hda->boot_iteration = HDA_FW_BOOT_ATTEMPTS; ret = cl_copy_fw(sdev, stream); if (!ret) { dev_dbg(sdev->dev, "Firmware download successful, booting...\n"); diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c index 1d6a95a00cf59..9abf7a8e55e08 100644 --- a/sound/soc/sof/ops.c +++ b/sound/soc/sof/ops.c @@ -142,7 +142,13 @@ void snd_sof_dsp_update_bits_forced(struct snd_sof_dev *sdev, u32 bar, } EXPORT_SYMBOL(snd_sof_dsp_update_bits_forced); -void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset) +/** + * snd_sof_dsp_panic - handle a received DSP panic message + * @sdev: Pointer to the device's sdev + * @offset: offset of panic information + * @non_recoverable: the panic is fatal, no recovery will be done by the caller + */ +void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset, bool non_recoverable) { /* * if DSP is not ready and the dsp_oops_offset is not yet set, use the @@ -160,12 +166,18 @@ void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset) "%s: dsp_oops_offset %zu differs from panic offset %u\n", __func__, sdev->dsp_oops_offset, offset); - dev_err(sdev->dev, "DSP panic!\n"); + /* + * Only print the panic information if we have non recoverable panic or + * if all dumps should be printed + */ + if (non_recoverable || sof_debug_check_flag(SOF_DBG_PRINT_ALL_DUMPS)) { + dev_err(sdev->dev, "DSP panic!\n"); - /* We want to see the DSP panic! */ - sdev->dbg_dump_printed = false; + /* We want to see the DSP panic! */ + sdev->dbg_dump_printed = false; - snd_sof_dsp_dbg_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX); - snd_sof_trace_notify_for_error(sdev); + snd_sof_dsp_dbg_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX); + snd_sof_trace_notify_for_error(sdev); + } } EXPORT_SYMBOL(snd_sof_dsp_panic); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index b0ffb2a93bcc2..bca7d35536e46 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -643,5 +643,5 @@ int snd_sof_dsp_register_poll(struct snd_sof_dev *sdev, u32 bar, u32 offset, u32 mask, u32 target, u32 timeout_ms, u32 interval_us); -void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset); +void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset, bool non_recoverable); #endif From 2f148430b96e975e895163d763bfc9c5088100eb Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 23 Dec 2021 13:36:14 +0200 Subject: [PATCH 277/327] ASoC: SOF: Add a 'message' parameter to snd_sof_dsp_dbg_dump() When snd_sof_dsp_dbg_dump() is called we have an explanatory message to give some hint on the reason why we have the dump on the caller level. Pass this message to snd_sof_dsp_dbg_dump() and handle the print according to the dump rules. This way we can finally print information on the HDA boot iteration if all dumps are enabled. Signed-off-by: Peter Ujfalusi Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20211223113628.18582-7-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/debug.c | 9 +++++++-- sound/soc/sof/intel/hda-loader.c | 15 +++++++++------ sound/soc/sof/loader.c | 8 ++++---- sound/soc/sof/ops.c | 5 ++--- sound/soc/sof/ops.h | 2 +- 5 files changed, 23 insertions(+), 16 deletions(-) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 9e4a128b59184..cf7d95c33afe5 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -955,7 +955,7 @@ static void snd_sof_dbg_print_fw_state(struct snd_sof_dev *sdev) dev_err(sdev->dev, "fw_state: UNKNOWN (%d)\n", sdev->fw_state); } -void snd_sof_dsp_dbg_dump(struct snd_sof_dev *sdev, u32 flags) +void snd_sof_dsp_dbg_dump(struct snd_sof_dev *sdev, const char *msg, u32 flags) { bool print_all = sof_debug_check_flag(SOF_DBG_PRINT_ALL_DUMPS); @@ -964,11 +964,15 @@ void snd_sof_dsp_dbg_dump(struct snd_sof_dev *sdev, u32 flags) if (sof_ops(sdev)->dbg_dump && !sdev->dbg_dump_printed) { dev_err(sdev->dev, "------------[ DSP dump start ]------------\n"); + if (msg) + dev_err(sdev->dev, "%s\n", msg); snd_sof_dbg_print_fw_state(sdev); sof_ops(sdev)->dbg_dump(sdev, flags); dev_err(sdev->dev, "------------[ DSP dump end ]------------\n"); if (!print_all) sdev->dbg_dump_printed = true; + } else if (msg) { + dev_err(sdev->dev, "%s\n", msg); } } EXPORT_SYMBOL(snd_sof_dsp_dbg_dump); @@ -997,7 +1001,8 @@ void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev) /* dump vital information to the logs */ snd_sof_ipc_dump(sdev); - snd_sof_dsp_dbg_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX); + snd_sof_dsp_dbg_dump(sdev, "Firmware exception", + SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX); snd_sof_trace_notify_for_error(sdev); } EXPORT_SYMBOL(snd_sof_handle_fw_exception); diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 8ef16f1082e35..33306d2023a78 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -88,6 +88,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag) const struct sof_intel_dsp_desc *chip = hda->desc; unsigned int status; unsigned long mask; + char *dump_msg; u32 flags, j; int ret; int i; @@ -189,9 +190,12 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag) if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) flags &= ~SOF_DBG_DUMP_OPTIONAL; - snd_sof_dsp_dbg_dump(sdev, flags); + dump_msg = kasprintf(GFP_KERNEL, "Boot iteration failed: %d/%d", + hda->boot_iteration, HDA_FW_BOOT_ATTEMPTS); + snd_sof_dsp_dbg_dump(sdev, dump_msg, flags); hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask); + kfree(dump_msg); return ret; } @@ -421,12 +425,11 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) */ hda->boot_iteration = HDA_FW_BOOT_ATTEMPTS; ret = cl_copy_fw(sdev, stream); - if (!ret) { + if (!ret) dev_dbg(sdev->dev, "Firmware download successful, booting...\n"); - } else { - snd_sof_dsp_dbg_dump(sdev, SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX); - dev_err(sdev->dev, "error: load fw failed ret: %d\n", ret); - } + else + snd_sof_dsp_dbg_dump(sdev, "Firmware download failed", + SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX); cleanup: /* diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index c04646647637e..8977a65b5704e 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -820,8 +820,8 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) /* boot the firmware on the DSP */ ret = snd_sof_dsp_run(sdev); if (ret < 0) { - dev_err(sdev->dev, "error: failed to start DSP\n"); - snd_sof_dsp_dbg_dump(sdev, SOF_DBG_DUMP_MBOX | SOF_DBG_DUMP_PCI); + snd_sof_dsp_dbg_dump(sdev, "Failed to start DSP", + SOF_DBG_DUMP_MBOX | SOF_DBG_DUMP_PCI); return ret; } @@ -835,8 +835,8 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) sdev->fw_state > SOF_FW_BOOT_IN_PROGRESS, msecs_to_jiffies(sdev->boot_timeout)); if (ret == 0) { - dev_err(sdev->dev, "error: firmware boot failure\n"); - snd_sof_dsp_dbg_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX | + snd_sof_dsp_dbg_dump(sdev, "Firmware boot failure due to timeout", + SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX | SOF_DBG_DUMP_TEXT | SOF_DBG_DUMP_PCI); sof_set_fw_state(sdev, SOF_FW_BOOT_FAILED); return -EIO; diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c index 9abf7a8e55e08..edfd080a3e4fc 100644 --- a/sound/soc/sof/ops.c +++ b/sound/soc/sof/ops.c @@ -171,12 +171,11 @@ void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset, bool non_recoverabl * if all dumps should be printed */ if (non_recoverable || sof_debug_check_flag(SOF_DBG_PRINT_ALL_DUMPS)) { - dev_err(sdev->dev, "DSP panic!\n"); - /* We want to see the DSP panic! */ sdev->dbg_dump_printed = false; - snd_sof_dsp_dbg_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX); + snd_sof_dsp_dbg_dump(sdev, "DSP panic!", + SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX); snd_sof_trace_notify_for_error(sdev); } } diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index bca7d35536e46..ffe7456e77139 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -274,7 +274,7 @@ snd_sof_dsp_set_power_state(struct snd_sof_dev *sdev, } /* debug */ -void snd_sof_dsp_dbg_dump(struct snd_sof_dev *sdev, u32 flags); +void snd_sof_dsp_dbg_dump(struct snd_sof_dev *sdev, const char *msg, u32 flags); static inline int snd_sof_debugfs_add_region_item(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type, u32 offset, size_t size, From 4e1f86482189ddbef73f7be8c6e62e8e3730e6b9 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 23 Dec 2021 13:36:15 +0200 Subject: [PATCH 278/327] ASoC: SOF: Introduce new firmware state: SOF_FW_CRASHED The SOF_FW_CRASHED state is meant to indicate the unfortunate case when the firmware has crashed after a successful boot. IPC tx timeout is not treated as indication of a firmware crash as it tends to happen regularly while the firmware is operational. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Kai Vehmanen Reviewed-by: Paul Olaru Link: https://lore.kernel.org/r/20211223113628.18582-8-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/debug.c | 1 + sound/soc/sof/ipc.c | 2 +- sound/soc/sof/ops.c | 2 ++ sound/soc/sof/pm.c | 7 +++++++ sound/soc/sof/sof-priv.h | 1 + 5 files changed, 12 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index cf7d95c33afe5..5941316751dde 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -939,6 +939,7 @@ static const struct soc_fw_state_info { {SOF_FW_BOOT_FAILED, "SOF_FW_BOOT_FAILED"}, {SOF_FW_BOOT_READY_FAILED, "SOF_FW_BOOT_READY_FAILED"}, {SOF_FW_BOOT_COMPLETE, "SOF_FW_BOOT_COMPLETE"}, + {SOF_FW_CRASHED, "SOF_FW_CRASHED"}, }; static void snd_sof_dbg_print_fw_state(struct snd_sof_dev *sdev) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 12860da1d3730..898f261e86035 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -302,7 +302,7 @@ static int sof_ipc_tx_message_unlocked(struct snd_sof_ipc *ipc, u32 header, struct snd_sof_ipc_msg *msg; int ret; - if (ipc->disable_ipc_tx) + if (ipc->disable_ipc_tx || sdev->fw_state == SOF_FW_CRASHED) return -ENODEV; /* diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c index edfd080a3e4fc..ed46f33ce72b7 100644 --- a/sound/soc/sof/ops.c +++ b/sound/soc/sof/ops.c @@ -176,6 +176,8 @@ void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset, bool non_recoverabl snd_sof_dsp_dbg_dump(sdev, "DSP panic!", SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX); + if (non_recoverable) + sof_set_fw_state(sdev, SOF_FW_CRASHED); snd_sof_trace_notify_for_error(sdev); } } diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index ac8ae6e422a78..f22b5ee234786 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -312,6 +312,13 @@ int snd_sof_prepare(struct device *dev) /* will suspend to S3 by default */ sdev->system_suspend_target = SOF_SUSPEND_S3; + /* + * if the firmware is crashed then we try to aim for S3 to reboot the + * firmware + */ + if (sdev->fw_state == SOF_FW_CRASHED) + return 0; + if (!desc->use_acpi_target_states) return 0; diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 0f849cdbfbc82..9bb30b2a516fd 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -382,6 +382,7 @@ enum snd_sof_fw_state { SOF_FW_BOOT_FAILED, SOF_FW_BOOT_READY_FAILED, /* firmware booted but fw_ready op failed */ SOF_FW_BOOT_COMPLETE, + SOF_FW_CRASHED, }; /* From b2e9eb3adb9a498b997b18852773e75d7af3b60d Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 23 Dec 2021 13:36:16 +0200 Subject: [PATCH 279/327] ASoC: SOF: Introduce new firmware state: SOF_FW_BOOT_READY_OK The SOF_FW_BOOT_READY_OK fw_state indicates that the boot ready message has been received and there were no errors found. The SOF_FW_BOOT_COMPLETE state will be reached after the snd_sof_dsp_post_fw_run() completes without error. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Kai Vehmanen Reviewed-by: Paul Olaru Link: https://lore.kernel.org/r/20211223113628.18582-9-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/debug.c | 1 + sound/soc/sof/ipc.c | 2 +- sound/soc/sof/loader.c | 7 ++++--- sound/soc/sof/sof-priv.h | 1 + 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 5941316751dde..75aaf0da87a07 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -938,6 +938,7 @@ static const struct soc_fw_state_info { {SOF_FW_BOOT_IN_PROGRESS, "SOF_FW_BOOT_IN_PROGRESS"}, {SOF_FW_BOOT_FAILED, "SOF_FW_BOOT_FAILED"}, {SOF_FW_BOOT_READY_FAILED, "SOF_FW_BOOT_READY_FAILED"}, + {SOF_FW_BOOT_READY_OK, "SOF_FW_BOOT_READY_OK"}, {SOF_FW_BOOT_COMPLETE, "SOF_FW_BOOT_COMPLETE"}, {SOF_FW_CRASHED, "SOF_FW_CRASHED"}, }; diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 898f261e86035..bbd539071ac50 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -536,7 +536,7 @@ void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) if (err < 0) sof_set_fw_state(sdev, SOF_FW_BOOT_READY_FAILED); else - sof_set_fw_state(sdev, SOF_FW_BOOT_COMPLETE); + sof_set_fw_state(sdev, SOF_FW_BOOT_READY_OK); /* wake up firmware loader */ wake_up(&sdev->boot_wait); diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 8977a65b5704e..f81f247327996 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -842,9 +842,7 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) return -EIO; } - if (sdev->fw_state == SOF_FW_BOOT_COMPLETE) - dev_dbg(sdev->dev, "firmware boot complete\n"); - else + if (sdev->fw_state == SOF_FW_BOOT_READY_FAILED) return -EIO; /* FW boots but fw_ready op failed */ /* perform post fw run operations */ @@ -854,6 +852,9 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) return ret; } + dev_dbg(sdev->dev, "firmware boot complete\n"); + sof_set_fw_state(sdev, SOF_FW_BOOT_COMPLETE); + return 0; } EXPORT_SYMBOL(snd_sof_run_firmware); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 9bb30b2a516fd..c92103a028ff9 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -381,6 +381,7 @@ enum snd_sof_fw_state { SOF_FW_BOOT_IN_PROGRESS, SOF_FW_BOOT_FAILED, SOF_FW_BOOT_READY_FAILED, /* firmware booted but fw_ready op failed */ + SOF_FW_BOOT_READY_OK, SOF_FW_BOOT_COMPLETE, SOF_FW_CRASHED, }; From fc179420fde3821c4d191e81b4f7b05c1dab87e2 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 23 Dec 2021 13:36:17 +0200 Subject: [PATCH 280/327] ASoC: SOF: Move the definition of enum snd_sof_fw_state to global header Move the enum snd_sof_fw_state to include/sound/sof.h to be accessible outside of the core SOF stack. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Kai Vehmanen Reviewed-by: Paul Olaru Link: https://lore.kernel.org/r/20211223113628.18582-10-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof.h | 22 ++++++++++++++++++++++ sound/soc/sof/sof-priv.h | 11 ----------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/include/sound/sof.h b/include/sound/sof.h index 23b374311d161..b9131c01eefd5 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -17,6 +17,28 @@ struct snd_sof_dsp_ops; +/** + * enum snd_sof_fw_state - DSP firmware state definitions + * @SOF_FW_BOOT_NOT_STARTED: firmware boot is not yet started + * @SOF_FW_BOOT_PREPARE: preparing for boot (firmware loading for exaqmple) + * @SOF_FW_BOOT_IN_PROGRESS: firmware boot is in progress + * @SOF_FW_BOOT_FAILED: firmware boot failed + * @SOF_FW_BOOT_READY_FAILED: firmware booted but fw_ready op failed + * @SOF_FW_BOOT_READY_OK: firmware booted and fw_ready op passed + * @SOF_FW_BOOT_COMPLETE: firmware is booted up and functional + * @SOF_FW_CRASHED: firmware crashed after successful boot + */ +enum snd_sof_fw_state { + SOF_FW_BOOT_NOT_STARTED = 0, + SOF_FW_BOOT_PREPARE, + SOF_FW_BOOT_IN_PROGRESS, + SOF_FW_BOOT_FAILED, + SOF_FW_BOOT_READY_FAILED, + SOF_FW_BOOT_READY_OK, + SOF_FW_BOOT_COMPLETE, + SOF_FW_CRASHED, +}; + /* * SOF Platform data. */ diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index c92103a028ff9..a1ebc89b216a7 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -375,17 +375,6 @@ struct snd_sof_ipc_msg { bool ipc_complete; }; -enum snd_sof_fw_state { - SOF_FW_BOOT_NOT_STARTED = 0, - SOF_FW_BOOT_PREPARE, - SOF_FW_BOOT_IN_PROGRESS, - SOF_FW_BOOT_FAILED, - SOF_FW_BOOT_READY_FAILED, /* firmware booted but fw_ready op failed */ - SOF_FW_BOOT_READY_OK, - SOF_FW_BOOT_COMPLETE, - SOF_FW_CRASHED, -}; - /* * SOF Device Level. */ From d41607d37c1385da799f9a2ddb10c460e573687e Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 23 Dec 2021 13:36:18 +0200 Subject: [PATCH 281/327] ASoC: SOF: Rename 'enum snd_sof_fw_state' to 'enum sof_fw_state' Since there is nothing SND about the firmware state, rename the enum from `snd_sof_fw_state` to simply `sof_fw_state` Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Kai Vehmanen Reviewed-by: Paul Olaru Link: https://lore.kernel.org/r/20211223113628.18582-11-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof.h | 4 ++-- sound/soc/sof/debug.c | 2 +- sound/soc/sof/sof-priv.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/sound/sof.h b/include/sound/sof.h index b9131c01eefd5..813680ab9aad4 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -18,7 +18,7 @@ struct snd_sof_dsp_ops; /** - * enum snd_sof_fw_state - DSP firmware state definitions + * enum sof_fw_state - DSP firmware state definitions * @SOF_FW_BOOT_NOT_STARTED: firmware boot is not yet started * @SOF_FW_BOOT_PREPARE: preparing for boot (firmware loading for exaqmple) * @SOF_FW_BOOT_IN_PROGRESS: firmware boot is in progress @@ -28,7 +28,7 @@ struct snd_sof_dsp_ops; * @SOF_FW_BOOT_COMPLETE: firmware is booted up and functional * @SOF_FW_CRASHED: firmware crashed after successful boot */ -enum snd_sof_fw_state { +enum sof_fw_state { SOF_FW_BOOT_NOT_STARTED = 0, SOF_FW_BOOT_PREPARE, SOF_FW_BOOT_IN_PROGRESS, diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 75aaf0da87a07..d3640ff33134b 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -930,7 +930,7 @@ void snd_sof_free_debug(struct snd_sof_dev *sdev) EXPORT_SYMBOL_GPL(snd_sof_free_debug); static const struct soc_fw_state_info { - enum snd_sof_fw_state state; + enum sof_fw_state state; const char *name; } fw_state_dbg[] = { {SOF_FW_BOOT_NOT_STARTED, "SOF_FW_BOOT_NOT_STARTED"}, diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index a1ebc89b216a7..44ae8d8d13335 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -399,7 +399,7 @@ struct snd_sof_dev { /* DSP firmware boot */ wait_queue_head_t boot_wait; - enum snd_sof_fw_state fw_state; + enum sof_fw_state fw_state; bool first_boot; /* work queue in case the probe is implemented in two steps */ @@ -591,7 +591,7 @@ extern const struct dsp_arch_ops sof_xtensa_arch_ops; * Firmware state tracking */ static inline void sof_set_fw_state(struct snd_sof_dev *sdev, - enum snd_sof_fw_state new_state) + enum sof_fw_state new_state) { if (sdev->fw_state == new_state) return; From 9421ff7665f66452f61ee40566c6f562d3847873 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 23 Dec 2021 13:36:19 +0200 Subject: [PATCH 282/327] ASoC: SOF: ipc: Only allow sending of an IPC in SOF_FW_BOOT_COMPLETE state If the state of the firmware is not BOOT_COMPLETE, it means that the firmware is not functioning, thus it is not capable of handling IPC messages. Do not try to send IPC if the state is not BOOT_COMPLETE Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20211223113628.18582-12-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index bbd539071ac50..5bcf906d90af2 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -302,7 +302,7 @@ static int sof_ipc_tx_message_unlocked(struct snd_sof_ipc *ipc, u32 header, struct snd_sof_ipc_msg *msg; int ret; - if (ipc->disable_ipc_tx || sdev->fw_state == SOF_FW_CRASHED) + if (ipc->disable_ipc_tx || sdev->fw_state != SOF_FW_BOOT_COMPLETE) return -ENODEV; /* From e2406275be2b6b15d985f33aec921e6555e4f87a Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 23 Dec 2021 13:36:20 +0200 Subject: [PATCH 283/327] ASoC: SOF: Set SOF_FW_BOOT_FAILED in case we have failure during boot Change the fw_state to SOF_FW_BOOT_FAILED if we encountered an error during booting the firmware. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20211223113628.18582-13-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/core.c | 2 ++ sound/soc/sof/loader.c | 1 - sound/soc/sof/pm.c | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 00f8ffee2866b..aa7a721f34e4a 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -202,6 +202,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) if (ret < 0) { dev_err(sdev->dev, "error: failed to load DSP firmware %d\n", ret); + sof_set_fw_state(sdev, SOF_FW_BOOT_FAILED); goto fw_load_err; } @@ -215,6 +216,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) if (ret < 0) { dev_err(sdev->dev, "error: failed to boot DSP firmware %d\n", ret); + sof_set_fw_state(sdev, SOF_FW_BOOT_FAILED); goto fw_run_err; } diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index f81f247327996..697f03565a70d 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -838,7 +838,6 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) snd_sof_dsp_dbg_dump(sdev, "Firmware boot failure due to timeout", SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX | SOF_DBG_DUMP_TEXT | SOF_DBG_DUMP_PCI); - sof_set_fw_state(sdev, SOF_FW_BOOT_FAILED); return -EIO; } diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index f22b5ee234786..022b196697351 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -130,6 +130,7 @@ static int sof_resume(struct device *dev, bool runtime_resume) dev_err(sdev->dev, "error: failed to load DSP firmware after resume %d\n", ret); + sof_set_fw_state(sdev, SOF_FW_BOOT_FAILED); return ret; } @@ -144,6 +145,7 @@ static int sof_resume(struct device *dev, bool runtime_resume) dev_err(sdev->dev, "error: failed to boot DSP firmware after resume %d\n", ret); + sof_set_fw_state(sdev, SOF_FW_BOOT_FAILED); return ret; } From b54b3a4e08bc0210768a1839af2ff888376cae4c Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 23 Dec 2021 13:36:21 +0200 Subject: [PATCH 284/327] ASoC: SOF: pm: Force DSP off on suspend in BOOT_FAILED state also Try to force the DSP to be turned off next time if the fw_state is either CRASHED or BOOT_FAILED when a suspend happens in order to attempt a clean boot to recover. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20211223113628.18582-14-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/pm.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 022b196697351..197a88695fef8 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -315,10 +315,11 @@ int snd_sof_prepare(struct device *dev) sdev->system_suspend_target = SOF_SUSPEND_S3; /* - * if the firmware is crashed then we try to aim for S3 to reboot the - * firmware + * if the firmware is crashed or boot failed then we try to aim for S3 + * to reboot the firmware */ - if (sdev->fw_state == SOF_FW_CRASHED) + if (sdev->fw_state == SOF_FW_CRASHED || + sdev->fw_state == SOF_FW_BOOT_FAILED) return 0; if (!desc->use_acpi_target_states) From 9f89a988d5c222f2fba495bbc861a476bdf1bd30 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 23 Dec 2021 13:36:22 +0200 Subject: [PATCH 285/327] ASoc: SOF: core: Update the FW boot state transition diagram Update the state flow diagram to reflect the current implementation. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20211223113628.18582-15-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/core.c | 52 ++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index aa7a721f34e4a..bc3d7192bdda3 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -114,32 +114,32 @@ EXPORT_SYMBOL(snd_sof_get_status); /* * FW Boot State Transition Diagram * - * +-----------------------------------------------------------------------+ - * | | - * ------------------ ------------------ | - * | | | | | - * | BOOT_FAILED | | READY_FAILED |-------------------------+ | - * | | | | | | - * ------------------ ------------------ | | - * ^ ^ | | - * | | | | - * (FW Boot Timeout) (FW_READY FAIL) | | - * | | | | - * | | | | - * ------------------ | ------------------ | | - * | | | | | | | - * | IN_PROGRESS |---------------+------------->| COMPLETE | | | - * | | (FW Boot OK) (FW_READY OK) | | | | - * ------------------ ------------------ | | - * ^ | | | - * | | | | - * (FW Loading OK) (System Suspend/Runtime Suspend) - * | | | | - * | | | | - * ------------------ ------------------ | | | - * | | | |<-----+ | | - * | PREPARE | | NOT_STARTED |<---------------------+ | - * | | | |<---------------------------+ + * +----------------------------------------------------------------------+ + * | | + * ------------------ ------------------ | + * | | | | | + * | BOOT_FAILED |<-------| READY_FAILED | | + * | |<--+ | | ------------------ | + * ------------------ | ------------------ | | | + * ^ | ^ | CRASHED |---+ | + * | | | | | | | + * (FW Boot Timeout) | (FW_READY FAIL) ------------------ | | + * | | | ^ | | + * | | | |(DSP Panic) | | + * ------------------ | | ------------------ | | + * | | | | | | | | + * | IN_PROGRESS |---------------+------------->| COMPLETE | | | + * | | (FW Boot OK) (FW_READY OK) | | | | + * ------------------ | ------------------ | | + * ^ | | | | + * | | | | | + * (FW Loading OK) | (System Suspend/Runtime Suspend) + * | | | | | + * | (FW Loading Fail) | | | + * ------------------ | ------------------ | | | + * | | | | |<-----+ | | + * | PREPARE |---+ | NOT_STARTED |<---------------------+ | + * | | | |<--------------------------+ * ------------------ ------------------ * | ^ | ^ * | | | | From fdc573b1c26a8859996de6fbae2d436511b74e00 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 23 Dec 2021 13:36:23 +0200 Subject: [PATCH 286/327] ASoC: SOF: ops: Always print DSP Panic message but use different message Never suppress the DSP panic dump as it is always originates from an assert() or panic() call within the firmware. Use different message for DSP panics when there will be recovery attempt going to be done compared to a definitive DSP panic. Suggested-by: Chao Song Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Chao Song Reviewed-by: Kai Vehmanen Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20211223113628.18582-16-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ops.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c index ed46f33ce72b7..235e2ef721781 100644 --- a/sound/soc/sof/ops.c +++ b/sound/soc/sof/ops.c @@ -167,18 +167,21 @@ void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset, bool non_recoverabl __func__, sdev->dsp_oops_offset, offset); /* - * Only print the panic information if we have non recoverable panic or - * if all dumps should be printed + * Set the fw_state to crashed only in case of non recoverable DSP panic + * event. + * Use different message within the snd_sof_dsp_dbg_dump() depending on + * the non_recoverable flag. */ - if (non_recoverable || sof_debug_check_flag(SOF_DBG_PRINT_ALL_DUMPS)) { - /* We want to see the DSP panic! */ - sdev->dbg_dump_printed = false; - + sdev->dbg_dump_printed = false; + if (non_recoverable) { snd_sof_dsp_dbg_dump(sdev, "DSP panic!", SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX); - if (non_recoverable) - sof_set_fw_state(sdev, SOF_FW_CRASHED); + sof_set_fw_state(sdev, SOF_FW_CRASHED); snd_sof_trace_notify_for_error(sdev); + } else { + snd_sof_dsp_dbg_dump(sdev, + "DSP panic (recovery will be attempted)", + SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX); } } EXPORT_SYMBOL(snd_sof_dsp_panic); From b9f0bfd16d8b390b35dbec67c3ed74e74a0ade24 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 23 Dec 2021 13:36:24 +0200 Subject: [PATCH 287/327] ASoC: SOF: dsp_arch_ops: add kernel log level parameter for oops and stack To allow custom log level to be used for the DSP oops and stack print, add a kernel log level parameter to the two ops. Modify the xtensa oops and stack functions tom use this new log level parameter. Pass KER_ERR from snd_sof_get_status() to make sure that there is no functional change with this new parameter. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Chao Song Reviewed-by: Kai Vehmanen Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20211223113628.18582-17-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/core.c | 4 ++-- sound/soc/sof/sof-priv.h | 15 +++++++------ sound/soc/sof/xtensa/core.c | 44 +++++++++++++++++++++---------------- 3 files changed, 35 insertions(+), 28 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index bc3d7192bdda3..c3630ecc7d89a 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -106,8 +106,8 @@ void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, out: dev_err(sdev->dev, "panic at %s:%d\n", panic_info->filename, panic_info->linenum); - sof_oops(sdev, oops); - sof_stack(sdev, oops, stack, stack_words); + sof_oops(sdev, KERN_ERR, oops); + sof_stack(sdev, KERN_ERR, oops, stack, stack_words); } EXPORT_SYMBOL(snd_sof_get_status); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 44ae8d8d13335..598f858f0e1bf 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -309,8 +309,8 @@ struct snd_sof_dsp_ops { /* DSP architecture specific callbacks for oops and stack dumps */ struct dsp_arch_ops { - void (*dsp_oops)(struct snd_sof_dev *sdev, void *oops); - void (*dsp_stack)(struct snd_sof_dev *sdev, void *oops, + void (*dsp_oops)(struct snd_sof_dev *sdev, const char *level, void *oops); + void (*dsp_stack)(struct snd_sof_dev *sdev, const char *level, void *oops, u32 *stack, u32 stack_words); }; @@ -573,16 +573,17 @@ int snd_sof_debugfs_add_region_item_iomem(struct snd_sof_dev *sdev, /* * DSP Architectures. */ -static inline void sof_stack(struct snd_sof_dev *sdev, void *oops, u32 *stack, - u32 stack_words) +static inline void sof_stack(struct snd_sof_dev *sdev, const char *level, + void *oops, u32 *stack, u32 stack_words) { - sof_dsp_arch_ops(sdev)->dsp_stack(sdev, oops, stack, stack_words); + sof_dsp_arch_ops(sdev)->dsp_stack(sdev, level, oops, stack, + stack_words); } -static inline void sof_oops(struct snd_sof_dev *sdev, void *oops) +static inline void sof_oops(struct snd_sof_dev *sdev, const char *level, void *oops) { if (sof_dsp_arch_ops(sdev)->dsp_oops) - sof_dsp_arch_ops(sdev)->dsp_oops(sdev, oops); + sof_dsp_arch_ops(sdev)->dsp_oops(sdev, level, oops); } extern const struct dsp_arch_ops sof_xtensa_arch_ops; diff --git a/sound/soc/sof/xtensa/core.c b/sound/soc/sof/xtensa/core.c index bd09c3825caff..bebbe3a2865c4 100644 --- a/sound/soc/sof/xtensa/core.c +++ b/sound/soc/sof/xtensa/core.c @@ -81,33 +81,39 @@ static const struct xtensa_exception_cause xtensa_exception_causes[] = { }; /* only need xtensa atm */ -static void xtensa_dsp_oops(struct snd_sof_dev *sdev, void *oops) +static void xtensa_dsp_oops(struct snd_sof_dev *sdev, const char *level, void *oops) { struct sof_ipc_dsp_oops_xtensa *xoops = oops; int i; - dev_err(sdev->dev, "error: DSP Firmware Oops\n"); + dev_printk(level, sdev->dev, "error: DSP Firmware Oops\n"); for (i = 0; i < ARRAY_SIZE(xtensa_exception_causes); i++) { if (xtensa_exception_causes[i].id == xoops->exccause) { - dev_err(sdev->dev, "error: Exception Cause: %s, %s\n", - xtensa_exception_causes[i].msg, - xtensa_exception_causes[i].description); + dev_printk(level, sdev->dev, + "error: Exception Cause: %s, %s\n", + xtensa_exception_causes[i].msg, + xtensa_exception_causes[i].description); } } - dev_err(sdev->dev, "EXCCAUSE 0x%8.8x EXCVADDR 0x%8.8x PS 0x%8.8x SAR 0x%8.8x\n", - xoops->exccause, xoops->excvaddr, xoops->ps, xoops->sar); - dev_err(sdev->dev, "EPC1 0x%8.8x EPC2 0x%8.8x EPC3 0x%8.8x EPC4 0x%8.8x", - xoops->epc1, xoops->epc2, xoops->epc3, xoops->epc4); - dev_err(sdev->dev, "EPC5 0x%8.8x EPC6 0x%8.8x EPC7 0x%8.8x DEPC 0x%8.8x", - xoops->epc5, xoops->epc6, xoops->epc7, xoops->depc); - dev_err(sdev->dev, "EPS2 0x%8.8x EPS3 0x%8.8x EPS4 0x%8.8x EPS5 0x%8.8x", - xoops->eps2, xoops->eps3, xoops->eps4, xoops->eps5); - dev_err(sdev->dev, "EPS6 0x%8.8x EPS7 0x%8.8x INTENABL 0x%8.8x INTERRU 0x%8.8x", - xoops->eps6, xoops->eps7, xoops->intenable, xoops->interrupt); + dev_printk(level, sdev->dev, + "EXCCAUSE 0x%8.8x EXCVADDR 0x%8.8x PS 0x%8.8x SAR 0x%8.8x\n", + xoops->exccause, xoops->excvaddr, xoops->ps, xoops->sar); + dev_printk(level, sdev->dev, + "EPC1 0x%8.8x EPC2 0x%8.8x EPC3 0x%8.8x EPC4 0x%8.8x", + xoops->epc1, xoops->epc2, xoops->epc3, xoops->epc4); + dev_printk(level, sdev->dev, + "EPC5 0x%8.8x EPC6 0x%8.8x EPC7 0x%8.8x DEPC 0x%8.8x", + xoops->epc5, xoops->epc6, xoops->epc7, xoops->depc); + dev_printk(level, sdev->dev, + "EPS2 0x%8.8x EPS3 0x%8.8x EPS4 0x%8.8x EPS5 0x%8.8x", + xoops->eps2, xoops->eps3, xoops->eps4, xoops->eps5); + dev_printk(level, sdev->dev, + "EPS6 0x%8.8x EPS7 0x%8.8x INTENABL 0x%8.8x INTERRU 0x%8.8x", + xoops->eps6, xoops->eps7, xoops->intenable, xoops->interrupt); } -static void xtensa_stack(struct snd_sof_dev *sdev, void *oops, u32 *stack, - u32 stack_words) +static void xtensa_stack(struct snd_sof_dev *sdev, const char *level, void *oops, + u32 *stack, u32 stack_words) { struct sof_ipc_dsp_oops_xtensa *xoops = oops; u32 stack_ptr = xoops->plat_hdr.stackptr; @@ -115,7 +121,7 @@ static void xtensa_stack(struct snd_sof_dev *sdev, void *oops, u32 *stack, unsigned char buf[4 * 8 + 3 + 1]; int i; - dev_err(sdev->dev, "stack dump from 0x%8.8x\n", stack_ptr); + dev_printk(level, sdev->dev, "stack dump from 0x%8.8x\n", stack_ptr); /* * example output: @@ -124,7 +130,7 @@ static void xtensa_stack(struct snd_sof_dev *sdev, void *oops, u32 *stack, for (i = 0; i < stack_words; i += 4) { hex_dump_to_buffer(stack + i, 16, 16, 4, buf, sizeof(buf), false); - dev_err(sdev->dev, "0x%08x: %s\n", stack_ptr + i * 4, buf); + dev_printk(level, sdev->dev, "0x%08x: %s\n", stack_ptr + i * 4, buf); } } From 4995ffce2ce2164fa507a5dbaf1aa38bab679cca Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 23 Dec 2021 13:36:25 +0200 Subject: [PATCH 288/327] ASoC: SOF: Rename snd_sof_get_status() and add kernel log level parameter The snd_sof_get_status() is not the best name for a function which in fact is tasked to print out DSP oops and stack. Rename it to sof_print_oops_and_stack(). At the same time add a new parameter to specify the desired kernel log level to be used for the prints. When updating the users of the function, pass KERN_ERR for now to make sure that there is no functional change happens. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Chao Song Reviewed-by: Kai Vehmanen Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20211223113628.18582-18-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/core.c | 45 +++++++++++++++++++++------------- sound/soc/sof/imx/imx-common.c | 4 +-- sound/soc/sof/intel/atom.c | 4 +-- sound/soc/sof/intel/bdw.c | 4 +-- sound/soc/sof/intel/hda.c | 4 +-- sound/soc/sof/sof-priv.h | 8 +++--- 6 files changed, 40 insertions(+), 29 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index c3630ecc7d89a..8f32b5b12b3e9 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -68,23 +68,33 @@ static const struct sof_panic_msg panic_msg[] = { {SOF_IPC_PANIC_ASSERT, "assertion failed"}, }; -/* +/** + * sof_print_oops_and_stack - Handle the printing of DSP oops and stack trace + * @sdev: Pointer to the device's sdev + * @level: prink log level to use for the printing + * @panic_code: the panic code + * @tracep_code: tracepoint code + * @oops: Pointer to DSP specific oops data + * @panic_info: Pointer to the received panic information message + * @stack: Pointer to the call stack data + * @stack_words: Number of words in the stack data + * * helper to be called from .dbg_dump callbacks. No error code is * provided, it's left as an exercise for the caller of .dbg_dump * (typically IPC or loader) */ -void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, - u32 tracep_code, void *oops, - struct sof_ipc_panic_info *panic_info, - void *stack, size_t stack_words) +void sof_print_oops_and_stack(struct snd_sof_dev *sdev, const char *level, + u32 panic_code, u32 tracep_code, void *oops, + struct sof_ipc_panic_info *panic_info, + void *stack, size_t stack_words) { u32 code; int i; /* is firmware dead ? */ if ((panic_code & SOF_IPC_PANIC_MAGIC_MASK) != SOF_IPC_PANIC_MAGIC) { - dev_err(sdev->dev, "unexpected fault %#010x trace %#010x\n", - panic_code, tracep_code); + dev_printk(level, sdev->dev, "unexpected fault %#010x trace %#010x\n", + panic_code, tracep_code); return; /* no fault ? */ } @@ -92,24 +102,25 @@ void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, for (i = 0; i < ARRAY_SIZE(panic_msg); i++) { if (panic_msg[i].id == code) { - dev_err(sdev->dev, "reason: %s (%#x)\n", panic_msg[i].msg, - code & SOF_IPC_PANIC_CODE_MASK); - dev_err(sdev->dev, "trace point: %#010x\n", tracep_code); + dev_printk(level, sdev->dev, "reason: %s (%#x)\n", + panic_msg[i].msg, code & SOF_IPC_PANIC_CODE_MASK); + dev_printk(level, sdev->dev, "trace point: %#010x\n", tracep_code); goto out; } } /* unknown error */ - dev_err(sdev->dev, "unknown panic code: %#x\n", code & SOF_IPC_PANIC_CODE_MASK); - dev_err(sdev->dev, "trace point: %#010x\n", tracep_code); + dev_printk(level, sdev->dev, "unknown panic code: %#x\n", + code & SOF_IPC_PANIC_CODE_MASK); + dev_printk(level, sdev->dev, "trace point: %#010x\n", tracep_code); out: - dev_err(sdev->dev, "panic at %s:%d\n", panic_info->filename, - panic_info->linenum); - sof_oops(sdev, KERN_ERR, oops); - sof_stack(sdev, KERN_ERR, oops, stack, stack_words); + dev_printk(level, sdev->dev, "panic at %s:%d\n", panic_info->filename, + panic_info->linenum); + sof_oops(sdev, level, oops); + sof_stack(sdev, level, oops, stack, stack_words); } -EXPORT_SYMBOL(snd_sof_get_status); +EXPORT_SYMBOL(sof_print_oops_and_stack); /* * FW Boot State Transition Diagram diff --git a/sound/soc/sof/imx/imx-common.c b/sound/soc/sof/imx/imx-common.c index 9371e9062cb14..36e3d414a18f4 100644 --- a/sound/soc/sof/imx/imx-common.c +++ b/sound/soc/sof/imx/imx-common.c @@ -69,8 +69,8 @@ void imx8_dump(struct snd_sof_dev *sdev, u32 flags) IMX8_STACK_DUMP_SIZE); /* Print the information to the console */ - snd_sof_get_status(sdev, status, status, &xoops, &panic_info, stack, - IMX8_STACK_DUMP_SIZE); + sof_print_oops_and_stack(sdev, KERN_ERR, status, status, &xoops, + &panic_info, stack, IMX8_STACK_DUMP_SIZE); } EXPORT_SYMBOL(imx8_dump); diff --git a/sound/soc/sof/intel/atom.c b/sound/soc/sof/intel/atom.c index bcb2eb2acf2e2..ff5900b155dc9 100644 --- a/sound/soc/sof/intel/atom.c +++ b/sound/soc/sof/intel/atom.c @@ -70,8 +70,8 @@ void atom_dump(struct snd_sof_dev *sdev, u32 flags) panic = snd_sof_dsp_read64(sdev, DSP_BAR, SHIM_IPCX); atom_get_registers(sdev, &xoops, &panic_info, stack, STACK_DUMP_SIZE); - snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, stack, - STACK_DUMP_SIZE); + sof_print_oops_and_stack(sdev, KERN_ERR, status, panic, &xoops, + &panic_info, stack, STACK_DUMP_SIZE); /* provide some context for firmware debug */ imrx = snd_sof_dsp_read64(sdev, DSP_BAR, SHIM_IMRX); diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 10c9a0b39371b..d627b7498d5e5 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -258,8 +258,8 @@ static void bdw_dump(struct snd_sof_dev *sdev, u32 flags) panic = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCX); bdw_get_registers(sdev, &xoops, &panic_info, stack, BDW_STACK_DUMP_SIZE); - snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, stack, - BDW_STACK_DUMP_SIZE); + sof_print_oops_and_stack(sdev, KERN_ERR, status, panic, &xoops, + &panic_info, stack, BDW_STACK_DUMP_SIZE); /* provide some context for firmware debug */ imrx = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IMRX); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 21100d2e6644b..97027530ecef9 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -554,8 +554,8 @@ void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags) hda_dsp_get_registers(sdev, &xoops, &panic_info, stack, HDA_DSP_STACK_DUMP_SIZE); - snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, - stack, HDA_DSP_STACK_DUMP_SIZE); + sof_print_oops_and_stack(sdev, KERN_ERR, status, panic, &xoops, + &panic_info, stack, HDA_DSP_STACK_DUMP_SIZE); } else { hda_dsp_dump_ext_rom_status(sdev, flags); } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 598f858f0e1bf..5fbd4f29321a5 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -559,10 +559,10 @@ int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev, int snd_sof_trace_update_pos(struct snd_sof_dev *sdev, struct sof_ipc_dma_trace_posn *posn); void snd_sof_trace_notify_for_error(struct snd_sof_dev *sdev); -void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, - u32 tracep_code, void *oops, - struct sof_ipc_panic_info *panic_info, - void *stack, size_t stack_words); +void sof_print_oops_and_stack(struct snd_sof_dev *sdev, const char *level, + u32 panic_code, u32 tracep_code, void *oops, + struct sof_ipc_panic_info *panic_info, + void *stack, size_t stack_words); int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev); void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev); int snd_sof_dbg_memory_info_init(struct snd_sof_dev *sdev); From beb6ade168177bf6c43abe78b3c9512b260b8068 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 23 Dec 2021 13:36:26 +0200 Subject: [PATCH 289/327] ASoC: SOF: Add clarifying comments for sof_core_debug and DSP dump flags Update the comment for the global SOF level debug flags and add one for the flags used to control the DSP dump functionality. Document the expected behavior when the SOF_DBG_DUMP_OPTIONAL is passed for the DSP dump: Only print the dump if SOF_DBG_PRINT_ALL_DUMPS is set Print must use KERN_DEBUG log level Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Chao Song Reviewed-by: Kai Vehmanen Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20211223113628.18582-19-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-priv.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 5fbd4f29321a5..087935192ce85 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -20,7 +20,7 @@ #include #include -/* debug flags */ +/* Flag definitions used in sof_core_debug (sof_debug module parameter) */ #define SOF_DBG_ENABLE_TRACE BIT(0) #define SOF_DBG_RETAIN_CTX BIT(1) /* prevent DSP D3 on FW exception */ #define SOF_DBG_VERIFY_TPLG BIT(2) /* verify topology during load */ @@ -35,11 +35,13 @@ */ #define SOF_DBG_PRINT_ALL_DUMPS BIT(6) /* Print all ipc and dsp dumps */ +/* Flag definitions used for controlling the DSP dump behavior */ #define SOF_DBG_DUMP_REGS BIT(0) #define SOF_DBG_DUMP_MBOX BIT(1) #define SOF_DBG_DUMP_TEXT BIT(2) #define SOF_DBG_DUMP_PCI BIT(3) -#define SOF_DBG_DUMP_OPTIONAL BIT(4) /* only dump if SOF_DBG_PRINT_ALL_DUMPS is set */ +/* Output this dump (at the DEBUG level) only when SOF_DBG_PRINT_ALL_DUMPS is set */ +#define SOF_DBG_DUMP_OPTIONAL BIT(4) /* global debug state set by SOF_DBG_ flags */ bool sof_debug_check_flag(int mask); From 0152b8a2f0831b03bb7483159ef28167dcd33ab0 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 23 Dec 2021 13:36:27 +0200 Subject: [PATCH 290/327] ASoC: SOF: debug: Use DEBUG log level for optional prints If the user requested to see all dumps (even the optional ones) then use KERN_DEBUG level for the optional dumps as they are only for debugging purposes. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Chao Song Reviewed-by: Kai Vehmanen Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20211223113628.18582-20-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/debug.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index d3640ff33134b..6d6757075f7c3 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -943,38 +943,42 @@ static const struct soc_fw_state_info { {SOF_FW_CRASHED, "SOF_FW_CRASHED"}, }; -static void snd_sof_dbg_print_fw_state(struct snd_sof_dev *sdev) +static void snd_sof_dbg_print_fw_state(struct snd_sof_dev *sdev, const char *level) { int i; for (i = 0; i < ARRAY_SIZE(fw_state_dbg); i++) { if (sdev->fw_state == fw_state_dbg[i].state) { - dev_err(sdev->dev, "fw_state: %s (%d)\n", fw_state_dbg[i].name, i); + dev_printk(level, sdev->dev, "fw_state: %s (%d)\n", + fw_state_dbg[i].name, i); return; } } - dev_err(sdev->dev, "fw_state: UNKNOWN (%d)\n", sdev->fw_state); + dev_printk(level, sdev->dev, "fw_state: UNKNOWN (%d)\n", sdev->fw_state); } void snd_sof_dsp_dbg_dump(struct snd_sof_dev *sdev, const char *msg, u32 flags) { + char *level = flags & SOF_DBG_DUMP_OPTIONAL ? KERN_DEBUG : KERN_ERR; bool print_all = sof_debug_check_flag(SOF_DBG_PRINT_ALL_DUMPS); if (flags & SOF_DBG_DUMP_OPTIONAL && !print_all) return; if (sof_ops(sdev)->dbg_dump && !sdev->dbg_dump_printed) { - dev_err(sdev->dev, "------------[ DSP dump start ]------------\n"); + dev_printk(level, sdev->dev, + "------------[ DSP dump start ]------------\n"); if (msg) - dev_err(sdev->dev, "%s\n", msg); - snd_sof_dbg_print_fw_state(sdev); + dev_printk(level, sdev->dev, "%s\n", msg); + snd_sof_dbg_print_fw_state(sdev, level); sof_ops(sdev)->dbg_dump(sdev, flags); - dev_err(sdev->dev, "------------[ DSP dump end ]------------\n"); + dev_printk(level, sdev->dev, + "------------[ DSP dump end ]------------\n"); if (!print_all) sdev->dbg_dump_printed = true; } else if (msg) { - dev_err(sdev->dev, "%s\n", msg); + dev_printk(level, sdev->dev, "%s\n", msg); } } EXPORT_SYMBOL(snd_sof_dsp_dbg_dump); From 34bfba9a63ece79c683591e757899e61fbcaa753 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 23 Dec 2021 13:36:28 +0200 Subject: [PATCH 291/327] ASoC: SOF: Intel: hda: Use DEBUG log level for optional prints If the user requested to see all dumps (even the optional ones) then use KERN_DEBUG level for the optional dumps as they are only for debugging purposes. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Chao Song Reviewed-by: Kai Vehmanen Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20211223113628.18582-21-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 97027530ecef9..18abbd13d5937 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -474,7 +474,7 @@ static const struct hda_dsp_msg_code hda_dsp_rom_msg[] = { {HDA_DSP_ROM_NULL_FW_ENTRY, "error: null FW entry point"}, }; -static void hda_dsp_get_status(struct snd_sof_dev *sdev) +static void hda_dsp_get_status(struct snd_sof_dev *sdev, const char *level) { u32 status; int i; @@ -484,8 +484,8 @@ static void hda_dsp_get_status(struct snd_sof_dev *sdev) for (i = 0; i < ARRAY_SIZE(hda_dsp_rom_msg); i++) { if (status == hda_dsp_rom_msg[i].code) { - dev_err(sdev->dev, "%s - code %8.8x\n", - hda_dsp_rom_msg[i].msg, status); + dev_printk(level, sdev->dev, "%s - code %8.8x\n", + hda_dsp_rom_msg[i].msg, status); return; } } @@ -523,7 +523,8 @@ static void hda_dsp_get_registers(struct snd_sof_dev *sdev, } /* dump the first 8 dwords representing the extended ROM status */ -static void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev, u32 flags) +static void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev, const char *level, + u32 flags) { char msg[128]; int len = 0; @@ -535,18 +536,19 @@ static void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev, u32 flags) len += snprintf(msg + len, sizeof(msg) - len, " 0x%x", value); } - dev_err(sdev->dev, "extended rom status: %s", msg); + dev_printk(level, sdev->dev, "extended rom status: %s", msg); } void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags) { + char *level = flags & SOF_DBG_DUMP_OPTIONAL ? KERN_DEBUG : KERN_ERR; struct sof_ipc_dsp_oops_xtensa xoops; struct sof_ipc_panic_info panic_info; u32 stack[HDA_DSP_STACK_DUMP_SIZE]; /* print ROM/FW status */ - hda_dsp_get_status(sdev); + hda_dsp_get_status(sdev, level); if (flags & SOF_DBG_DUMP_REGS) { u32 status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_FW_STATUS); @@ -554,10 +556,10 @@ void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags) hda_dsp_get_registers(sdev, &xoops, &panic_info, stack, HDA_DSP_STACK_DUMP_SIZE); - sof_print_oops_and_stack(sdev, KERN_ERR, status, panic, &xoops, + sof_print_oops_and_stack(sdev, level, status, panic, &xoops, &panic_info, stack, HDA_DSP_STACK_DUMP_SIZE); } else { - hda_dsp_dump_ext_rom_status(sdev, flags); + hda_dsp_dump_ext_rom_status(sdev, level, flags); } } From c6cef35bf723ef0152258d15179c725c5f8cbeba Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 23 Dec 2021 13:24:33 +0100 Subject: [PATCH 292/327] ASoC: dt-bindings: spdif-dit: add missing sound-name-prefix property This is used in meson-axg, meson-g12 and meson-gx. Add the property to the binding. This fixes the dtschema warning: audio-codec-0: 'sound-name-prefix' does not match any of the regexes: 'pinctrl-[0-9]+' Signed-off-by: Alexander Stein Link: https://lore.kernel.org/r/20211223122434.39378-3-alexander.stein@mailbox.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/linux,spdif-dit.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/linux,spdif-dit.yaml b/Documentation/devicetree/bindings/sound/linux,spdif-dit.yaml index c6b070e1d0147..a4f9257e313da 100644 --- a/Documentation/devicetree/bindings/sound/linux,spdif-dit.yaml +++ b/Documentation/devicetree/bindings/sound/linux,spdif-dit.yaml @@ -9,6 +9,9 @@ title: Dummy SPDIF Transmitter Device Tree Bindings maintainers: - Mark Brown +allOf: + - $ref: name-prefix.yaml# + properties: compatible: const: linux,spdif-dit @@ -16,6 +19,8 @@ properties: "#sound-dai-cells": const: 0 + sound-name-prefix: true + required: - "#sound-dai-cells" - compatible From 559ec82aa47d7c9ce39f3c769f1ba5f3237f6869 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 23 Dec 2021 13:24:34 +0100 Subject: [PATCH 293/327] ASoC: dt-bindings: aiu: spdif-dit: add missing sound-name-prefix property This is used in meson-gx. Add the property to the binding. This fixes the dtschema warning: audio-controller@5400: 'sound-name-prefix' does not match any of the regexes: 'pinctrl-[0-9]+' Signed-off-by: Alexander Stein Link: https://lore.kernel.org/r/20211223122434.39378-4-alexander.stein@mailbox.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/amlogic,aiu.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/amlogic,aiu.yaml b/Documentation/devicetree/bindings/sound/amlogic,aiu.yaml index f50558ed914f7..0705f91199a08 100644 --- a/Documentation/devicetree/bindings/sound/amlogic,aiu.yaml +++ b/Documentation/devicetree/bindings/sound/amlogic,aiu.yaml @@ -9,6 +9,9 @@ title: Amlogic AIU audio output controller maintainers: - Jerome Brunet +allOf: + - $ref: name-prefix.yaml# + properties: $nodename: pattern: "^audio-controller@.*" @@ -65,6 +68,8 @@ properties: resets: maxItems: 1 + sound-name-prefix: true + required: - "#sound-dai-cells" - compatible From 8a2d8e4fed6d5829ec3681af313d63e02bc22dad Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Thu, 23 Dec 2021 16:22:12 +0800 Subject: [PATCH 294/327] ASoC: codec: tlv320adc3xxx: Fix missing clk_disable_unprepare() on error in adc3xxx_i2c_probe() Fix the missing clk_disable_unprepare() before return from adc3xxx_i2c_probe() in the error handling case. Fixes: e9a3b57efd28 ("ASoC: codec: tlv320adc3xxx: New codec driver") Reported-by: Hulk Robot Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20211223082212.3342184-1-yangyingliang@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320adc3xxx.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/tlv320adc3xxx.c b/sound/soc/codecs/tlv320adc3xxx.c index a683bda7eb36e..4baf3d8816334 100644 --- a/sound/soc/codecs/tlv320adc3xxx.c +++ b/sound/soc/codecs/tlv320adc3xxx.c @@ -1232,21 +1232,21 @@ static int adc3xxx_i2c_probe(struct i2c_client *i2c, ret = adc3xxx_parse_dt_gpio(adc3xxx, "ti,dmdin-gpio1", &adc3xxx->gpio_cfg[0]); if (ret < 0) - return ret; + goto err_unprepare_mclk; ret = adc3xxx_parse_dt_gpio(adc3xxx, "ti,dmclk-gpio2", &adc3xxx->gpio_cfg[1]); if (ret < 0) - return ret; + goto err_unprepare_mclk; ret = adc3xxx_parse_dt_micbias(adc3xxx, "ti,micbias1-vg", &adc3xxx->micbias_vg[0]); if (ret < 0) - return ret; + goto err_unprepare_mclk; ret = adc3xxx_parse_dt_micbias(adc3xxx, "ti,micbias2-vg", &adc3xxx->micbias_vg[1]); if (ret < 0) - return ret; + goto err_unprepare_mclk; adc3xxx->regmap = devm_regmap_init_i2c(i2c, &adc3xxx_regmap); if (IS_ERR(adc3xxx->regmap)) { ret = PTR_ERR(adc3xxx->regmap); - return ret; + goto err_unprepare_mclk; } i2c_set_clientdata(i2c, adc3xxx); @@ -1263,9 +1263,15 @@ static int adc3xxx_i2c_probe(struct i2c_client *i2c, ret = snd_soc_register_component(dev, &soc_component_dev_adc3xxx, &adc3xxx_dai, 1); - if (ret < 0) + if (ret < 0) { dev_err(dev, "Failed to register codec: %d\n", ret); + goto err_unprepare_mclk; + } + + return 0; +err_unprepare_mclk: + clk_disable_unprepare(adc3xxx->mclk); return ret; } From 4e28491a7a198c668437f2be8a91a76aa52f20eb Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Tue, 14 Dec 2021 12:00:28 +0800 Subject: [PATCH 295/327] ASoC: mediatek: mt8192-mt6359: fix device_node leak The of_parse_phandle() document: >>> Use of_node_put() on it when done. The driver didn't call of_node_put(). Fixes the leak. Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20211214040028.2992627-1-tzungbi@google.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c index 1d16939f80e36..2552f30d8fe43 100644 --- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c +++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c @@ -1172,7 +1172,11 @@ static int mt8192_mt6359_dev_probe(struct platform_device *pdev) return ret; } - return devm_snd_soc_register_card(&pdev->dev, card); + ret = devm_snd_soc_register_card(&pdev->dev, card); + + of_node_put(platform_node); + of_node_put(hdmi_codec); + return ret; } #ifdef CONFIG_OF From 3d4641a42ccf1593b3f3a474ee7541727acbb8e0 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Tue, 14 Dec 2021 15:20:46 +0100 Subject: [PATCH 296/327] ASoC: core: Add snd_soc_of_parse_pin_switches() from simple-card-utils The ASoC core already has several helpers to parse card properties from the device tree. Move the parsing code for "pin-switches" from simple-card-utils to a shared snd_soc_of_parse_pin_switches() function so other drivers can also use it to set up pin switches configured in the device tree. Cc: Paul Cercueil Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20211214142049.20422-2-stephan@gerhold.net Signed-off-by: Mark Brown --- include/sound/soc.h | 1 + sound/soc/generic/simple-card-utils.c | 45 +----------------------- sound/soc/soc-core.c | 50 +++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 44 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 5872a8864f3b6..7a1650b303f14 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1211,6 +1211,7 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card, const char *propname); int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, const char *propname); +int snd_soc_of_parse_pin_switches(struct snd_soc_card *card, const char *prop); int snd_soc_of_get_slot_mask(struct device_node *np, const char *prop_name, unsigned int *mask); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 850e968677f10..a81323d1691d0 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -499,57 +499,14 @@ EXPORT_SYMBOL_GPL(asoc_simple_parse_widgets); int asoc_simple_parse_pin_switches(struct snd_soc_card *card, char *prefix) { - const unsigned int nb_controls_max = 16; - const char **strings, *control_name; - struct snd_kcontrol_new *controls; - struct device *dev = card->dev; - unsigned int i, nb_controls; char prop[128]; - int ret; if (!prefix) prefix = ""; snprintf(prop, sizeof(prop), "%s%s", prefix, "pin-switches"); - if (!of_property_read_bool(dev->of_node, prop)) - return 0; - - strings = devm_kcalloc(dev, nb_controls_max, - sizeof(*strings), GFP_KERNEL); - if (!strings) - return -ENOMEM; - - ret = of_property_read_string_array(dev->of_node, prop, - strings, nb_controls_max); - if (ret < 0) - return ret; - - nb_controls = (unsigned int)ret; - - controls = devm_kcalloc(dev, nb_controls, - sizeof(*controls), GFP_KERNEL); - if (!controls) - return -ENOMEM; - - for (i = 0; i < nb_controls; i++) { - control_name = devm_kasprintf(dev, GFP_KERNEL, - "%s Switch", strings[i]); - if (!control_name) - return -ENOMEM; - - controls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; - controls[i].name = control_name; - controls[i].info = snd_soc_dapm_info_pin_switch; - controls[i].get = snd_soc_dapm_get_pin_switch; - controls[i].put = snd_soc_dapm_put_pin_switch; - controls[i].private_value = (unsigned long)strings[i]; - } - - card->controls = controls; - card->num_controls = nb_controls; - - return 0; + return snd_soc_of_parse_pin_switches(card, prop); } EXPORT_SYMBOL_GPL(asoc_simple_parse_pin_switches); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1d62160f96b11..434e61b46983c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2823,6 +2823,56 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets); +int snd_soc_of_parse_pin_switches(struct snd_soc_card *card, const char *prop) +{ + const unsigned int nb_controls_max = 16; + const char **strings, *control_name; + struct snd_kcontrol_new *controls; + struct device *dev = card->dev; + unsigned int i, nb_controls; + int ret; + + if (!of_property_read_bool(dev->of_node, prop)) + return 0; + + strings = devm_kcalloc(dev, nb_controls_max, + sizeof(*strings), GFP_KERNEL); + if (!strings) + return -ENOMEM; + + ret = of_property_read_string_array(dev->of_node, prop, + strings, nb_controls_max); + if (ret < 0) + return ret; + + nb_controls = (unsigned int)ret; + + controls = devm_kcalloc(dev, nb_controls, + sizeof(*controls), GFP_KERNEL); + if (!controls) + return -ENOMEM; + + for (i = 0; i < nb_controls; i++) { + control_name = devm_kasprintf(dev, GFP_KERNEL, + "%s Switch", strings[i]); + if (!control_name) + return -ENOMEM; + + controls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + controls[i].name = control_name; + controls[i].info = snd_soc_dapm_info_pin_switch; + controls[i].get = snd_soc_dapm_get_pin_switch; + controls[i].put = snd_soc_dapm_put_pin_switch; + controls[i].private_value = (unsigned long)strings[i]; + } + + card->controls = controls; + card->num_controls = nb_controls; + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_of_parse_pin_switches); + int snd_soc_of_get_slot_mask(struct device_node *np, const char *prop_name, unsigned int *mask) From 37a49da9a7d5ac1f7128000de42ff222da46ba7a Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Tue, 14 Dec 2021 15:20:47 +0100 Subject: [PATCH 297/327] ASoC: dt-bindings: qcom: sm8250: Document "pin-switches" and "widgets" Some sound card setups might require extra pin switches to allow turning off certain audio components. There are two real examples for this in smartphones/tablets based on MSM8916: 1. Analog speaker amplifiers connected to headphone outputs. The MSM8916 analog codec does not have a separate "Line Out" port so some devices have an analog speaker amplifier connected to one of the headphone outputs. A pin switch is necessary to allow playback on headphones without also activating the speaker. 2. External speaker codec also used as earpiece. Some smartphones have two front-facing (stereo) speakers that can be also configured to act as an earpiece during voice calls. A pin switch is needed to allow disabling the second speaker during voice calls. There are existing bindings that allow setting up such pin switches in simple-card.yaml. Document the same for Qcom sound cards. One variant of example 1 above is added to the examples in the DT schema: There is an analog speaker amplifier connected to the HPH_R (right headphone channel) output. Adding a "Speaker" pin switch and widget allows turning off the speaker when audio should be only played via the connected headphones. Cc: Srinivas Kandagatla Signed-off-by: Stephan Gerhold Acked-by: Rob Herring Link: https://lore.kernel.org/r/20211214142049.20422-3-stephan@gerhold.net Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/qcom,sm8250.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index e50964c54bb91..4bfda04b4608a 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -39,6 +39,14 @@ properties: $ref: /schemas/types.yaml#/definitions/string description: User visible long sound card name + pin-switches: + description: List of widget names for which pin switches should be created. + $ref: /schemas/types.yaml#/definitions/string-array + + widgets: + description: User specified audio sound widgets. + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + # Only valid for some compatibles (see allOf if below) reg: true reg-names: true @@ -251,7 +259,15 @@ examples: reg-names = "mic-iomux", "spkr-iomux"; model = "msm8916"; + widgets = + "Speaker", "Speaker", + "Headphone", "Headphones"; + pin-switches = "Speaker"; audio-routing = + "Speaker", "Speaker Amp OUT", + "Speaker Amp IN", "HPH_R", + "Headphones", "HPH_L", + "Headphones", "HPH_R", "AMIC1", "MIC BIAS Internal1", "AMIC2", "MIC BIAS Internal2", "AMIC3", "MIC BIAS Internal3"; From 2623e66de125ba153e41be6a0b8af24cae8aa436 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Tue, 14 Dec 2021 15:20:48 +0100 Subject: [PATCH 298/327] ASoC: qcom: common: Parse "pin-switches" and "widgets" from DT Use the DT helpers in the ASoC core to parse the "pin-switches" and "widgets" properties from the device tree. This allows adding extra mixers to disable e.g. an extra speaker amplifier that would be normally powered on automatically because it is connected to a shared output pin. Cc: Srinivas Kandagatla Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20211214142049.20422-4-stephan@gerhold.net Signed-off-by: Mark Brown --- sound/soc/qcom/common.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c index e1bf04d006259..c407684ce1a22 100644 --- a/sound/soc/qcom/common.c +++ b/sound/soc/qcom/common.c @@ -26,6 +26,12 @@ int qcom_snd_parse_of(struct snd_soc_card *card) return ret; } + if (of_property_read_bool(dev->of_node, "widgets")) { + ret = snd_soc_of_parse_audio_simple_widgets(card, "widgets"); + if (ret) + return ret; + } + /* DAPM routes */ if (of_property_read_bool(dev->of_node, "audio-routing")) { ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); @@ -39,6 +45,10 @@ int qcom_snd_parse_of(struct snd_soc_card *card) return ret; } + ret = snd_soc_of_parse_pin_switches(card, "pin-switches"); + if (ret) + return ret; + ret = snd_soc_of_parse_aux_devs(card, "aux-devs"); if (ret) return ret; From 319a05330f4ff3f951f9c42094958c6cdef393b3 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Tue, 14 Dec 2021 15:20:49 +0100 Subject: [PATCH 299/327] ASoC: msm8916-wcd-analog: Use separate outputs for HPH_L/HPH_R The analog codec has separate output paths for the left headphone channel (HPH_L) and the right headphone channel (HPH_R). While they are usually used together for actual headphones output, some devices also have an analog speaker amplifier connected to one of the headphone channels. To allow modelling that properly (and to avoid powering on the unneeded output path), HPH_L and HPH_R should be represented by separate outputs rather than a shared HEADPHONE output that always activates both paths. Cc: Srinivas Kandagatla Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20211214142049.20422-5-stephan@gerhold.net Signed-off-by: Mark Brown --- sound/soc/codecs/msm8916-wcd-analog.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index 3ddd822240e3a..485cda46dbb9b 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -822,8 +822,8 @@ static const struct snd_soc_dapm_route pm8916_wcd_analog_audio_map[] = { {"EAR PA", NULL, "EAR CP"}, /* Headset (RX MIX1 and RX MIX2) */ - {"HEADPHONE", NULL, "HPHL PA"}, - {"HEADPHONE", NULL, "HPHR PA"}, + {"HPH_L", NULL, "HPHL PA"}, + {"HPH_R", NULL, "HPHR PA"}, {"HPHL DAC", NULL, "EAR_HPHL_CLK"}, {"HPHR DAC", NULL, "EAR_HPHR_CLK"}, @@ -870,7 +870,8 @@ static const struct snd_soc_dapm_widget pm8916_wcd_analog_dapm_widgets[] = { SND_SOC_DAPM_INPUT("AMIC3"), SND_SOC_DAPM_INPUT("AMIC2"), SND_SOC_DAPM_OUTPUT("EAR"), - SND_SOC_DAPM_OUTPUT("HEADPHONE"), + SND_SOC_DAPM_OUTPUT("HPH_L"), + SND_SOC_DAPM_OUTPUT("HPH_R"), /* RX stuff */ SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0), From da893a93eaf8eb2bce03862e00b9998463eeaecf Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 24 Dec 2021 10:10:28 +0800 Subject: [PATCH 300/327] ASOC: SOF: Intel: use snd_soc_dai_get_widget() We have a helper, use it to simplify widget lookup Suggested-by: Peter Ujfalusi Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20211224021034.26635-2-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 18abbd13d5937..99255028d3fec 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -189,10 +189,7 @@ static int sdw_params_stream(struct device *dev, struct snd_soc_dai *d = params_data->dai; struct snd_soc_dapm_widget *w; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - w = d->playback_widget; - else - w = d->capture_widget; + w = snd_soc_dai_get_widget(d, substream->stream); return sdw_dai_config_ipc(sdev, w, params_data->link_id, params_data->alh_stream_id, d->id, true); @@ -206,10 +203,7 @@ static int sdw_free_stream(struct device *dev, struct snd_soc_dai *d = free_data->dai; struct snd_soc_dapm_widget *w; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - w = d->playback_widget; - else - w = d->capture_widget; + w = snd_soc_dai_get_widget(d, substream->stream); /* send invalid stream_id */ return sdw_dai_config_ipc(sdev, w, free_data->link_id, 0xFFFF, d->id, false); From b86947b52f0d0e5b6e6f0510933ca13aad266e47 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 24 Dec 2021 10:10:29 +0800 Subject: [PATCH 301/327] ASoC/soundwire: intel: simplify callbacks for params/hw_free We don't really need to pass a substream to the callback, we only need the direction. No functionality change, only simplification to enable improve suspend with paused streams. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Signed-off-by: Bard Liao Acked-By: Vinod Koul Link: https://lore.kernel.org/r/20211224021034.26635-3-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- drivers/soundwire/intel.c | 14 +++++++------- include/linux/soundwire/sdw_intel.h | 4 ++-- sound/soc/sof/intel/hda.c | 6 ++---- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 78037ffdb09ba..25c5f5b9f058e 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -711,7 +711,7 @@ intel_pdi_alh_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi) } static int intel_params_stream(struct sdw_intel *sdw, - struct snd_pcm_substream *substream, + int stream, struct snd_soc_dai *dai, struct snd_pcm_hw_params *hw_params, int link_id, int alh_stream_id) @@ -719,7 +719,7 @@ static int intel_params_stream(struct sdw_intel *sdw, struct sdw_intel_link_res *res = sdw->link_res; struct sdw_intel_stream_params_data params_data; - params_data.substream = substream; + params_data.stream = stream; /* direction */ params_data.dai = dai; params_data.hw_params = hw_params; params_data.link_id = link_id; @@ -732,14 +732,14 @@ static int intel_params_stream(struct sdw_intel *sdw, } static int intel_free_stream(struct sdw_intel *sdw, - struct snd_pcm_substream *substream, + int stream, struct snd_soc_dai *dai, int link_id) { struct sdw_intel_link_res *res = sdw->link_res; struct sdw_intel_stream_free_data free_data; - free_data.substream = substream; + free_data.stream = stream; /* direction */ free_data.dai = dai; free_data.link_id = link_id; @@ -876,7 +876,7 @@ static int intel_hw_params(struct snd_pcm_substream *substream, dma->hw_params = params; /* Inform DSP about PDI stream number */ - ret = intel_params_stream(sdw, substream, dai, params, + ret = intel_params_stream(sdw, substream->stream, dai, params, sdw->instance, pdi->intel_alh_id); if (ret) @@ -953,7 +953,7 @@ static int intel_prepare(struct snd_pcm_substream *substream, sdw_cdns_config_stream(cdns, ch, dir, dma->pdi); /* Inform DSP about PDI stream number */ - ret = intel_params_stream(sdw, substream, dai, + ret = intel_params_stream(sdw, substream->stream, dai, dma->hw_params, sdw->instance, dma->pdi->intel_alh_id); @@ -987,7 +987,7 @@ intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) return ret; } - ret = intel_free_stream(sdw, substream, dai, sdw->instance); + ret = intel_free_stream(sdw, substream->stream, dai, sdw->instance); if (ret < 0) { dev_err(dai->dev, "intel_free_stream: failed %d\n", ret); return ret; diff --git a/include/linux/soundwire/sdw_intel.h b/include/linux/soundwire/sdw_intel.h index 8a463b8fc12ad..67e0d3e750b5c 100644 --- a/include/linux/soundwire/sdw_intel.h +++ b/include/linux/soundwire/sdw_intel.h @@ -92,7 +92,7 @@ * firmware. */ struct sdw_intel_stream_params_data { - struct snd_pcm_substream *substream; + int stream; struct snd_soc_dai *dai; struct snd_pcm_hw_params *hw_params; int link_id; @@ -105,7 +105,7 @@ struct sdw_intel_stream_params_data { * firmware. */ struct sdw_intel_stream_free_data { - struct snd_pcm_substream *substream; + int stream; struct snd_soc_dai *dai; int link_id; }; diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 99255028d3fec..c8fb082209ce4 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -184,12 +184,11 @@ static int sdw_dai_config_ipc(struct snd_sof_dev *sdev, static int sdw_params_stream(struct device *dev, struct sdw_intel_stream_params_data *params_data) { - struct snd_pcm_substream *substream = params_data->substream; struct snd_sof_dev *sdev = dev_get_drvdata(dev); struct snd_soc_dai *d = params_data->dai; struct snd_soc_dapm_widget *w; - w = snd_soc_dai_get_widget(d, substream->stream); + w = snd_soc_dai_get_widget(d, params_data->stream); return sdw_dai_config_ipc(sdev, w, params_data->link_id, params_data->alh_stream_id, d->id, true); @@ -198,12 +197,11 @@ static int sdw_params_stream(struct device *dev, static int sdw_free_stream(struct device *dev, struct sdw_intel_stream_free_data *free_data) { - struct snd_pcm_substream *substream = free_data->substream; struct snd_sof_dev *sdev = dev_get_drvdata(dev); struct snd_soc_dai *d = free_data->dai; struct snd_soc_dapm_widget *w; - w = snd_soc_dai_get_widget(d, substream->stream); + w = snd_soc_dai_get_widget(d, free_data->stream); /* send invalid stream_id */ return sdw_dai_config_ipc(sdev, w, free_data->link_id, 0xFFFF, d->id, false); From 8ddeafb957a9a6dd33b2c80309d726d3141df08f Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 24 Dec 2021 10:10:30 +0800 Subject: [PATCH 302/327] soundwire: intel: improve suspend flows This patch provides both a simplification of the suspend flows and a better balanced operation during suspend/resume transition, as part of the transition of Sound Open Firmware (SOF) to dynamic pipelines: the DSP resources are only enabled when required instead of enabled on startup. The exiting code relies on a convoluted way of dealing with suspend signals. Since there is no .suspend DAI callback, we used the component .suspend and marked all the component DAI dmas as 'suspended'. The information was used in the .prepare stage to differentiate resume operations from xrun handling, and only reinitialize SHIM registers and DMA in the former case. While this solution has been working reliably for about 2 years, there is a much better solution consisting in trapping the TRIGGER_SUSPEND in the .trigger DAI ops. The DMA is still marked in the same way for the .prepare op to run, but in addition the callbacks sent to DSP firmware are now balanced. Normal operation: hw_params -> intel_params_stream hw_free -> intel_free_stream suspend -> intel_free_stream prepare -> intel_params_stream This balanced operation was not required with existing SOF firmware relying on static pipelines instantiated at every boot. With the on-going transition to dynamic pipelines, it's however a requirement to keep the use count for the DAI widget balanced across all transitions. The component suspend is not removed but instead modified to deal with a corner case: when a substream is PAUSED, the ALSA core does not throw the TRIGGER_SUSPEND. This is problematic since the refcount for all pipelines and widgets is not balanced, leading to issues on resume. The trigger callback keeps track of the 'paused' state with a new flag, which is tested during the component suspend called later to release the remaining DSP resources. These resources will be re-enabled in the .prepare step. The IPC used in the TRIGGER_SUSPEND to release DSP resources is not a problem since the BE dailink is already marked as non-atomic. Co-developed-by: Pierre-Louis Bossart Signed-off-by: Pierre-Louis Bossart Signed-off-by: Ranjani Sridharan Signed-off-by: Bard Liao Acked-By: Vinod Koul Link: https://lore.kernel.org/r/20211224021034.26635-4-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- drivers/soundwire/cadence_master.h | 2 + drivers/soundwire/intel.c | 110 +++++++++++++++++++++++------ 2 files changed, 89 insertions(+), 23 deletions(-) diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h index e587aede63bf0..aa4b9b0eb2a89 100644 --- a/drivers/soundwire/cadence_master.h +++ b/drivers/soundwire/cadence_master.h @@ -86,6 +86,7 @@ struct sdw_cdns_stream_config { * @link_id: Master link id * @hw_params: hw_params to be applied in .prepare step * @suspended: status set when suspended, to be used in .prepare + * @paused: status set in .trigger, to be used in suspend */ struct sdw_cdns_dma_data { char *name; @@ -96,6 +97,7 @@ struct sdw_cdns_dma_data { int link_id; struct snd_pcm_hw_params *hw_params; bool suspended; + bool paused; }; /** diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 25c5f5b9f058e..3d29f02ad5a6b 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -871,6 +871,7 @@ static int intel_hw_params(struct snd_pcm_substream *substream, sdw_cdns_config_stream(cdns, ch, dir, pdi); /* store pdi and hw_params, may be needed in prepare step */ + dma->paused = false; dma->suspended = false; dma->pdi = pdi; dma->hw_params = params; @@ -1008,29 +1009,6 @@ static void intel_shutdown(struct snd_pcm_substream *substream, pm_runtime_put_autosuspend(cdns->dev); } -static int intel_component_dais_suspend(struct snd_soc_component *component) -{ - struct sdw_cdns_dma_data *dma; - struct snd_soc_dai *dai; - - for_each_component_dais(component, dai) { - /* - * we don't have a .suspend dai_ops, and we don't have access - * to the substream, so let's mark both capture and playback - * DMA contexts as suspended - */ - dma = dai->playback_dma_data; - if (dma) - dma->suspended = true; - - dma = dai->capture_dma_data; - if (dma) - dma->suspended = true; - } - - return 0; -} - static int intel_pcm_set_sdw_stream(struct snd_soc_dai *dai, void *stream, int direction) { @@ -1059,11 +1037,97 @@ static void *intel_get_sdw_stream(struct snd_soc_dai *dai, return dma->stream; } +static int intel_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) +{ + struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); + struct sdw_intel *sdw = cdns_to_intel(cdns); + struct sdw_cdns_dma_data *dma; + int ret = 0; + + dma = snd_soc_dai_get_dma_data(dai, substream); + if (!dma) { + dev_err(dai->dev, "failed to get dma data in %s\n", + __func__); + return -EIO; + } + + switch (cmd) { + case SNDRV_PCM_TRIGGER_SUSPEND: + + /* + * The .prepare callback is used to deal with xruns and resume operations. + * In the case of xruns, the DMAs and SHIM registers cannot be touched, + * but for resume operations the DMAs and SHIM registers need to be initialized. + * the .trigger callback is used to track the suspend case only. + */ + + dma->suspended = true; + + ret = intel_free_stream(sdw, substream->stream, dai, sdw->instance); + break; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + dma->paused = true; + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + dma->paused = false; + break; + default: + break; + } + + return ret; +} + +static int intel_component_dais_suspend(struct snd_soc_component *component) +{ + struct snd_soc_dai *dai; + + /* + * In the corner case where a SUSPEND happens during a PAUSE, the ALSA core + * does not throw the TRIGGER_SUSPEND. This leaves the DAIs in an unbalanced state. + * Since the component suspend is called last, we can trap this corner case + * and force the DAIs to release their resources. + */ + for_each_component_dais(component, dai) { + struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); + struct sdw_intel *sdw = cdns_to_intel(cdns); + struct sdw_cdns_dma_data *dma; + int stream; + int ret; + + dma = dai->playback_dma_data; + stream = SNDRV_PCM_STREAM_PLAYBACK; + if (!dma) { + dma = dai->capture_dma_data; + stream = SNDRV_PCM_STREAM_CAPTURE; + } + + if (!dma) + continue; + + if (dma->suspended) + continue; + + if (dma->paused) { + dma->suspended = true; + + ret = intel_free_stream(sdw, stream, dai, sdw->instance); + if (ret < 0) + return ret; + } + } + + return 0; +} + static const struct snd_soc_dai_ops intel_pcm_dai_ops = { .startup = intel_startup, .hw_params = intel_hw_params, .prepare = intel_prepare, .hw_free = intel_hw_free, + .trigger = intel_trigger, .shutdown = intel_shutdown, .set_sdw_stream = intel_pcm_set_sdw_stream, .get_sdw_stream = intel_get_sdw_stream, From e8444560b4d9302a511f0996f4cfdf85b628f4ca Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 24 Dec 2021 10:10:31 +0800 Subject: [PATCH 303/327] ASoC/SoundWire: dai: expand 'stream' concept beyond SoundWire The HDAudio ASoC support relies on the set_tdm_slots() helper to store the HDaudio stream tag in the tx_mask. This only works because of the pre-existing order in soc-pcm.c, where the hw_params() is handled for codec_dais *before* cpu_dais. When the order is reversed, the stream_tag is used as a mask in the codec fixup functions: /* fixup params based on TDM slot masks */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && codec_dai->tx_mask) soc_pcm_codec_params_fixup(&codec_params, codec_dai->tx_mask); As a result of this confusion, the codec_params_fixup() ends-up generating bad channel masks, depending on what stream_tag was allocated. We could add a flag to state that the tx_mask is really not a mask, but it would be quite ugly to persist in overloading concepts. Instead, this patch suggests a more generic get/set 'stream' API based on the existing model for SoundWire. We can expand the concept to store 'stream' opaque information that is specific to different DAI types. In the case of HDAudio DAIs, we only need to store a stream tag as an unsigned char pointer. The TDM rx_ and tx_masks should really only be used to store masks. Rename get_sdw_stream/set_sdw_stream callbacks and helpers as get_stream/set_stream. No functionality change beyond the rename. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Ranjani Sridharan Signed-off-by: Bard Liao Acked-By: Vinod Koul Link: https://lore.kernel.org/r/20211224021034.26635-5-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- drivers/soundwire/intel.c | 8 ++++---- drivers/soundwire/qcom.c | 8 ++++---- drivers/soundwire/stream.c | 4 ++-- include/sound/soc-dai.h | 32 ++++++++++++++++---------------- sound/soc/codecs/max98373-sdw.c | 2 +- sound/soc/codecs/rt1308-sdw.c | 2 +- sound/soc/codecs/rt1316-sdw.c | 2 +- sound/soc/codecs/rt5682-sdw.c | 2 +- sound/soc/codecs/rt700.c | 2 +- sound/soc/codecs/rt711-sdca.c | 2 +- sound/soc/codecs/rt711.c | 2 +- sound/soc/codecs/rt715-sdca.c | 2 +- sound/soc/codecs/rt715.c | 2 +- sound/soc/codecs/sdw-mockup.c | 2 +- sound/soc/codecs/wcd938x.c | 2 +- sound/soc/codecs/wsa881x.c | 2 +- sound/soc/intel/boards/sof_sdw.c | 6 +++--- sound/soc/qcom/sdm845.c | 4 ++-- sound/soc/qcom/sm8250.c | 4 ++-- 19 files changed, 45 insertions(+), 45 deletions(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 3d29f02ad5a6b..70d164372a2ba 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1129,8 +1129,8 @@ static const struct snd_soc_dai_ops intel_pcm_dai_ops = { .hw_free = intel_hw_free, .trigger = intel_trigger, .shutdown = intel_shutdown, - .set_sdw_stream = intel_pcm_set_sdw_stream, - .get_sdw_stream = intel_get_sdw_stream, + .set_stream = intel_pcm_set_sdw_stream, + .get_stream = intel_get_sdw_stream, }; static const struct snd_soc_dai_ops intel_pdm_dai_ops = { @@ -1139,8 +1139,8 @@ static const struct snd_soc_dai_ops intel_pdm_dai_ops = { .prepare = intel_prepare, .hw_free = intel_hw_free, .shutdown = intel_shutdown, - .set_sdw_stream = intel_pdm_set_sdw_stream, - .get_sdw_stream = intel_get_sdw_stream, + .set_stream = intel_pdm_set_sdw_stream, + .get_stream = intel_get_sdw_stream, }; static const struct snd_soc_component_driver dai_component = { diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index a317bea2d42dd..9d42891ac3d69 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -1024,8 +1024,8 @@ static int qcom_swrm_startup(struct snd_pcm_substream *substream, ctrl->sruntime[dai->id] = sruntime; for_each_rtd_codec_dais(rtd, i, codec_dai) { - ret = snd_soc_dai_set_sdw_stream(codec_dai, sruntime, - substream->stream); + ret = snd_soc_dai_set_stream(codec_dai, sruntime, + substream->stream); if (ret < 0 && ret != -ENOTSUPP) { dev_err(dai->dev, "Failed to set sdw stream on %s\n", codec_dai->name); @@ -1051,8 +1051,8 @@ static const struct snd_soc_dai_ops qcom_swrm_pdm_dai_ops = { .hw_free = qcom_swrm_hw_free, .startup = qcom_swrm_startup, .shutdown = qcom_swrm_shutdown, - .set_sdw_stream = qcom_swrm_set_sdw_stream, - .get_sdw_stream = qcom_swrm_get_sdw_stream, + .set_stream = qcom_swrm_set_sdw_stream, + .get_stream = qcom_swrm_get_sdw_stream, }; static const struct snd_soc_component_driver qcom_swrm_dai_component = { diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index 5d4f6b308ef73..980f26d49b66f 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -1863,7 +1863,7 @@ static int set_stream(struct snd_pcm_substream *substream, /* Set stream pointer on all DAIs */ for_each_rtd_dais(rtd, i, dai) { - ret = snd_soc_dai_set_sdw_stream(dai, sdw_stream, substream->stream); + ret = snd_soc_dai_set_stream(dai, sdw_stream, substream->stream); if (ret < 0) { dev_err(rtd->dev, "failed to set stream pointer on dai %s\n", dai->name); break; @@ -1934,7 +1934,7 @@ void sdw_shutdown_stream(void *sdw_substream) /* Find stream from first CPU DAI */ dai = asoc_rtd_to_cpu(rtd, 0); - sdw_stream = snd_soc_dai_get_sdw_stream(dai, substream->stream); + sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); if (IS_ERR(sdw_stream)) { dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 5d4dd7c5450bc..bbd821d2df9ca 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -295,9 +295,9 @@ struct snd_soc_dai_ops { unsigned int *rx_num, unsigned int *rx_slot); int (*set_tristate)(struct snd_soc_dai *dai, int tristate); - int (*set_sdw_stream)(struct snd_soc_dai *dai, - void *stream, int direction); - void *(*get_sdw_stream)(struct snd_soc_dai *dai, int direction); + int (*set_stream)(struct snd_soc_dai *dai, + void *stream, int direction); + void *(*get_stream)(struct snd_soc_dai *dai, int direction); /* * DAI digital mute - optional. @@ -515,42 +515,42 @@ static inline void *snd_soc_dai_get_drvdata(struct snd_soc_dai *dai) } /** - * snd_soc_dai_set_sdw_stream() - Configures a DAI for SDW stream operation + * snd_soc_dai_set_stream() - Configures a DAI for stream operation * @dai: DAI - * @stream: STREAM + * @stream: STREAM (opaque structure depending on DAI type) * @direction: Stream direction(Playback/Capture) - * SoundWire subsystem doesn't have a notion of direction and we reuse + * Some subsystems, such as SoundWire, don't have a notion of direction and we reuse * the ASoC stream direction to configure sink/source ports. * Playback maps to source ports and Capture for sink ports. * * This should be invoked with NULL to clear the stream set previously. * Returns 0 on success, a negative error code otherwise. */ -static inline int snd_soc_dai_set_sdw_stream(struct snd_soc_dai *dai, - void *stream, int direction) +static inline int snd_soc_dai_set_stream(struct snd_soc_dai *dai, + void *stream, int direction) { - if (dai->driver->ops->set_sdw_stream) - return dai->driver->ops->set_sdw_stream(dai, stream, direction); + if (dai->driver->ops->set_stream) + return dai->driver->ops->set_stream(dai, stream, direction); else return -ENOTSUPP; } /** - * snd_soc_dai_get_sdw_stream() - Retrieves SDW stream from DAI + * snd_soc_dai_get_stream() - Retrieves stream from DAI * @dai: DAI * @direction: Stream direction(Playback/Capture) * * This routine only retrieves that was previously configured - * with snd_soc_dai_get_sdw_stream() + * with snd_soc_dai_get_stream() * * Returns pointer to stream or an ERR_PTR value, e.g. * ERR_PTR(-ENOTSUPP) if callback is not supported; */ -static inline void *snd_soc_dai_get_sdw_stream(struct snd_soc_dai *dai, - int direction) +static inline void *snd_soc_dai_get_stream(struct snd_soc_dai *dai, + int direction) { - if (dai->driver->ops->get_sdw_stream) - return dai->driver->ops->get_sdw_stream(dai, direction); + if (dai->driver->ops->get_stream) + return dai->driver->ops->get_stream(dai, direction); else return ERR_PTR(-ENOTSUPP); } diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c index dc520effc61cb..f47e956d4f55a 100644 --- a/sound/soc/codecs/max98373-sdw.c +++ b/sound/soc/codecs/max98373-sdw.c @@ -741,7 +741,7 @@ static int max98373_sdw_set_tdm_slot(struct snd_soc_dai *dai, static const struct snd_soc_dai_ops max98373_dai_sdw_ops = { .hw_params = max98373_sdw_dai_hw_params, .hw_free = max98373_pcm_hw_free, - .set_sdw_stream = max98373_set_sdw_stream, + .set_stream = max98373_set_sdw_stream, .shutdown = max98373_shutdown, .set_tdm_slot = max98373_sdw_set_tdm_slot, }; diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index f716668de6400..149a76075c76a 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -613,7 +613,7 @@ static const struct snd_soc_component_driver soc_component_sdw_rt1308 = { static const struct snd_soc_dai_ops rt1308_aif_dai_ops = { .hw_params = rt1308_sdw_hw_params, .hw_free = rt1308_sdw_pcm_hw_free, - .set_sdw_stream = rt1308_set_sdw_stream, + .set_stream = rt1308_set_sdw_stream, .shutdown = rt1308_sdw_shutdown, .set_tdm_slot = rt1308_sdw_set_tdm_slot, }; diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c index 09b4914bba1bf..c66d7b20cb4dd 100644 --- a/sound/soc/codecs/rt1316-sdw.c +++ b/sound/soc/codecs/rt1316-sdw.c @@ -602,7 +602,7 @@ static const struct snd_soc_component_driver soc_component_sdw_rt1316 = { static const struct snd_soc_dai_ops rt1316_aif_dai_ops = { .hw_params = rt1316_sdw_hw_params, .hw_free = rt1316_sdw_pcm_hw_free, - .set_sdw_stream = rt1316_set_sdw_stream, + .set_stream = rt1316_set_sdw_stream, .shutdown = rt1316_sdw_shutdown, }; diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index 31a4f286043e4..248257a2e4e0f 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -272,7 +272,7 @@ static int rt5682_sdw_hw_free(struct snd_pcm_substream *substream, static const struct snd_soc_dai_ops rt5682_sdw_ops = { .hw_params = rt5682_sdw_hw_params, .hw_free = rt5682_sdw_hw_free, - .set_sdw_stream = rt5682_set_sdw_stream, + .set_stream = rt5682_set_sdw_stream, .shutdown = rt5682_sdw_shutdown, }; diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c index 921382724f9cd..e61a8257bf647 100644 --- a/sound/soc/codecs/rt700.c +++ b/sound/soc/codecs/rt700.c @@ -1005,7 +1005,7 @@ static int rt700_pcm_hw_free(struct snd_pcm_substream *substream, static const struct snd_soc_dai_ops rt700_ops = { .hw_params = rt700_pcm_hw_params, .hw_free = rt700_pcm_hw_free, - .set_sdw_stream = rt700_set_sdw_stream, + .set_stream = rt700_set_sdw_stream, .shutdown = rt700_shutdown, }; diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c index 2e992589f1e42..bdb1375f03388 100644 --- a/sound/soc/codecs/rt711-sdca.c +++ b/sound/soc/codecs/rt711-sdca.c @@ -1358,7 +1358,7 @@ static int rt711_sdca_pcm_hw_free(struct snd_pcm_substream *substream, static const struct snd_soc_dai_ops rt711_sdca_ops = { .hw_params = rt711_sdca_pcm_hw_params, .hw_free = rt711_sdca_pcm_hw_free, - .set_sdw_stream = rt711_sdca_set_sdw_stream, + .set_stream = rt711_sdca_set_sdw_stream, .shutdown = rt711_sdca_shutdown, }; diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c index a7c5608a0ef87..6770825d037a8 100644 --- a/sound/soc/codecs/rt711.c +++ b/sound/soc/codecs/rt711.c @@ -1089,7 +1089,7 @@ static int rt711_pcm_hw_free(struct snd_pcm_substream *substream, static const struct snd_soc_dai_ops rt711_ops = { .hw_params = rt711_pcm_hw_params, .hw_free = rt711_pcm_hw_free, - .set_sdw_stream = rt711_set_sdw_stream, + .set_stream = rt711_set_sdw_stream, .shutdown = rt711_shutdown, }; diff --git a/sound/soc/codecs/rt715-sdca.c b/sound/soc/codecs/rt715-sdca.c index 66e166568c508..bfa536bd71960 100644 --- a/sound/soc/codecs/rt715-sdca.c +++ b/sound/soc/codecs/rt715-sdca.c @@ -938,7 +938,7 @@ static int rt715_sdca_pcm_hw_free(struct snd_pcm_substream *substream, static const struct snd_soc_dai_ops rt715_sdca_ops = { .hw_params = rt715_sdca_pcm_hw_params, .hw_free = rt715_sdca_pcm_hw_free, - .set_sdw_stream = rt715_sdca_set_sdw_stream, + .set_stream = rt715_sdca_set_sdw_stream, .shutdown = rt715_sdca_shutdown, }; diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c index 1352869cc0867..a64d11a747513 100644 --- a/sound/soc/codecs/rt715.c +++ b/sound/soc/codecs/rt715.c @@ -909,7 +909,7 @@ static int rt715_pcm_hw_free(struct snd_pcm_substream *substream, static const struct snd_soc_dai_ops rt715_ops = { .hw_params = rt715_pcm_hw_params, .hw_free = rt715_pcm_hw_free, - .set_sdw_stream = rt715_set_sdw_stream, + .set_stream = rt715_set_sdw_stream, .shutdown = rt715_shutdown, }; diff --git a/sound/soc/codecs/sdw-mockup.c b/sound/soc/codecs/sdw-mockup.c index 8ea13cfa9f8ed..7c612aaf31c75 100644 --- a/sound/soc/codecs/sdw-mockup.c +++ b/sound/soc/codecs/sdw-mockup.c @@ -138,7 +138,7 @@ static int sdw_mockup_pcm_hw_free(struct snd_pcm_substream *substream, static const struct snd_soc_dai_ops sdw_mockup_ops = { .hw_params = sdw_mockup_pcm_hw_params, .hw_free = sdw_mockup_pcm_hw_free, - .set_sdw_stream = sdw_mockup_set_sdw_stream, + .set_stream = sdw_mockup_set_sdw_stream, .shutdown = sdw_mockup_shutdown, }; diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index 67151c7770c65..0b5266c56a3fb 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -4287,7 +4287,7 @@ static int wcd938x_codec_set_sdw_stream(struct snd_soc_dai *dai, static const struct snd_soc_dai_ops wcd938x_sdw_dai_ops = { .hw_params = wcd938x_codec_hw_params, .hw_free = wcd938x_codec_free, - .set_sdw_stream = wcd938x_codec_set_sdw_stream, + .set_stream = wcd938x_codec_set_sdw_stream, }; static struct snd_soc_dai_driver wcd938x_dais[] = { diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c index 2da4a5fa7a18d..ffc025e01bce4 100644 --- a/sound/soc/codecs/wsa881x.c +++ b/sound/soc/codecs/wsa881x.c @@ -1018,7 +1018,7 @@ static const struct snd_soc_dai_ops wsa881x_dai_ops = { .hw_params = wsa881x_hw_params, .hw_free = wsa881x_hw_free, .mute_stream = wsa881x_digital_mute, - .set_sdw_stream = wsa881x_set_sdw_stream, + .set_stream = wsa881x_set_sdw_stream, }; static struct snd_soc_dai_driver wsa881x_dais[] = { diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index de303a9808791..da515eb1ddbe7 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -347,7 +347,7 @@ int sdw_prepare(struct snd_pcm_substream *substream) /* Find stream from first CPU DAI */ dai = asoc_rtd_to_cpu(rtd, 0); - sdw_stream = snd_soc_dai_get_sdw_stream(dai, substream->stream); + sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); if (IS_ERR(sdw_stream)) { dev_err(rtd->dev, "no stream found for DAI %s", dai->name); @@ -367,7 +367,7 @@ int sdw_trigger(struct snd_pcm_substream *substream, int cmd) /* Find stream from first CPU DAI */ dai = asoc_rtd_to_cpu(rtd, 0); - sdw_stream = snd_soc_dai_get_sdw_stream(dai, substream->stream); + sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); if (IS_ERR(sdw_stream)) { dev_err(rtd->dev, "no stream found for DAI %s", dai->name); @@ -406,7 +406,7 @@ int sdw_hw_free(struct snd_pcm_substream *substream) /* Find stream from first CPU DAI */ dai = asoc_rtd_to_cpu(rtd, 0); - sdw_stream = snd_soc_dai_get_sdw_stream(dai, substream->stream); + sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); if (IS_ERR(sdw_stream)) { dev_err(rtd->dev, "no stream found for DAI %s", dai->name); diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c index 10d724bd1d67c..5c1d13eccbee5 100644 --- a/sound/soc/qcom/sdm845.c +++ b/sound/soc/qcom/sdm845.c @@ -57,8 +57,8 @@ static int sdm845_slim_snd_hw_params(struct snd_pcm_substream *substream, int ret = 0, i; for_each_rtd_codec_dais(rtd, i, codec_dai) { - sruntime = snd_soc_dai_get_sdw_stream(codec_dai, - substream->stream); + sruntime = snd_soc_dai_get_stream(codec_dai, + substream->stream); if (sruntime != ERR_PTR(-ENOTSUPP)) pdata->sruntime[cpu_dai->id] = sruntime; diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index b2ca2579810b0..114a29e01c0fe 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -136,8 +136,8 @@ static int sm8250_snd_hw_params(struct snd_pcm_substream *substream, case TX_CODEC_DMA_TX_2: case TX_CODEC_DMA_TX_3: for_each_rtd_codec_dais(rtd, i, codec_dai) { - sruntime = snd_soc_dai_get_sdw_stream(codec_dai, - substream->stream); + sruntime = snd_soc_dai_get_stream(codec_dai, + substream->stream); if (sruntime != ERR_PTR(-ENOTSUPP)) pdata->sruntime[cpu_dai->id] = sruntime; } From 636110411ca726f19ef8e87b0be51bb9a4cdef06 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 24 Dec 2021 10:10:32 +0800 Subject: [PATCH 304/327] ASoC: Intel/SOF: use set_stream() instead of set_tdm_slots() for HDAudio Overloading the tx_mask with a linear value is asking for trouble and only works because the codec_dai hw_params() is called before the cpu_dai hw_params(). Move to the more generic set_stream() API to pass the hdac_stream information. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Ranjani Sridharan Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20211224021034.26635-6-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hda.c | 22 +++++++++++----------- sound/soc/intel/skylake/skl-pcm.c | 7 ++----- sound/soc/sof/intel/hda-dai.c | 7 ++----- 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index 390dd6c7f6a50..de5955db0a5f0 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -46,9 +46,8 @@ static int hdac_hda_dai_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai); static int hdac_hda_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai); -static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai, - unsigned int tx_mask, unsigned int rx_mask, - int slots, int slot_width); +static int hdac_hda_dai_set_stream(struct snd_soc_dai *dai, void *stream, + int direction); static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt, struct snd_soc_dai *dai); @@ -58,7 +57,7 @@ static const struct snd_soc_dai_ops hdac_hda_dai_ops = { .prepare = hdac_hda_dai_prepare, .hw_params = hdac_hda_dai_hw_params, .hw_free = hdac_hda_dai_hw_free, - .set_tdm_slot = hdac_hda_dai_set_tdm_slot, + .set_stream = hdac_hda_dai_set_stream, }; static struct snd_soc_dai_driver hdac_hda_dais[] = { @@ -180,21 +179,22 @@ static struct snd_soc_dai_driver hdac_hda_dais[] = { }; -static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai, - unsigned int tx_mask, unsigned int rx_mask, - int slots, int slot_width) +static int hdac_hda_dai_set_stream(struct snd_soc_dai *dai, + void *stream, int direction) { struct snd_soc_component *component = dai->component; struct hdac_hda_priv *hda_pvt; struct hdac_hda_pcm *pcm; + struct hdac_stream *hstream; + + if (!stream) + return -EINVAL; hda_pvt = snd_soc_component_get_drvdata(component); pcm = &hda_pvt->pcm[dai->id]; + hstream = (struct hdac_stream *)stream; - if (tx_mask) - pcm->stream_tag[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask; - else - pcm->stream_tag[SNDRV_PCM_STREAM_CAPTURE] = rx_mask; + pcm->stream_tag[direction] = hstream->stream_tag; return 0; } diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 9ecaf6a1e8475..8378c187959fb 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -562,11 +562,8 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, stream_tag = hdac_stream(link_dev)->stream_tag; - /* set the stream tag in the codec dai dma params */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0); - else - snd_soc_dai_set_tdm_slot(codec_dai, 0, stream_tag, 0, 0); + /* set the hdac_stream in the codec dai */ + snd_soc_dai_set_stream(codec_dai, hdac_stream(link_dev), substream->stream); p_params.s_fmt = snd_pcm_format_width(params_format(params)); p_params.ch = params_channels(params); diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 6381f2b227f01..cd12589355eff 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -243,11 +243,8 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream, if (!link) return -EINVAL; - /* set the stream tag in the codec dai dma params */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0); - else - snd_soc_dai_set_tdm_slot(codec_dai, 0, stream_tag, 0, 0); + /* set the hdac_stream in the codec dai */ + snd_soc_dai_set_stream(codec_dai, hdac_stream(link_dev), substream->stream); p_params.s_fmt = snd_pcm_format_width(params_format(params)); p_params.ch = params_channels(params); From 9283b6f923f3bdd92bdeaf259c6b7a5e9dac6900 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 24 Dec 2021 10:10:33 +0800 Subject: [PATCH 305/327] soundwire: intel: remove unnecessary init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cppcheck warning: drivers/soundwire/intel.c:1487:10: style: Variable 'ret' is assigned a value that is never used. [unreadVariable] int ret = 0; ^ Signed-off-by: Pierre-Louis Bossart Reviewed-by: Péter Ujfalusi Reviewed-by: Rander Wang Signed-off-by: Bard Liao Acked-By: Vinod Koul Link: https://lore.kernel.org/r/20211224021034.26635-7-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- drivers/soundwire/intel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 70d164372a2ba..0d1c86e6ac2e0 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1613,7 +1613,7 @@ static int __maybe_unused intel_pm_prepare(struct device *dev) struct sdw_intel *sdw = cdns_to_intel(cdns); struct sdw_bus *bus = &cdns->bus; u32 clock_stop_quirks; - int ret = 0; + int ret; if (bus->prop.hw_disabled || !sdw->startup_done) { dev_dbg(dev, "SoundWire master %d is disabled or not-started, ignoring\n", From 63a6aa963dd01b66019b7834cc84d032e145bb00 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 24 Dec 2021 10:10:34 +0800 Subject: [PATCH 306/327] soundwire: intel: remove PDM support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While the hardware supports PDM streams, this capability has never been tested or enabled on any product, so this is dead-code. Let's remove all this. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Péter Ujfalusi Reviewed-by: Rander Wang Signed-off-by: Bard Liao Acked-By: Vinod Koul Link: https://lore.kernel.org/r/20211224021034.26635-8-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- drivers/soundwire/cadence_master.c | 36 +-------- drivers/soundwire/cadence_master.h | 12 +-- drivers/soundwire/intel.c | 123 +++++++---------------------- 3 files changed, 31 insertions(+), 140 deletions(-) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 4fcc3ba93004a..558390af44b64 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -1178,9 +1178,6 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns, cdns->pcm.num_bd = config.pcm_bd; cdns->pcm.num_in = config.pcm_in; cdns->pcm.num_out = config.pcm_out; - cdns->pdm.num_bd = config.pdm_bd; - cdns->pdm.num_in = config.pdm_in; - cdns->pdm.num_out = config.pdm_out; /* Allocate PDIs for PCMs */ stream = &cdns->pcm; @@ -1211,32 +1208,6 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns, stream->num_pdi = stream->num_bd + stream->num_in + stream->num_out; cdns->num_ports = stream->num_pdi; - /* Allocate PDIs for PDMs */ - stream = &cdns->pdm; - ret = cdns_allocate_pdi(cdns, &stream->bd, - stream->num_bd, offset); - if (ret) - return ret; - - offset += stream->num_bd; - - ret = cdns_allocate_pdi(cdns, &stream->in, - stream->num_in, offset); - if (ret) - return ret; - - offset += stream->num_in; - - ret = cdns_allocate_pdi(cdns, &stream->out, - stream->num_out, offset); - - if (ret) - return ret; - - /* Update total number of PDM PDIs */ - stream->num_pdi = stream->num_bd + stream->num_in + stream->num_out; - cdns->num_ports += stream->num_pdi; - return 0; } EXPORT_SYMBOL(sdw_cdns_pdi_init); @@ -1681,7 +1652,7 @@ int sdw_cdns_probe(struct sdw_cdns *cdns) EXPORT_SYMBOL(sdw_cdns_probe); int cdns_set_sdw_stream(struct snd_soc_dai *dai, - void *stream, bool pcm, int direction) + void *stream, int direction) { struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); struct sdw_cdns_dma_data *dma; @@ -1705,10 +1676,7 @@ int cdns_set_sdw_stream(struct snd_soc_dai *dai, if (!dma) return -ENOMEM; - if (pcm) - dma->stream_type = SDW_STREAM_PCM; - else - dma->stream_type = SDW_STREAM_PDM; + dma->stream_type = SDW_STREAM_PCM; dma->bus = &cdns->bus; dma->link_id = cdns->instance; diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h index aa4b9b0eb2a89..595d72c15d977 100644 --- a/drivers/soundwire/cadence_master.h +++ b/drivers/soundwire/cadence_master.h @@ -17,7 +17,7 @@ * @h_ch_num: high channel for PDI * @ch_count: total channel count for PDI * @dir: data direction - * @type: stream type, PDM or PCM + * @type: stream type, (only PCM supported) */ struct sdw_cdns_pdi { int num; @@ -62,17 +62,11 @@ struct sdw_cdns_streams { * @pcm_bd: number of bidirectional PCM streams supported * @pcm_in: number of input PCM streams supported * @pcm_out: number of output PCM streams supported - * @pdm_bd: number of bidirectional PDM streams supported - * @pdm_in: number of input PDM streams supported - * @pdm_out: number of output PDM streams supported */ struct sdw_cdns_stream_config { unsigned int pcm_bd; unsigned int pcm_in; unsigned int pcm_out; - unsigned int pdm_bd; - unsigned int pdm_in; - unsigned int pdm_out; }; /** @@ -111,7 +105,6 @@ struct sdw_cdns_dma_data { * @ports: Data ports * @num_ports: Total number of data ports * @pcm: PCM streams - * @pdm: PDM streams * @registers: Cadence registers * @link_up: Link status * @msg_count: Messages sent on bus @@ -129,7 +122,6 @@ struct sdw_cdns { int num_ports; struct sdw_cdns_streams pcm; - struct sdw_cdns_streams pdm; int pdi_loopback_source; int pdi_loopback_target; @@ -188,7 +180,7 @@ cdns_xfer_msg_defer(struct sdw_bus *bus, int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params); int cdns_set_sdw_stream(struct snd_soc_dai *dai, - void *stream, bool pcm, int direction); + void *stream, int direction); void sdw_cdns_check_self_clearing_bits(struct sdw_cdns *cdns, const char *string, bool initial_delay, int reset_iterations); diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 0d1c86e6ac2e0..79ba0e3f6dac8 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -564,7 +564,7 @@ static void intel_pdi_init(struct sdw_intel *sdw, { void __iomem *shim = sdw->link_res->shim; unsigned int link_id = sdw->instance; - int pcm_cap, pdm_cap; + int pcm_cap; /* PCM Stream Capability */ pcm_cap = intel_readw(shim, SDW_SHIM_PCMSCAP(link_id)); @@ -575,41 +575,25 @@ static void intel_pdi_init(struct sdw_intel *sdw, dev_dbg(sdw->cdns.dev, "PCM cap bd:%d in:%d out:%d\n", config->pcm_bd, config->pcm_in, config->pcm_out); - - /* PDM Stream Capability */ - pdm_cap = intel_readw(shim, SDW_SHIM_PDMSCAP(link_id)); - - config->pdm_bd = FIELD_GET(SDW_SHIM_PDMSCAP_BSS, pdm_cap); - config->pdm_in = FIELD_GET(SDW_SHIM_PDMSCAP_ISS, pdm_cap); - config->pdm_out = FIELD_GET(SDW_SHIM_PDMSCAP_OSS, pdm_cap); - - dev_dbg(sdw->cdns.dev, "PDM cap bd:%d in:%d out:%d\n", - config->pdm_bd, config->pdm_in, config->pdm_out); } static int -intel_pdi_get_ch_cap(struct sdw_intel *sdw, unsigned int pdi_num, bool pcm) +intel_pdi_get_ch_cap(struct sdw_intel *sdw, unsigned int pdi_num) { void __iomem *shim = sdw->link_res->shim; unsigned int link_id = sdw->instance; int count; - if (pcm) { - count = intel_readw(shim, SDW_SHIM_PCMSYCHC(link_id, pdi_num)); + count = intel_readw(shim, SDW_SHIM_PCMSYCHC(link_id, pdi_num)); - /* - * WORKAROUND: on all existing Intel controllers, pdi - * number 2 reports channel count as 1 even though it - * supports 8 channels. Performing hardcoding for pdi - * number 2. - */ - if (pdi_num == 2) - count = 7; - - } else { - count = intel_readw(shim, SDW_SHIM_PDMSCAP(link_id)); - count = FIELD_GET(SDW_SHIM_PDMSCAP_CPSS, count); - } + /* + * WORKAROUND: on all existing Intel controllers, pdi + * number 2 reports channel count as 1 even though it + * supports 8 channels. Performing hardcoding for pdi + * number 2. + */ + if (pdi_num == 2) + count = 7; /* zero based values for channel count in register */ count++; @@ -620,12 +604,12 @@ intel_pdi_get_ch_cap(struct sdw_intel *sdw, unsigned int pdi_num, bool pcm) static int intel_pdi_get_ch_update(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi, unsigned int num_pdi, - unsigned int *num_ch, bool pcm) + unsigned int *num_ch) { int i, ch_count = 0; for (i = 0; i < num_pdi; i++) { - pdi->ch_count = intel_pdi_get_ch_cap(sdw, pdi->num, pcm); + pdi->ch_count = intel_pdi_get_ch_cap(sdw, pdi->num); ch_count += pdi->ch_count; pdi++; } @@ -635,25 +619,23 @@ static int intel_pdi_get_ch_update(struct sdw_intel *sdw, } static int intel_pdi_stream_ch_update(struct sdw_intel *sdw, - struct sdw_cdns_streams *stream, bool pcm) + struct sdw_cdns_streams *stream) { intel_pdi_get_ch_update(sdw, stream->bd, stream->num_bd, - &stream->num_ch_bd, pcm); + &stream->num_ch_bd); intel_pdi_get_ch_update(sdw, stream->in, stream->num_in, - &stream->num_ch_in, pcm); + &stream->num_ch_in); intel_pdi_get_ch_update(sdw, stream->out, stream->num_out, - &stream->num_ch_out, pcm); + &stream->num_ch_out); return 0; } static int intel_pdi_ch_update(struct sdw_intel *sdw) { - /* First update PCM streams followed by PDM streams */ - intel_pdi_stream_ch_update(sdw, &sdw->cdns.pcm, true); - intel_pdi_stream_ch_update(sdw, &sdw->cdns.pdm, false); + intel_pdi_stream_ch_update(sdw, &sdw->cdns.pcm); return 0; } @@ -840,7 +822,6 @@ static int intel_hw_params(struct snd_pcm_substream *substream, struct sdw_port_config *pconfig; int ch, dir; int ret; - bool pcm = true; dma = snd_soc_dai_get_dma_data(dai, substream); if (!dma) @@ -852,13 +833,7 @@ static int intel_hw_params(struct snd_pcm_substream *substream, else dir = SDW_DATA_DIR_TX; - if (dma->stream_type == SDW_STREAM_PDM) - pcm = false; - - if (pcm) - pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pcm, ch, dir, dai->id); - else - pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pdm, ch, dir, dai->id); + pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pcm, ch, dir, dai->id); if (!pdi) { ret = -EINVAL; @@ -888,12 +863,7 @@ static int intel_hw_params(struct snd_pcm_substream *substream, sconfig.frame_rate = params_rate(params); sconfig.type = dma->stream_type; - if (dma->stream_type == SDW_STREAM_PDM) { - sconfig.frame_rate *= 50; - sconfig.bps = 1; - } else { - sconfig.bps = snd_pcm_format_width(params_format(params)); - } + sconfig.bps = snd_pcm_format_width(params_format(params)); /* Port configuration */ pconfig = kzalloc(sizeof(*pconfig), GFP_KERNEL); @@ -1012,13 +982,7 @@ static void intel_shutdown(struct snd_pcm_substream *substream, static int intel_pcm_set_sdw_stream(struct snd_soc_dai *dai, void *stream, int direction) { - return cdns_set_sdw_stream(dai, stream, true, direction); -} - -static int intel_pdm_set_sdw_stream(struct snd_soc_dai *dai, - void *stream, int direction) -{ - return cdns_set_sdw_stream(dai, stream, false, direction); + return cdns_set_sdw_stream(dai, stream, direction); } static void *intel_get_sdw_stream(struct snd_soc_dai *dai, @@ -1133,16 +1097,6 @@ static const struct snd_soc_dai_ops intel_pcm_dai_ops = { .get_stream = intel_get_sdw_stream, }; -static const struct snd_soc_dai_ops intel_pdm_dai_ops = { - .startup = intel_startup, - .hw_params = intel_hw_params, - .prepare = intel_prepare, - .hw_free = intel_hw_free, - .shutdown = intel_shutdown, - .set_stream = intel_pdm_set_sdw_stream, - .get_stream = intel_get_sdw_stream, -}; - static const struct snd_soc_component_driver dai_component = { .name = "soundwire", .suspend = intel_component_dais_suspend @@ -1151,7 +1105,7 @@ static const struct snd_soc_component_driver dai_component = { static int intel_create_dai(struct sdw_cdns *cdns, struct snd_soc_dai_driver *dais, enum intel_pdi_type type, - u32 num, u32 off, u32 max_ch, bool pcm) + u32 num, u32 off, u32 max_ch) { int i; @@ -1180,10 +1134,7 @@ static int intel_create_dai(struct sdw_cdns *cdns, dais[i].capture.formats = SNDRV_PCM_FMTBIT_S16_LE; } - if (pcm) - dais[i].ops = &intel_pcm_dai_ops; - else - dais[i].ops = &intel_pdm_dai_ops; + dais[i].ops = &intel_pcm_dai_ops; } return 0; @@ -1197,7 +1148,7 @@ static int intel_register_dai(struct sdw_intel *sdw) int num_dai, ret, off = 0; /* DAIs are created based on total number of PDIs supported */ - num_dai = cdns->pcm.num_pdi + cdns->pdm.num_pdi; + num_dai = cdns->pcm.num_pdi; dais = devm_kcalloc(cdns->dev, num_dai, sizeof(*dais), GFP_KERNEL); if (!dais) @@ -1207,39 +1158,19 @@ static int intel_register_dai(struct sdw_intel *sdw) stream = &cdns->pcm; ret = intel_create_dai(cdns, dais, INTEL_PDI_IN, cdns->pcm.num_in, - off, stream->num_ch_in, true); + off, stream->num_ch_in); if (ret) return ret; off += cdns->pcm.num_in; ret = intel_create_dai(cdns, dais, INTEL_PDI_OUT, cdns->pcm.num_out, - off, stream->num_ch_out, true); + off, stream->num_ch_out); if (ret) return ret; off += cdns->pcm.num_out; ret = intel_create_dai(cdns, dais, INTEL_PDI_BD, cdns->pcm.num_bd, - off, stream->num_ch_bd, true); - if (ret) - return ret; - - /* Create PDM DAIs */ - stream = &cdns->pdm; - off += cdns->pcm.num_bd; - ret = intel_create_dai(cdns, dais, INTEL_PDI_IN, cdns->pdm.num_in, - off, stream->num_ch_in, false); - if (ret) - return ret; - - off += cdns->pdm.num_in; - ret = intel_create_dai(cdns, dais, INTEL_PDI_OUT, cdns->pdm.num_out, - off, stream->num_ch_out, false); - if (ret) - return ret; - - off += cdns->pdm.num_out; - ret = intel_create_dai(cdns, dais, INTEL_PDI_BD, cdns->pdm.num_bd, - off, stream->num_ch_bd, false); + off, stream->num_ch_bd); if (ret) return ret; From 493433785df0075afc0c106ab65f10a605d0b35d Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Fri, 24 Dec 2021 14:47:16 +0800 Subject: [PATCH 307/327] ASoC: mediatek: mt8173: fix device_node leak Fixes the device_node leak. Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20211224064719.2031210-2-tzungbi@google.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8173/mt8173-max98090.c | 3 +++ sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c | 2 ++ sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c | 2 ++ sound/soc/mediatek/mt8173/mt8173-rt5650.c | 2 ++ 4 files changed, 9 insertions(+) diff --git a/sound/soc/mediatek/mt8173/mt8173-max98090.c b/sound/soc/mediatek/mt8173/mt8173-max98090.c index 2408c9d3d9b39..65941dd2295d5 100644 --- a/sound/soc/mediatek/mt8173/mt8173-max98090.c +++ b/sound/soc/mediatek/mt8173/mt8173-max98090.c @@ -180,6 +180,9 @@ static int mt8173_max98090_dev_probe(struct platform_device *pdev) if (ret) dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", __func__, ret); + + of_node_put(codec_node); + of_node_put(platform_node); return ret; } diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c index e6e824f3d24ae..227b0b72c66e9 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c @@ -218,6 +218,8 @@ static int mt8173_rt5650_rt5514_dev_probe(struct platform_device *pdev) if (ret) dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", __func__, ret); + + of_node_put(platform_node); return ret; } diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c index ba6fe3d90bfc1..8df2ff2f2aab2 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c @@ -285,6 +285,8 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev) if (ret) dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", __func__, ret); + + of_node_put(platform_node); return ret; } diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c index 9b933cce0b209..16ddf9f8bbcb8 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c @@ -323,6 +323,8 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev) if (ret) dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", __func__, ret); + + of_node_put(platform_node); return ret; } From cb006006fe6221f092fadaffd3f219288304c9ad Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Fri, 24 Dec 2021 14:47:17 +0800 Subject: [PATCH 308/327] ASoC: mediatek: mt8183: fix device_node leak Fixes the device_node leak. Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20211224064719.2031210-3-tzungbi@google.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c | 6 +++++- sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c | 7 ++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c index f8a72a5102ad5..ca893feab7ebf 100644 --- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c @@ -781,7 +781,11 @@ static int mt8183_da7219_max98357_dev_probe(struct platform_device *pdev) return ret; } - return devm_snd_soc_register_card(&pdev->dev, card); + ret = devm_snd_soc_register_card(&pdev->dev, card); + + of_node_put(platform_node); + of_node_put(hdmi_codec); + return ret; } #ifdef CONFIG_OF diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index d5fc86132b495..19f8aead775de 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -780,7 +780,12 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev) __func__, ret); } - return devm_snd_soc_register_card(&pdev->dev, card); + ret = devm_snd_soc_register_card(&pdev->dev, card); + + of_node_put(platform_node); + of_node_put(ec_codec); + of_node_put(hdmi_codec); + return ret; } #ifdef CONFIG_OF From db3f5abe68ea5ea39d84e6af4f0f2ce5d5e2daf4 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Fri, 24 Dec 2021 14:47:18 +0800 Subject: [PATCH 309/327] ASoC: mediatek: mt8173: reduce log verbosity in probe() Eliminates error messages if snd_soc_register_card() failed. Kernel emits messages if device probe error anyway. Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20211224064719.2031210-4-tzungbi@google.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8173/mt8173-max98090.c | 3 --- sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c | 3 --- sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c | 3 --- sound/soc/mediatek/mt8173/mt8173-rt5650.c | 3 --- 4 files changed, 12 deletions(-) diff --git a/sound/soc/mediatek/mt8173/mt8173-max98090.c b/sound/soc/mediatek/mt8173/mt8173-max98090.c index 65941dd2295d5..4cb90da89262b 100644 --- a/sound/soc/mediatek/mt8173/mt8173-max98090.c +++ b/sound/soc/mediatek/mt8173/mt8173-max98090.c @@ -177,9 +177,6 @@ static int mt8173_max98090_dev_probe(struct platform_device *pdev) card->dev = &pdev->dev; ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) - dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", - __func__, ret); of_node_put(codec_node); of_node_put(platform_node); diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c index 227b0b72c66e9..b55122b99f074 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c @@ -215,9 +215,6 @@ static int mt8173_rt5650_rt5514_dev_probe(struct platform_device *pdev) card->dev = &pdev->dev; ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) - dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", - __func__, ret); of_node_put(platform_node); return ret; diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c index 8df2ff2f2aab2..5716d92990668 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c @@ -282,9 +282,6 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev) card->dev = &pdev->dev; ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) - dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", - __func__, ret); of_node_put(platform_node); return ret; diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c index 16ddf9f8bbcb8..fc164f4f95f85 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c @@ -320,9 +320,6 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev) card->dev = &pdev->dev; ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) - dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", - __func__, ret); of_node_put(platform_node); return ret; From 082482a5022780d42180a394fe6843e71fe963d8 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Fri, 24 Dec 2021 14:47:19 +0800 Subject: [PATCH 310/327] ASoC: mediatek: mt8195: release device_node after snd_soc_register_card Device nodes can be released after components have bound. Shortens the lifecycle of the device nodes. Releases the reference counts after snd_soc_register_card. Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20211224064719.2031210-5-tzungbi@google.com Signed-off-by: Mark Brown --- .../mt8195/mt8195-mt6359-rt1011-rt5682.c | 53 +++++---------- .../mt8195/mt8195-mt6359-rt1019-rt5682.c | 64 ++++++------------- 2 files changed, 36 insertions(+), 81 deletions(-) diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c index 9cf907c49ea80..ce8dace6527cb 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c @@ -31,9 +31,6 @@ #define RT5682S_DEV0_NAME "rt5682s.2-001a" struct mt8195_mt6359_rt1011_rt5682_priv { - struct device_node *platform_node; - struct device_node *hdmi_node; - struct device_node *dp_node; struct snd_soc_jack headset_jack; struct snd_soc_jack dp_jack; struct snd_soc_jack hdmi_jack; @@ -1047,6 +1044,7 @@ static int mt8195_mt6359_rt1011_rt5682_dev_probe(struct platform_device *pdev) struct snd_soc_card *card = &mt8195_mt6359_rt1011_rt5682_soc_card; struct snd_soc_dai_link *dai_link; struct mt8195_mt6359_rt1011_rt5682_priv *priv; + struct device_node *platform_node, *dp_node, *hdmi_node; int is5682s = 0; int ret, i; @@ -1065,38 +1063,35 @@ static int mt8195_mt6359_rt1011_rt5682_dev_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - priv->platform_node = of_parse_phandle(pdev->dev.of_node, - "mediatek,platform", 0); - if (!priv->platform_node) { + platform_node = of_parse_phandle(pdev->dev.of_node, + "mediatek,platform", 0); + if (!platform_node) { dev_dbg(&pdev->dev, "Property 'platform' missing or invalid\n"); return -EINVAL; } + dp_node = of_parse_phandle(pdev->dev.of_node, "mediatek,dptx-codec", 0); + hdmi_node = of_parse_phandle(pdev->dev.of_node, + "mediatek,hdmi-codec", 0); + for_each_card_prelinks(card, i, dai_link) { if (!dai_link->platforms->name) - dai_link->platforms->of_node = priv->platform_node; + dai_link->platforms->of_node = platform_node; if (strcmp(dai_link->name, "DPTX_BE") == 0) { - priv->dp_node = - of_parse_phandle(pdev->dev.of_node, - "mediatek,dptx-codec", 0); - - if (!priv->dp_node) { + if (!dp_node) { dev_dbg(&pdev->dev, "No property 'dptx-codec'\n"); } else { - dai_link->codecs->of_node = priv->dp_node; + dai_link->codecs->of_node = dp_node; dai_link->codecs->name = NULL; dai_link->codecs->dai_name = "i2s-hifi"; dai_link->init = mt8195_dptx_codec_init; } } else if (strcmp(dai_link->name, "ETDM3_OUT_BE") == 0) { - priv->hdmi_node = - of_parse_phandle(pdev->dev.of_node, - "mediatek,hdmi-codec", 0); - if (!priv->hdmi_node) { + if (!hdmi_node) { dev_dbg(&pdev->dev, "No property 'hdmi-codec'\n"); } else { - dai_link->codecs->of_node = priv->hdmi_node; + dai_link->codecs->of_node = hdmi_node; dai_link->codecs->name = NULL; dai_link->codecs->dai_name = "i2s-hifi"; dai_link->init = mt8195_hdmi_codec_init; @@ -1113,28 +1108,13 @@ static int mt8195_mt6359_rt1011_rt5682_dev_probe(struct platform_device *pdev) snd_soc_card_set_drvdata(card, priv); ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) { - of_node_put(priv->hdmi_node); - of_node_put(priv->dp_node); - of_node_put(priv->platform_node); - } + of_node_put(platform_node); + of_node_put(dp_node); + of_node_put(hdmi_node); return ret; } -static int mt8195_mt6359_rt1011_rt5682_dev_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - struct mt8195_mt6359_rt1011_rt5682_priv *priv = - snd_soc_card_get_drvdata(card); - - of_node_put(priv->hdmi_node); - of_node_put(priv->dp_node); - of_node_put(priv->platform_node); - - return 0; -} - #ifdef CONFIG_OF static const struct of_device_id mt8195_mt6359_rt1011_rt5682_dt_match[] = { {.compatible = "mediatek,mt8195_mt6359_rt1011_rt5682",}, @@ -1156,7 +1136,6 @@ static struct platform_driver mt8195_mt6359_rt1011_rt5682_driver = { .pm = &mt8195_mt6359_rt1011_rt5682_pm_ops, }, .probe = mt8195_mt6359_rt1011_rt5682_dev_probe, - .remove = mt8195_mt6359_rt1011_rt5682_dev_remove, }; module_platform_driver(mt8195_mt6359_rt1011_rt5682_driver); diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c index fdd4441387281..c15c58170e9dd 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c @@ -43,10 +43,6 @@ struct sof_conn_stream { }; struct mt8195_mt6359_rt1019_rt5682_priv { - struct device_node *platform_node; - struct device_node *adsp_node; - struct device_node *hdmi_node; - struct device_node *dp_node; struct snd_soc_jack headset_jack; struct snd_soc_jack dp_jack; struct snd_soc_jack hdmi_jack; @@ -1257,6 +1253,7 @@ static int mt8195_mt6359_rt1019_rt5682_dev_probe(struct platform_device *pdev) struct snd_soc_card *card = &mt8195_mt6359_rt1019_rt5682_soc_card; struct snd_soc_dai_link *dai_link; struct mt8195_mt6359_rt1019_rt5682_priv *priv; + struct device_node *platform_node, *adsp_node, *dp_node, *hdmi_node; int is5682s = 0; int init6359 = 0; int sof_on = 0; @@ -1278,19 +1275,21 @@ static int mt8195_mt6359_rt1019_rt5682_dev_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - priv->platform_node = of_parse_phandle(pdev->dev.of_node, - "mediatek,platform", 0); - if (!priv->platform_node) { + platform_node = of_parse_phandle(pdev->dev.of_node, + "mediatek,platform", 0); + if (!platform_node) { dev_dbg(&pdev->dev, "Property 'platform' missing or invalid\n"); return -EINVAL; } - /* dai link */ - priv->adsp_node = of_parse_phandle(pdev->dev.of_node, - "mediatek,adsp", 0); - if (priv->adsp_node) + adsp_node = of_parse_phandle(pdev->dev.of_node, "mediatek,adsp", 0); + if (adsp_node) sof_on = 1; + dp_node = of_parse_phandle(pdev->dev.of_node, "mediatek,dptx-codec", 0); + hdmi_node = of_parse_phandle(pdev->dev.of_node, + "mediatek,hdmi-codec", 0); + if (of_property_read_bool(pdev->dev.of_node, "mediatek,dai-link")) { ret = mt8195_dailink_parse_of(card, pdev->dev.of_node, "mediatek,dai-link"); @@ -1306,31 +1305,25 @@ static int mt8195_mt6359_rt1019_rt5682_dev_probe(struct platform_device *pdev) for_each_card_prelinks(card, i, dai_link) { if (!dai_link->platforms->name) { if (!strncmp(dai_link->name, "AFE_SOF", strlen("AFE_SOF")) && sof_on) - dai_link->platforms->of_node = priv->adsp_node; + dai_link->platforms->of_node = adsp_node; else - dai_link->platforms->of_node = priv->platform_node; + dai_link->platforms->of_node = platform_node; } if (strcmp(dai_link->name, "DPTX_BE") == 0) { - priv->dp_node = - of_parse_phandle(pdev->dev.of_node, - "mediatek,dptx-codec", 0); - if (!priv->dp_node) { + if (!dp_node) { dev_dbg(&pdev->dev, "No property 'dptx-codec'\n"); } else { - dai_link->codecs->of_node = priv->dp_node; + dai_link->codecs->of_node = dp_node; dai_link->codecs->name = NULL; dai_link->codecs->dai_name = "i2s-hifi"; dai_link->init = mt8195_dptx_codec_init; } } else if (strcmp(dai_link->name, "ETDM3_OUT_BE") == 0) { - priv->hdmi_node = - of_parse_phandle(pdev->dev.of_node, - "mediatek,hdmi-codec", 0); - if (!priv->hdmi_node) { + if (!hdmi_node) { dev_dbg(&pdev->dev, "No property 'hdmi-codec'\n"); } else { - dai_link->codecs->of_node = priv->hdmi_node; + dai_link->codecs->of_node = hdmi_node; dai_link->codecs->name = NULL; dai_link->codecs->dai_name = "i2s-hifi"; dai_link->init = mt8195_hdmi_codec_init; @@ -1357,30 +1350,14 @@ static int mt8195_mt6359_rt1019_rt5682_dev_probe(struct platform_device *pdev) snd_soc_card_set_drvdata(card, priv); ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) { - of_node_put(priv->hdmi_node); - of_node_put(priv->dp_node); - of_node_put(priv->platform_node); - of_node_put(priv->adsp_node); - } + of_node_put(platform_node); + of_node_put(adsp_node); + of_node_put(dp_node); + of_node_put(hdmi_node); return ret; } -static int mt8195_mt6359_rt1019_rt5682_dev_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - struct mt8195_mt6359_rt1019_rt5682_priv *priv = - snd_soc_card_get_drvdata(card); - - of_node_put(priv->hdmi_node); - of_node_put(priv->dp_node); - of_node_put(priv->platform_node); - of_node_put(priv->adsp_node); - - return 0; -} - #ifdef CONFIG_OF static const struct of_device_id mt8195_mt6359_rt1019_rt5682_dt_match[] = { {.compatible = "mediatek,mt8195_mt6359_rt1019_rt5682",}, @@ -1402,7 +1379,6 @@ static struct platform_driver mt8195_mt6359_rt1019_rt5682_driver = { .pm = &mt8195_mt6359_rt1019_rt5682_pm_ops, }, .probe = mt8195_mt6359_rt1019_rt5682_dev_probe, - .remove = mt8195_mt6359_rt1019_rt5682_dev_remove, }; module_platform_driver(mt8195_mt6359_rt1019_rt5682_driver); From 9de2b9286a6dd16966959b3cb34fc2ddfd39213e Mon Sep 17 00:00:00 2001 From: Jiasheng Jiang Date: Wed, 22 Dec 2021 09:51:57 +0800 Subject: [PATCH 311/327] ASoC: mediatek: Check for error clk pointer Yes, you are right and now the return code depending on the init_clks(). Fixes: 6078c651947a ("soc: mediatek: Refine scpsys to support multiple platform") Signed-off-by: Jiasheng Jiang Link: https://lore.kernel.org/r/20211222015157.1025853-1-jiasheng@iscas.ac.cn Signed-off-by: Mark Brown --- drivers/soc/mediatek/mtk-scpsys.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c index ca75b14931ec9..670cc82d17dc2 100644 --- a/drivers/soc/mediatek/mtk-scpsys.c +++ b/drivers/soc/mediatek/mtk-scpsys.c @@ -411,12 +411,17 @@ static int scpsys_power_off(struct generic_pm_domain *genpd) return ret; } -static void init_clks(struct platform_device *pdev, struct clk **clk) +static int init_clks(struct platform_device *pdev, struct clk **clk) { int i; - for (i = CLK_NONE + 1; i < CLK_MAX; i++) + for (i = CLK_NONE + 1; i < CLK_MAX; i++) { clk[i] = devm_clk_get(&pdev->dev, clk_names[i]); + if (IS_ERR(clk[i])) + return PTR_ERR(clk[i]); + } + + return 0; } static struct scp *init_scp(struct platform_device *pdev, @@ -426,7 +431,7 @@ static struct scp *init_scp(struct platform_device *pdev, { struct genpd_onecell_data *pd_data; struct resource *res; - int i, j; + int i, j, ret; struct scp *scp; struct clk *clk[CLK_MAX]; @@ -481,7 +486,9 @@ static struct scp *init_scp(struct platform_device *pdev, pd_data->num_domains = num; - init_clks(pdev, clk); + ret = init_clks(pdev, clk); + if (ret) + return ERR_PTR(ret); for (i = 0; i < num; i++) { struct scp_domain *scpd = &scp->domains[i]; From b2fde4deff854ca7d49ec735a8252d944418b64d Mon Sep 17 00:00:00 2001 From: chiminghao Date: Thu, 9 Dec 2021 01:57:07 +0000 Subject: [PATCH 312/327] ASoC: remove unneeded variable return value form directly instead of taking this in another redundant variable. Reported-by: Zeal Robot Signed-off-by: chiminghao Link: https://lore.kernel.org/r/20211209015707.409870-1-chi.minghao@zte.com.cn Signed-off-by: Mark Brown --- sound/soc/codecs/mt6660.c | 5 ++--- sound/soc/codecs/wcd938x.c | 6 ++---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/mt6660.c b/sound/soc/codecs/mt6660.c index 358c500377dff..3a881523c30ff 100644 --- a/sound/soc/codecs/mt6660.c +++ b/sound/soc/codecs/mt6660.c @@ -47,13 +47,12 @@ static int mt6660_reg_write(void *context, unsigned int reg, unsigned int val) struct mt6660_chip *chip = context; int size = mt6660_get_reg_size(reg); u8 reg_data[4]; - int i, ret; + int i; for (i = 0; i < size; i++) reg_data[size - i - 1] = (val >> (8 * i)) & 0xff; - ret = i2c_smbus_write_i2c_block_data(chip->i2c, reg, size, reg_data); - return ret; + return i2c_smbus_write_i2c_block_data(chip->i2c, reg, size, reg_data); } static int mt6660_reg_read(void *context, unsigned int reg, unsigned int *val) diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index 67151c7770c65..54152b57eeeb7 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -3086,7 +3086,7 @@ static int wcd938x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *compon int micb_num, bool req_en) { struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); - int rc, micb_mv; + int micb_mv; if (micb_num != MIC_BIAS_2) return -EINVAL; @@ -3100,9 +3100,7 @@ static int wcd938x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *compon micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : wcd938x->micb2_mv; - rc = wcd938x_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2); - - return rc; + return wcd938x_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2); } static inline void wcd938x_mbhc_get_result_params(struct wcd938x_priv *wcd938x, From 5c5f08f7fc0bee9a1bc3fbdcb7a21cfd0648ab14 Mon Sep 17 00:00:00 2001 From: V sujith kumar Reddy Date: Fri, 24 Dec 2021 20:30:43 +0530 Subject: [PATCH 313/327] ASoC: amd: acp: Power on/off the speaker enable gpio pin based on DAPM callback. Configure the speaker gpio pin based on power sequence of the DAPM speaker events. Enable speaker after widget power up and Disable before widget powerdown. Signed-off-by: V sujith kumar Reddy Link: https://lore.kernel.org/r/20211224150058.2444776-1-vsujithkumar.reddy@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/Kconfig | 6 +++--- sound/soc/amd/acp/acp-legacy-mach.c | 19 ++++++++++++++++--- sound/soc/amd/acp/acp-mach-common.c | 25 +++++++++++++++++++++++++ sound/soc/amd/acp/acp-mach.h | 10 +++++++++- sound/soc/amd/acp/acp-sof-mach.c | 21 ++++++++++++++++++--- 5 files changed, 71 insertions(+), 10 deletions(-) diff --git a/sound/soc/amd/acp/Kconfig b/sound/soc/amd/acp/Kconfig index 154be5e70821a..d5838df3064b2 100644 --- a/sound/soc/amd/acp/Kconfig +++ b/sound/soc/amd/acp/Kconfig @@ -32,7 +32,7 @@ config SND_AMD_ASOC_RENOIR config SND_SOC_AMD_MACH_COMMON tristate - depends on X86 && PCI && I2C + depends on X86 && PCI && I2C && GPIOLIB select CLK_FIXED_FCH select SND_SOC_RT5682_I2C select SND_SOC_DMIC @@ -44,14 +44,14 @@ config SND_SOC_AMD_MACH_COMMON config SND_SOC_AMD_LEGACY_MACH tristate "AMD Legacy Machine Driver Support" - depends on X86 && PCI && I2C + depends on X86 && PCI && I2C && GPIOLIB select SND_SOC_AMD_MACH_COMMON help This option enables legacy sound card support for ACP audio. config SND_SOC_AMD_SOF_MACH tristate "AMD SOF Machine Driver Support" - depends on X86 && PCI && I2C + depends on X86 && PCI && I2C && GPIOLIB select SND_SOC_AMD_MACH_COMMON help This option enables SOF sound card support for ACP audio. diff --git a/sound/soc/amd/acp/acp-legacy-mach.c b/sound/soc/amd/acp/acp-legacy-mach.c index de0f8024e2fb5..0ad1cf41b3084 100644 --- a/sound/soc/amd/acp/acp-legacy-mach.c +++ b/sound/soc/amd/acp/acp-legacy-mach.c @@ -27,6 +27,7 @@ static struct acp_card_drvdata rt5682_rt1019_data = { .hs_codec_id = RT5682, .amp_codec_id = RT1019, .dmic_codec_id = NONE, + .gpio_spkr_en = EN_SPKR_GPIO_GB, }; static const struct snd_kcontrol_new acp_controls[] = { @@ -41,15 +42,16 @@ static const struct snd_kcontrol_new acp_controls[] = { static const struct snd_soc_dapm_widget acp_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Spk", NULL), - SND_SOC_DAPM_SPK("Left Spk", NULL), - SND_SOC_DAPM_SPK("Right Spk", NULL), + SND_SOC_DAPM_SPK("Spk", event_spkr_handler), + SND_SOC_DAPM_SPK("Left Spk", event_spkr_handler), + SND_SOC_DAPM_SPK("Right Spk", event_spkr_handler), }; static int acp_asoc_probe(struct platform_device *pdev) { struct snd_soc_card *card = NULL; struct device *dev = &pdev->dev; + unsigned int spkr_gpio; int ret; if (!pdev->id_entry) @@ -67,9 +69,20 @@ static int acp_asoc_probe(struct platform_device *pdev) card->controls = acp_controls; card->num_controls = ARRAY_SIZE(acp_controls); card->drvdata = (struct acp_card_drvdata *)pdev->id_entry->driver_data; + spkr_gpio = ((struct acp_card_drvdata *)(card->drvdata))->gpio_spkr_en; acp_legacy_dai_links_create(card); + if (gpio_is_valid(spkr_gpio)) { + ret = devm_gpio_request(dev, spkr_gpio, "spkren"); + if (ret) { + dev_err(dev, "(%s) gpio request failed: %d\n", + __func__, ret); + return ret; + } + gpio_direction_output(spkr_gpio, 0); + } + ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) { dev_err(&pdev->dev, diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c index 7785f12aa0065..03d8d1af14b3e 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -71,6 +71,31 @@ static const struct snd_soc_dapm_route rt5682_map[] = { { "IN1P", NULL, "Headset Mic" }, }; +int event_spkr_handler(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct acp_card_drvdata *drvdata = snd_soc_card_get_drvdata(card); + + if (!gpio_is_valid(drvdata->gpio_spkr_en)) + return 0; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + gpio_set_value(drvdata->gpio_spkr_en, 1); + break; + case SND_SOC_DAPM_PRE_PMD: + gpio_set_value(drvdata->gpio_spkr_en, 0); + break; + default: + dev_warn(card->dev, "%s invalid setting\n", __func__); + break; + } + return 0; +} +EXPORT_SYMBOL_NS_GPL(event_spkr_handler, SND_SOC_AMD_MACH); + /* Define card ops for RT5682 CODEC */ static int acp_card_rt5682_init(struct snd_soc_pcm_runtime *rtd) { diff --git a/sound/soc/amd/acp/acp-mach.h b/sound/soc/amd/acp/acp-mach.h index 5dc47cfbff10e..fd6299844ebe4 100644 --- a/sound/soc/amd/acp/acp-mach.h +++ b/sound/soc/amd/acp/acp-mach.h @@ -17,6 +17,12 @@ #include #include #include +#include +#include + +#define EN_SPKR_GPIO_GB 0x11F +#define EN_SPKR_GPIO_NK 0x146 +#define EN_SPKR_GPIO_NONE -EINVAL enum be_id { HEADSET_BE_ID = 0, @@ -49,9 +55,11 @@ struct acp_card_drvdata { unsigned int dai_fmt; struct clk *wclk; struct clk *bclk; + unsigned int gpio_spkr_en; }; int acp_sofdsp_dai_links_create(struct snd_soc_card *card); int acp_legacy_dai_links_create(struct snd_soc_card *card); - +int event_spkr_handler(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event); #endif diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c index 854eb7214cead..07de461426559 100644 --- a/sound/soc/amd/acp/acp-sof-mach.c +++ b/sound/soc/amd/acp/acp-sof-mach.c @@ -27,6 +27,7 @@ static struct acp_card_drvdata sof_rt5682_rt1019_data = { .hs_codec_id = RT5682, .amp_codec_id = RT1019, .dmic_codec_id = DMIC, + .gpio_spkr_en = EN_SPKR_GPIO_GB, }; static struct acp_card_drvdata sof_rt5682_max_data = { @@ -36,6 +37,7 @@ static struct acp_card_drvdata sof_rt5682_max_data = { .hs_codec_id = RT5682, .amp_codec_id = MAX98360A, .dmic_codec_id = DMIC, + .gpio_spkr_en = EN_SPKR_GPIO_NK, }; static struct acp_card_drvdata sof_rt5682s_max_data = { @@ -45,6 +47,7 @@ static struct acp_card_drvdata sof_rt5682s_max_data = { .hs_codec_id = RT5682S, .amp_codec_id = MAX98360A, .dmic_codec_id = DMIC, + .gpio_spkr_en = EN_SPKR_GPIO_NK, }; static const struct snd_kcontrol_new acp_controls[] = { @@ -58,15 +61,16 @@ static const struct snd_kcontrol_new acp_controls[] = { static const struct snd_soc_dapm_widget acp_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Spk", NULL), - SND_SOC_DAPM_SPK("Left Spk", NULL), - SND_SOC_DAPM_SPK("Right Spk", NULL), + SND_SOC_DAPM_SPK("Spk", event_spkr_handler), + SND_SOC_DAPM_SPK("Left Spk", event_spkr_handler), + SND_SOC_DAPM_SPK("Right Spk", event_spkr_handler), }; static int acp_sof_probe(struct platform_device *pdev) { struct snd_soc_card *card = NULL; struct device *dev = &pdev->dev; + unsigned int spkr_gpio; int ret; if (!pdev->id_entry) @@ -84,9 +88,20 @@ static int acp_sof_probe(struct platform_device *pdev) card->controls = acp_controls; card->num_controls = ARRAY_SIZE(acp_controls); card->drvdata = (struct acp_card_drvdata *)pdev->id_entry->driver_data; + spkr_gpio = ((struct acp_card_drvdata *)(card->drvdata))->gpio_spkr_en; acp_sofdsp_dai_links_create(card); + if (gpio_is_valid(spkr_gpio)) { + ret = devm_gpio_request(dev, spkr_gpio, "spkren"); + if (ret) { + dev_err(dev, "(%s) gpio request failed: %d\n", + __func__, ret); + return ret; + } + gpio_direction_output(spkr_gpio, 0); + } + ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) { dev_err(&pdev->dev, From 8f85317292f1d99e8a70a400a46ee697d64e3326 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 22 Dec 2021 11:19:19 -0300 Subject: [PATCH 314/327] ASoC: cs4265: Fix part number ID error message The Chip ID - Register 01h contains the following description as per the CS4265 datasheet: "Bits 7 through 4 are the part number ID, which is 1101b (0Dh)" The current error message is incorrect as it prints CS4265_CHIP_ID, which is the register number, instead of printing the expected part number ID value. To make it clearer, also do a shift by 4, so that the error message would become: [ 4.218083] cs4265 1-004f: CS4265 Part Number ID: 0x0 Expected: 0xd Signed-off-by: Fabio Estevam Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20211222141920.1482451-1-festevam@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs4265.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index cffd6111afaca..b89002189a2bf 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -611,8 +611,8 @@ static int cs4265_i2c_probe(struct i2c_client *i2c_client, if (devid != CS4265_CHIP_ID_VAL) { ret = -ENODEV; dev_err(&i2c_client->dev, - "CS4265 Device ID (%X). Expected %X\n", - devid, CS4265_CHIP_ID); + "CS4265 Part Number ID: 0x%x Expected: 0x%x\n", + devid >> 4, CS4265_CHIP_ID_VAL >> 4); return ret; } dev_info(&i2c_client->dev, From 3667a037e50a31555276a7989435126e501f0f15 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 27 Dec 2021 14:21:53 +0800 Subject: [PATCH 315/327] ASoC: mediatek: use of_device_get_match_data() Uses of_device_get_match_data() helper to clean some boilerplate code. Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20211227062153.3887447-1-tzungbi@google.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c | 7 ++----- sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c | 7 ++----- sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c | 7 ++----- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c index ca893feab7ebf..718505c754188 100644 --- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c @@ -685,7 +685,6 @@ static int mt8183_da7219_max98357_dev_probe(struct platform_device *pdev) struct snd_soc_dai_link *dai_link; struct mt8183_da7219_max98357_priv *priv; struct pinctrl *pinctrl; - const struct of_device_id *match; int ret, i; platform_node = of_parse_phandle(pdev->dev.of_node, @@ -695,11 +694,9 @@ static int mt8183_da7219_max98357_dev_probe(struct platform_device *pdev) return -EINVAL; } - match = of_match_device(pdev->dev.driver->of_match_table, &pdev->dev); - if (!match || !match->data) + card = (struct snd_soc_card *)of_device_get_match_data(&pdev->dev); + if (!card) return -EINVAL; - - card = (struct snd_soc_card *)match->data; card->dev = &pdev->dev; hdmi_codec = of_parse_phandle(pdev->dev.of_node, diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index 19f8aead775de..b0ec5ebd4f2d9 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -637,7 +637,6 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev) struct device_node *platform_node, *ec_codec, *hdmi_codec; struct snd_soc_dai_link *dai_link; struct mt8183_mt6358_ts3a227_max98357_priv *priv; - const struct of_device_id *match; int ret, i; platform_node = of_parse_phandle(pdev->dev.of_node, @@ -647,11 +646,9 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev) return -EINVAL; } - match = of_match_device(pdev->dev.driver->of_match_table, &pdev->dev); - if (!match || !match->data) + card = (struct snd_soc_card *)of_device_get_match_data(&pdev->dev); + if (!card) return -EINVAL; - - card = (struct snd_soc_card *)match->data; card->dev = &pdev->dev; ec_codec = of_parse_phandle(pdev->dev.of_node, "mediatek,ec-codec", 0); diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c index 2552f30d8fe43..f7daad1bfe1ed 100644 --- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c +++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c @@ -1106,7 +1106,6 @@ static int mt8192_mt6359_dev_probe(struct platform_device *pdev) struct device_node *platform_node, *hdmi_codec; int ret, i; struct snd_soc_dai_link *dai_link; - const struct of_device_id *match; struct mt8192_mt6359_priv *priv; platform_node = of_parse_phandle(pdev->dev.of_node, @@ -1116,11 +1115,9 @@ static int mt8192_mt6359_dev_probe(struct platform_device *pdev) return -EINVAL; } - match = of_match_device(pdev->dev.driver->of_match_table, &pdev->dev); - if (!match || !match->data) + card = (struct snd_soc_card *)of_device_get_match_data(&pdev->dev); + if (!card) return -EINVAL; - - card = (struct snd_soc_card *)match->data; card->dev = &pdev->dev; hdmi_codec = of_parse_phandle(pdev->dev.of_node, From 3ecb46755eb85456b459a1a9f952c52986bce8ec Mon Sep 17 00:00:00 2001 From: Jiasheng Jiang Date: Tue, 28 Dec 2021 11:40:26 +0800 Subject: [PATCH 316/327] ASoC: samsung: idma: Check of ioremap return value Because of the potential failure of the ioremap(), the buf->area could be NULL. Therefore, we need to check it and return -ENOMEM in order to transfer the error. Fixes: f09aecd50f39 ("ASoC: SAMSUNG: Add I2S0 internal dma driver") Signed-off-by: Jiasheng Jiang Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20211228034026.1659385-1-jiasheng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/samsung/idma.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/samsung/idma.c b/sound/soc/samsung/idma.c index 66bcc2f97544b..c3f1b054e2389 100644 --- a/sound/soc/samsung/idma.c +++ b/sound/soc/samsung/idma.c @@ -360,6 +360,8 @@ static int preallocate_idma_buffer(struct snd_pcm *pcm, int stream) buf->addr = idma.lp_tx_addr; buf->bytes = idma_hardware.buffer_bytes_max; buf->area = (unsigned char * __force)ioremap(buf->addr, buf->bytes); + if (!buf->area) + return -ENOMEM; return 0; } From c5ab93e289ce554a4e0d47330dde120284541aa1 Mon Sep 17 00:00:00 2001 From: Trevor Wu Date: Tue, 28 Dec 2021 14:48:21 +0800 Subject: [PATCH 317/327] ASoC: mediatek: mt8195: update control for RT5682 series Playback pop is observed and the root cause is the reference clock provided by MT8195 is diabled before RT5682 finishes the control flow. To ensure the reference clock supplied to RT5682 is disabled after RT5682 finishes all register controls. We replace BCLK with MCLK for RT5682 reference clock, and makes use of set_bias_level_post to handle MCLK which guarantees MCLK is off after all RT5682 register access. Signed-off-by: Trevor Wu Reviewed-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20211228064821.27865-1-trevor.wu@mediatek.com Signed-off-by: Mark Brown --- .../mt8195/mt8195-mt6359-rt1011-rt5682.c | 56 ++++++++++++++- .../mt8195/mt8195-mt6359-rt1019-rt5682.c | 68 ++++++++++++++++--- 2 files changed, 110 insertions(+), 14 deletions(-) diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c index ce8dace6527cb..8adbd46c4bc41 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c @@ -18,6 +18,7 @@ #include "../../codecs/rt1011.h" #include "../../codecs/rt5682.h" #include "../common/mtk-afe-platform-driver.h" +#include "mt8195-afe-clk.h" #include "mt8195-afe-common.h" #define RT1011_CODEC_DAI "rt1011-aif" @@ -34,6 +35,7 @@ struct mt8195_mt6359_rt1011_rt5682_priv { struct snd_soc_jack headset_jack; struct snd_soc_jack dp_jack; struct snd_soc_jack hdmi_jack; + struct clk *i2so1_mclk; }; static const struct snd_soc_dapm_widget @@ -84,8 +86,8 @@ static int mt8195_rt5682_etdm_hw_params(struct snd_pcm_substream *substream, return ret; } - ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL1, RT5682_PLL1_S_BCLK1, - rate * 64, rate * 512); + ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL1, RT5682_PLL1_S_MCLK, + rate * 256, rate * 512); if (ret) { dev_err(card->dev, "failed to set pll\n"); return ret; @@ -98,7 +100,7 @@ static int mt8195_rt5682_etdm_hw_params(struct snd_pcm_substream *substream, return ret; } - return snd_soc_dai_set_sysclk(cpu_dai, 0, rate * 128, + return snd_soc_dai_set_sysclk(cpu_dai, 0, rate * 256, SND_SOC_CLOCK_OUT); } @@ -327,8 +329,14 @@ static int mt8195_rt5682_init(struct snd_soc_pcm_runtime *rtd) struct mt8195_mt6359_rt1011_rt5682_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_jack *jack = &priv->headset_jack; + struct snd_soc_component *cmpnt_afe = + snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt_afe); + struct mt8195_afe_private *afe_priv = afe->platform_priv; int ret; + priv->i2so1_mclk = afe_priv->clk[MT8195_CLK_TOP_APLL12_DIV2]; + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | @@ -562,6 +570,47 @@ static const struct snd_soc_ops mt8195_capture_ops = { .startup = mt8195_capture_startup, }; +static int mt8195_set_bias_level_post(struct snd_soc_card *card, + struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) +{ + struct snd_soc_component *component = dapm->component; + struct mt8195_mt6359_rt1011_rt5682_priv *priv = + snd_soc_card_get_drvdata(card); + int ret; + + /* + * It's required to control mclk directly in the set_bias_level_post + * function for rt5682 and rt5682s codec, or the unexpected pop happens + * at the end of playback. + */ + if (!component || + (strcmp(component->name, RT5682_DEV0_NAME) && + strcmp(component->name, RT5682S_DEV0_NAME))) + return 0; + + switch (level) { + case SND_SOC_BIAS_OFF: + if (!__clk_is_enabled(priv->i2so1_mclk)) + return 0; + + clk_disable_unprepare(priv->i2so1_mclk); + dev_dbg(card->dev, "Disable i2so1 mclk\n"); + break; + case SND_SOC_BIAS_ON: + ret = clk_prepare_enable(priv->i2so1_mclk); + if (ret) { + dev_err(card->dev, "Can't enable i2so1 mclk: %d\n", ret); + return ret; + } + dev_dbg(card->dev, "Enable i2so1 mclk\n"); + break; + default: + break; + } + + return 0; +} + enum { DAI_LINK_DL2_FE, DAI_LINK_DL3_FE, @@ -1037,6 +1086,7 @@ static struct snd_soc_card mt8195_mt6359_rt1011_rt5682_soc_card = { .num_dapm_routes = ARRAY_SIZE(mt8195_mt6359_rt1011_rt5682_routes), .codec_conf = rt1011_amp_conf, .num_configs = ARRAY_SIZE(rt1011_amp_conf), + .set_bias_level_post = mt8195_set_bias_level_post, }; static int mt8195_mt6359_rt1011_rt5682_dev_probe(struct platform_device *pdev) diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c index c15c58170e9dd..20b351faeaff0 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c @@ -19,6 +19,7 @@ #include "../../codecs/mt6359.h" #include "../../codecs/rt5682.h" #include "../common/mtk-afe-platform-driver.h" +#include "mt8195-afe-clk.h" #include "mt8195-afe-common.h" #define RT1019_CODEC_DAI "HiFi" @@ -46,6 +47,7 @@ struct mt8195_mt6359_rt1019_rt5682_priv { struct snd_soc_jack headset_jack; struct snd_soc_jack dp_jack; struct snd_soc_jack hdmi_jack; + struct clk *i2so1_mclk; }; static const struct snd_soc_dapm_widget @@ -92,8 +94,6 @@ static int mt8195_rt5682_etdm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); unsigned int rate = params_rate(params); - unsigned int mclk_fs_ratio = 128; - unsigned int mclk_fs = rate * mclk_fs_ratio; int bitwidth; int ret; @@ -109,25 +109,22 @@ static int mt8195_rt5682_etdm_hw_params(struct snd_pcm_substream *substream, return ret; } - ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL1, - RT5682_PLL1_S_BCLK1, - params_rate(params) * 64, - params_rate(params) * 512); + ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL1, RT5682_PLL1_S_MCLK, + rate * 256, rate * 512); if (ret) { dev_err(card->dev, "failed to set pll\n"); return ret; } - ret = snd_soc_dai_set_sysclk(codec_dai, - RT5682_SCLK_S_PLL1, - params_rate(params) * 512, - SND_SOC_CLOCK_IN); + ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, + rate * 512, SND_SOC_CLOCK_IN); if (ret) { dev_err(card->dev, "failed to set sysclk\n"); return ret; } - return snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_fs, SND_SOC_CLOCK_OUT); + return snd_soc_dai_set_sysclk(cpu_dai, 0, rate * 256, + SND_SOC_CLOCK_OUT); } static const struct snd_soc_ops mt8195_rt5682_etdm_ops = { @@ -322,8 +319,14 @@ static int mt8195_rt5682_init(struct snd_soc_pcm_runtime *rtd) struct mt8195_mt6359_rt1019_rt5682_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_jack *jack = &priv->headset_jack; + struct snd_soc_component *cmpnt_afe = + snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt_afe); + struct mt8195_afe_private *afe_priv = afe->platform_priv; int ret; + priv->i2so1_mclk = afe_priv->clk[MT8195_CLK_TOP_APLL12_DIV2]; + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | @@ -560,6 +563,48 @@ static const struct snd_soc_ops mt8195_capture_ops = { .startup = mt8195_capture_startup, }; +static int mt8195_set_bias_level_post(struct snd_soc_card *card, + struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) +{ + struct snd_soc_component *component = dapm->component; + struct mt8195_mt6359_rt1019_rt5682_priv *priv = + snd_soc_card_get_drvdata(card); + int ret; + + /* + * It's required to control mclk directly in the set_bias_level_post + * function for rt5682 and rt5682s codec, or the unexpected pop happens + * at the end of playback. + */ + if (!component || + (strcmp(component->name, RT5682_DEV0_NAME) && + strcmp(component->name, RT5682S_DEV0_NAME))) + return 0; + + + switch (level) { + case SND_SOC_BIAS_OFF: + if (!__clk_is_enabled(priv->i2so1_mclk)) + return 0; + + clk_disable_unprepare(priv->i2so1_mclk); + dev_dbg(card->dev, "Disable i2so1 mclk\n"); + break; + case SND_SOC_BIAS_ON: + ret = clk_prepare_enable(priv->i2so1_mclk); + if (ret) { + dev_err(card->dev, "Can't enable i2so1 mclk: %d\n", ret); + return ret; + } + dev_dbg(card->dev, "Enable i2so1 mclk\n"); + break; + default: + break; + } + + return 0; +} + enum { DAI_LINK_DL2_FE, DAI_LINK_DL3_FE, @@ -1199,6 +1244,7 @@ static struct snd_soc_card mt8195_mt6359_rt1019_rt5682_soc_card = { .num_dapm_widgets = ARRAY_SIZE(mt8195_mt6359_rt1019_rt5682_widgets), .dapm_routes = mt8195_mt6359_rt1019_rt5682_routes, .num_dapm_routes = ARRAY_SIZE(mt8195_mt6359_rt1019_rt5682_routes), + .set_bias_level_post = mt8195_set_bias_level_post, }; static int mt8195_dailink_parse_of(struct snd_soc_card *card, struct device_node *np, From cc5c9788106fb1b9e03c8c57d8d7166073a54416 Mon Sep 17 00:00:00 2001 From: Derek Fang Date: Mon, 27 Dec 2021 13:54:46 +0800 Subject: [PATCH 318/327] ASoC: rt5682: Register wclk with its parent_hws instead of parent_data The mclk might not be registered as a fixed clk name "mclk" on some platforms. In those platforms, if the mclk needed to be controlled by codec driver and acquired by a fixed name, it would be a problem. This patch to fix the issue that wclk becomes an orphan due to the fixed mclk's name. Signed-off-by: Derek Fang Link: https://lore.kernel.org/r/20211227055446.27563-1-derek.fang@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 5224123d0d3bb..4709c0628804a 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -2858,7 +2858,6 @@ int rt5682_register_dai_clks(struct rt5682_priv *rt5682) for (i = 0; i < RT5682_DAI_NUM_CLKS; ++i) { struct clk_init_data init = { }; - struct clk_parent_data parent_data; const struct clk_hw *parent; dai_clk_hw = &rt5682->dai_clks_hw[i]; @@ -2867,10 +2866,8 @@ int rt5682_register_dai_clks(struct rt5682_priv *rt5682) case RT5682_DAI_WCLK_IDX: /* Make MCLK the parent of WCLK */ if (rt5682->mclk) { - parent_data = (struct clk_parent_data){ - .fw_name = "mclk", - }; - init.parent_data = &parent_data; + parent = __clk_get_hw(rt5682->mclk); + init.parent_hws = &parent; init.num_parents = 1; } break; From 2355028c0c54c03afb66c589347f1dc9f6fe2e38 Mon Sep 17 00:00:00 2001 From: Trevor Wu Date: Thu, 30 Dec 2021 16:47:30 +0800 Subject: [PATCH 319/327] ASoC: mediatek: mt8195: correct pcmif BE dai control flow Originally, the conditions for preventing reentry are not correct. dai->component->active is not the state specifically for pcmif dai, so it is not a correct condition to indicate the status of pcmif dai. On the other hand, snd_soc_dai_stream_actvie() in prepare ops for both playback and capture possibly return true at the first entry when these two streams are opened at the same time. In the patch, I refer to the implementation in mt8192-dai-pcm.c. Clock and enabling bit for PCMIF are managed by DAPM, and the condition for prepare ops is replaced by the status of dai widget. Fixes: 1f95c019115c ("ASoC: mediatek: mt8195: support pcm in platform driver") Signed-off-by: Trevor Wu Link: https://lore.kernel.org/r/20211230084731.31372-2-trevor.wu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8195/mt8195-dai-pcm.c | 73 +++++++--------------- sound/soc/mediatek/mt8195/mt8195-reg.h | 1 + 2 files changed, 22 insertions(+), 52 deletions(-) diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c b/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c index 5d10d2c4c991c..151914c873acd 100644 --- a/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c +++ b/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c @@ -80,8 +80,15 @@ static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = { mtk_dai_pcm_o001_mix, ARRAY_SIZE(mtk_dai_pcm_o001_mix)), + SND_SOC_DAPM_SUPPLY("PCM_EN", PCM_INTF_CON1, + PCM_INTF_CON1_PCM_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_INPUT("PCM1_INPUT"), SND_SOC_DAPM_OUTPUT("PCM1_OUTPUT"), + + SND_SOC_DAPM_CLOCK_SUPPLY("aud_asrc11"), + SND_SOC_DAPM_CLOCK_SUPPLY("aud_asrc12"), + SND_SOC_DAPM_CLOCK_SUPPLY("aud_pcmif"), }; static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = { @@ -97,22 +104,18 @@ static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = { {"PCM1 Playback", NULL, "O000"}, {"PCM1 Playback", NULL, "O001"}, + {"PCM1 Playback", NULL, "PCM_EN"}, + {"PCM1 Playback", NULL, "aud_asrc12"}, + {"PCM1 Playback", NULL, "aud_pcmif"}, + + {"PCM1 Capture", NULL, "PCM_EN"}, + {"PCM1 Capture", NULL, "aud_asrc11"}, + {"PCM1 Capture", NULL, "aud_pcmif"}, + {"PCM1_OUTPUT", NULL, "PCM1 Playback"}, {"PCM1 Capture", NULL, "PCM1_INPUT"}, }; -static void mtk_dai_pcm_enable(struct mtk_base_afe *afe) -{ - regmap_update_bits(afe->regmap, PCM_INTF_CON1, - PCM_INTF_CON1_PCM_EN, PCM_INTF_CON1_PCM_EN); -} - -static void mtk_dai_pcm_disable(struct mtk_base_afe *afe) -{ - regmap_update_bits(afe->regmap, PCM_INTF_CON1, - PCM_INTF_CON1_PCM_EN, 0x0); -} - static int mtk_dai_pcm_configure(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -207,54 +210,22 @@ static int mtk_dai_pcm_configure(struct snd_pcm_substream *substream, } /* dai ops */ -static int mtk_dai_pcm_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); - struct mt8195_afe_private *afe_priv = afe->platform_priv; - - if (dai->component->active) - return 0; - - mt8195_afe_enable_clk(afe, afe_priv->clk[MT8195_CLK_AUD_ASRC11]); - mt8195_afe_enable_clk(afe, afe_priv->clk[MT8195_CLK_AUD_ASRC12]); - mt8195_afe_enable_clk(afe, afe_priv->clk[MT8195_CLK_AUD_PCMIF]); - - return 0; -} - -static void mtk_dai_pcm_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); - struct mt8195_afe_private *afe_priv = afe->platform_priv; - - if (dai->component->active) - return; - - mtk_dai_pcm_disable(afe); - - mt8195_afe_disable_clk(afe, afe_priv->clk[MT8195_CLK_AUD_PCMIF]); - mt8195_afe_disable_clk(afe, afe_priv->clk[MT8195_CLK_AUD_ASRC12]); - mt8195_afe_disable_clk(afe, afe_priv->clk[MT8195_CLK_AUD_ASRC11]); -} - static int mtk_dai_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); - int ret = 0; + int ret; - if (snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_PLAYBACK) && - snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_CAPTURE)) + dev_dbg(dai->dev, "%s(), id %d, stream %d, widget active p %d, c %d\n", + __func__, dai->id, substream->stream, + dai->playback_widget->active, dai->capture_widget->active); + + if (dai->playback_widget->active || dai->capture_widget->active) return 0; ret = mtk_dai_pcm_configure(substream, dai); if (ret) return ret; - mtk_dai_pcm_enable(afe); - return 0; } @@ -316,8 +287,6 @@ static int mtk_dai_pcm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) } static const struct snd_soc_dai_ops mtk_dai_pcm_ops = { - .startup = mtk_dai_pcm_startup, - .shutdown = mtk_dai_pcm_shutdown, .prepare = mtk_dai_pcm_prepare, .set_fmt = mtk_dai_pcm_set_fmt, }; diff --git a/sound/soc/mediatek/mt8195/mt8195-reg.h b/sound/soc/mediatek/mt8195/mt8195-reg.h index d06f9cf85a4ec..d3871353db415 100644 --- a/sound/soc/mediatek/mt8195/mt8195-reg.h +++ b/sound/soc/mediatek/mt8195/mt8195-reg.h @@ -2550,6 +2550,7 @@ #define PCM_INTF_CON1_PCM_FMT(x) (((x) & 0x3) << 1) #define PCM_INTF_CON1_PCM_FMT_MASK (0x3 << 1) #define PCM_INTF_CON1_PCM_EN BIT(0) +#define PCM_INTF_CON1_PCM_EN_SHIFT 0 /* PCM_INTF_CON2 */ #define PCM_INTF_CON2_CLK_DOMAIN_SEL(x) (((x) & 0x3) << 23) From db5e1c209b92a67ab7c1d7771a48294c9c093f7c Mon Sep 17 00:00:00 2001 From: Trevor Wu Date: Thu, 30 Dec 2021 16:47:31 +0800 Subject: [PATCH 320/327] ASoC: mediatek: mt8195: add playback support to PCM1_BE dai_link PCM1_BE should be a dai_link for both playback and capture. In the patch, the missing DPCM playback support is added. Signed-off-by: Trevor Wu Link: https://lore.kernel.org/r/20211230084731.31372-3-trevor.wu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c | 1 + sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c | 1 + 2 files changed, 2 insertions(+) diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c index 8adbd46c4bc41..5443a29da7b1b 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1011-rt5682.c @@ -1045,6 +1045,7 @@ static struct snd_soc_dai_link mt8195_mt6359_rt1011_rt5682_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, + .dpcm_playback = 1, .dpcm_capture = 1, SND_SOC_DAILINK_REG(PCM1_BE), }, diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c index 20b351faeaff0..29c2d3407cc7c 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c @@ -1191,6 +1191,7 @@ static struct snd_soc_dai_link mt8195_mt6359_rt1019_rt5682_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, + .dpcm_playback = 1, .dpcm_capture = 1, SND_SOC_DAILINK_REG(PCM1_BE), }, From a87d42227cf5614fe0040ddd1fe642c54298b42c Mon Sep 17 00:00:00 2001 From: Lucas Tanure Date: Fri, 17 Dec 2021 11:56:59 +0000 Subject: [PATCH 321/327] ASoC: cs35l41: Convert tables to shared source code To support CS35L41 in HDA systems the HDA driver for CS35L41 would have to duplicate some functions that already exist on ASoC driver So instead of duplicate the code, use the new lib source as a shared resource for both ASoC and HDA Also, change the way CONFIG_SND_SOC_CS35L41 is selected, as reported by Intel Kernel test robot, it is possible to build SND_SOC_CS35L41_SPI/I2C without the main driver, which would lead to build failures. Signed-off-by: Lucas Tanure Reported-by: kernel test robot Link: https://lore.kernel.org/r/20211217115708.882525-2-tanureal@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/cs35l41.h | 733 +++++++++++++++++ sound/soc/codecs/Kconfig | 11 +- sound/soc/codecs/Makefile | 4 +- sound/soc/codecs/cs35l41-i2c.c | 1 - .../{cs35l41-tables.c => cs35l41-lib.c} | 14 +- sound/soc/codecs/cs35l41-spi.c | 1 - sound/soc/codecs/cs35l41.h | 734 ------------------ 7 files changed, 755 insertions(+), 743 deletions(-) rename sound/soc/codecs/{cs35l41-tables.c => cs35l41-lib.c} (98%) diff --git a/include/sound/cs35l41.h b/include/sound/cs35l41.h index 1f1e3c6c9be1c..aac3ffb9bc894 100644 --- a/include/sound/cs35l41.h +++ b/include/sound/cs35l41.h @@ -10,6 +10,721 @@ #ifndef __CS35L41_H #define __CS35L41_H +#include + +#define CS35L41_FIRSTREG 0x00000000 +#define CS35L41_LASTREG 0x03804FE8 +#define CS35L41_DEVID 0x00000000 +#define CS35L41_REVID 0x00000004 +#define CS35L41_FABID 0x00000008 +#define CS35L41_RELID 0x0000000C +#define CS35L41_OTPID 0x00000010 +#define CS35L41_SFT_RESET 0x00000020 +#define CS35L41_TEST_KEY_CTL 0x00000040 +#define CS35L41_USER_KEY_CTL 0x00000044 +#define CS35L41_OTP_MEM0 0x00000400 +#define CS35L41_OTP_MEM31 0x0000047C +#define CS35L41_OTP_CTRL0 0x00000500 +#define CS35L41_OTP_CTRL1 0x00000504 +#define CS35L41_OTP_CTRL3 0x00000508 +#define CS35L41_OTP_CTRL4 0x0000050C +#define CS35L41_OTP_CTRL5 0x00000510 +#define CS35L41_OTP_CTRL6 0x00000514 +#define CS35L41_OTP_CTRL7 0x00000518 +#define CS35L41_OTP_CTRL8 0x0000051C +#define CS35L41_PWR_CTRL1 0x00002014 +#define CS35L41_PWR_CTRL2 0x00002018 +#define CS35L41_PWR_CTRL3 0x0000201C +#define CS35L41_CTRL_OVRRIDE 0x00002020 +#define CS35L41_AMP_OUT_MUTE 0x00002024 +#define CS35L41_PROTECT_REL_ERR_IGN 0x00002034 +#define CS35L41_GPIO_PAD_CONTROL 0x0000242C +#define CS35L41_JTAG_CONTROL 0x00002438 +#define CS35L41_PLL_CLK_CTRL 0x00002C04 +#define CS35L41_DSP_CLK_CTRL 0x00002C08 +#define CS35L41_GLOBAL_CLK_CTRL 0x00002C0C +#define CS35L41_DATA_FS_SEL 0x00002C10 +#define CS35L41_TST_FS_MON0 0x00002D10 +#define CS35L41_MDSYNC_EN 0x00003400 +#define CS35L41_MDSYNC_TX_ID 0x00003408 +#define CS35L41_MDSYNC_PWR_CTRL 0x0000340C +#define CS35L41_MDSYNC_DATA_TX 0x00003410 +#define CS35L41_MDSYNC_TX_STATUS 0x00003414 +#define CS35L41_MDSYNC_DATA_RX 0x0000341C +#define CS35L41_MDSYNC_RX_STATUS 0x00003420 +#define CS35L41_MDSYNC_ERR_STATUS 0x00003424 +#define CS35L41_MDSYNC_SYNC_PTE2 0x00003528 +#define CS35L41_MDSYNC_SYNC_PTE3 0x0000352C +#define CS35L41_MDSYNC_SYNC_MSM_STATUS 0x0000353C +#define CS35L41_BSTCVRT_VCTRL1 0x00003800 +#define CS35L41_BSTCVRT_VCTRL2 0x00003804 +#define CS35L41_BSTCVRT_PEAK_CUR 0x00003808 +#define CS35L41_BSTCVRT_SFT_RAMP 0x0000380C +#define CS35L41_BSTCVRT_COEFF 0x00003810 +#define CS35L41_BSTCVRT_SLOPE_LBST 0x00003814 +#define CS35L41_BSTCVRT_SW_FREQ 0x00003818 +#define CS35L41_BSTCVRT_DCM_CTRL 0x0000381C +#define CS35L41_BSTCVRT_DCM_MODE_FORCE 0x00003820 +#define CS35L41_BSTCVRT_OVERVOLT_CTRL 0x00003830 +#define CS35L41_VI_VOL_POL 0x00004000 +#define CS35L41_VIMON_SPKMON_RESYNC 0x00004100 +#define CS35L41_DTEMP_WARN_THLD 0x00004220 +#define CS35L41_DTEMP_CFG 0x00004224 +#define CS35L41_DTEMP_EN 0x00004308 +#define CS35L41_VPVBST_FS_SEL 0x00004400 +#define CS35L41_SP_ENABLES 0x00004800 +#define CS35L41_SP_RATE_CTRL 0x00004804 +#define CS35L41_SP_FORMAT 0x00004808 +#define CS35L41_SP_HIZ_CTRL 0x0000480C +#define CS35L41_SP_FRAME_TX_SLOT 0x00004810 +#define CS35L41_SP_FRAME_RX_SLOT 0x00004820 +#define CS35L41_SP_TX_WL 0x00004830 +#define CS35L41_SP_RX_WL 0x00004840 +#define CS35L41_ASP_CONTROL4 0x00004854 +#define CS35L41_DAC_PCM1_SRC 0x00004C00 +#define CS35L41_ASP_TX1_SRC 0x00004C20 +#define CS35L41_ASP_TX2_SRC 0x00004C24 +#define CS35L41_ASP_TX3_SRC 0x00004C28 +#define CS35L41_ASP_TX4_SRC 0x00004C2C +#define CS35L41_DSP1_RX1_SRC 0x00004C40 +#define CS35L41_DSP1_RX2_SRC 0x00004C44 +#define CS35L41_DSP1_RX3_SRC 0x00004C48 +#define CS35L41_DSP1_RX4_SRC 0x00004C4C +#define CS35L41_DSP1_RX5_SRC 0x00004C50 +#define CS35L41_DSP1_RX6_SRC 0x00004C54 +#define CS35L41_DSP1_RX7_SRC 0x00004C58 +#define CS35L41_DSP1_RX8_SRC 0x00004C5C +#define CS35L41_NGATE1_SRC 0x00004C60 +#define CS35L41_NGATE2_SRC 0x00004C64 +#define CS35L41_AMP_DIG_VOL_CTRL 0x00006000 +#define CS35L41_VPBR_CFG 0x00006404 +#define CS35L41_VBBR_CFG 0x00006408 +#define CS35L41_VPBR_STATUS 0x0000640C +#define CS35L41_VBBR_STATUS 0x00006410 +#define CS35L41_OVERTEMP_CFG 0x00006414 +#define CS35L41_AMP_ERR_VOL 0x00006418 +#define CS35L41_VOL_STATUS_TO_DSP 0x00006450 +#define CS35L41_CLASSH_CFG 0x00006800 +#define CS35L41_WKFET_CFG 0x00006804 +#define CS35L41_NG_CFG 0x00006808 +#define CS35L41_AMP_GAIN_CTRL 0x00006C04 +#define CS35L41_DAC_MSM_CFG 0x00007400 +#define CS35L41_IRQ1_CFG 0x00010000 +#define CS35L41_IRQ1_STATUS 0x00010004 +#define CS35L41_IRQ1_STATUS1 0x00010010 +#define CS35L41_IRQ1_STATUS2 0x00010014 +#define CS35L41_IRQ1_STATUS3 0x00010018 +#define CS35L41_IRQ1_STATUS4 0x0001001C +#define CS35L41_IRQ1_RAW_STATUS1 0x00010090 +#define CS35L41_IRQ1_RAW_STATUS2 0x00010094 +#define CS35L41_IRQ1_RAW_STATUS3 0x00010098 +#define CS35L41_IRQ1_RAW_STATUS4 0x0001009C +#define CS35L41_IRQ1_MASK1 0x00010110 +#define CS35L41_IRQ1_MASK2 0x00010114 +#define CS35L41_IRQ1_MASK3 0x00010118 +#define CS35L41_IRQ1_MASK4 0x0001011C +#define CS35L41_IRQ1_FRC1 0x00010190 +#define CS35L41_IRQ1_FRC2 0x00010194 +#define CS35L41_IRQ1_FRC3 0x00010198 +#define CS35L41_IRQ1_FRC4 0x0001019C +#define CS35L41_IRQ1_EDGE1 0x00010210 +#define CS35L41_IRQ1_EDGE4 0x0001021C +#define CS35L41_IRQ1_POL1 0x00010290 +#define CS35L41_IRQ1_POL2 0x00010294 +#define CS35L41_IRQ1_POL3 0x00010298 +#define CS35L41_IRQ1_POL4 0x0001029C +#define CS35L41_IRQ1_DB3 0x00010318 +#define CS35L41_IRQ2_CFG 0x00010800 +#define CS35L41_IRQ2_STATUS 0x00010804 +#define CS35L41_IRQ2_STATUS1 0x00010810 +#define CS35L41_IRQ2_STATUS2 0x00010814 +#define CS35L41_IRQ2_STATUS3 0x00010818 +#define CS35L41_IRQ2_STATUS4 0x0001081C +#define CS35L41_IRQ2_RAW_STATUS1 0x00010890 +#define CS35L41_IRQ2_RAW_STATUS2 0x00010894 +#define CS35L41_IRQ2_RAW_STATUS3 0x00010898 +#define CS35L41_IRQ2_RAW_STATUS4 0x0001089C +#define CS35L41_IRQ2_MASK1 0x00010910 +#define CS35L41_IRQ2_MASK2 0x00010914 +#define CS35L41_IRQ2_MASK3 0x00010918 +#define CS35L41_IRQ2_MASK4 0x0001091C +#define CS35L41_IRQ2_FRC1 0x00010990 +#define CS35L41_IRQ2_FRC2 0x00010994 +#define CS35L41_IRQ2_FRC3 0x00010998 +#define CS35L41_IRQ2_FRC4 0x0001099C +#define CS35L41_IRQ2_EDGE1 0x00010A10 +#define CS35L41_IRQ2_EDGE4 0x00010A1C +#define CS35L41_IRQ2_POL1 0x00010A90 +#define CS35L41_IRQ2_POL2 0x00010A94 +#define CS35L41_IRQ2_POL3 0x00010A98 +#define CS35L41_IRQ2_POL4 0x00010A9C +#define CS35L41_IRQ2_DB3 0x00010B18 +#define CS35L41_GPIO_STATUS1 0x00011000 +#define CS35L41_GPIO1_CTRL1 0x00011008 +#define CS35L41_GPIO2_CTRL1 0x0001100C +#define CS35L41_MIXER_NGATE_CFG 0x00012000 +#define CS35L41_MIXER_NGATE_CH1_CFG 0x00012004 +#define CS35L41_MIXER_NGATE_CH2_CFG 0x00012008 +#define CS35L41_DSP_MBOX_1 0x00013000 +#define CS35L41_DSP_MBOX_2 0x00013004 +#define CS35L41_DSP_MBOX_3 0x00013008 +#define CS35L41_DSP_MBOX_4 0x0001300C +#define CS35L41_DSP_MBOX_5 0x00013010 +#define CS35L41_DSP_MBOX_6 0x00013014 +#define CS35L41_DSP_MBOX_7 0x00013018 +#define CS35L41_DSP_MBOX_8 0x0001301C +#define CS35L41_DSP_VIRT1_MBOX_1 0x00013020 +#define CS35L41_DSP_VIRT1_MBOX_2 0x00013024 +#define CS35L41_DSP_VIRT1_MBOX_3 0x00013028 +#define CS35L41_DSP_VIRT1_MBOX_4 0x0001302C +#define CS35L41_DSP_VIRT1_MBOX_5 0x00013030 +#define CS35L41_DSP_VIRT1_MBOX_6 0x00013034 +#define CS35L41_DSP_VIRT1_MBOX_7 0x00013038 +#define CS35L41_DSP_VIRT1_MBOX_8 0x0001303C +#define CS35L41_DSP_VIRT2_MBOX_1 0x00013040 +#define CS35L41_DSP_VIRT2_MBOX_2 0x00013044 +#define CS35L41_DSP_VIRT2_MBOX_3 0x00013048 +#define CS35L41_DSP_VIRT2_MBOX_4 0x0001304C +#define CS35L41_DSP_VIRT2_MBOX_5 0x00013050 +#define CS35L41_DSP_VIRT2_MBOX_6 0x00013054 +#define CS35L41_DSP_VIRT2_MBOX_7 0x00013058 +#define CS35L41_DSP_VIRT2_MBOX_8 0x0001305C +#define CS35L41_CLOCK_DETECT_1 0x00014000 +#define CS35L41_TIMER1_CONTROL 0x00015000 +#define CS35L41_TIMER1_COUNT_PRESET 0x00015004 +#define CS35L41_TIMER1_START_STOP 0x0001500C +#define CS35L41_TIMER1_STATUS 0x00015010 +#define CS35L41_TIMER1_COUNT_READBACK 0x00015014 +#define CS35L41_TIMER1_DSP_CLK_CFG 0x00015018 +#define CS35L41_TIMER1_DSP_CLK_STATUS 0x0001501C +#define CS35L41_TIMER2_CONTROL 0x00015100 +#define CS35L41_TIMER2_COUNT_PRESET 0x00015104 +#define CS35L41_TIMER2_START_STOP 0x0001510C +#define CS35L41_TIMER2_STATUS 0x00015110 +#define CS35L41_TIMER2_COUNT_READBACK 0x00015114 +#define CS35L41_TIMER2_DSP_CLK_CFG 0x00015118 +#define CS35L41_TIMER2_DSP_CLK_STATUS 0x0001511C +#define CS35L41_DFT_JTAG_CONTROL 0x00016000 +#define CS35L41_DIE_STS1 0x00017040 +#define CS35L41_DIE_STS2 0x00017044 +#define CS35L41_TEMP_CAL1 0x00017048 +#define CS35L41_TEMP_CAL2 0x0001704C +#define CS35L41_DSP1_XMEM_PACK_0 0x02000000 +#define CS35L41_DSP1_XMEM_PACK_3068 0x02002FF0 +#define CS35L41_DSP1_XMEM_UNPACK32_0 0x02400000 +#define CS35L41_DSP1_XMEM_UNPACK32_2046 0x02401FF8 +#define CS35L41_DSP1_TIMESTAMP_COUNT 0x025C0800 +#define CS35L41_DSP1_SYS_ID 0x025E0000 +#define CS35L41_DSP1_SYS_VERSION 0x025E0004 +#define CS35L41_DSP1_SYS_CORE_ID 0x025E0008 +#define CS35L41_DSP1_SYS_AHB_ADDR 0x025E000C +#define CS35L41_DSP1_SYS_XSRAM_SIZE 0x025E0010 +#define CS35L41_DSP1_SYS_YSRAM_SIZE 0x025E0018 +#define CS35L41_DSP1_SYS_PSRAM_SIZE 0x025E0020 +#define CS35L41_DSP1_SYS_PM_BOOT_SIZE 0x025E0028 +#define CS35L41_DSP1_SYS_FEATURES 0x025E002C +#define CS35L41_DSP1_SYS_FIR_FILTERS 0x025E0030 +#define CS35L41_DSP1_SYS_LMS_FILTERS 0x025E0034 +#define CS35L41_DSP1_SYS_XM_BANK_SIZE 0x025E0038 +#define CS35L41_DSP1_SYS_YM_BANK_SIZE 0x025E003C +#define CS35L41_DSP1_SYS_PM_BANK_SIZE 0x025E0040 +#define CS35L41_DSP1_AHBM_WIN0_CTRL0 0x025E2000 +#define CS35L41_DSP1_AHBM_WIN0_CTRL1 0x025E2004 +#define CS35L41_DSP1_AHBM_WIN1_CTRL0 0x025E2008 +#define CS35L41_DSP1_AHBM_WIN1_CTRL1 0x025E200C +#define CS35L41_DSP1_AHBM_WIN2_CTRL0 0x025E2010 +#define CS35L41_DSP1_AHBM_WIN2_CTRL1 0x025E2014 +#define CS35L41_DSP1_AHBM_WIN3_CTRL0 0x025E2018 +#define CS35L41_DSP1_AHBM_WIN3_CTRL1 0x025E201C +#define CS35L41_DSP1_AHBM_WIN4_CTRL0 0x025E2020 +#define CS35L41_DSP1_AHBM_WIN4_CTRL1 0x025E2024 +#define CS35L41_DSP1_AHBM_WIN5_CTRL0 0x025E2028 +#define CS35L41_DSP1_AHBM_WIN5_CTRL1 0x025E202C +#define CS35L41_DSP1_AHBM_WIN6_CTRL0 0x025E2030 +#define CS35L41_DSP1_AHBM_WIN6_CTRL1 0x025E2034 +#define CS35L41_DSP1_AHBM_WIN7_CTRL0 0x025E2038 +#define CS35L41_DSP1_AHBM_WIN7_CTRL1 0x025E203C +#define CS35L41_DSP1_AHBM_WIN_DBG_CTRL0 0x025E2040 +#define CS35L41_DSP1_AHBM_WIN_DBG_CTRL1 0x025E2044 +#define CS35L41_DSP1_XMEM_UNPACK24_0 0x02800000 +#define CS35L41_DSP1_XMEM_UNPACK24_4093 0x02803FF4 +#define CS35L41_DSP1_CTRL_BASE 0x02B80000 +#define CS35L41_DSP1_CORE_SOFT_RESET 0x02B80010 +#define CS35L41_DSP1_DEBUG 0x02B80040 +#define CS35L41_DSP1_TIMER_CTRL 0x02B80048 +#define CS35L41_DSP1_STREAM_ARB_CTRL 0x02B80050 +#define CS35L41_DSP1_RX1_RATE 0x02B80080 +#define CS35L41_DSP1_RX2_RATE 0x02B80088 +#define CS35L41_DSP1_RX3_RATE 0x02B80090 +#define CS35L41_DSP1_RX4_RATE 0x02B80098 +#define CS35L41_DSP1_RX5_RATE 0x02B800A0 +#define CS35L41_DSP1_RX6_RATE 0x02B800A8 +#define CS35L41_DSP1_RX7_RATE 0x02B800B0 +#define CS35L41_DSP1_RX8_RATE 0x02B800B8 +#define CS35L41_DSP1_TX1_RATE 0x02B80280 +#define CS35L41_DSP1_TX2_RATE 0x02B80288 +#define CS35L41_DSP1_TX3_RATE 0x02B80290 +#define CS35L41_DSP1_TX4_RATE 0x02B80298 +#define CS35L41_DSP1_TX5_RATE 0x02B802A0 +#define CS35L41_DSP1_TX6_RATE 0x02B802A8 +#define CS35L41_DSP1_TX7_RATE 0x02B802B0 +#define CS35L41_DSP1_TX8_RATE 0x02B802B8 +#define CS35L41_DSP1_NMI_CTRL1 0x02B80480 +#define CS35L41_DSP1_NMI_CTRL2 0x02B80488 +#define CS35L41_DSP1_NMI_CTRL3 0x02B80490 +#define CS35L41_DSP1_NMI_CTRL4 0x02B80498 +#define CS35L41_DSP1_NMI_CTRL5 0x02B804A0 +#define CS35L41_DSP1_NMI_CTRL6 0x02B804A8 +#define CS35L41_DSP1_NMI_CTRL7 0x02B804B0 +#define CS35L41_DSP1_NMI_CTRL8 0x02B804B8 +#define CS35L41_DSP1_RESUME_CTRL 0x02B80500 +#define CS35L41_DSP1_IRQ1_CTRL 0x02B80508 +#define CS35L41_DSP1_IRQ2_CTRL 0x02B80510 +#define CS35L41_DSP1_IRQ3_CTRL 0x02B80518 +#define CS35L41_DSP1_IRQ4_CTRL 0x02B80520 +#define CS35L41_DSP1_IRQ5_CTRL 0x02B80528 +#define CS35L41_DSP1_IRQ6_CTRL 0x02B80530 +#define CS35L41_DSP1_IRQ7_CTRL 0x02B80538 +#define CS35L41_DSP1_IRQ8_CTRL 0x02B80540 +#define CS35L41_DSP1_IRQ9_CTRL 0x02B80548 +#define CS35L41_DSP1_IRQ10_CTRL 0x02B80550 +#define CS35L41_DSP1_IRQ11_CTRL 0x02B80558 +#define CS35L41_DSP1_IRQ12_CTRL 0x02B80560 +#define CS35L41_DSP1_IRQ13_CTRL 0x02B80568 +#define CS35L41_DSP1_IRQ14_CTRL 0x02B80570 +#define CS35L41_DSP1_IRQ15_CTRL 0x02B80578 +#define CS35L41_DSP1_IRQ16_CTRL 0x02B80580 +#define CS35L41_DSP1_IRQ17_CTRL 0x02B80588 +#define CS35L41_DSP1_IRQ18_CTRL 0x02B80590 +#define CS35L41_DSP1_IRQ19_CTRL 0x02B80598 +#define CS35L41_DSP1_IRQ20_CTRL 0x02B805A0 +#define CS35L41_DSP1_IRQ21_CTRL 0x02B805A8 +#define CS35L41_DSP1_IRQ22_CTRL 0x02B805B0 +#define CS35L41_DSP1_IRQ23_CTRL 0x02B805B8 +#define CS35L41_DSP1_SCRATCH1 0x02B805C0 +#define CS35L41_DSP1_SCRATCH2 0x02B805C8 +#define CS35L41_DSP1_SCRATCH3 0x02B805D0 +#define CS35L41_DSP1_SCRATCH4 0x02B805D8 +#define CS35L41_DSP1_CCM_CORE_CTRL 0x02BC1000 +#define CS35L41_DSP1_CCM_CLK_OVERRIDE 0x02BC1008 +#define CS35L41_DSP1_XM_MSTR_EN 0x02BC2000 +#define CS35L41_DSP1_XM_CORE_PRI 0x02BC2008 +#define CS35L41_DSP1_XM_AHB_PACK_PL_PRI 0x02BC2010 +#define CS35L41_DSP1_XM_AHB_UP_PL_PRI 0x02BC2018 +#define CS35L41_DSP1_XM_ACCEL_PL0_PRI 0x02BC2020 +#define CS35L41_DSP1_XM_NPL0_PRI 0x02BC2078 +#define CS35L41_DSP1_YM_MSTR_EN 0x02BC20C0 +#define CS35L41_DSP1_YM_CORE_PRI 0x02BC20C8 +#define CS35L41_DSP1_YM_AHB_PACK_PL_PRI 0x02BC20D0 +#define CS35L41_DSP1_YM_AHB_UP_PL_PRI 0x02BC20D8 +#define CS35L41_DSP1_YM_ACCEL_PL0_PRI 0x02BC20E0 +#define CS35L41_DSP1_YM_NPL0_PRI 0x02BC2138 +#define CS35L41_DSP1_PM_MSTR_EN 0x02BC2180 +#define CS35L41_DSP1_PM_PATCH0_ADDR 0x02BC2188 +#define CS35L41_DSP1_PM_PATCH0_EN 0x02BC218C +#define CS35L41_DSP1_PM_PATCH0_DATA_LO 0x02BC2190 +#define CS35L41_DSP1_PM_PATCH0_DATA_HI 0x02BC2194 +#define CS35L41_DSP1_PM_PATCH1_ADDR 0x02BC2198 +#define CS35L41_DSP1_PM_PATCH1_EN 0x02BC219C +#define CS35L41_DSP1_PM_PATCH1_DATA_LO 0x02BC21A0 +#define CS35L41_DSP1_PM_PATCH1_DATA_HI 0x02BC21A4 +#define CS35L41_DSP1_PM_PATCH2_ADDR 0x02BC21A8 +#define CS35L41_DSP1_PM_PATCH2_EN 0x02BC21AC +#define CS35L41_DSP1_PM_PATCH2_DATA_LO 0x02BC21B0 +#define CS35L41_DSP1_PM_PATCH2_DATA_HI 0x02BC21B4 +#define CS35L41_DSP1_PM_PATCH3_ADDR 0x02BC21B8 +#define CS35L41_DSP1_PM_PATCH3_EN 0x02BC21BC +#define CS35L41_DSP1_PM_PATCH3_DATA_LO 0x02BC21C0 +#define CS35L41_DSP1_PM_PATCH3_DATA_HI 0x02BC21C4 +#define CS35L41_DSP1_PM_PATCH4_ADDR 0x02BC21C8 +#define CS35L41_DSP1_PM_PATCH4_EN 0x02BC21CC +#define CS35L41_DSP1_PM_PATCH4_DATA_LO 0x02BC21D0 +#define CS35L41_DSP1_PM_PATCH4_DATA_HI 0x02BC21D4 +#define CS35L41_DSP1_PM_PATCH5_ADDR 0x02BC21D8 +#define CS35L41_DSP1_PM_PATCH5_EN 0x02BC21DC +#define CS35L41_DSP1_PM_PATCH5_DATA_LO 0x02BC21E0 +#define CS35L41_DSP1_PM_PATCH5_DATA_HI 0x02BC21E4 +#define CS35L41_DSP1_PM_PATCH6_ADDR 0x02BC21E8 +#define CS35L41_DSP1_PM_PATCH6_EN 0x02BC21EC +#define CS35L41_DSP1_PM_PATCH6_DATA_LO 0x02BC21F0 +#define CS35L41_DSP1_PM_PATCH6_DATA_HI 0x02BC21F4 +#define CS35L41_DSP1_PM_PATCH7_ADDR 0x02BC21F8 +#define CS35L41_DSP1_PM_PATCH7_EN 0x02BC21FC +#define CS35L41_DSP1_PM_PATCH7_DATA_LO 0x02BC2200 +#define CS35L41_DSP1_PM_PATCH7_DATA_HI 0x02BC2204 +#define CS35L41_DSP1_MPU_XM_ACCESS0 0x02BC3000 +#define CS35L41_DSP1_MPU_YM_ACCESS0 0x02BC3004 +#define CS35L41_DSP1_MPU_WNDW_ACCESS0 0x02BC3008 +#define CS35L41_DSP1_MPU_XREG_ACCESS0 0x02BC300C +#define CS35L41_DSP1_MPU_YREG_ACCESS0 0x02BC3014 +#define CS35L41_DSP1_MPU_XM_ACCESS1 0x02BC3018 +#define CS35L41_DSP1_MPU_YM_ACCESS1 0x02BC301C +#define CS35L41_DSP1_MPU_WNDW_ACCESS1 0x02BC3020 +#define CS35L41_DSP1_MPU_XREG_ACCESS1 0x02BC3024 +#define CS35L41_DSP1_MPU_YREG_ACCESS1 0x02BC302C +#define CS35L41_DSP1_MPU_XM_ACCESS2 0x02BC3030 +#define CS35L41_DSP1_MPU_YM_ACCESS2 0x02BC3034 +#define CS35L41_DSP1_MPU_WNDW_ACCESS2 0x02BC3038 +#define CS35L41_DSP1_MPU_XREG_ACCESS2 0x02BC303C +#define CS35L41_DSP1_MPU_YREG_ACCESS2 0x02BC3044 +#define CS35L41_DSP1_MPU_XM_ACCESS3 0x02BC3048 +#define CS35L41_DSP1_MPU_YM_ACCESS3 0x02BC304C +#define CS35L41_DSP1_MPU_WNDW_ACCESS3 0x02BC3050 +#define CS35L41_DSP1_MPU_XREG_ACCESS3 0x02BC3054 +#define CS35L41_DSP1_MPU_YREG_ACCESS3 0x02BC305C +#define CS35L41_DSP1_MPU_XM_VIO_ADDR 0x02BC3100 +#define CS35L41_DSP1_MPU_XM_VIO_STATUS 0x02BC3104 +#define CS35L41_DSP1_MPU_YM_VIO_ADDR 0x02BC3108 +#define CS35L41_DSP1_MPU_YM_VIO_STATUS 0x02BC310C +#define CS35L41_DSP1_MPU_PM_VIO_ADDR 0x02BC3110 +#define CS35L41_DSP1_MPU_PM_VIO_STATUS 0x02BC3114 +#define CS35L41_DSP1_MPU_LOCK_CONFIG 0x02BC3140 +#define CS35L41_DSP1_MPU_WDT_RST_CTRL 0x02BC3180 +#define CS35L41_DSP1_STRMARB_MSTR0_CFG0 0x02BC5000 +#define CS35L41_DSP1_STRMARB_MSTR0_CFG1 0x02BC5004 +#define CS35L41_DSP1_STRMARB_MSTR0_CFG2 0x02BC5008 +#define CS35L41_DSP1_STRMARB_MSTR1_CFG0 0x02BC5010 +#define CS35L41_DSP1_STRMARB_MSTR1_CFG1 0x02BC5014 +#define CS35L41_DSP1_STRMARB_MSTR1_CFG2 0x02BC5018 +#define CS35L41_DSP1_STRMARB_MSTR2_CFG0 0x02BC5020 +#define CS35L41_DSP1_STRMARB_MSTR2_CFG1 0x02BC5024 +#define CS35L41_DSP1_STRMARB_MSTR2_CFG2 0x02BC5028 +#define CS35L41_DSP1_STRMARB_MSTR3_CFG0 0x02BC5030 +#define CS35L41_DSP1_STRMARB_MSTR3_CFG1 0x02BC5034 +#define CS35L41_DSP1_STRMARB_MSTR3_CFG2 0x02BC5038 +#define CS35L41_DSP1_STRMARB_MSTR4_CFG0 0x02BC5040 +#define CS35L41_DSP1_STRMARB_MSTR4_CFG1 0x02BC5044 +#define CS35L41_DSP1_STRMARB_MSTR4_CFG2 0x02BC5048 +#define CS35L41_DSP1_STRMARB_MSTR5_CFG0 0x02BC5050 +#define CS35L41_DSP1_STRMARB_MSTR5_CFG1 0x02BC5054 +#define CS35L41_DSP1_STRMARB_MSTR5_CFG2 0x02BC5058 +#define CS35L41_DSP1_STRMARB_MSTR6_CFG0 0x02BC5060 +#define CS35L41_DSP1_STRMARB_MSTR6_CFG1 0x02BC5064 +#define CS35L41_DSP1_STRMARB_MSTR6_CFG2 0x02BC5068 +#define CS35L41_DSP1_STRMARB_MSTR7_CFG0 0x02BC5070 +#define CS35L41_DSP1_STRMARB_MSTR7_CFG1 0x02BC5074 +#define CS35L41_DSP1_STRMARB_MSTR7_CFG2 0x02BC5078 +#define CS35L41_DSP1_STRMARB_TX0_CFG0 0x02BC5200 +#define CS35L41_DSP1_STRMARB_TX0_CFG1 0x02BC5204 +#define CS35L41_DSP1_STRMARB_TX1_CFG0 0x02BC5208 +#define CS35L41_DSP1_STRMARB_TX1_CFG1 0x02BC520C +#define CS35L41_DSP1_STRMARB_TX2_CFG0 0x02BC5210 +#define CS35L41_DSP1_STRMARB_TX2_CFG1 0x02BC5214 +#define CS35L41_DSP1_STRMARB_TX3_CFG0 0x02BC5218 +#define CS35L41_DSP1_STRMARB_TX3_CFG1 0x02BC521C +#define CS35L41_DSP1_STRMARB_TX4_CFG0 0x02BC5220 +#define CS35L41_DSP1_STRMARB_TX4_CFG1 0x02BC5224 +#define CS35L41_DSP1_STRMARB_TX5_CFG0 0x02BC5228 +#define CS35L41_DSP1_STRMARB_TX5_CFG1 0x02BC522C +#define CS35L41_DSP1_STRMARB_TX6_CFG0 0x02BC5230 +#define CS35L41_DSP1_STRMARB_TX6_CFG1 0x02BC5234 +#define CS35L41_DSP1_STRMARB_TX7_CFG0 0x02BC5238 +#define CS35L41_DSP1_STRMARB_TX7_CFG1 0x02BC523C +#define CS35L41_DSP1_STRMARB_RX0_CFG0 0x02BC5400 +#define CS35L41_DSP1_STRMARB_RX0_CFG1 0x02BC5404 +#define CS35L41_DSP1_STRMARB_RX1_CFG0 0x02BC5408 +#define CS35L41_DSP1_STRMARB_RX1_CFG1 0x02BC540C +#define CS35L41_DSP1_STRMARB_RX2_CFG0 0x02BC5410 +#define CS35L41_DSP1_STRMARB_RX2_CFG1 0x02BC5414 +#define CS35L41_DSP1_STRMARB_RX3_CFG0 0x02BC5418 +#define CS35L41_DSP1_STRMARB_RX3_CFG1 0x02BC541C +#define CS35L41_DSP1_STRMARB_RX4_CFG0 0x02BC5420 +#define CS35L41_DSP1_STRMARB_RX4_CFG1 0x02BC5424 +#define CS35L41_DSP1_STRMARB_RX5_CFG0 0x02BC5428 +#define CS35L41_DSP1_STRMARB_RX5_CFG1 0x02BC542C +#define CS35L41_DSP1_STRMARB_RX6_CFG0 0x02BC5430 +#define CS35L41_DSP1_STRMARB_RX6_CFG1 0x02BC5434 +#define CS35L41_DSP1_STRMARB_RX7_CFG0 0x02BC5438 +#define CS35L41_DSP1_STRMARB_RX7_CFG1 0x02BC543C +#define CS35L41_DSP1_STRMARB_IRQ0_CFG0 0x02BC5600 +#define CS35L41_DSP1_STRMARB_IRQ0_CFG1 0x02BC5604 +#define CS35L41_DSP1_STRMARB_IRQ0_CFG2 0x02BC5608 +#define CS35L41_DSP1_STRMARB_IRQ1_CFG0 0x02BC5610 +#define CS35L41_DSP1_STRMARB_IRQ1_CFG1 0x02BC5614 +#define CS35L41_DSP1_STRMARB_IRQ1_CFG2 0x02BC5618 +#define CS35L41_DSP1_STRMARB_IRQ2_CFG0 0x02BC5620 +#define CS35L41_DSP1_STRMARB_IRQ2_CFG1 0x02BC5624 +#define CS35L41_DSP1_STRMARB_IRQ2_CFG2 0x02BC5628 +#define CS35L41_DSP1_STRMARB_IRQ3_CFG0 0x02BC5630 +#define CS35L41_DSP1_STRMARB_IRQ3_CFG1 0x02BC5634 +#define CS35L41_DSP1_STRMARB_IRQ3_CFG2 0x02BC5638 +#define CS35L41_DSP1_STRMARB_IRQ4_CFG0 0x02BC5640 +#define CS35L41_DSP1_STRMARB_IRQ4_CFG1 0x02BC5644 +#define CS35L41_DSP1_STRMARB_IRQ4_CFG2 0x02BC5648 +#define CS35L41_DSP1_STRMARB_IRQ5_CFG0 0x02BC5650 +#define CS35L41_DSP1_STRMARB_IRQ5_CFG1 0x02BC5654 +#define CS35L41_DSP1_STRMARB_IRQ5_CFG2 0x02BC5658 +#define CS35L41_DSP1_STRMARB_IRQ6_CFG0 0x02BC5660 +#define CS35L41_DSP1_STRMARB_IRQ6_CFG1 0x02BC5664 +#define CS35L41_DSP1_STRMARB_IRQ6_CFG2 0x02BC5668 +#define CS35L41_DSP1_STRMARB_IRQ7_CFG0 0x02BC5670 +#define CS35L41_DSP1_STRMARB_IRQ7_CFG1 0x02BC5674 +#define CS35L41_DSP1_STRMARB_IRQ7_CFG2 0x02BC5678 +#define CS35L41_DSP1_STRMARB_RESYNC_MSK 0x02BC5A00 +#define CS35L41_DSP1_STRMARB_ERR_STATUS 0x02BC5A08 +#define CS35L41_DSP1_INTPCTL_RES_STATIC 0x02BC6000 +#define CS35L41_DSP1_INTPCTL_RES_DYN 0x02BC6004 +#define CS35L41_DSP1_INTPCTL_NMI_CTRL 0x02BC6008 +#define CS35L41_DSP1_INTPCTL_IRQ_INV 0x02BC6010 +#define CS35L41_DSP1_INTPCTL_IRQ_MODE 0x02BC6014 +#define CS35L41_DSP1_INTPCTL_IRQ_EN 0x02BC6018 +#define CS35L41_DSP1_INTPCTL_IRQ_MSK 0x02BC601C +#define CS35L41_DSP1_INTPCTL_IRQ_FLUSH 0x02BC6020 +#define CS35L41_DSP1_INTPCTL_IRQ_MSKCLR 0x02BC6024 +#define CS35L41_DSP1_INTPCTL_IRQ_FRC 0x02BC6028 +#define CS35L41_DSP1_INTPCTL_IRQ_MSKSET 0x02BC602C +#define CS35L41_DSP1_INTPCTL_IRQ_ERR 0x02BC6030 +#define CS35L41_DSP1_INTPCTL_IRQ_PEND 0x02BC6034 +#define CS35L41_DSP1_INTPCTL_IRQ_GEN 0x02BC6038 +#define CS35L41_DSP1_INTPCTL_TESTBITS 0x02BC6040 +#define CS35L41_DSP1_WDT_CONTROL 0x02BC7000 +#define CS35L41_DSP1_WDT_STATUS 0x02BC7008 +#define CS35L41_DSP1_YMEM_PACK_0 0x02C00000 +#define CS35L41_DSP1_YMEM_PACK_1532 0x02C017F0 +#define CS35L41_DSP1_YMEM_UNPACK32_0 0x03000000 +#define CS35L41_DSP1_YMEM_UNPACK32_1022 0x03000FF8 +#define CS35L41_DSP1_YMEM_UNPACK24_0 0x03400000 +#define CS35L41_DSP1_YMEM_UNPACK24_2045 0x03401FF4 +#define CS35L41_DSP1_PMEM_0 0x03800000 +#define CS35L41_DSP1_PMEM_5114 0x03804FE8 + +/*test regs for emulation bringup*/ +#define CS35L41_PLL_OVR 0x00003018 +#define CS35L41_BST_TEST_DUTY 0x00003900 +#define CS35L41_DIGPWM_IOCTRL 0x0000706C + +/*registers populated by OTP*/ +#define CS35L41_OTP_TRIM_1 0x0000208c +#define CS35L41_OTP_TRIM_2 0x00002090 +#define CS35L41_OTP_TRIM_3 0x00003010 +#define CS35L41_OTP_TRIM_4 0x0000300C +#define CS35L41_OTP_TRIM_5 0x0000394C +#define CS35L41_OTP_TRIM_6 0x00003950 +#define CS35L41_OTP_TRIM_7 0x00003954 +#define CS35L41_OTP_TRIM_8 0x00003958 +#define CS35L41_OTP_TRIM_9 0x0000395C +#define CS35L41_OTP_TRIM_10 0x0000416C +#define CS35L41_OTP_TRIM_11 0x00004160 +#define CS35L41_OTP_TRIM_12 0x00004170 +#define CS35L41_OTP_TRIM_13 0x00004360 +#define CS35L41_OTP_TRIM_14 0x00004448 +#define CS35L41_OTP_TRIM_15 0x0000444C +#define CS35L41_OTP_TRIM_16 0x00006E30 +#define CS35L41_OTP_TRIM_17 0x00006E34 +#define CS35L41_OTP_TRIM_18 0x00006E38 +#define CS35L41_OTP_TRIM_19 0x00006E3C +#define CS35L41_OTP_TRIM_20 0x00006E40 +#define CS35L41_OTP_TRIM_21 0x00006E44 +#define CS35L41_OTP_TRIM_22 0x00006E48 +#define CS35L41_OTP_TRIM_23 0x00006E4C +#define CS35L41_OTP_TRIM_24 0x00006E50 +#define CS35L41_OTP_TRIM_25 0x00006E54 +#define CS35L41_OTP_TRIM_26 0x00006E58 +#define CS35L41_OTP_TRIM_27 0x00006E5C +#define CS35L41_OTP_TRIM_28 0x00006E60 +#define CS35L41_OTP_TRIM_29 0x00006E64 +#define CS35L41_OTP_TRIM_30 0x00007418 +#define CS35L41_OTP_TRIM_31 0x0000741C +#define CS35L41_OTP_TRIM_32 0x00007434 +#define CS35L41_OTP_TRIM_33 0x00007068 +#define CS35L41_OTP_TRIM_34 0x0000410C +#define CS35L41_OTP_TRIM_35 0x0000400C +#define CS35L41_OTP_TRIM_36 0x00002030 + +#define CS35L41_MAX_CACHE_REG 36 +#define CS35L41_OTP_SIZE_WORDS 32 +#define CS35L41_NUM_OTP_ELEM 100 +#define CS35L41_NUM_OTP_MAPS 5 + +#define CS35L41_VALID_PDATA 0x80000000 +#define CS35L41_NUM_SUPPLIES 2 + +#define CS35L41_SCLK_MSTR_MASK 0x10 +#define CS35L41_SCLK_MSTR_SHIFT 4 +#define CS35L41_LRCLK_MSTR_MASK 0x01 +#define CS35L41_LRCLK_MSTR_SHIFT 0 +#define CS35L41_SCLK_INV_MASK 0x40 +#define CS35L41_SCLK_INV_SHIFT 6 +#define CS35L41_LRCLK_INV_MASK 0x04 +#define CS35L41_LRCLK_INV_SHIFT 2 +#define CS35L41_SCLK_FRC_MASK 0x20 +#define CS35L41_SCLK_FRC_SHIFT 5 +#define CS35L41_LRCLK_FRC_MASK 0x02 +#define CS35L41_LRCLK_FRC_SHIFT 1 + +#define CS35L41_AMP_GAIN_PCM_MASK 0x3E0 +#define CS35L41_AMP_GAIN_ZC_MASK 0x0400 +#define CS35L41_AMP_GAIN_ZC_SHIFT 10 + +#define CS35L41_BST_CTL_MASK 0xFF +#define CS35L41_BST_CTL_SEL_MASK 0x03 +#define CS35L41_BST_CTL_SEL_REG 0x00 +#define CS35L41_BST_CTL_SEL_CLASSH 0x01 +#define CS35L41_BST_IPK_MASK 0x7F +#define CS35L41_BST_IPK_SHIFT 0 +#define CS35L41_BST_LIM_MASK 0x4 +#define CS35L41_BST_LIM_SHIFT 2 +#define CS35L41_BST_K1_MASK 0x000000FF +#define CS35L41_BST_K1_SHIFT 0 +#define CS35L41_BST_K2_MASK 0x0000FF00 +#define CS35L41_BST_K2_SHIFT 8 +#define CS35L41_BST_SLOPE_MASK 0x0000FF00 +#define CS35L41_BST_SLOPE_SHIFT 8 +#define CS35L41_BST_LBST_VAL_MASK 0x00000003 +#define CS35L41_BST_LBST_VAL_SHIFT 0 + +#define CS35L41_TEMP_THLD_MASK 0x03 +#define CS35L41_VMON_IMON_VOL_MASK 0x07FF07FF +#define CS35L41_PDM_MODE_MASK 0x01 +#define CS35L41_PDM_MODE_SHIFT 0 + +#define CS35L41_CH_MEM_DEPTH_MASK 0x07 +#define CS35L41_CH_MEM_DEPTH_SHIFT 0 +#define CS35L41_CH_HDRM_CTL_MASK 0x007F0000 +#define CS35L41_CH_HDRM_CTL_SHIFT 16 +#define CS35L41_CH_REL_RATE_MASK 0xFF00 +#define CS35L41_CH_REL_RATE_SHIFT 8 +#define CS35L41_CH_WKFET_DLY_MASK 0x001C +#define CS35L41_CH_WKFET_DLY_SHIFT 2 +#define CS35L41_CH_WKFET_THLD_MASK 0x0F00 +#define CS35L41_CH_WKFET_THLD_SHIFT 8 + +#define CS35L41_HW_NG_SEL_MASK 0x3F00 +#define CS35L41_HW_NG_SEL_SHIFT 8 +#define CS35L41_HW_NG_DLY_MASK 0x0070 +#define CS35L41_HW_NG_DLY_SHIFT 4 +#define CS35L41_HW_NG_THLD_MASK 0x0007 +#define CS35L41_HW_NG_THLD_SHIFT 0 + +#define CS35L41_DSP_NG_ENABLE_MASK 0x00010000 +#define CS35L41_DSP_NG_ENABLE_SHIFT 16 +#define CS35L41_DSP_NG_THLD_MASK 0x7 +#define CS35L41_DSP_NG_THLD_SHIFT 0 +#define CS35L41_DSP_NG_DELAY_MASK 0x0F00 +#define CS35L41_DSP_NG_DELAY_SHIFT 8 + +#define CS35L41_ASP_FMT_MASK 0x0700 +#define CS35L41_ASP_FMT_SHIFT 8 +#define CS35L41_ASP_DOUT_HIZ_MASK 0x03 +#define CS35L41_ASP_DOUT_HIZ_SHIFT 0 +#define CS35L41_ASP_WIDTH_16 0x10 +#define CS35L41_ASP_WIDTH_24 0x18 +#define CS35L41_ASP_WIDTH_32 0x20 +#define CS35L41_ASP_WIDTH_TX_MASK 0xFF0000 +#define CS35L41_ASP_WIDTH_TX_SHIFT 16 +#define CS35L41_ASP_WIDTH_RX_MASK 0xFF000000 +#define CS35L41_ASP_WIDTH_RX_SHIFT 24 +#define CS35L41_ASP_RX1_SLOT_MASK 0x3F +#define CS35L41_ASP_RX1_SLOT_SHIFT 0 +#define CS35L41_ASP_RX2_SLOT_MASK 0x3F00 +#define CS35L41_ASP_RX2_SLOT_SHIFT 8 +#define CS35L41_ASP_RX_WL_MASK 0x3F +#define CS35L41_ASP_TX_WL_MASK 0x3F +#define CS35L41_ASP_RX_WL_SHIFT 0 +#define CS35L41_ASP_TX_WL_SHIFT 0 +#define CS35L41_ASP_SOURCE_MASK 0x7F + +#define CS35L41_INPUT_SRC_ASPRX1 0x08 +#define CS35L41_INPUT_SRC_ASPRX2 0x09 +#define CS35L41_INPUT_SRC_VMON 0x18 +#define CS35L41_INPUT_SRC_IMON 0x19 +#define CS35L41_INPUT_SRC_CLASSH 0x21 +#define CS35L41_INPUT_SRC_VPMON 0x28 +#define CS35L41_INPUT_SRC_VBSTMON 0x29 +#define CS35L41_INPUT_SRC_TEMPMON 0x3A +#define CS35L41_INPUT_SRC_RSVD 0x3B +#define CS35L41_INPUT_DSP_TX1 0x32 +#define CS35L41_INPUT_DSP_TX2 0x33 + +#define CS35L41_PLL_CLK_SEL_MASK 0x07 +#define CS35L41_PLL_CLK_SEL_SHIFT 0 +#define CS35L41_PLL_CLK_EN_MASK 0x10 +#define CS35L41_PLL_CLK_EN_SHIFT 4 +#define CS35L41_PLL_OPENLOOP_MASK 0x0800 +#define CS35L41_PLL_OPENLOOP_SHIFT 11 +#define CS35L41_PLLSRC_SCLK 0 +#define CS35L41_PLLSRC_LRCLK 1 +#define CS35L41_PLLSRC_SELF 3 +#define CS35L41_PLLSRC_PDMCLK 4 +#define CS35L41_PLLSRC_MCLK 5 +#define CS35L41_PLLSRC_SWIRE 7 +#define CS35L41_REFCLK_FREQ_MASK 0x7E0 +#define CS35L41_REFCLK_FREQ_SHIFT 5 + +#define CS35L41_GLOBAL_FS_MASK 0x1F +#define CS35L41_GLOBAL_FS_SHIFT 0 + +#define CS35L41_GLOBAL_EN_MASK 0x01 +#define CS35L41_GLOBAL_EN_SHIFT 0 +#define CS35L41_BST_EN_MASK 0x0030 +#define CS35L41_BST_EN_SHIFT 4 +#define CS35L41_BST_EN_DEFAULT 0x2 +#define CS35L41_AMP_EN_SHIFT 0 +#define CS35L41_AMP_EN_MASK 1 + +#define CS35L41_PDN_DONE_MASK 0x00800000 +#define CS35L41_PDN_DONE_SHIFT 23 +#define CS35L41_PUP_DONE_MASK 0x01000000 +#define CS35L41_PUP_DONE_SHIFT 24 + +#define CS35L36_PUP_DONE_IRQ_UNMASK 0x5F +#define CS35L36_PUP_DONE_IRQ_MASK 0xBF + +#define CS35L41_AMP_SHORT_ERR 0x80000000 +#define CS35L41_BST_SHORT_ERR 0x0100 +#define CS35L41_TEMP_WARN 0x8000 +#define CS35L41_TEMP_ERR 0x00020000 +#define CS35L41_BST_OVP_ERR 0x40 +#define CS35L41_BST_DCM_UVP_ERR 0x80 +#define CS35L41_OTP_BOOT_DONE 0x02 +#define CS35L41_PLL_UNLOCK 0x10 +#define CS35L41_OTP_BOOT_ERR 0x80000000 + +#define CS35L41_AMP_SHORT_ERR_RLS 0x02 +#define CS35L41_BST_SHORT_ERR_RLS 0x04 +#define CS35L41_BST_OVP_ERR_RLS 0x08 +#define CS35L41_BST_UVP_ERR_RLS 0x10 +#define CS35L41_TEMP_WARN_ERR_RLS 0x20 +#define CS35L41_TEMP_ERR_RLS 0x40 + +#define CS35L41_INT1_MASK_DEFAULT 0x7FFCFE3F +#define CS35L41_INT1_UNMASK_PUP 0xFEFFFFFF +#define CS35L41_INT1_UNMASK_PDN 0xFF7FFFFF + +#define CS35L41_GPIO_DIR_MASK 0x80000000 +#define CS35L41_GPIO_DIR_SHIFT 31 +#define CS35L41_GPIO1_CTRL_MASK 0x00030000 +#define CS35L41_GPIO1_CTRL_SHIFT 16 +#define CS35L41_GPIO2_CTRL_MASK 0x07000000 +#define CS35L41_GPIO2_CTRL_SHIFT 24 +#define CS35L41_GPIO_CTRL_OPEN_INT 2 +#define CS35L41_GPIO_CTRL_ACTV_LO 4 +#define CS35L41_GPIO_CTRL_ACTV_HI 5 +#define CS35L41_GPIO_POL_MASK 0x1000 +#define CS35L41_GPIO_POL_SHIFT 12 + +#define CS35L41_AMP_INV_PCM_SHIFT 14 +#define CS35L41_AMP_INV_PCM_MASK BIT(CS35L41_AMP_INV_PCM_SHIFT) +#define CS35L41_AMP_PCM_VOL_SHIFT 3 +#define CS35L41_AMP_PCM_VOL_MASK (0x7FF << 3) +#define CS35L41_AMP_PCM_VOL_MUTE 0x4CF + +#define CS35L41_CHIP_ID 0x35a40 +#define CS35L41R_CHIP_ID 0x35b40 +#define CS35L41_MTLREVID_MASK 0x0F +#define CS35L41_REVID_A0 0xA0 +#define CS35L41_REVID_B0 0xB0 +#define CS35L41_REVID_B2 0xB2 + +#define CS35L41_HALO_CORE_RESET 0x00000200 + +#define CS35L41_FS1_WINDOW_MASK 0x000007FF +#define CS35L41_FS2_WINDOW_MASK 0x00FFF800 +#define CS35L41_FS2_WINDOW_SHIFT 12 + +#define CS35L41_SPI_MAX_FREQ 4000000 +#define CS35L41_REGSTRIDE 4 + enum cs35l41_clk_ids { CS35L41_CLKID_SCLK = 0, CS35L41_CLKID_LRCLK = 1, @@ -31,4 +746,22 @@ struct cs35l41_platform_data { struct cs35l41_irq_cfg irq_config2; }; +struct cs35l41_otp_packed_element_t { + u32 reg; + u8 shift; + u8 size; +}; + +struct cs35l41_otp_map_element_t { + u32 id; + u32 num_elements; + const struct cs35l41_otp_packed_element_t *map; + u32 bit_offset; + u32 word_offset; +}; + +extern const struct cs35l41_otp_map_element_t cs35l41_otp_map_map[CS35L41_NUM_OTP_MAPS]; +extern struct regmap_config cs35l41_regmap_i2c; +extern struct regmap_config cs35l41_regmap_spi; + #endif /* __CS35L41_H */ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 5fe9ec9248642..d3e5ae8310ef2 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -624,21 +624,24 @@ config SND_SOC_CS35L36 tristate "Cirrus Logic CS35L36 CODEC" depends on I2C +config SND_SOC_CS35L41_LIB + tristate + config SND_SOC_CS35L41 tristate - default y if SND_SOC_CS35L41_SPI=y - default y if SND_SOC_CS35L41_I2C=y - default m if SND_SOC_CS35L41_SPI=m - default m if SND_SOC_CS35L41_I2C=m config SND_SOC_CS35L41_SPI tristate "Cirrus Logic CS35L41 CODEC (SPI)" depends on SPI_MASTER + select SND_SOC_CS35L41_LIB + select SND_SOC_CS35L41 select REGMAP_SPI config SND_SOC_CS35L41_I2C tristate "Cirrus Logic CS35L41 CODEC (I2C)" depends on I2C + select SND_SOC_CS35L41_LIB + select SND_SOC_CS35L41 select REGMAP_I2C config SND_SOC_CS42L42 diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 8dbdf3518bda4..ac7f20972470a 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -55,7 +55,8 @@ snd-soc-cs35l33-objs := cs35l33.o snd-soc-cs35l34-objs := cs35l34.o snd-soc-cs35l35-objs := cs35l35.o snd-soc-cs35l36-objs := cs35l36.o -snd-soc-cs35l41-objs := cs35l41.o cs35l41-tables.o +snd-soc-cs35l41-lib-objs := cs35l41-lib.o +snd-soc-cs35l41-objs := cs35l41.o snd-soc-cs35l41-spi-objs := cs35l41-spi.o snd-soc-cs35l41-i2c-objs := cs35l41-i2c.o snd-soc-cs42l42-objs := cs42l42.o @@ -396,6 +397,7 @@ obj-$(CONFIG_SND_SOC_CS35L34) += snd-soc-cs35l34.o obj-$(CONFIG_SND_SOC_CS35L35) += snd-soc-cs35l35.o obj-$(CONFIG_SND_SOC_CS35L36) += snd-soc-cs35l36.o obj-$(CONFIG_SND_SOC_CS35L41) += snd-soc-cs35l41.o +obj-$(CONFIG_SND_SOC_CS35L41_LIB) += snd-soc-cs35l41-lib.o obj-$(CONFIG_SND_SOC_CS35L41_SPI) += snd-soc-cs35l41-spi.o obj-$(CONFIG_SND_SOC_CS35L41_I2C) += snd-soc-cs35l41-i2c.o obj-$(CONFIG_SND_SOC_CS42L42) += snd-soc-cs42l42.o diff --git a/sound/soc/codecs/cs35l41-i2c.c b/sound/soc/codecs/cs35l41-i2c.c index c9b604af6b71e..de5c8612f0307 100644 --- a/sound/soc/codecs/cs35l41-i2c.c +++ b/sound/soc/codecs/cs35l41-i2c.c @@ -17,7 +17,6 @@ #include #include -#include #include "cs35l41.h" static const struct i2c_device_id cs35l41_id_i2c[] = { diff --git a/sound/soc/codecs/cs35l41-tables.c b/sound/soc/codecs/cs35l41-lib.c similarity index 98% rename from sound/soc/codecs/cs35l41-tables.c rename to sound/soc/codecs/cs35l41-lib.c index 3eb18b17a7b0f..f19531ebf7296 100644 --- a/sound/soc/codecs/cs35l41-tables.c +++ b/sound/soc/codecs/cs35l41-lib.c @@ -1,12 +1,16 @@ // SPDX-License-Identifier: GPL-2.0 // -// cs35l41-tables.c -- CS35L41 ALSA SoC audio driver +// cs35l41-lib.c -- CS35L41 Common functions for HDA and ASoC Audio drivers // // Copyright 2017-2021 Cirrus Logic, Inc. // // Author: David Rhodes +// Author: Lucas Tanure -#include "cs35l41.h" +#include +#include + +#include static const struct reg_default cs35l41_reg[] = { { CS35L41_PWR_CTRL1, 0x00000000 }, @@ -688,6 +692,7 @@ const struct cs35l41_otp_map_element_t cs35l41_otp_map_map[CS35L41_NUM_OTP_MAPS] .word_offset = 2, }, }; +EXPORT_SYMBOL_GPL(cs35l41_otp_map_map); struct regmap_config cs35l41_regmap_i2c = { .reg_bits = 32, @@ -721,3 +726,8 @@ struct regmap_config cs35l41_regmap_spi = { .cache_type = REGCACHE_RBTREE, }; EXPORT_SYMBOL_GPL(cs35l41_regmap_spi); + +MODULE_DESCRIPTION("CS35L41 library"); +MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, "); +MODULE_AUTHOR("Lucas Tanure, Cirrus Logic Inc, "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs35l41-spi.c b/sound/soc/codecs/cs35l41-spi.c index c202d9df70ee2..c157153f28d87 100644 --- a/sound/soc/codecs/cs35l41-spi.c +++ b/sound/soc/codecs/cs35l41-spi.c @@ -15,7 +15,6 @@ #include #include -#include #include "cs35l41.h" static const struct spi_device_id cs35l41_id_spi[] = { diff --git a/sound/soc/codecs/cs35l41.h b/sound/soc/codecs/cs35l41.h index c7c45f19754b1..26a08d58a8c34 100644 --- a/sound/soc/codecs/cs35l41.h +++ b/sound/soc/codecs/cs35l41.h @@ -11,7 +11,6 @@ #define __CS35L41_H__ #include -#include #include #include #include @@ -19,742 +18,9 @@ #include "wm_adsp.h" -#define CS35L41_FIRSTREG 0x00000000 -#define CS35L41_LASTREG 0x03804FE8 -#define CS35L41_DEVID 0x00000000 -#define CS35L41_REVID 0x00000004 -#define CS35L41_FABID 0x00000008 -#define CS35L41_RELID 0x0000000C -#define CS35L41_OTPID 0x00000010 -#define CS35L41_SFT_RESET 0x00000020 -#define CS35L41_TEST_KEY_CTL 0x00000040 -#define CS35L41_USER_KEY_CTL 0x00000044 -#define CS35L41_OTP_MEM0 0x00000400 -#define CS35L41_OTP_MEM31 0x0000047C -#define CS35L41_OTP_CTRL0 0x00000500 -#define CS35L41_OTP_CTRL1 0x00000504 -#define CS35L41_OTP_CTRL3 0x00000508 -#define CS35L41_OTP_CTRL4 0x0000050C -#define CS35L41_OTP_CTRL5 0x00000510 -#define CS35L41_OTP_CTRL6 0x00000514 -#define CS35L41_OTP_CTRL7 0x00000518 -#define CS35L41_OTP_CTRL8 0x0000051C -#define CS35L41_PWR_CTRL1 0x00002014 -#define CS35L41_PWR_CTRL2 0x00002018 -#define CS35L41_PWR_CTRL3 0x0000201C -#define CS35L41_CTRL_OVRRIDE 0x00002020 -#define CS35L41_AMP_OUT_MUTE 0x00002024 -#define CS35L41_PROTECT_REL_ERR_IGN 0x00002034 -#define CS35L41_GPIO_PAD_CONTROL 0x0000242C -#define CS35L41_JTAG_CONTROL 0x00002438 -#define CS35L41_PLL_CLK_CTRL 0x00002C04 -#define CS35L41_DSP_CLK_CTRL 0x00002C08 -#define CS35L41_GLOBAL_CLK_CTRL 0x00002C0C -#define CS35L41_DATA_FS_SEL 0x00002C10 -#define CS35L41_TST_FS_MON0 0x00002D10 -#define CS35L41_MDSYNC_EN 0x00003400 -#define CS35L41_MDSYNC_TX_ID 0x00003408 -#define CS35L41_MDSYNC_PWR_CTRL 0x0000340C -#define CS35L41_MDSYNC_DATA_TX 0x00003410 -#define CS35L41_MDSYNC_TX_STATUS 0x00003414 -#define CS35L41_MDSYNC_DATA_RX 0x0000341C -#define CS35L41_MDSYNC_RX_STATUS 0x00003420 -#define CS35L41_MDSYNC_ERR_STATUS 0x00003424 -#define CS35L41_MDSYNC_SYNC_PTE2 0x00003528 -#define CS35L41_MDSYNC_SYNC_PTE3 0x0000352C -#define CS35L41_MDSYNC_SYNC_MSM_STATUS 0x0000353C -#define CS35L41_BSTCVRT_VCTRL1 0x00003800 -#define CS35L41_BSTCVRT_VCTRL2 0x00003804 -#define CS35L41_BSTCVRT_PEAK_CUR 0x00003808 -#define CS35L41_BSTCVRT_SFT_RAMP 0x0000380C -#define CS35L41_BSTCVRT_COEFF 0x00003810 -#define CS35L41_BSTCVRT_SLOPE_LBST 0x00003814 -#define CS35L41_BSTCVRT_SW_FREQ 0x00003818 -#define CS35L41_BSTCVRT_DCM_CTRL 0x0000381C -#define CS35L41_BSTCVRT_DCM_MODE_FORCE 0x00003820 -#define CS35L41_BSTCVRT_OVERVOLT_CTRL 0x00003830 -#define CS35L41_VI_VOL_POL 0x00004000 -#define CS35L41_VIMON_SPKMON_RESYNC 0x00004100 -#define CS35L41_DTEMP_WARN_THLD 0x00004220 -#define CS35L41_DTEMP_CFG 0x00004224 -#define CS35L41_DTEMP_EN 0x00004308 -#define CS35L41_VPVBST_FS_SEL 0x00004400 -#define CS35L41_SP_ENABLES 0x00004800 -#define CS35L41_SP_RATE_CTRL 0x00004804 -#define CS35L41_SP_FORMAT 0x00004808 -#define CS35L41_SP_HIZ_CTRL 0x0000480C -#define CS35L41_SP_FRAME_TX_SLOT 0x00004810 -#define CS35L41_SP_FRAME_RX_SLOT 0x00004820 -#define CS35L41_SP_TX_WL 0x00004830 -#define CS35L41_SP_RX_WL 0x00004840 -#define CS35L41_ASP_CONTROL4 0x00004854 -#define CS35L41_DAC_PCM1_SRC 0x00004C00 -#define CS35L41_ASP_TX1_SRC 0x00004C20 -#define CS35L41_ASP_TX2_SRC 0x00004C24 -#define CS35L41_ASP_TX3_SRC 0x00004C28 -#define CS35L41_ASP_TX4_SRC 0x00004C2C -#define CS35L41_DSP1_RX1_SRC 0x00004C40 -#define CS35L41_DSP1_RX2_SRC 0x00004C44 -#define CS35L41_DSP1_RX3_SRC 0x00004C48 -#define CS35L41_DSP1_RX4_SRC 0x00004C4C -#define CS35L41_DSP1_RX5_SRC 0x00004C50 -#define CS35L41_DSP1_RX6_SRC 0x00004C54 -#define CS35L41_DSP1_RX7_SRC 0x00004C58 -#define CS35L41_DSP1_RX8_SRC 0x00004C5C -#define CS35L41_NGATE1_SRC 0x00004C60 -#define CS35L41_NGATE2_SRC 0x00004C64 -#define CS35L41_AMP_DIG_VOL_CTRL 0x00006000 -#define CS35L41_VPBR_CFG 0x00006404 -#define CS35L41_VBBR_CFG 0x00006408 -#define CS35L41_VPBR_STATUS 0x0000640C -#define CS35L41_VBBR_STATUS 0x00006410 -#define CS35L41_OVERTEMP_CFG 0x00006414 -#define CS35L41_AMP_ERR_VOL 0x00006418 -#define CS35L41_VOL_STATUS_TO_DSP 0x00006450 -#define CS35L41_CLASSH_CFG 0x00006800 -#define CS35L41_WKFET_CFG 0x00006804 -#define CS35L41_NG_CFG 0x00006808 -#define CS35L41_AMP_GAIN_CTRL 0x00006C04 -#define CS35L41_DAC_MSM_CFG 0x00007400 -#define CS35L41_IRQ1_CFG 0x00010000 -#define CS35L41_IRQ1_STATUS 0x00010004 -#define CS35L41_IRQ1_STATUS1 0x00010010 -#define CS35L41_IRQ1_STATUS2 0x00010014 -#define CS35L41_IRQ1_STATUS3 0x00010018 -#define CS35L41_IRQ1_STATUS4 0x0001001C -#define CS35L41_IRQ1_RAW_STATUS1 0x00010090 -#define CS35L41_IRQ1_RAW_STATUS2 0x00010094 -#define CS35L41_IRQ1_RAW_STATUS3 0x00010098 -#define CS35L41_IRQ1_RAW_STATUS4 0x0001009C -#define CS35L41_IRQ1_MASK1 0x00010110 -#define CS35L41_IRQ1_MASK2 0x00010114 -#define CS35L41_IRQ1_MASK3 0x00010118 -#define CS35L41_IRQ1_MASK4 0x0001011C -#define CS35L41_IRQ1_FRC1 0x00010190 -#define CS35L41_IRQ1_FRC2 0x00010194 -#define CS35L41_IRQ1_FRC3 0x00010198 -#define CS35L41_IRQ1_FRC4 0x0001019C -#define CS35L41_IRQ1_EDGE1 0x00010210 -#define CS35L41_IRQ1_EDGE4 0x0001021C -#define CS35L41_IRQ1_POL1 0x00010290 -#define CS35L41_IRQ1_POL2 0x00010294 -#define CS35L41_IRQ1_POL3 0x00010298 -#define CS35L41_IRQ1_POL4 0x0001029C -#define CS35L41_IRQ1_DB3 0x00010318 -#define CS35L41_IRQ2_CFG 0x00010800 -#define CS35L41_IRQ2_STATUS 0x00010804 -#define CS35L41_IRQ2_STATUS1 0x00010810 -#define CS35L41_IRQ2_STATUS2 0x00010814 -#define CS35L41_IRQ2_STATUS3 0x00010818 -#define CS35L41_IRQ2_STATUS4 0x0001081C -#define CS35L41_IRQ2_RAW_STATUS1 0x00010890 -#define CS35L41_IRQ2_RAW_STATUS2 0x00010894 -#define CS35L41_IRQ2_RAW_STATUS3 0x00010898 -#define CS35L41_IRQ2_RAW_STATUS4 0x0001089C -#define CS35L41_IRQ2_MASK1 0x00010910 -#define CS35L41_IRQ2_MASK2 0x00010914 -#define CS35L41_IRQ2_MASK3 0x00010918 -#define CS35L41_IRQ2_MASK4 0x0001091C -#define CS35L41_IRQ2_FRC1 0x00010990 -#define CS35L41_IRQ2_FRC2 0x00010994 -#define CS35L41_IRQ2_FRC3 0x00010998 -#define CS35L41_IRQ2_FRC4 0x0001099C -#define CS35L41_IRQ2_EDGE1 0x00010A10 -#define CS35L41_IRQ2_EDGE4 0x00010A1C -#define CS35L41_IRQ2_POL1 0x00010A90 -#define CS35L41_IRQ2_POL2 0x00010A94 -#define CS35L41_IRQ2_POL3 0x00010A98 -#define CS35L41_IRQ2_POL4 0x00010A9C -#define CS35L41_IRQ2_DB3 0x00010B18 -#define CS35L41_GPIO_STATUS1 0x00011000 -#define CS35L41_GPIO1_CTRL1 0x00011008 -#define CS35L41_GPIO2_CTRL1 0x0001100C -#define CS35L41_MIXER_NGATE_CFG 0x00012000 -#define CS35L41_MIXER_NGATE_CH1_CFG 0x00012004 -#define CS35L41_MIXER_NGATE_CH2_CFG 0x00012008 -#define CS35L41_DSP_MBOX_1 0x00013000 -#define CS35L41_DSP_MBOX_2 0x00013004 -#define CS35L41_DSP_MBOX_3 0x00013008 -#define CS35L41_DSP_MBOX_4 0x0001300C -#define CS35L41_DSP_MBOX_5 0x00013010 -#define CS35L41_DSP_MBOX_6 0x00013014 -#define CS35L41_DSP_MBOX_7 0x00013018 -#define CS35L41_DSP_MBOX_8 0x0001301C -#define CS35L41_DSP_VIRT1_MBOX_1 0x00013020 -#define CS35L41_DSP_VIRT1_MBOX_2 0x00013024 -#define CS35L41_DSP_VIRT1_MBOX_3 0x00013028 -#define CS35L41_DSP_VIRT1_MBOX_4 0x0001302C -#define CS35L41_DSP_VIRT1_MBOX_5 0x00013030 -#define CS35L41_DSP_VIRT1_MBOX_6 0x00013034 -#define CS35L41_DSP_VIRT1_MBOX_7 0x00013038 -#define CS35L41_DSP_VIRT1_MBOX_8 0x0001303C -#define CS35L41_DSP_VIRT2_MBOX_1 0x00013040 -#define CS35L41_DSP_VIRT2_MBOX_2 0x00013044 -#define CS35L41_DSP_VIRT2_MBOX_3 0x00013048 -#define CS35L41_DSP_VIRT2_MBOX_4 0x0001304C -#define CS35L41_DSP_VIRT2_MBOX_5 0x00013050 -#define CS35L41_DSP_VIRT2_MBOX_6 0x00013054 -#define CS35L41_DSP_VIRT2_MBOX_7 0x00013058 -#define CS35L41_DSP_VIRT2_MBOX_8 0x0001305C -#define CS35L41_CLOCK_DETECT_1 0x00014000 -#define CS35L41_TIMER1_CONTROL 0x00015000 -#define CS35L41_TIMER1_COUNT_PRESET 0x00015004 -#define CS35L41_TIMER1_START_STOP 0x0001500C -#define CS35L41_TIMER1_STATUS 0x00015010 -#define CS35L41_TIMER1_COUNT_READBACK 0x00015014 -#define CS35L41_TIMER1_DSP_CLK_CFG 0x00015018 -#define CS35L41_TIMER1_DSP_CLK_STATUS 0x0001501C -#define CS35L41_TIMER2_CONTROL 0x00015100 -#define CS35L41_TIMER2_COUNT_PRESET 0x00015104 -#define CS35L41_TIMER2_START_STOP 0x0001510C -#define CS35L41_TIMER2_STATUS 0x00015110 -#define CS35L41_TIMER2_COUNT_READBACK 0x00015114 -#define CS35L41_TIMER2_DSP_CLK_CFG 0x00015118 -#define CS35L41_TIMER2_DSP_CLK_STATUS 0x0001511C -#define CS35L41_DFT_JTAG_CONTROL 0x00016000 -#define CS35L41_DIE_STS1 0x00017040 -#define CS35L41_DIE_STS2 0x00017044 -#define CS35L41_TEMP_CAL1 0x00017048 -#define CS35L41_TEMP_CAL2 0x0001704C -#define CS35L41_DSP1_XMEM_PACK_0 0x02000000 -#define CS35L41_DSP1_XMEM_PACK_3068 0x02002FF0 -#define CS35L41_DSP1_XMEM_UNPACK32_0 0x02400000 -#define CS35L41_DSP1_XMEM_UNPACK32_2046 0x02401FF8 -#define CS35L41_DSP1_TIMESTAMP_COUNT 0x025C0800 -#define CS35L41_DSP1_SYS_ID 0x025E0000 -#define CS35L41_DSP1_SYS_VERSION 0x025E0004 -#define CS35L41_DSP1_SYS_CORE_ID 0x025E0008 -#define CS35L41_DSP1_SYS_AHB_ADDR 0x025E000C -#define CS35L41_DSP1_SYS_XSRAM_SIZE 0x025E0010 -#define CS35L41_DSP1_SYS_YSRAM_SIZE 0x025E0018 -#define CS35L41_DSP1_SYS_PSRAM_SIZE 0x025E0020 -#define CS35L41_DSP1_SYS_PM_BOOT_SIZE 0x025E0028 -#define CS35L41_DSP1_SYS_FEATURES 0x025E002C -#define CS35L41_DSP1_SYS_FIR_FILTERS 0x025E0030 -#define CS35L41_DSP1_SYS_LMS_FILTERS 0x025E0034 -#define CS35L41_DSP1_SYS_XM_BANK_SIZE 0x025E0038 -#define CS35L41_DSP1_SYS_YM_BANK_SIZE 0x025E003C -#define CS35L41_DSP1_SYS_PM_BANK_SIZE 0x025E0040 -#define CS35L41_DSP1_AHBM_WIN0_CTRL0 0x025E2000 -#define CS35L41_DSP1_AHBM_WIN0_CTRL1 0x025E2004 -#define CS35L41_DSP1_AHBM_WIN1_CTRL0 0x025E2008 -#define CS35L41_DSP1_AHBM_WIN1_CTRL1 0x025E200C -#define CS35L41_DSP1_AHBM_WIN2_CTRL0 0x025E2010 -#define CS35L41_DSP1_AHBM_WIN2_CTRL1 0x025E2014 -#define CS35L41_DSP1_AHBM_WIN3_CTRL0 0x025E2018 -#define CS35L41_DSP1_AHBM_WIN3_CTRL1 0x025E201C -#define CS35L41_DSP1_AHBM_WIN4_CTRL0 0x025E2020 -#define CS35L41_DSP1_AHBM_WIN4_CTRL1 0x025E2024 -#define CS35L41_DSP1_AHBM_WIN5_CTRL0 0x025E2028 -#define CS35L41_DSP1_AHBM_WIN5_CTRL1 0x025E202C -#define CS35L41_DSP1_AHBM_WIN6_CTRL0 0x025E2030 -#define CS35L41_DSP1_AHBM_WIN6_CTRL1 0x025E2034 -#define CS35L41_DSP1_AHBM_WIN7_CTRL0 0x025E2038 -#define CS35L41_DSP1_AHBM_WIN7_CTRL1 0x025E203C -#define CS35L41_DSP1_AHBM_WIN_DBG_CTRL0 0x025E2040 -#define CS35L41_DSP1_AHBM_WIN_DBG_CTRL1 0x025E2044 -#define CS35L41_DSP1_XMEM_UNPACK24_0 0x02800000 -#define CS35L41_DSP1_XMEM_UNPACK24_4093 0x02803FF4 -#define CS35L41_DSP1_CTRL_BASE 0x02B80000 -#define CS35L41_DSP1_CORE_SOFT_RESET 0x02B80010 -#define CS35L41_DSP1_DEBUG 0x02B80040 -#define CS35L41_DSP1_TIMER_CTRL 0x02B80048 -#define CS35L41_DSP1_STREAM_ARB_CTRL 0x02B80050 -#define CS35L41_DSP1_RX1_RATE 0x02B80080 -#define CS35L41_DSP1_RX2_RATE 0x02B80088 -#define CS35L41_DSP1_RX3_RATE 0x02B80090 -#define CS35L41_DSP1_RX4_RATE 0x02B80098 -#define CS35L41_DSP1_RX5_RATE 0x02B800A0 -#define CS35L41_DSP1_RX6_RATE 0x02B800A8 -#define CS35L41_DSP1_RX7_RATE 0x02B800B0 -#define CS35L41_DSP1_RX8_RATE 0x02B800B8 -#define CS35L41_DSP1_TX1_RATE 0x02B80280 -#define CS35L41_DSP1_TX2_RATE 0x02B80288 -#define CS35L41_DSP1_TX3_RATE 0x02B80290 -#define CS35L41_DSP1_TX4_RATE 0x02B80298 -#define CS35L41_DSP1_TX5_RATE 0x02B802A0 -#define CS35L41_DSP1_TX6_RATE 0x02B802A8 -#define CS35L41_DSP1_TX7_RATE 0x02B802B0 -#define CS35L41_DSP1_TX8_RATE 0x02B802B8 -#define CS35L41_DSP1_NMI_CTRL1 0x02B80480 -#define CS35L41_DSP1_NMI_CTRL2 0x02B80488 -#define CS35L41_DSP1_NMI_CTRL3 0x02B80490 -#define CS35L41_DSP1_NMI_CTRL4 0x02B80498 -#define CS35L41_DSP1_NMI_CTRL5 0x02B804A0 -#define CS35L41_DSP1_NMI_CTRL6 0x02B804A8 -#define CS35L41_DSP1_NMI_CTRL7 0x02B804B0 -#define CS35L41_DSP1_NMI_CTRL8 0x02B804B8 -#define CS35L41_DSP1_RESUME_CTRL 0x02B80500 -#define CS35L41_DSP1_IRQ1_CTRL 0x02B80508 -#define CS35L41_DSP1_IRQ2_CTRL 0x02B80510 -#define CS35L41_DSP1_IRQ3_CTRL 0x02B80518 -#define CS35L41_DSP1_IRQ4_CTRL 0x02B80520 -#define CS35L41_DSP1_IRQ5_CTRL 0x02B80528 -#define CS35L41_DSP1_IRQ6_CTRL 0x02B80530 -#define CS35L41_DSP1_IRQ7_CTRL 0x02B80538 -#define CS35L41_DSP1_IRQ8_CTRL 0x02B80540 -#define CS35L41_DSP1_IRQ9_CTRL 0x02B80548 -#define CS35L41_DSP1_IRQ10_CTRL 0x02B80550 -#define CS35L41_DSP1_IRQ11_CTRL 0x02B80558 -#define CS35L41_DSP1_IRQ12_CTRL 0x02B80560 -#define CS35L41_DSP1_IRQ13_CTRL 0x02B80568 -#define CS35L41_DSP1_IRQ14_CTRL 0x02B80570 -#define CS35L41_DSP1_IRQ15_CTRL 0x02B80578 -#define CS35L41_DSP1_IRQ16_CTRL 0x02B80580 -#define CS35L41_DSP1_IRQ17_CTRL 0x02B80588 -#define CS35L41_DSP1_IRQ18_CTRL 0x02B80590 -#define CS35L41_DSP1_IRQ19_CTRL 0x02B80598 -#define CS35L41_DSP1_IRQ20_CTRL 0x02B805A0 -#define CS35L41_DSP1_IRQ21_CTRL 0x02B805A8 -#define CS35L41_DSP1_IRQ22_CTRL 0x02B805B0 -#define CS35L41_DSP1_IRQ23_CTRL 0x02B805B8 -#define CS35L41_DSP1_SCRATCH1 0x02B805C0 -#define CS35L41_DSP1_SCRATCH2 0x02B805C8 -#define CS35L41_DSP1_SCRATCH3 0x02B805D0 -#define CS35L41_DSP1_SCRATCH4 0x02B805D8 -#define CS35L41_DSP1_CCM_CORE_CTRL 0x02BC1000 -#define CS35L41_DSP1_CCM_CLK_OVERRIDE 0x02BC1008 -#define CS35L41_DSP1_XM_MSTR_EN 0x02BC2000 -#define CS35L41_DSP1_XM_CORE_PRI 0x02BC2008 -#define CS35L41_DSP1_XM_AHB_PACK_PL_PRI 0x02BC2010 -#define CS35L41_DSP1_XM_AHB_UP_PL_PRI 0x02BC2018 -#define CS35L41_DSP1_XM_ACCEL_PL0_PRI 0x02BC2020 -#define CS35L41_DSP1_XM_NPL0_PRI 0x02BC2078 -#define CS35L41_DSP1_YM_MSTR_EN 0x02BC20C0 -#define CS35L41_DSP1_YM_CORE_PRI 0x02BC20C8 -#define CS35L41_DSP1_YM_AHB_PACK_PL_PRI 0x02BC20D0 -#define CS35L41_DSP1_YM_AHB_UP_PL_PRI 0x02BC20D8 -#define CS35L41_DSP1_YM_ACCEL_PL0_PRI 0x02BC20E0 -#define CS35L41_DSP1_YM_NPL0_PRI 0x02BC2138 -#define CS35L41_DSP1_PM_MSTR_EN 0x02BC2180 -#define CS35L41_DSP1_PM_PATCH0_ADDR 0x02BC2188 -#define CS35L41_DSP1_PM_PATCH0_EN 0x02BC218C -#define CS35L41_DSP1_PM_PATCH0_DATA_LO 0x02BC2190 -#define CS35L41_DSP1_PM_PATCH0_DATA_HI 0x02BC2194 -#define CS35L41_DSP1_PM_PATCH1_ADDR 0x02BC2198 -#define CS35L41_DSP1_PM_PATCH1_EN 0x02BC219C -#define CS35L41_DSP1_PM_PATCH1_DATA_LO 0x02BC21A0 -#define CS35L41_DSP1_PM_PATCH1_DATA_HI 0x02BC21A4 -#define CS35L41_DSP1_PM_PATCH2_ADDR 0x02BC21A8 -#define CS35L41_DSP1_PM_PATCH2_EN 0x02BC21AC -#define CS35L41_DSP1_PM_PATCH2_DATA_LO 0x02BC21B0 -#define CS35L41_DSP1_PM_PATCH2_DATA_HI 0x02BC21B4 -#define CS35L41_DSP1_PM_PATCH3_ADDR 0x02BC21B8 -#define CS35L41_DSP1_PM_PATCH3_EN 0x02BC21BC -#define CS35L41_DSP1_PM_PATCH3_DATA_LO 0x02BC21C0 -#define CS35L41_DSP1_PM_PATCH3_DATA_HI 0x02BC21C4 -#define CS35L41_DSP1_PM_PATCH4_ADDR 0x02BC21C8 -#define CS35L41_DSP1_PM_PATCH4_EN 0x02BC21CC -#define CS35L41_DSP1_PM_PATCH4_DATA_LO 0x02BC21D0 -#define CS35L41_DSP1_PM_PATCH4_DATA_HI 0x02BC21D4 -#define CS35L41_DSP1_PM_PATCH5_ADDR 0x02BC21D8 -#define CS35L41_DSP1_PM_PATCH5_EN 0x02BC21DC -#define CS35L41_DSP1_PM_PATCH5_DATA_LO 0x02BC21E0 -#define CS35L41_DSP1_PM_PATCH5_DATA_HI 0x02BC21E4 -#define CS35L41_DSP1_PM_PATCH6_ADDR 0x02BC21E8 -#define CS35L41_DSP1_PM_PATCH6_EN 0x02BC21EC -#define CS35L41_DSP1_PM_PATCH6_DATA_LO 0x02BC21F0 -#define CS35L41_DSP1_PM_PATCH6_DATA_HI 0x02BC21F4 -#define CS35L41_DSP1_PM_PATCH7_ADDR 0x02BC21F8 -#define CS35L41_DSP1_PM_PATCH7_EN 0x02BC21FC -#define CS35L41_DSP1_PM_PATCH7_DATA_LO 0x02BC2200 -#define CS35L41_DSP1_PM_PATCH7_DATA_HI 0x02BC2204 -#define CS35L41_DSP1_MPU_XM_ACCESS0 0x02BC3000 -#define CS35L41_DSP1_MPU_YM_ACCESS0 0x02BC3004 -#define CS35L41_DSP1_MPU_WNDW_ACCESS0 0x02BC3008 -#define CS35L41_DSP1_MPU_XREG_ACCESS0 0x02BC300C -#define CS35L41_DSP1_MPU_YREG_ACCESS0 0x02BC3014 -#define CS35L41_DSP1_MPU_XM_ACCESS1 0x02BC3018 -#define CS35L41_DSP1_MPU_YM_ACCESS1 0x02BC301C -#define CS35L41_DSP1_MPU_WNDW_ACCESS1 0x02BC3020 -#define CS35L41_DSP1_MPU_XREG_ACCESS1 0x02BC3024 -#define CS35L41_DSP1_MPU_YREG_ACCESS1 0x02BC302C -#define CS35L41_DSP1_MPU_XM_ACCESS2 0x02BC3030 -#define CS35L41_DSP1_MPU_YM_ACCESS2 0x02BC3034 -#define CS35L41_DSP1_MPU_WNDW_ACCESS2 0x02BC3038 -#define CS35L41_DSP1_MPU_XREG_ACCESS2 0x02BC303C -#define CS35L41_DSP1_MPU_YREG_ACCESS2 0x02BC3044 -#define CS35L41_DSP1_MPU_XM_ACCESS3 0x02BC3048 -#define CS35L41_DSP1_MPU_YM_ACCESS3 0x02BC304C -#define CS35L41_DSP1_MPU_WNDW_ACCESS3 0x02BC3050 -#define CS35L41_DSP1_MPU_XREG_ACCESS3 0x02BC3054 -#define CS35L41_DSP1_MPU_YREG_ACCESS3 0x02BC305C -#define CS35L41_DSP1_MPU_XM_VIO_ADDR 0x02BC3100 -#define CS35L41_DSP1_MPU_XM_VIO_STATUS 0x02BC3104 -#define CS35L41_DSP1_MPU_YM_VIO_ADDR 0x02BC3108 -#define CS35L41_DSP1_MPU_YM_VIO_STATUS 0x02BC310C -#define CS35L41_DSP1_MPU_PM_VIO_ADDR 0x02BC3110 -#define CS35L41_DSP1_MPU_PM_VIO_STATUS 0x02BC3114 -#define CS35L41_DSP1_MPU_LOCK_CONFIG 0x02BC3140 -#define CS35L41_DSP1_MPU_WDT_RST_CTRL 0x02BC3180 -#define CS35L41_DSP1_STRMARB_MSTR0_CFG0 0x02BC5000 -#define CS35L41_DSP1_STRMARB_MSTR0_CFG1 0x02BC5004 -#define CS35L41_DSP1_STRMARB_MSTR0_CFG2 0x02BC5008 -#define CS35L41_DSP1_STRMARB_MSTR1_CFG0 0x02BC5010 -#define CS35L41_DSP1_STRMARB_MSTR1_CFG1 0x02BC5014 -#define CS35L41_DSP1_STRMARB_MSTR1_CFG2 0x02BC5018 -#define CS35L41_DSP1_STRMARB_MSTR2_CFG0 0x02BC5020 -#define CS35L41_DSP1_STRMARB_MSTR2_CFG1 0x02BC5024 -#define CS35L41_DSP1_STRMARB_MSTR2_CFG2 0x02BC5028 -#define CS35L41_DSP1_STRMARB_MSTR3_CFG0 0x02BC5030 -#define CS35L41_DSP1_STRMARB_MSTR3_CFG1 0x02BC5034 -#define CS35L41_DSP1_STRMARB_MSTR3_CFG2 0x02BC5038 -#define CS35L41_DSP1_STRMARB_MSTR4_CFG0 0x02BC5040 -#define CS35L41_DSP1_STRMARB_MSTR4_CFG1 0x02BC5044 -#define CS35L41_DSP1_STRMARB_MSTR4_CFG2 0x02BC5048 -#define CS35L41_DSP1_STRMARB_MSTR5_CFG0 0x02BC5050 -#define CS35L41_DSP1_STRMARB_MSTR5_CFG1 0x02BC5054 -#define CS35L41_DSP1_STRMARB_MSTR5_CFG2 0x02BC5058 -#define CS35L41_DSP1_STRMARB_MSTR6_CFG0 0x02BC5060 -#define CS35L41_DSP1_STRMARB_MSTR6_CFG1 0x02BC5064 -#define CS35L41_DSP1_STRMARB_MSTR6_CFG2 0x02BC5068 -#define CS35L41_DSP1_STRMARB_MSTR7_CFG0 0x02BC5070 -#define CS35L41_DSP1_STRMARB_MSTR7_CFG1 0x02BC5074 -#define CS35L41_DSP1_STRMARB_MSTR7_CFG2 0x02BC5078 -#define CS35L41_DSP1_STRMARB_TX0_CFG0 0x02BC5200 -#define CS35L41_DSP1_STRMARB_TX0_CFG1 0x02BC5204 -#define CS35L41_DSP1_STRMARB_TX1_CFG0 0x02BC5208 -#define CS35L41_DSP1_STRMARB_TX1_CFG1 0x02BC520C -#define CS35L41_DSP1_STRMARB_TX2_CFG0 0x02BC5210 -#define CS35L41_DSP1_STRMARB_TX2_CFG1 0x02BC5214 -#define CS35L41_DSP1_STRMARB_TX3_CFG0 0x02BC5218 -#define CS35L41_DSP1_STRMARB_TX3_CFG1 0x02BC521C -#define CS35L41_DSP1_STRMARB_TX4_CFG0 0x02BC5220 -#define CS35L41_DSP1_STRMARB_TX4_CFG1 0x02BC5224 -#define CS35L41_DSP1_STRMARB_TX5_CFG0 0x02BC5228 -#define CS35L41_DSP1_STRMARB_TX5_CFG1 0x02BC522C -#define CS35L41_DSP1_STRMARB_TX6_CFG0 0x02BC5230 -#define CS35L41_DSP1_STRMARB_TX6_CFG1 0x02BC5234 -#define CS35L41_DSP1_STRMARB_TX7_CFG0 0x02BC5238 -#define CS35L41_DSP1_STRMARB_TX7_CFG1 0x02BC523C -#define CS35L41_DSP1_STRMARB_RX0_CFG0 0x02BC5400 -#define CS35L41_DSP1_STRMARB_RX0_CFG1 0x02BC5404 -#define CS35L41_DSP1_STRMARB_RX1_CFG0 0x02BC5408 -#define CS35L41_DSP1_STRMARB_RX1_CFG1 0x02BC540C -#define CS35L41_DSP1_STRMARB_RX2_CFG0 0x02BC5410 -#define CS35L41_DSP1_STRMARB_RX2_CFG1 0x02BC5414 -#define CS35L41_DSP1_STRMARB_RX3_CFG0 0x02BC5418 -#define CS35L41_DSP1_STRMARB_RX3_CFG1 0x02BC541C -#define CS35L41_DSP1_STRMARB_RX4_CFG0 0x02BC5420 -#define CS35L41_DSP1_STRMARB_RX4_CFG1 0x02BC5424 -#define CS35L41_DSP1_STRMARB_RX5_CFG0 0x02BC5428 -#define CS35L41_DSP1_STRMARB_RX5_CFG1 0x02BC542C -#define CS35L41_DSP1_STRMARB_RX6_CFG0 0x02BC5430 -#define CS35L41_DSP1_STRMARB_RX6_CFG1 0x02BC5434 -#define CS35L41_DSP1_STRMARB_RX7_CFG0 0x02BC5438 -#define CS35L41_DSP1_STRMARB_RX7_CFG1 0x02BC543C -#define CS35L41_DSP1_STRMARB_IRQ0_CFG0 0x02BC5600 -#define CS35L41_DSP1_STRMARB_IRQ0_CFG1 0x02BC5604 -#define CS35L41_DSP1_STRMARB_IRQ0_CFG2 0x02BC5608 -#define CS35L41_DSP1_STRMARB_IRQ1_CFG0 0x02BC5610 -#define CS35L41_DSP1_STRMARB_IRQ1_CFG1 0x02BC5614 -#define CS35L41_DSP1_STRMARB_IRQ1_CFG2 0x02BC5618 -#define CS35L41_DSP1_STRMARB_IRQ2_CFG0 0x02BC5620 -#define CS35L41_DSP1_STRMARB_IRQ2_CFG1 0x02BC5624 -#define CS35L41_DSP1_STRMARB_IRQ2_CFG2 0x02BC5628 -#define CS35L41_DSP1_STRMARB_IRQ3_CFG0 0x02BC5630 -#define CS35L41_DSP1_STRMARB_IRQ3_CFG1 0x02BC5634 -#define CS35L41_DSP1_STRMARB_IRQ3_CFG2 0x02BC5638 -#define CS35L41_DSP1_STRMARB_IRQ4_CFG0 0x02BC5640 -#define CS35L41_DSP1_STRMARB_IRQ4_CFG1 0x02BC5644 -#define CS35L41_DSP1_STRMARB_IRQ4_CFG2 0x02BC5648 -#define CS35L41_DSP1_STRMARB_IRQ5_CFG0 0x02BC5650 -#define CS35L41_DSP1_STRMARB_IRQ5_CFG1 0x02BC5654 -#define CS35L41_DSP1_STRMARB_IRQ5_CFG2 0x02BC5658 -#define CS35L41_DSP1_STRMARB_IRQ6_CFG0 0x02BC5660 -#define CS35L41_DSP1_STRMARB_IRQ6_CFG1 0x02BC5664 -#define CS35L41_DSP1_STRMARB_IRQ6_CFG2 0x02BC5668 -#define CS35L41_DSP1_STRMARB_IRQ7_CFG0 0x02BC5670 -#define CS35L41_DSP1_STRMARB_IRQ7_CFG1 0x02BC5674 -#define CS35L41_DSP1_STRMARB_IRQ7_CFG2 0x02BC5678 -#define CS35L41_DSP1_STRMARB_RESYNC_MSK 0x02BC5A00 -#define CS35L41_DSP1_STRMARB_ERR_STATUS 0x02BC5A08 -#define CS35L41_DSP1_INTPCTL_RES_STATIC 0x02BC6000 -#define CS35L41_DSP1_INTPCTL_RES_DYN 0x02BC6004 -#define CS35L41_DSP1_INTPCTL_NMI_CTRL 0x02BC6008 -#define CS35L41_DSP1_INTPCTL_IRQ_INV 0x02BC6010 -#define CS35L41_DSP1_INTPCTL_IRQ_MODE 0x02BC6014 -#define CS35L41_DSP1_INTPCTL_IRQ_EN 0x02BC6018 -#define CS35L41_DSP1_INTPCTL_IRQ_MSK 0x02BC601C -#define CS35L41_DSP1_INTPCTL_IRQ_FLUSH 0x02BC6020 -#define CS35L41_DSP1_INTPCTL_IRQ_MSKCLR 0x02BC6024 -#define CS35L41_DSP1_INTPCTL_IRQ_FRC 0x02BC6028 -#define CS35L41_DSP1_INTPCTL_IRQ_MSKSET 0x02BC602C -#define CS35L41_DSP1_INTPCTL_IRQ_ERR 0x02BC6030 -#define CS35L41_DSP1_INTPCTL_IRQ_PEND 0x02BC6034 -#define CS35L41_DSP1_INTPCTL_IRQ_GEN 0x02BC6038 -#define CS35L41_DSP1_INTPCTL_TESTBITS 0x02BC6040 -#define CS35L41_DSP1_WDT_CONTROL 0x02BC7000 -#define CS35L41_DSP1_WDT_STATUS 0x02BC7008 -#define CS35L41_DSP1_YMEM_PACK_0 0x02C00000 -#define CS35L41_DSP1_YMEM_PACK_1532 0x02C017F0 -#define CS35L41_DSP1_YMEM_UNPACK32_0 0x03000000 -#define CS35L41_DSP1_YMEM_UNPACK32_1022 0x03000FF8 -#define CS35L41_DSP1_YMEM_UNPACK24_0 0x03400000 -#define CS35L41_DSP1_YMEM_UNPACK24_2045 0x03401FF4 -#define CS35L41_DSP1_PMEM_0 0x03800000 -#define CS35L41_DSP1_PMEM_5114 0x03804FE8 - -/*test regs for emulation bringup*/ -#define CS35L41_PLL_OVR 0x00003018 -#define CS35L41_BST_TEST_DUTY 0x00003900 -#define CS35L41_DIGPWM_IOCTRL 0x0000706C - -/*registers populated by OTP*/ -#define CS35L41_OTP_TRIM_1 0x0000208c -#define CS35L41_OTP_TRIM_2 0x00002090 -#define CS35L41_OTP_TRIM_3 0x00003010 -#define CS35L41_OTP_TRIM_4 0x0000300C -#define CS35L41_OTP_TRIM_5 0x0000394C -#define CS35L41_OTP_TRIM_6 0x00003950 -#define CS35L41_OTP_TRIM_7 0x00003954 -#define CS35L41_OTP_TRIM_8 0x00003958 -#define CS35L41_OTP_TRIM_9 0x0000395C -#define CS35L41_OTP_TRIM_10 0x0000416C -#define CS35L41_OTP_TRIM_11 0x00004160 -#define CS35L41_OTP_TRIM_12 0x00004170 -#define CS35L41_OTP_TRIM_13 0x00004360 -#define CS35L41_OTP_TRIM_14 0x00004448 -#define CS35L41_OTP_TRIM_15 0x0000444C -#define CS35L41_OTP_TRIM_16 0x00006E30 -#define CS35L41_OTP_TRIM_17 0x00006E34 -#define CS35L41_OTP_TRIM_18 0x00006E38 -#define CS35L41_OTP_TRIM_19 0x00006E3C -#define CS35L41_OTP_TRIM_20 0x00006E40 -#define CS35L41_OTP_TRIM_21 0x00006E44 -#define CS35L41_OTP_TRIM_22 0x00006E48 -#define CS35L41_OTP_TRIM_23 0x00006E4C -#define CS35L41_OTP_TRIM_24 0x00006E50 -#define CS35L41_OTP_TRIM_25 0x00006E54 -#define CS35L41_OTP_TRIM_26 0x00006E58 -#define CS35L41_OTP_TRIM_27 0x00006E5C -#define CS35L41_OTP_TRIM_28 0x00006E60 -#define CS35L41_OTP_TRIM_29 0x00006E64 -#define CS35L41_OTP_TRIM_30 0x00007418 -#define CS35L41_OTP_TRIM_31 0x0000741C -#define CS35L41_OTP_TRIM_32 0x00007434 -#define CS35L41_OTP_TRIM_33 0x00007068 -#define CS35L41_OTP_TRIM_34 0x0000410C -#define CS35L41_OTP_TRIM_35 0x0000400C -#define CS35L41_OTP_TRIM_36 0x00002030 - -#define CS35L41_OTP_SIZE_WORDS 32 -#define CS35L41_NUM_OTP_ELEM 100 -#define CS35L41_NUM_OTP_MAPS 5 - -#define CS35L41_VALID_PDATA 0x80000000 -#define CS35L41_NUM_SUPPLIES 2 - -#define CS35L41_SCLK_MSTR_MASK 0x10 -#define CS35L41_SCLK_MSTR_SHIFT 4 -#define CS35L41_LRCLK_MSTR_MASK 0x01 -#define CS35L41_LRCLK_MSTR_SHIFT 0 -#define CS35L41_SCLK_INV_MASK 0x40 -#define CS35L41_SCLK_INV_SHIFT 6 -#define CS35L41_LRCLK_INV_MASK 0x04 -#define CS35L41_LRCLK_INV_SHIFT 2 -#define CS35L41_SCLK_FRC_MASK 0x20 -#define CS35L41_SCLK_FRC_SHIFT 5 -#define CS35L41_LRCLK_FRC_MASK 0x02 -#define CS35L41_LRCLK_FRC_SHIFT 1 - -#define CS35L41_AMP_GAIN_PCM_MASK 0x3E0 -#define CS35L41_AMP_GAIN_ZC_MASK 0x0400 -#define CS35L41_AMP_GAIN_ZC_SHIFT 10 - -#define CS35L41_BST_CTL_MASK 0xFF -#define CS35L41_BST_CTL_SEL_MASK 0x03 -#define CS35L41_BST_CTL_SEL_REG 0x00 -#define CS35L41_BST_CTL_SEL_CLASSH 0x01 -#define CS35L41_BST_IPK_MASK 0x7F -#define CS35L41_BST_IPK_SHIFT 0 -#define CS35L41_BST_LIM_MASK 0x4 -#define CS35L41_BST_LIM_SHIFT 2 -#define CS35L41_BST_K1_MASK 0x000000FF -#define CS35L41_BST_K1_SHIFT 0 -#define CS35L41_BST_K2_MASK 0x0000FF00 -#define CS35L41_BST_K2_SHIFT 8 -#define CS35L41_BST_SLOPE_MASK 0x0000FF00 -#define CS35L41_BST_SLOPE_SHIFT 8 -#define CS35L41_BST_LBST_VAL_MASK 0x00000003 -#define CS35L41_BST_LBST_VAL_SHIFT 0 - -#define CS35L41_TEMP_THLD_MASK 0x03 -#define CS35L41_VMON_IMON_VOL_MASK 0x07FF07FF -#define CS35L41_PDM_MODE_MASK 0x01 -#define CS35L41_PDM_MODE_SHIFT 0 - -#define CS35L41_CH_MEM_DEPTH_MASK 0x07 -#define CS35L41_CH_MEM_DEPTH_SHIFT 0 -#define CS35L41_CH_HDRM_CTL_MASK 0x007F0000 -#define CS35L41_CH_HDRM_CTL_SHIFT 16 -#define CS35L41_CH_REL_RATE_MASK 0xFF00 -#define CS35L41_CH_REL_RATE_SHIFT 8 -#define CS35L41_CH_WKFET_DLY_MASK 0x001C -#define CS35L41_CH_WKFET_DLY_SHIFT 2 -#define CS35L41_CH_WKFET_THLD_MASK 0x0F00 -#define CS35L41_CH_WKFET_THLD_SHIFT 8 - -#define CS35L41_HW_NG_SEL_MASK 0x3F00 -#define CS35L41_HW_NG_SEL_SHIFT 8 -#define CS35L41_HW_NG_DLY_MASK 0x0070 -#define CS35L41_HW_NG_DLY_SHIFT 4 -#define CS35L41_HW_NG_THLD_MASK 0x0007 -#define CS35L41_HW_NG_THLD_SHIFT 0 - -#define CS35L41_DSP_NG_ENABLE_MASK 0x00010000 -#define CS35L41_DSP_NG_ENABLE_SHIFT 16 -#define CS35L41_DSP_NG_THLD_MASK 0x7 -#define CS35L41_DSP_NG_THLD_SHIFT 0 -#define CS35L41_DSP_NG_DELAY_MASK 0x0F00 -#define CS35L41_DSP_NG_DELAY_SHIFT 8 - -#define CS35L41_ASP_FMT_MASK 0x0700 -#define CS35L41_ASP_FMT_SHIFT 8 -#define CS35L41_ASP_DOUT_HIZ_MASK 0x03 -#define CS35L41_ASP_DOUT_HIZ_SHIFT 0 -#define CS35L41_ASP_WIDTH_16 0x10 -#define CS35L41_ASP_WIDTH_24 0x18 -#define CS35L41_ASP_WIDTH_32 0x20 -#define CS35L41_ASP_WIDTH_TX_MASK 0xFF0000 -#define CS35L41_ASP_WIDTH_TX_SHIFT 16 -#define CS35L41_ASP_WIDTH_RX_MASK 0xFF000000 -#define CS35L41_ASP_WIDTH_RX_SHIFT 24 -#define CS35L41_ASP_RX1_SLOT_MASK 0x3F -#define CS35L41_ASP_RX1_SLOT_SHIFT 0 -#define CS35L41_ASP_RX2_SLOT_MASK 0x3F00 -#define CS35L41_ASP_RX2_SLOT_SHIFT 8 -#define CS35L41_ASP_RX_WL_MASK 0x3F -#define CS35L41_ASP_TX_WL_MASK 0x3F -#define CS35L41_ASP_RX_WL_SHIFT 0 -#define CS35L41_ASP_TX_WL_SHIFT 0 -#define CS35L41_ASP_SOURCE_MASK 0x7F - -#define CS35L41_INPUT_SRC_ASPRX1 0x08 -#define CS35L41_INPUT_SRC_ASPRX2 0x09 -#define CS35L41_INPUT_SRC_VMON 0x18 -#define CS35L41_INPUT_SRC_IMON 0x19 -#define CS35L41_INPUT_SRC_CLASSH 0x21 -#define CS35L41_INPUT_SRC_VPMON 0x28 -#define CS35L41_INPUT_SRC_VBSTMON 0x29 -#define CS35L41_INPUT_SRC_TEMPMON 0x3A -#define CS35L41_INPUT_SRC_RSVD 0x3B -#define CS35L41_INPUT_DSP_TX1 0x32 -#define CS35L41_INPUT_DSP_TX2 0x33 - -#define CS35L41_PLL_CLK_SEL_MASK 0x07 -#define CS35L41_PLL_CLK_SEL_SHIFT 0 -#define CS35L41_PLL_CLK_EN_MASK 0x10 -#define CS35L41_PLL_CLK_EN_SHIFT 4 -#define CS35L41_PLL_OPENLOOP_MASK 0x0800 -#define CS35L41_PLL_OPENLOOP_SHIFT 11 -#define CS35L41_PLLSRC_SCLK 0 -#define CS35L41_PLLSRC_LRCLK 1 -#define CS35L41_PLLSRC_SELF 3 -#define CS35L41_PLLSRC_PDMCLK 4 -#define CS35L41_PLLSRC_MCLK 5 -#define CS35L41_PLLSRC_SWIRE 7 -#define CS35L41_REFCLK_FREQ_MASK 0x7E0 -#define CS35L41_REFCLK_FREQ_SHIFT 5 - -#define CS35L41_GLOBAL_FS_MASK 0x1F -#define CS35L41_GLOBAL_FS_SHIFT 0 - -#define CS35L41_GLOBAL_EN_MASK 0x01 -#define CS35L41_GLOBAL_EN_SHIFT 0 -#define CS35L41_BST_EN_MASK 0x0030 -#define CS35L41_BST_EN_SHIFT 4 -#define CS35L41_BST_EN_DEFAULT 0x2 -#define CS35L41_AMP_EN_SHIFT 0 -#define CS35L41_AMP_EN_MASK 1 - -#define CS35L41_PDN_DONE_MASK 0x00800000 -#define CS35L41_PDN_DONE_SHIFT 23 -#define CS35L41_PUP_DONE_MASK 0x01000000 -#define CS35L41_PUP_DONE_SHIFT 24 - -#define CS35L36_PUP_DONE_IRQ_UNMASK 0x5F -#define CS35L36_PUP_DONE_IRQ_MASK 0xBF - -#define CS35L41_AMP_SHORT_ERR 0x80000000 -#define CS35L41_BST_SHORT_ERR 0x0100 -#define CS35L41_TEMP_WARN 0x8000 -#define CS35L41_TEMP_ERR 0x00020000 -#define CS35L41_BST_OVP_ERR 0x40 -#define CS35L41_BST_DCM_UVP_ERR 0x80 -#define CS35L41_OTP_BOOT_DONE 0x02 -#define CS35L41_PLL_UNLOCK 0x10 -#define CS35L41_OTP_BOOT_ERR 0x80000000 - -#define CS35L41_AMP_SHORT_ERR_RLS 0x02 -#define CS35L41_BST_SHORT_ERR_RLS 0x04 -#define CS35L41_BST_OVP_ERR_RLS 0x08 -#define CS35L41_BST_UVP_ERR_RLS 0x10 -#define CS35L41_TEMP_WARN_ERR_RLS 0x20 -#define CS35L41_TEMP_ERR_RLS 0x40 - -#define CS35L41_INT1_MASK_DEFAULT 0x7FFCFE3F -#define CS35L41_INT1_UNMASK_PUP 0xFEFFFFFF -#define CS35L41_INT1_UNMASK_PDN 0xFF7FFFFF - -#define CS35L41_GPIO_DIR_MASK 0x80000000 -#define CS35L41_GPIO_DIR_SHIFT 31 -#define CS35L41_GPIO1_CTRL_MASK 0x00030000 -#define CS35L41_GPIO1_CTRL_SHIFT 16 -#define CS35L41_GPIO2_CTRL_MASK 0x07000000 -#define CS35L41_GPIO2_CTRL_SHIFT 24 -#define CS35L41_GPIO_CTRL_OPEN_INT 2 -#define CS35L41_GPIO_CTRL_ACTV_LO 4 -#define CS35L41_GPIO_CTRL_ACTV_HI 5 -#define CS35L41_GPIO_POL_MASK 0x1000 -#define CS35L41_GPIO_POL_SHIFT 12 - -#define CS35L41_AMP_INV_PCM_SHIFT 14 -#define CS35L41_AMP_INV_PCM_MASK BIT(CS35L41_AMP_INV_PCM_SHIFT) -#define CS35L41_AMP_PCM_VOL_SHIFT 3 -#define CS35L41_AMP_PCM_VOL_MASK (0x7FF << 3) -#define CS35L41_AMP_PCM_VOL_MUTE 0x4CF - -#define CS35L41_CHIP_ID 0x35a40 -#define CS35L41R_CHIP_ID 0x35b40 -#define CS35L41_MTLREVID_MASK 0x0F -#define CS35L41_REVID_A0 0xA0 -#define CS35L41_REVID_B0 0xB0 -#define CS35L41_REVID_B2 0xB2 - -#define CS35L41_HALO_CORE_RESET 0x00000200 - -#define CS35L41_FS1_WINDOW_MASK 0x000007FF -#define CS35L41_FS2_WINDOW_MASK 0x00FFF800 -#define CS35L41_FS2_WINDOW_SHIFT 12 - -#define CS35L41_SPI_MAX_FREQ 4000000 - #define CS35L41_RX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) #define CS35L41_TX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) -extern struct regmap_config cs35l41_regmap_i2c; -extern struct regmap_config cs35l41_regmap_spi; - -struct cs35l41_otp_packed_element_t { - u32 reg; - u8 shift; - u8 size; -}; - -struct cs35l41_otp_map_element_t { - u32 id; - u32 num_elements; - const struct cs35l41_otp_packed_element_t *map; - u32 bit_offset; - u32 word_offset; -}; - -extern const struct cs35l41_otp_map_element_t - cs35l41_otp_map_map[CS35L41_NUM_OTP_MAPS]; - -#define CS35L41_REGSTRIDE 4 - enum cs35l41_cspl_mbox_status { CSPL_MBOX_STS_RUNNING = 0, CSPL_MBOX_STS_PAUSED = 1, From fe120d4cb6f6cd03007239e7c578b8703fe6d336 Mon Sep 17 00:00:00 2001 From: Lucas Tanure Date: Fri, 17 Dec 2021 11:57:00 +0000 Subject: [PATCH 322/327] ASoC: cs35l41: Move cs35l41_otp_unpack to shared code ASoC and HDA will do the same cs35l41_otp_unpack, so move it to shared code Signed-off-by: Lucas Tanure Link: https://lore.kernel.org/r/20211217115708.882525-3-tanureal@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/cs35l41.h | 4 +- sound/soc/codecs/cs35l41-lib.c | 121 ++++++++++++++++++++++++++++++- sound/soc/codecs/cs35l41.c | 125 +-------------------------------- 3 files changed, 122 insertions(+), 128 deletions(-) diff --git a/include/sound/cs35l41.h b/include/sound/cs35l41.h index aac3ffb9bc894..6cf3ef02b26a5 100644 --- a/include/sound/cs35l41.h +++ b/include/sound/cs35l41.h @@ -534,7 +534,6 @@ #define CS35L41_MAX_CACHE_REG 36 #define CS35L41_OTP_SIZE_WORDS 32 #define CS35L41_NUM_OTP_ELEM 100 -#define CS35L41_NUM_OTP_MAPS 5 #define CS35L41_VALID_PDATA 0x80000000 #define CS35L41_NUM_SUPPLIES 2 @@ -760,8 +759,9 @@ struct cs35l41_otp_map_element_t { u32 word_offset; }; -extern const struct cs35l41_otp_map_element_t cs35l41_otp_map_map[CS35L41_NUM_OTP_MAPS]; extern struct regmap_config cs35l41_regmap_i2c; extern struct regmap_config cs35l41_regmap_spi; +int cs35l41_otp_unpack(struct device *dev, struct regmap *regmap); + #endif /* __CS35L41_H */ diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c index f19531ebf7296..dc5f502447a25 100644 --- a/sound/soc/codecs/cs35l41-lib.c +++ b/sound/soc/codecs/cs35l41-lib.c @@ -7,8 +7,11 @@ // Author: David Rhodes // Author: Lucas Tanure +#include #include #include +#include +#include #include @@ -655,7 +658,7 @@ static const struct cs35l41_otp_packed_element_t otp_map_2[CS35L41_NUM_OTP_ELEM] { 0x00017044, 0, 24 }, /*LOT_NUMBER*/ }; -const struct cs35l41_otp_map_element_t cs35l41_otp_map_map[CS35L41_NUM_OTP_MAPS] = { +static const struct cs35l41_otp_map_element_t cs35l41_otp_map_map[] = { { .id = 0x01, .map = otp_map_1, @@ -692,7 +695,6 @@ const struct cs35l41_otp_map_element_t cs35l41_otp_map_map[CS35L41_NUM_OTP_MAPS] .word_offset = 2, }, }; -EXPORT_SYMBOL_GPL(cs35l41_otp_map_map); struct regmap_config cs35l41_regmap_i2c = { .reg_bits = 32, @@ -727,6 +729,121 @@ struct regmap_config cs35l41_regmap_spi = { }; EXPORT_SYMBOL_GPL(cs35l41_regmap_spi); +static const struct cs35l41_otp_map_element_t *cs35l41_find_otp_map(u32 otp_id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cs35l41_otp_map_map); i++) { + if (cs35l41_otp_map_map[i].id == otp_id) + return &cs35l41_otp_map_map[i]; + } + + return NULL; +} + +int cs35l41_otp_unpack(struct device *dev, struct regmap *regmap) +{ + const struct cs35l41_otp_map_element_t *otp_map_match; + const struct cs35l41_otp_packed_element_t *otp_map; + int bit_offset, word_offset, ret, i; + unsigned int bit_sum = 8; + u32 otp_val, otp_id_reg; + u32 *otp_mem; + + otp_mem = kmalloc_array(CS35L41_OTP_SIZE_WORDS, sizeof(*otp_mem), GFP_KERNEL); + if (!otp_mem) + return -ENOMEM; + + ret = regmap_read(regmap, CS35L41_OTPID, &otp_id_reg); + if (ret) { + dev_err(dev, "Read OTP ID failed: %d\n", ret); + goto err_otp_unpack; + } + + otp_map_match = cs35l41_find_otp_map(otp_id_reg); + + if (!otp_map_match) { + dev_err(dev, "OTP Map matching ID %d not found\n", otp_id_reg); + ret = -EINVAL; + goto err_otp_unpack; + } + + ret = regmap_bulk_read(regmap, CS35L41_OTP_MEM0, otp_mem, CS35L41_OTP_SIZE_WORDS); + if (ret) { + dev_err(dev, "Read OTP Mem failed: %d\n", ret); + goto err_otp_unpack; + } + + otp_map = otp_map_match->map; + + bit_offset = otp_map_match->bit_offset; + word_offset = otp_map_match->word_offset; + + ret = regmap_write(regmap, CS35L41_TEST_KEY_CTL, 0x00000055); + if (ret) { + dev_err(dev, "Write Unlock key failed 1/2: %d\n", ret); + goto err_otp_unpack; + } + ret = regmap_write(regmap, CS35L41_TEST_KEY_CTL, 0x000000AA); + if (ret) { + dev_err(dev, "Write Unlock key failed 2/2: %d\n", ret); + goto err_otp_unpack; + } + + for (i = 0; i < otp_map_match->num_elements; i++) { + dev_dbg(dev, "bitoffset= %d, word_offset=%d, bit_sum mod 32=%d\n", + bit_offset, word_offset, bit_sum % 32); + if (bit_offset + otp_map[i].size - 1 >= 32) { + otp_val = (otp_mem[word_offset] & + GENMASK(31, bit_offset)) >> bit_offset; + otp_val |= (otp_mem[++word_offset] & + GENMASK(bit_offset + otp_map[i].size - 33, 0)) << + (32 - bit_offset); + bit_offset += otp_map[i].size - 32; + } else { + otp_val = (otp_mem[word_offset] & + GENMASK(bit_offset + otp_map[i].size - 1, bit_offset) + ) >> bit_offset; + bit_offset += otp_map[i].size; + } + bit_sum += otp_map[i].size; + + if (bit_offset == 32) { + bit_offset = 0; + word_offset++; + } + + if (otp_map[i].reg != 0) { + ret = regmap_update_bits(regmap, otp_map[i].reg, + GENMASK(otp_map[i].shift + otp_map[i].size - 1, + otp_map[i].shift), + otp_val << otp_map[i].shift); + if (ret < 0) { + dev_err(dev, "Write OTP val failed: %d\n", ret); + goto err_otp_unpack; + } + } + } + + ret = regmap_write(regmap, CS35L41_TEST_KEY_CTL, 0x000000CC); + if (ret) { + dev_err(dev, "Write Lock key failed 1/2: %d\n", ret); + goto err_otp_unpack; + } + ret = regmap_write(regmap, CS35L41_TEST_KEY_CTL, 0x00000033); + if (ret) { + dev_err(dev, "Write Lock key failed 2/2: %d\n", ret); + goto err_otp_unpack; + } + ret = 0; + +err_otp_unpack: + kfree(otp_mem); + + return ret; +} +EXPORT_SYMBOL_GPL(cs35l41_otp_unpack); + MODULE_DESCRIPTION("CS35L41 library"); MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, "); MODULE_AUTHOR("Lucas Tanure, Cirrus Logic Inc, "); diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c index 60332eae11620..aa57c59b334d8 100644 --- a/sound/soc/codecs/cs35l41.c +++ b/sound/soc/codecs/cs35l41.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -420,128 +419,6 @@ static const struct snd_kcontrol_new cs35l41_aud_controls[] = { WM_ADSP_FW_CONTROL("DSP1", 0), }; -static const struct cs35l41_otp_map_element_t *cs35l41_find_otp_map(u32 otp_id) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(cs35l41_otp_map_map); i++) { - if (cs35l41_otp_map_map[i].id == otp_id) - return &cs35l41_otp_map_map[i]; - } - - return NULL; -} - -static int cs35l41_otp_unpack(void *data) -{ - const struct cs35l41_otp_map_element_t *otp_map_match; - const struct cs35l41_otp_packed_element_t *otp_map; - struct cs35l41_private *cs35l41 = data; - int bit_offset, word_offset, ret, i; - unsigned int bit_sum = 8; - u32 otp_val, otp_id_reg; - u32 *otp_mem; - - otp_mem = kmalloc_array(CS35L41_OTP_SIZE_WORDS, sizeof(*otp_mem), GFP_KERNEL); - if (!otp_mem) - return -ENOMEM; - - ret = regmap_read(cs35l41->regmap, CS35L41_OTPID, &otp_id_reg); - if (ret < 0) { - dev_err(cs35l41->dev, "Read OTP ID failed: %d\n", ret); - goto err_otp_unpack; - } - - otp_map_match = cs35l41_find_otp_map(otp_id_reg); - - if (!otp_map_match) { - dev_err(cs35l41->dev, "OTP Map matching ID %d not found\n", - otp_id_reg); - ret = -EINVAL; - goto err_otp_unpack; - } - - ret = regmap_bulk_read(cs35l41->regmap, CS35L41_OTP_MEM0, otp_mem, - CS35L41_OTP_SIZE_WORDS); - if (ret < 0) { - dev_err(cs35l41->dev, "Read OTP Mem failed: %d\n", ret); - goto err_otp_unpack; - } - - otp_map = otp_map_match->map; - - bit_offset = otp_map_match->bit_offset; - word_offset = otp_map_match->word_offset; - - ret = regmap_write(cs35l41->regmap, CS35L41_TEST_KEY_CTL, 0x00000055); - if (ret < 0) { - dev_err(cs35l41->dev, "Write Unlock key failed 1/2: %d\n", ret); - goto err_otp_unpack; - } - ret = regmap_write(cs35l41->regmap, CS35L41_TEST_KEY_CTL, 0x000000AA); - if (ret < 0) { - dev_err(cs35l41->dev, "Write Unlock key failed 2/2: %d\n", ret); - goto err_otp_unpack; - } - - for (i = 0; i < otp_map_match->num_elements; i++) { - dev_dbg(cs35l41->dev, - "bitoffset= %d, word_offset=%d, bit_sum mod 32=%d\n", - bit_offset, word_offset, bit_sum % 32); - if (bit_offset + otp_map[i].size - 1 >= 32) { - otp_val = (otp_mem[word_offset] & - GENMASK(31, bit_offset)) >> - bit_offset; - otp_val |= (otp_mem[++word_offset] & - GENMASK(bit_offset + - otp_map[i].size - 33, 0)) << - (32 - bit_offset); - bit_offset += otp_map[i].size - 32; - } else { - otp_val = (otp_mem[word_offset] & - GENMASK(bit_offset + otp_map[i].size - 1, - bit_offset)) >> bit_offset; - bit_offset += otp_map[i].size; - } - bit_sum += otp_map[i].size; - - if (bit_offset == 32) { - bit_offset = 0; - word_offset++; - } - - if (otp_map[i].reg != 0) { - ret = regmap_update_bits(cs35l41->regmap, - otp_map[i].reg, - GENMASK(otp_map[i].shift + - otp_map[i].size - 1, - otp_map[i].shift), - otp_val << otp_map[i].shift); - if (ret < 0) { - dev_err(cs35l41->dev, "Write OTP val failed: %d\n", - ret); - goto err_otp_unpack; - } - } - } - - ret = regmap_write(cs35l41->regmap, CS35L41_TEST_KEY_CTL, 0x000000CC); - if (ret < 0) { - dev_err(cs35l41->dev, "Write Lock key failed 1/2: %d\n", ret); - goto err_otp_unpack; - } - ret = regmap_write(cs35l41->regmap, CS35L41_TEST_KEY_CTL, 0x00000033); - if (ret < 0) { - dev_err(cs35l41->dev, "Write Lock key failed 2/2: %d\n", ret); - goto err_otp_unpack; - } - ret = 0; - -err_otp_unpack: - kfree(otp_mem); - return ret; -} - static irqreturn_t cs35l41_irq(int irq, void *data) { struct cs35l41_private *cs35l41 = data; @@ -1667,7 +1544,7 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, goto err; } - ret = cs35l41_otp_unpack(cs35l41); + ret = cs35l41_otp_unpack(cs35l41->dev, cs35l41->regmap); if (ret < 0) { dev_err(cs35l41->dev, "OTP Unpack failed: %d\n", ret); goto err; From 062ce0593315e22aac527389dd6dd4328c49f0fb Mon Sep 17 00:00:00 2001 From: Lucas Tanure Date: Fri, 17 Dec 2021 11:57:01 +0000 Subject: [PATCH 323/327] ASoC: cs35l41: Move power initializations to reg_sequence ASoC and HDA systems for all revisions of CS35L41 will benefit from having this initialization, so add it to reg_sequence of each revision By moving to reg_sequence all gains are set to zero. And boost, monitoring parts, and class D amplifier are disabled. Signed-off-by: Lucas Tanure Link: https://lore.kernel.org/r/20211217115708.882525-4-tanureal@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l41-lib.c | 3 ++- sound/soc/codecs/cs35l41.c | 20 ++++++-------------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c index dc5f502447a25..b3567e10adc4c 100644 --- a/sound/soc/codecs/cs35l41-lib.c +++ b/sound/soc/codecs/cs35l41-lib.c @@ -17,6 +17,7 @@ static const struct reg_default cs35l41_reg[] = { { CS35L41_PWR_CTRL1, 0x00000000 }, + { CS35L41_PWR_CTRL2, 0x00000000 }, { CS35L41_PWR_CTRL3, 0x01000010 }, { CS35L41_GPIO_PAD_CONTROL, 0x00000000 }, { CS35L41_SP_ENABLES, 0x00000000 }, @@ -46,7 +47,7 @@ static const struct reg_default cs35l41_reg[] = { { CS35L41_CLASSH_CFG, 0x000B0405 }, { CS35L41_WKFET_CFG, 0x00000111 }, { CS35L41_NG_CFG, 0x00000033 }, - { CS35L41_AMP_GAIN_CTRL, 0x00000273 }, + { CS35L41_AMP_GAIN_CTRL, 0x00000000 }, { CS35L41_GPIO1_CTRL1, 0xE1000001 }, { CS35L41_GPIO2_CTRL1, 0xE1000001 }, { CS35L41_MIXER_NGATE_CFG, 0x00000000 }, diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c index aa57c59b334d8..7494710ae6e68 100644 --- a/sound/soc/codecs/cs35l41.c +++ b/sound/soc/codecs/cs35l41.c @@ -1288,6 +1288,8 @@ static const struct reg_sequence cs35l41_reva0_errata_patch[] = { { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 }, { 0x00000040, 0x0000CCCC }, { 0x00000040, 0x00003333 }, + { CS35L41_PWR_CTRL2, 0x00000000 }, + { CS35L41_AMP_GAIN_CTRL, 0x00000000 }, }; static const struct reg_sequence cs35l41_revb0_errata_patch[] = { @@ -1301,6 +1303,8 @@ static const struct reg_sequence cs35l41_revb0_errata_patch[] = { { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 }, { 0x00000040, 0x0000CCCC }, { 0x00000040, 0x00003333 }, + { CS35L41_PWR_CTRL2, 0x00000000 }, + { CS35L41_AMP_GAIN_CTRL, 0x00000000 }, }; static const struct reg_sequence cs35l41_revb2_errata_patch[] = { @@ -1314,6 +1318,8 @@ static const struct reg_sequence cs35l41_revb2_errata_patch[] = { { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 }, { 0x00000040, 0x0000CCCC }, { 0x00000040, 0x00003333 }, + { CS35L41_PWR_CTRL2, 0x00000000 }, + { CS35L41_AMP_GAIN_CTRL, 0x00000000 }, }; static const struct reg_sequence cs35l41_fs_errata_patch[] = { @@ -1556,20 +1562,6 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, goto err; } - ret = regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, - CS35L41_AMP_EN_MASK, 0); - if (ret < 0) { - dev_err(cs35l41->dev, "Write CS35L41_PWR_CTRL2 failed: %d\n", ret); - goto err; - } - - ret = regmap_update_bits(cs35l41->regmap, CS35L41_AMP_GAIN_CTRL, - CS35L41_AMP_GAIN_PCM_MASK, 0); - if (ret < 0) { - dev_err(cs35l41->dev, "Write CS35L41_AMP_GAIN_CTRL failed: %d\n", ret); - goto err; - } - ret = cs35l41_set_pdata(cs35l41); if (ret < 0) { dev_err(cs35l41->dev, "Set pdata failed: %d\n", ret); From 8b2278604b6de27329ec7ed82ca696c4751111b6 Mon Sep 17 00:00:00 2001 From: Lucas Tanure Date: Fri, 17 Dec 2021 11:57:02 +0000 Subject: [PATCH 324/327] ASoC: cs35l41: Create shared function for errata patches ASoC and HDA systems require the same errata patches, so move it to the shared code using a function the correctly applies the patches by revision Also, move CS35L41_DSP1_CCM_CORE_CTRL write to errata patch function as is required to be written at boot, but not in regmap_register_patch sequence as will affect waking up from hibernation Signed-off-by: Lucas Tanure Link: https://lore.kernel.org/r/20211217115708.882525-5-tanureal@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/cs35l41.h | 1 + sound/soc/codecs/cs35l41-lib.c | 89 ++++++++++++++++++++++++++++++++ sound/soc/codecs/cs35l41.c | 92 ++-------------------------------- 3 files changed, 93 insertions(+), 89 deletions(-) diff --git a/include/sound/cs35l41.h b/include/sound/cs35l41.h index 6cf3ef02b26a5..ad2e32a12b8c2 100644 --- a/include/sound/cs35l41.h +++ b/include/sound/cs35l41.h @@ -763,5 +763,6 @@ extern struct regmap_config cs35l41_regmap_i2c; extern struct regmap_config cs35l41_regmap_spi; int cs35l41_otp_unpack(struct device *dev, struct regmap *regmap); +int cs35l41_register_errata_patch(struct device *dev, struct regmap *reg, unsigned int reg_revid); #endif /* __CS35L41_H */ diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c index b3567e10adc4c..5e382eaea340a 100644 --- a/sound/soc/codecs/cs35l41-lib.c +++ b/sound/soc/codecs/cs35l41-lib.c @@ -659,6 +659,57 @@ static const struct cs35l41_otp_packed_element_t otp_map_2[CS35L41_NUM_OTP_ELEM] { 0x00017044, 0, 24 }, /*LOT_NUMBER*/ }; +static const struct reg_sequence cs35l41_reva0_errata_patch[] = { + { 0x00000040, 0x00005555 }, + { 0x00000040, 0x0000AAAA }, + { 0x00003854, 0x05180240 }, + { CS35L41_VIMON_SPKMON_RESYNC, 0x00000000 }, + { 0x00004310, 0x00000000 }, + { CS35L41_VPVBST_FS_SEL, 0x00000000 }, + { CS35L41_OTP_TRIM_30, 0x9091A1C8 }, + { 0x00003014, 0x0200EE0E }, + { CS35L41_BSTCVRT_DCM_CTRL, 0x00000051 }, + { 0x00000054, 0x00000004 }, + { CS35L41_IRQ1_DB3, 0x00000000 }, + { CS35L41_IRQ2_DB3, 0x00000000 }, + { CS35L41_DSP1_YM_ACCEL_PL0_PRI, 0x00000000 }, + { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 }, + { 0x00000040, 0x0000CCCC }, + { 0x00000040, 0x00003333 }, + { CS35L41_PWR_CTRL2, 0x00000000 }, + { CS35L41_AMP_GAIN_CTRL, 0x00000000 }, +}; + +static const struct reg_sequence cs35l41_revb0_errata_patch[] = { + { 0x00000040, 0x00005555 }, + { 0x00000040, 0x0000AAAA }, + { CS35L41_VIMON_SPKMON_RESYNC, 0x00000000 }, + { 0x00004310, 0x00000000 }, + { CS35L41_VPVBST_FS_SEL, 0x00000000 }, + { CS35L41_BSTCVRT_DCM_CTRL, 0x00000051 }, + { CS35L41_DSP1_YM_ACCEL_PL0_PRI, 0x00000000 }, + { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 }, + { 0x00000040, 0x0000CCCC }, + { 0x00000040, 0x00003333 }, + { CS35L41_PWR_CTRL2, 0x00000000 }, + { CS35L41_AMP_GAIN_CTRL, 0x00000000 }, +}; + +static const struct reg_sequence cs35l41_revb2_errata_patch[] = { + { 0x00000040, 0x00005555 }, + { 0x00000040, 0x0000AAAA }, + { CS35L41_VIMON_SPKMON_RESYNC, 0x00000000 }, + { 0x00004310, 0x00000000 }, + { CS35L41_VPVBST_FS_SEL, 0x00000000 }, + { CS35L41_BSTCVRT_DCM_CTRL, 0x00000051 }, + { CS35L41_DSP1_YM_ACCEL_PL0_PRI, 0x00000000 }, + { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 }, + { 0x00000040, 0x0000CCCC }, + { 0x00000040, 0x00003333 }, + { CS35L41_PWR_CTRL2, 0x00000000 }, + { CS35L41_AMP_GAIN_CTRL, 0x00000000 }, +}; + static const struct cs35l41_otp_map_element_t cs35l41_otp_map_map[] = { { .id = 0x01, @@ -845,6 +896,44 @@ int cs35l41_otp_unpack(struct device *dev, struct regmap *regmap) } EXPORT_SYMBOL_GPL(cs35l41_otp_unpack); +int cs35l41_register_errata_patch(struct device *dev, struct regmap *reg, unsigned int reg_revid) +{ + char *rev; + int ret; + + switch (reg_revid) { + case CS35L41_REVID_A0: + ret = regmap_register_patch(reg, cs35l41_reva0_errata_patch, + ARRAY_SIZE(cs35l41_reva0_errata_patch)); + rev = "A0"; + break; + case CS35L41_REVID_B0: + ret = regmap_register_patch(reg, cs35l41_revb0_errata_patch, + ARRAY_SIZE(cs35l41_revb0_errata_patch)); + rev = "B0"; + break; + case CS35L41_REVID_B2: + ret = regmap_register_patch(reg, cs35l41_revb2_errata_patch, + ARRAY_SIZE(cs35l41_revb2_errata_patch)); + rev = "B2"; + break; + default: + ret = -EINVAL; + rev = "XX"; + break; + } + + if (ret) + dev_err(dev, "Failed to apply %s errata patch: %d\n", rev, ret); + + ret = regmap_write(reg, CS35L41_DSP1_CCM_CORE_CTRL, 0); + if (ret < 0) + dev_err(dev, "Write CCM_CORE_CTRL failed: %d\n", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(cs35l41_register_errata_patch); + MODULE_DESCRIPTION("CS35L41 library"); MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, "); MODULE_AUTHOR("Lucas Tanure, Cirrus Logic Inc, "); diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c index 7494710ae6e68..afc10f7ca65ea 100644 --- a/sound/soc/codecs/cs35l41.c +++ b/sound/soc/codecs/cs35l41.c @@ -1271,57 +1271,6 @@ static int cs35l41_handle_pdata(struct device *dev, return 0; } -static const struct reg_sequence cs35l41_reva0_errata_patch[] = { - { 0x00000040, 0x00005555 }, - { 0x00000040, 0x0000AAAA }, - { 0x00003854, 0x05180240 }, - { CS35L41_VIMON_SPKMON_RESYNC, 0x00000000 }, - { 0x00004310, 0x00000000 }, - { CS35L41_VPVBST_FS_SEL, 0x00000000 }, - { CS35L41_OTP_TRIM_30, 0x9091A1C8 }, - { 0x00003014, 0x0200EE0E }, - { CS35L41_BSTCVRT_DCM_CTRL, 0x00000051 }, - { 0x00000054, 0x00000004 }, - { CS35L41_IRQ1_DB3, 0x00000000 }, - { CS35L41_IRQ2_DB3, 0x00000000 }, - { CS35L41_DSP1_YM_ACCEL_PL0_PRI, 0x00000000 }, - { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 }, - { 0x00000040, 0x0000CCCC }, - { 0x00000040, 0x00003333 }, - { CS35L41_PWR_CTRL2, 0x00000000 }, - { CS35L41_AMP_GAIN_CTRL, 0x00000000 }, -}; - -static const struct reg_sequence cs35l41_revb0_errata_patch[] = { - { 0x00000040, 0x00005555 }, - { 0x00000040, 0x0000AAAA }, - { CS35L41_VIMON_SPKMON_RESYNC, 0x00000000 }, - { 0x00004310, 0x00000000 }, - { CS35L41_VPVBST_FS_SEL, 0x00000000 }, - { CS35L41_BSTCVRT_DCM_CTRL, 0x00000051 }, - { CS35L41_DSP1_YM_ACCEL_PL0_PRI, 0x00000000 }, - { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 }, - { 0x00000040, 0x0000CCCC }, - { 0x00000040, 0x00003333 }, - { CS35L41_PWR_CTRL2, 0x00000000 }, - { CS35L41_AMP_GAIN_CTRL, 0x00000000 }, -}; - -static const struct reg_sequence cs35l41_revb2_errata_patch[] = { - { 0x00000040, 0x00005555 }, - { 0x00000040, 0x0000AAAA }, - { CS35L41_VIMON_SPKMON_RESYNC, 0x00000000 }, - { 0x00004310, 0x00000000 }, - { CS35L41_VPVBST_FS_SEL, 0x00000000 }, - { CS35L41_BSTCVRT_DCM_CTRL, 0x00000051 }, - { CS35L41_DSP1_YM_ACCEL_PL0_PRI, 0x00000000 }, - { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 }, - { 0x00000040, 0x0000CCCC }, - { 0x00000040, 0x00003333 }, - { CS35L41_PWR_CTRL2, 0x00000000 }, - { CS35L41_AMP_GAIN_CTRL, 0x00000000 }, -}; - static const struct reg_sequence cs35l41_fs_errata_patch[] = { { CS35L41_DSP1_RX1_RATE, 0x00000001 }, { CS35L41_DSP1_RX2_RATE, 0x00000001 }, @@ -1501,38 +1450,9 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, goto err; } - switch (reg_revid) { - case CS35L41_REVID_A0: - ret = regmap_register_patch(cs35l41->regmap, - cs35l41_reva0_errata_patch, - ARRAY_SIZE(cs35l41_reva0_errata_patch)); - if (ret < 0) { - dev_err(cs35l41->dev, - "Failed to apply A0 errata patch: %d\n", ret); - goto err; - } - break; - case CS35L41_REVID_B0: - ret = regmap_register_patch(cs35l41->regmap, - cs35l41_revb0_errata_patch, - ARRAY_SIZE(cs35l41_revb0_errata_patch)); - if (ret < 0) { - dev_err(cs35l41->dev, - "Failed to apply B0 errata patch: %d\n", ret); - goto err; - } - break; - case CS35L41_REVID_B2: - ret = regmap_register_patch(cs35l41->regmap, - cs35l41_revb2_errata_patch, - ARRAY_SIZE(cs35l41_revb2_errata_patch)); - if (ret < 0) { - dev_err(cs35l41->dev, - "Failed to apply B2 errata patch: %d\n", ret); - goto err; - } - break; - } + ret = cs35l41_register_errata_patch(cs35l41->dev, cs35l41->regmap, reg_revid); + if (ret) + goto err; irq_pol = cs35l41_irq_gpio_config(cs35l41); @@ -1556,12 +1476,6 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, goto err; } - ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_CCM_CORE_CTRL, 0); - if (ret < 0) { - dev_err(cs35l41->dev, "Write CCM_CORE_CTRL failed: %d\n", ret); - goto err; - } - ret = cs35l41_set_pdata(cs35l41); if (ret < 0) { dev_err(cs35l41->dev, "Set pdata failed: %d\n", ret); From 3bc3e3da657f17c14df8ae8fab58183407bd7521 Mon Sep 17 00:00:00 2001 From: Lucas Tanure Date: Fri, 17 Dec 2021 11:57:03 +0000 Subject: [PATCH 325/327] ASoC: cs35l41: Create shared function for setting channels ASoC and HDA will use the same register to set channels for the device Signed-off-by: Lucas Tanure Link: https://lore.kernel.org/r/20211217115708.882525-6-tanureal@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/cs35l41.h | 3 +++ sound/soc/codecs/cs35l41-lib.c | 32 ++++++++++++++++++++++++++++++++ sound/soc/codecs/cs35l41.c | 30 +++--------------------------- 3 files changed, 38 insertions(+), 27 deletions(-) diff --git a/include/sound/cs35l41.h b/include/sound/cs35l41.h index ad2e32a12b8c2..39d150f613821 100644 --- a/include/sound/cs35l41.h +++ b/include/sound/cs35l41.h @@ -764,5 +764,8 @@ extern struct regmap_config cs35l41_regmap_spi; int cs35l41_otp_unpack(struct device *dev, struct regmap *regmap); int cs35l41_register_errata_patch(struct device *dev, struct regmap *reg, unsigned int reg_revid); +int cs35l41_set_channels(struct device *dev, struct regmap *reg, + unsigned int tx_num, unsigned int *tx_slot, + unsigned int rx_num, unsigned int *rx_slot); #endif /* __CS35L41_H */ diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c index 5e382eaea340a..afcec715374d0 100644 --- a/sound/soc/codecs/cs35l41-lib.c +++ b/sound/soc/codecs/cs35l41-lib.c @@ -934,6 +934,38 @@ int cs35l41_register_errata_patch(struct device *dev, struct regmap *reg, unsign } EXPORT_SYMBOL_GPL(cs35l41_register_errata_patch); +int cs35l41_set_channels(struct device *dev, struct regmap *reg, + unsigned int tx_num, unsigned int *tx_slot, + unsigned int rx_num, unsigned int *rx_slot) +{ + unsigned int val, mask; + int i; + + if (tx_num > 4 || rx_num > 2) + return -EINVAL; + + val = 0; + mask = 0; + for (i = 0; i < rx_num; i++) { + dev_dbg(dev, "rx slot %d position = %d\n", i, rx_slot[i]); + val |= rx_slot[i] << (i * 8); + mask |= 0x3F << (i * 8); + } + regmap_update_bits(reg, CS35L41_SP_FRAME_RX_SLOT, mask, val); + + val = 0; + mask = 0; + for (i = 0; i < tx_num; i++) { + dev_dbg(dev, "tx slot %d position = %d\n", i, tx_slot[i]); + val |= tx_slot[i] << (i * 8); + mask |= 0x3F << (i * 8); + } + regmap_update_bits(reg, CS35L41_SP_FRAME_TX_SLOT, mask, val); + + return 0; +} +EXPORT_SYMBOL_GPL(cs35l41_set_channels); + MODULE_DESCRIPTION("CS35L41 library"); MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, "); MODULE_AUTHOR("Lucas Tanure, Cirrus Logic Inc, "); diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c index afc10f7ca65ea..88d6e77fdb50d 100644 --- a/sound/soc/codecs/cs35l41.c +++ b/sound/soc/codecs/cs35l41.c @@ -751,36 +751,12 @@ static const struct cs_dsp_region cs35l41_dsp1_regions[] = { {. type = WMFW_ADSP2_YM, .base = CS35L41_DSP1_YMEM_UNPACK24_0}, }; -static int cs35l41_set_channel_map(struct snd_soc_dai *dai, unsigned int tx_num, - unsigned int *tx_slot, unsigned int rx_num, - unsigned int *rx_slot) +static int cs35l41_set_channel_map(struct snd_soc_dai *dai, unsigned int tx_n, + unsigned int *tx_slot, unsigned int rx_n, unsigned int *rx_slot) { struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(dai->component); - unsigned int val, mask; - int i; - - if (tx_num > 4 || rx_num > 2) - return -EINVAL; - val = 0; - mask = 0; - for (i = 0; i < rx_num; i++) { - dev_dbg(cs35l41->dev, "rx slot %d position = %d\n", i, rx_slot[i]); - val |= rx_slot[i] << (i * 8); - mask |= 0x3F << (i * 8); - } - regmap_update_bits(cs35l41->regmap, CS35L41_SP_FRAME_RX_SLOT, mask, val); - - val = 0; - mask = 0; - for (i = 0; i < tx_num; i++) { - dev_dbg(cs35l41->dev, "tx slot %d position = %d\n", i, tx_slot[i]); - val |= tx_slot[i] << (i * 8); - mask |= 0x3F << (i * 8); - } - regmap_update_bits(cs35l41->regmap, CS35L41_SP_FRAME_TX_SLOT, mask, val); - - return 0; + return cs35l41_set_channels(cs35l41->dev, cs35l41->regmap, tx_n, tx_slot, rx_n, rx_slot); } static int cs35l41_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) From e8e4fcc047c6e0c5411faeb8cc29aed2e5036a00 Mon Sep 17 00:00:00 2001 From: Lucas Tanure Date: Fri, 17 Dec 2021 11:57:04 +0000 Subject: [PATCH 326/327] ASoC: cs35l41: Create shared function for boost configuration ASoC and HDA will use the same registers to configure internal boost for the device Signed-off-by: Lucas Tanure Link: https://lore.kernel.org/r/20211217115708.882525-7-tanureal@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/cs35l41.h | 2 + sound/soc/codecs/cs35l41-lib.c | 98 ++++++++++++++++++++++++++++++ sound/soc/codecs/cs35l41.c | 105 +-------------------------------- 3 files changed, 102 insertions(+), 103 deletions(-) diff --git a/include/sound/cs35l41.h b/include/sound/cs35l41.h index 39d150f613821..29a527457b486 100644 --- a/include/sound/cs35l41.h +++ b/include/sound/cs35l41.h @@ -767,5 +767,7 @@ int cs35l41_register_errata_patch(struct device *dev, struct regmap *reg, unsign int cs35l41_set_channels(struct device *dev, struct regmap *reg, unsigned int tx_num, unsigned int *tx_slot, unsigned int rx_num, unsigned int *rx_slot); +int cs35l41_boost_config(struct device *dev, struct regmap *regmap, int boost_ind, int boost_cap, + int boost_ipk); #endif /* __CS35L41_H */ diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c index afcec715374d0..d026c5e3a378b 100644 --- a/sound/soc/codecs/cs35l41-lib.c +++ b/sound/soc/codecs/cs35l41-lib.c @@ -966,6 +966,104 @@ int cs35l41_set_channels(struct device *dev, struct regmap *reg, } EXPORT_SYMBOL_GPL(cs35l41_set_channels); +static const unsigned char cs35l41_bst_k1_table[4][5] = { + { 0x24, 0x32, 0x32, 0x4F, 0x57 }, + { 0x24, 0x32, 0x32, 0x4F, 0x57 }, + { 0x40, 0x32, 0x32, 0x4F, 0x57 }, + { 0x40, 0x32, 0x32, 0x4F, 0x57 } +}; + +static const unsigned char cs35l41_bst_k2_table[4][5] = { + { 0x24, 0x49, 0x66, 0xA3, 0xEA }, + { 0x24, 0x49, 0x66, 0xA3, 0xEA }, + { 0x48, 0x49, 0x66, 0xA3, 0xEA }, + { 0x48, 0x49, 0x66, 0xA3, 0xEA } +}; + +static const unsigned char cs35l41_bst_slope_table[4] = { + 0x75, 0x6B, 0x3B, 0x28 +}; + + +int cs35l41_boost_config(struct device *dev, struct regmap *regmap, int boost_ind, int boost_cap, + int boost_ipk) +{ + unsigned char bst_lbst_val, bst_cbst_range, bst_ipk_scaled; + int ret; + + switch (boost_ind) { + case 1000: /* 1.0 uH */ + bst_lbst_val = 0; + break; + case 1200: /* 1.2 uH */ + bst_lbst_val = 1; + break; + case 1500: /* 1.5 uH */ + bst_lbst_val = 2; + break; + case 2200: /* 2.2 uH */ + bst_lbst_val = 3; + break; + default: + dev_err(dev, "Invalid boost inductor value: %d nH\n", boost_ind); + return -EINVAL; + } + + switch (boost_cap) { + case 0 ... 19: + bst_cbst_range = 0; + break; + case 20 ... 50: + bst_cbst_range = 1; + break; + case 51 ... 100: + bst_cbst_range = 2; + break; + case 101 ... 200: + bst_cbst_range = 3; + break; + default: /* 201 uF and greater */ + bst_cbst_range = 4; + } + + ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_COEFF, + CS35L41_BST_K1_MASK | CS35L41_BST_K2_MASK, + cs35l41_bst_k1_table[bst_lbst_val][bst_cbst_range] + << CS35L41_BST_K1_SHIFT | + cs35l41_bst_k2_table[bst_lbst_val][bst_cbst_range] + << CS35L41_BST_K2_SHIFT); + if (ret) { + dev_err(dev, "Failed to write boost coefficients: %d\n", ret); + return ret; + } + + ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_SLOPE_LBST, + CS35L41_BST_SLOPE_MASK | CS35L41_BST_LBST_VAL_MASK, + cs35l41_bst_slope_table[bst_lbst_val] + << CS35L41_BST_SLOPE_SHIFT | + bst_lbst_val << CS35L41_BST_LBST_VAL_SHIFT); + if (ret) { + dev_err(dev, "Failed to write boost slope/inductor value: %d\n", ret); + return ret; + } + + if (boost_ipk < 1600 || boost_ipk > 4500) { + dev_err(dev, "Invalid boost inductor peak current: %d mA\n", boost_ipk); + return -EINVAL; + } + bst_ipk_scaled = ((boost_ipk - 1600) / 50) + 0x10; + + ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_PEAK_CUR, CS35L41_BST_IPK_MASK, + bst_ipk_scaled << CS35L41_BST_IPK_SHIFT); + if (ret) { + dev_err(dev, "Failed to write boost inductor peak current: %d\n", ret); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(cs35l41_boost_config); + MODULE_DESCRIPTION("CS35L41 library"); MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, "); MODULE_AUTHOR("Lucas Tanure, Cirrus Logic Inc, "); diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c index 88d6e77fdb50d..d9e6e84e64d0b 100644 --- a/sound/soc/codecs/cs35l41.c +++ b/sound/soc/codecs/cs35l41.c @@ -150,24 +150,6 @@ static const struct cs35l41_fs_mon_config cs35l41_fs_mon[] = { { 6144000, 16, 24 }, }; -static const unsigned char cs35l41_bst_k1_table[4][5] = { - { 0x24, 0x32, 0x32, 0x4F, 0x57 }, - { 0x24, 0x32, 0x32, 0x4F, 0x57 }, - { 0x40, 0x32, 0x32, 0x4F, 0x57 }, - { 0x40, 0x32, 0x32, 0x4F, 0x57 } -}; - -static const unsigned char cs35l41_bst_k2_table[4][5] = { - { 0x24, 0x49, 0x66, 0xA3, 0xEA }, - { 0x24, 0x49, 0x66, 0xA3, 0xEA }, - { 0x48, 0x49, 0x66, 0xA3, 0xEA }, - { 0x48, 0x49, 0x66, 0xA3, 0xEA } -}; - -static const unsigned char cs35l41_bst_slope_table[4] = { - 0x75, 0x6B, 0x3B, 0x28 -}; - static int cs35l41_get_fs_mon_config_index(int freq) { int i; @@ -992,88 +974,6 @@ static int cs35l41_dai_set_sysclk(struct snd_soc_dai *dai, return 0; } -static int cs35l41_boost_config(struct cs35l41_private *cs35l41, - int boost_ind, int boost_cap, int boost_ipk) -{ - unsigned char bst_lbst_val, bst_cbst_range, bst_ipk_scaled; - struct regmap *regmap = cs35l41->regmap; - struct device *dev = cs35l41->dev; - int ret; - - switch (boost_ind) { - case 1000: /* 1.0 uH */ - bst_lbst_val = 0; - break; - case 1200: /* 1.2 uH */ - bst_lbst_val = 1; - break; - case 1500: /* 1.5 uH */ - bst_lbst_val = 2; - break; - case 2200: /* 2.2 uH */ - bst_lbst_val = 3; - break; - default: - dev_err(dev, "Invalid boost inductor value: %d nH\n", boost_ind); - return -EINVAL; - } - - switch (boost_cap) { - case 0 ... 19: - bst_cbst_range = 0; - break; - case 20 ... 50: - bst_cbst_range = 1; - break; - case 51 ... 100: - bst_cbst_range = 2; - break; - case 101 ... 200: - bst_cbst_range = 3; - break; - default: /* 201 uF and greater */ - bst_cbst_range = 4; - } - - ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_COEFF, - CS35L41_BST_K1_MASK | CS35L41_BST_K2_MASK, - cs35l41_bst_k1_table[bst_lbst_val][bst_cbst_range] - << CS35L41_BST_K1_SHIFT | - cs35l41_bst_k2_table[bst_lbst_val][bst_cbst_range] - << CS35L41_BST_K2_SHIFT); - if (ret) { - dev_err(dev, "Failed to write boost coefficients: %d\n", ret); - return ret; - } - - ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_SLOPE_LBST, - CS35L41_BST_SLOPE_MASK | CS35L41_BST_LBST_VAL_MASK, - cs35l41_bst_slope_table[bst_lbst_val] - << CS35L41_BST_SLOPE_SHIFT | - bst_lbst_val << CS35L41_BST_LBST_VAL_SHIFT); - if (ret) { - dev_err(dev, "Failed to write boost slope/inductor value: %d\n", ret); - return ret; - } - - if (boost_ipk < 1600 || boost_ipk > 4500) { - dev_err(dev, "Invalid boost inductor peak current: %d mA\n", - boost_ipk); - return -EINVAL; - } - bst_ipk_scaled = ((boost_ipk - 1600) / 50) + 0x10; - - ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_PEAK_CUR, - CS35L41_BST_IPK_MASK, - bst_ipk_scaled << CS35L41_BST_IPK_SHIFT); - if (ret) { - dev_err(dev, "Failed to write boost inductor peak current: %d\n", ret); - return ret; - } - - return 0; -} - static int cs35l41_set_pdata(struct cs35l41_private *cs35l41) { int ret; @@ -1082,9 +982,8 @@ static int cs35l41_set_pdata(struct cs35l41_private *cs35l41) /* Required */ if (cs35l41->pdata.bst_ipk && cs35l41->pdata.bst_ind && cs35l41->pdata.bst_cap) { - ret = cs35l41_boost_config(cs35l41, cs35l41->pdata.bst_ind, - cs35l41->pdata.bst_cap, - cs35l41->pdata.bst_ipk); + ret = cs35l41_boost_config(cs35l41->dev, cs35l41->regmap, cs35l41->pdata.bst_ind, + cs35l41->pdata.bst_cap, cs35l41->pdata.bst_ipk); if (ret) { dev_err(cs35l41->dev, "Error in Boost DT config: %d\n", ret); return ret; From 9f3d45318dd9e739ed62e4218839a7a824d3cced Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Tue, 4 Jan 2022 13:22:16 +0000 Subject: [PATCH 327/327] ASoC: fsl_mqs: fix MODULE_ALIAS modprobe can't handle spaces in aliases. Fixes: 9e28f6532c61 ("ASoC: fsl_mqs: Add MQS component driver") Signed-off-by: Alyssa Ross Link: https://lore.kernel.org/r/20220104132218.1690103-1-hi@alyssa.is Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_mqs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_mqs.c b/sound/soc/fsl/fsl_mqs.c index 27b4536dce443..ceaecbe3a25e4 100644 --- a/sound/soc/fsl/fsl_mqs.c +++ b/sound/soc/fsl/fsl_mqs.c @@ -337,4 +337,4 @@ module_platform_driver(fsl_mqs_driver); MODULE_AUTHOR("Shengjiu Wang "); MODULE_DESCRIPTION("MQS codec driver"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform: fsl-mqs"); +MODULE_ALIAS("platform:fsl-mqs");