From 7929985cfe36c336e3d0753e9f23ac4c7758ea7e Mon Sep 17 00:00:00 2001 From: Ajit Kumar Pandey Date: Wed, 10 Aug 2022 18:59:12 +0530 Subject: ASoC: amd: acp: Initialize list to store acp_stream during pcm_open We are currently allocating acp_stream during pcm_open and saving it in static array corresponds to array index calculated based on cpu dai->driver id. This approach will fail if we have single dai linked to multiple pcm device as we will have same dai->driver id or array index for multiple pcm open. Initialize new linked list stream_list to store opened pcm stream info dynamically. Signed-off-by: Ajit Kumar Pandey Signed-off-by: Venkata Prasad Potturu Reviewed-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20220810132913.1181247-2-venkataprasad.potturu@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-platform.c | 40 +++++++++++++++++++--------------------- sound/soc/amd/acp/amd.h | 4 +++- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/sound/soc/amd/acp/acp-platform.c b/sound/soc/amd/acp/acp-platform.c index f561d39b33e2..beee53aedeaf 100644 --- a/sound/soc/amd/acp/acp-platform.c +++ b/sound/soc/amd/acp/acp-platform.c @@ -94,7 +94,7 @@ static irqreturn_t i2s_irq_handler(int irq, void *data) struct acp_resource *rsrc = adata->rsrc; struct acp_stream *stream; u16 i2s_flag = 0; - u32 ext_intr_stat, ext_intr_stat1, i; + u32 ext_intr_stat, ext_intr_stat1; if (!adata) return IRQ_NONE; @@ -104,14 +104,13 @@ static irqreturn_t i2s_irq_handler(int irq, void *data) ext_intr_stat = readl(ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used)); - for (i = 0; i < ACP_MAX_STREAM; i++) { - stream = adata->stream[i]; + spin_lock(&adata->acp_lock); + list_for_each_entry(stream, &adata->stream_list, list) { if (stream && (ext_intr_stat & stream->irq_bit)) { writel(stream->irq_bit, ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used)); snd_pcm_period_elapsed(stream->substream); i2s_flag = 1; - break; } if (adata->rsrc->no_of_ctrls == 2) { if (stream && (ext_intr_stat1 & stream->irq_bit)) { @@ -119,10 +118,10 @@ static irqreturn_t i2s_irq_handler(int irq, void *data) (rsrc->irqp_used - 1))); snd_pcm_period_elapsed(stream->substream); i2s_flag = 1; - break; } } } + spin_unlock(&adata->acp_lock); if (i2s_flag) return IRQ_HANDLED; @@ -146,9 +145,8 @@ static void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream writel(0x01, adata->acp_base + ACPAXI2AXI_ATU_CTRL); } -static void config_acp_dma(struct acp_dev_data *adata, int cpu_id, int size) +static void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream, int size) { - struct acp_stream *stream = adata->stream[cpu_id]; struct snd_pcm_substream *substream = stream->substream; struct acp_resource *rsrc = adata->rsrc; dma_addr_t addr = substream->dma_buffer.addr; @@ -174,13 +172,10 @@ static void config_acp_dma(struct acp_dev_data *adata, int cpu_id, int size) static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream); - struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0); struct snd_pcm_runtime *runtime = substream->runtime; struct device *dev = component->dev; struct acp_dev_data *adata = dev_get_drvdata(dev); struct acp_stream *stream; - int stream_id = cpu_dai->driver->id * 2 + substream->stream; int ret; stream = kzalloc(sizeof(*stream), GFP_KERNEL); @@ -188,7 +183,10 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs return -ENOMEM; stream->substream = substream; - adata->stream[stream_id] = stream; + + spin_lock_irq(&adata->acp_lock); + list_add_tail(&stream->list, &adata->stream_list); + spin_unlock_irq(&adata->acp_lock); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) runtime->hw = acp_pcm_hardware_playback; @@ -212,16 +210,13 @@ static int acp_dma_hw_params(struct snd_soc_component *component, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream); struct acp_dev_data *adata = snd_soc_component_get_drvdata(component); - struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0); struct acp_stream *stream = substream->runtime->private_data; - int stream_id = cpu_dai->driver->id * 2 + substream->stream; u64 size = params_buffer_bytes(params); /* Configure ACP DMA block with params */ config_pte_for_stream(adata, stream); - config_acp_dma(adata, stream_id, size); + config_acp_dma(adata, stream, size); return 0; } @@ -261,16 +256,15 @@ static int acp_dma_new(struct snd_soc_component *component, static int acp_dma_close(struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream); - struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0); struct device *dev = component->dev; struct acp_dev_data *adata = dev_get_drvdata(dev); - struct acp_stream *stream; - int stream_id = cpu_dai->driver->id * 2 + substream->stream; + struct acp_stream *stream = substream->runtime->private_data; - stream = adata->stream[stream_id]; + /* Remove entry from list */ + spin_lock_irq(&adata->acp_lock); + list_del(&stream->list); + spin_unlock_irq(&adata->acp_lock); kfree(stream); - adata->stream[stream_id] = NULL; return 0; } @@ -305,6 +299,10 @@ int acp_platform_register(struct device *dev) dev_err(dev, "Fail to register acp i2s component\n"); return status; } + + INIT_LIST_HEAD(&adata->stream_list); + spin_lock_init(&adata->acp_lock); + return 0; } EXPORT_SYMBOL_NS_GPL(acp_platform_register, SND_SOC_ACP_COMMON); diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h index af9603724a68..e49269f42a4e 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -91,6 +91,7 @@ struct acp_chip_info { }; struct acp_stream { + struct list_head list; struct snd_pcm_substream *substream; int irq_bit; int dai_id; @@ -123,7 +124,8 @@ struct acp_dev_data { struct snd_soc_dai_driver *dai_driver; int num_dai; - struct acp_stream *stream[ACP_MAX_STREAM]; + struct list_head stream_list; + spinlock_t acp_lock; struct snd_soc_acpi_mach *machines; struct platform_device *mach_dev; -- cgit v1.2.3 From 12229b7e50cfa95fda55b83a2617eafd6ac4c8c5 Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Wed, 10 Aug 2022 18:59:13 +0530 Subject: ASoC: amd: acp: Add TDM support for acp i2s stream Add callback and code changes to enable ACP I2S controller in TDM mode. Add new fields in acp_stream and acp_dev_data struct to configure tdm related registers for ACP i2s controllers. Signed-off-by: Venkata Prasad Potturu Link: https://lore.kernel.org/r/20220810132913.1181247-3-venkataprasad.potturu@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-i2s.c | 80 ++++++++++++++++++++++++++++++++++++++++++++- sound/soc/amd/acp/amd.h | 12 +++++++ 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c index 393f729ef561..ac416572db0d 100644 --- a/sound/soc/amd/acp/acp-i2s.c +++ b/sound/soc/amd/acp/acp-i2s.c @@ -25,6 +25,65 @@ #define DRV_NAME "acp_i2s_playcap" +static int acp_i2s_set_fmt(struct snd_soc_dai *cpu_dai, + unsigned int fmt) +{ + struct acp_dev_data *adata = snd_soc_dai_get_drvdata(cpu_dai); + int mode; + + mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK; + switch (mode) { + case SND_SOC_DAIFMT_I2S: + adata->tdm_mode = TDM_DISABLE; + break; + case SND_SOC_DAIFMT_DSP_A: + adata->tdm_mode = TDM_ENABLE; + break; + default: + return -EINVAL; + } + return 0; +} + +static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mask, + int slots, int slot_width) +{ + struct device *dev = dai->component->dev; + struct acp_dev_data *adata = snd_soc_dai_get_drvdata(dai); + struct acp_stream *stream; + int slot_len; + + switch (slot_width) { + case SLOT_WIDTH_8: + slot_len = 8; + break; + case SLOT_WIDTH_16: + slot_len = 16; + break; + case SLOT_WIDTH_24: + slot_len = 24; + break; + case SLOT_WIDTH_32: + slot_len = 0; + break; + default: + dev_err(dev, "Unsupported bitdepth %d\n", slot_width); + return -EINVAL; + } + + spin_lock_irq(&adata->acp_lock); + list_for_each_entry(stream, &adata->stream_list, list) { + if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK) + adata->tdm_tx_fmt[stream->dai_id - 1] = + FRM_LEN | (slots << 15) | (slot_len << 18); + else if (rx_mask && stream->dir == SNDRV_PCM_STREAM_CAPTURE) + adata->tdm_rx_fmt[stream->dai_id - 1] = + FRM_LEN | (slots << 15) | (slot_len << 18); + } + spin_unlock_irq(&adata->acp_lock); + return 0; +} + static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { @@ -33,7 +92,7 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_ struct acp_resource *rsrc; u32 val; u32 xfer_resolution; - u32 reg_val; + u32 reg_val, fmt_reg, tdm_fmt; u32 lrclk_div_val, bclk_div_val; adata = snd_soc_dai_get_drvdata(dai); @@ -62,12 +121,15 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_ switch (dai->driver->id) { case I2S_BT_INSTANCE: reg_val = ACP_BTTDM_ITER; + fmt_reg = ACP_BTTDM_TXFRMT; break; case I2S_SP_INSTANCE: reg_val = ACP_I2STDM_ITER; + fmt_reg = ACP_I2STDM_TXFRMT; break; case I2S_HS_INSTANCE: reg_val = ACP_HSTDM_ITER; + fmt_reg = ACP_HSTDM_TXFRMT; break; default: dev_err(dev, "Invalid dai id %x\n", dai->driver->id); @@ -77,12 +139,15 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_ switch (dai->driver->id) { case I2S_BT_INSTANCE: reg_val = ACP_BTTDM_IRER; + fmt_reg = ACP_BTTDM_RXFRMT; break; case I2S_SP_INSTANCE: reg_val = ACP_I2STDM_IRER; + fmt_reg = ACP_I2STDM_RXFRMT; break; case I2S_HS_INSTANCE: reg_val = ACP_HSTDM_IRER; + fmt_reg = ACP_HSTDM_RXFRMT; break; default: dev_err(dev, "Invalid dai id %x\n", dai->driver->id); @@ -95,6 +160,16 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_ val = val | (xfer_resolution << 3); writel(val, adata->acp_base + reg_val); + if (adata->tdm_mode) { + val = readl(adata->acp_base + reg_val); + writel(val | BIT(1), adata->acp_base + reg_val); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + tdm_fmt = adata->tdm_tx_fmt[dai->driver->id - 1]; + else + tdm_fmt = adata->tdm_rx_fmt[dai->driver->id - 1]; + writel(tdm_fmt, adata->acp_base + fmt_reg); + } + if (rsrc->soc_mclk) { switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: @@ -443,6 +518,7 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d stream->id = dai->driver->id + dir; stream->dai_id = dai->driver->id; stream->irq_bit = irq_bit; + stream->dir = substream->stream; return 0; } @@ -452,6 +528,8 @@ const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = { .hw_params = acp_i2s_hwparams, .prepare = acp_i2s_prepare, .trigger = acp_i2s_trigger, + .set_fmt = acp_i2s_set_fmt, + .set_tdm_slot = acp_i2s_set_tdm_slot, }; EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, SND_SOC_ACP_COMMON); diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h index e49269f42a4e..afa4e25cba19 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -84,6 +84,14 @@ #define ACP_MAX_STREAM 8 +#define TDM_ENABLE 1 +#define TDM_DISABLE 0 + +#define SLOT_WIDTH_8 0x8 +#define SLOT_WIDTH_16 0x10 +#define SLOT_WIDTH_24 0x18 +#define SLOT_WIDTH_32 0x20 + struct acp_chip_info { char *name; /* Platform name */ unsigned int acp_rev; /* ACP Revision id */ @@ -96,6 +104,7 @@ struct acp_stream { int irq_bit; int dai_id; int id; + int dir; u64 bytescount; u32 reg_offset; u32 pte_offset; @@ -120,6 +129,7 @@ struct acp_dev_data { void __iomem *acp_base; unsigned int i2s_irq; + bool tdm_mode; /* SOC specific dais */ struct snd_soc_dai_driver *dai_driver; int num_dai; @@ -134,6 +144,8 @@ struct acp_dev_data { u32 lrclk_div; struct acp_resource *rsrc; + u32 tdm_tx_fmt[3]; + u32 tdm_rx_fmt[3]; }; union acp_i2stdm_mstrclkgen { -- cgit v1.2.3 From 32d3679cbb383478c7e9dff590f367f1d7dda975 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Aug 2022 19:01:01 +0200 Subject: ASoC: cs43130: Replace scnprintf() with sysfs_emit() sysfs_emit() is a new helper to simplify the sysfs string output. Replace the open-code straightforwardly with this new helper. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20220801170108.26340-2-tiwai@suse.de Signed-off-by: Mark Brown --- sound/soc/codecs/cs43130.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c index ca4d47cc9c91..06c6ad3ca2b7 100644 --- a/sound/soc/codecs/cs43130.c +++ b/sound/soc/codecs/cs43130.c @@ -1666,10 +1666,9 @@ static int cs43130_show_dc(struct device *dev, char *buf, u8 ch) struct cs43130_private *cs43130 = i2c_get_clientdata(client); if (!cs43130->hpload_done) - return scnprintf(buf, PAGE_SIZE, "NO_HPLOAD\n"); + return sysfs_emit(buf, "NO_HPLOAD\n"); else - return scnprintf(buf, PAGE_SIZE, "%u\n", - cs43130->hpload_dc[ch]); + return sysfs_emit(buf, "%u\n", cs43130->hpload_dc[ch]); } static ssize_t hpload_dc_l_show(struct device *dev, @@ -1705,8 +1704,8 @@ static int cs43130_show_ac(struct device *dev, char *buf, u8 ch) if (cs43130->hpload_done && cs43130->ac_meas) { for (i = 0; i < ARRAY_SIZE(cs43130_ac_freq); i++) { - tmp = scnprintf(buf + j, PAGE_SIZE - j, "%u\n", - cs43130->hpload_ac[i][ch]); + tmp = sysfs_emit_at(buf, j, "%u\n", + cs43130->hpload_ac[i][ch]); if (!tmp) break; @@ -1715,7 +1714,7 @@ static int cs43130_show_ac(struct device *dev, char *buf, u8 ch) return j; } else { - return scnprintf(buf, PAGE_SIZE, "NO_HPLOAD\n"); + return sysfs_emit(buf, "NO_HPLOAD\n"); } } -- cgit v1.2.3 From 1218d67d376156aa8dc9dbc39616867823f60783 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Aug 2022 19:01:02 +0200 Subject: ASoC: tlv320aic26: Replace sprintf() with sysfs_emit() For sysfs outputs, it's safer to use a new helper, sysfs_emit(), instead of the raw sprintf() & co. This patch replaces the sprintf() usage straightforwardly with a new helper, sysfs_emit(). Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20220801170108.26340-3-tiwai@suse.de Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic26.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index 8bae4b475068..e5dfb3d752a3 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c @@ -271,7 +271,7 @@ static ssize_t keyclick_show(struct device *dev, freq = (125 << ((val >> 8) & 0x7)) >> 1; len = 2 * (1 + ((val >> 4) & 0xf)); - return sprintf(buf, "amp=%x freq=%iHz len=%iclks\n", amp, freq, len); + return sysfs_emit(buf, "amp=%x freq=%iHz len=%iclks\n", amp, freq, len); } /* Any write to the keyclick attribute will trigger the keyclick event */ -- cgit v1.2.3 From 0aab7bda03086061abd5f8a7794324bb70f769a3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Aug 2022 19:01:03 +0200 Subject: ASoC: Intel: sst: Replace sprintf() with sysfs_emit() For sysfs outputs, it's safer to use a new helper, sysfs_emit(), instead of the raw sprintf() & co. This patch replaces those usages straightforwardly with a new helper, sysfs_emit(). Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20220801170108.26340-4-tiwai@suse.de Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c index 160b50f479fb..a0d29510d2bc 100644 --- a/sound/soc/intel/atom/sst/sst.c +++ b/sound/soc/intel/atom/sst/sst.c @@ -242,11 +242,11 @@ static ssize_t firmware_version_show(struct device *dev, if (ctx->fw_version.type == 0 && ctx->fw_version.major == 0 && ctx->fw_version.minor == 0 && ctx->fw_version.build == 0) - return sprintf(buf, "FW not yet loaded\n"); + return sysfs_emit(buf, "FW not yet loaded\n"); else - return sprintf(buf, "v%02x.%02x.%02x.%02x\n", - ctx->fw_version.type, ctx->fw_version.major, - ctx->fw_version.minor, ctx->fw_version.build); + return sysfs_emit(buf, "v%02x.%02x.%02x.%02x\n", + ctx->fw_version.type, ctx->fw_version.major, + ctx->fw_version.minor, ctx->fw_version.build); } -- cgit v1.2.3 From 7ae8d8ea9427b6fb1ed04b02faf31ad5e3a6de8b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Aug 2022 19:01:04 +0200 Subject: ASoC: Intel: catpt: Replace sprintf() with sysfs_emit() For sysfs outputs, it's safer to use a new helper, sysfs_emit(), instead of the raw sprintf() & co. This patch replaces those usages straightforwardly with a new helper, sysfs_emit(). Signed-off-by: Takashi Iwai Acked-by: Cezary Rojewski Link: https://lore.kernel.org/r/20220801170108.26340-5-tiwai@suse.de Signed-off-by: Mark Brown --- sound/soc/intel/catpt/sysfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/catpt/sysfs.c b/sound/soc/intel/catpt/sysfs.c index 1bdbcc04dc71..9b6d2d93a2e7 100644 --- a/sound/soc/intel/catpt/sysfs.c +++ b/sound/soc/intel/catpt/sysfs.c @@ -27,8 +27,8 @@ static ssize_t fw_version_show(struct device *dev, if (ret) return CATPT_IPC_ERROR(ret); - return sprintf(buf, "%d.%d.%d.%d\n", version.type, version.major, - version.minor, version.build); + return sysfs_emit(buf, "%d.%d.%d.%d\n", version.type, version.major, + version.minor, version.build); } static DEVICE_ATTR_RO(fw_version); @@ -37,7 +37,7 @@ static ssize_t fw_info_show(struct device *dev, { struct catpt_dev *cdev = dev_get_drvdata(dev); - return sprintf(buf, "%s\n", cdev->ipc.config.fw_info); + return sysfs_emit(buf, "%s\n", cdev->ipc.config.fw_info); } static DEVICE_ATTR_RO(fw_info); -- cgit v1.2.3 From 11af2b1e33e8c9e72ddf14cd61f9494f34e06c40 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Aug 2022 19:01:05 +0200 Subject: ASoC: Intel: skylake: Replace sprintf() with sysfs_emit() For sysfs outputs, it's safer to use a new helper, sysfs_emit(), instead of the raw sprintf() & co. This patch replaces those usages straightforwardly with a new helper, sysfs_emit(). Signed-off-by: Takashi Iwai Acked-by: Cezary Rojewski Link: https://lore.kernel.org/r/20220801170108.26340-6-tiwai@suse.de Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-nhlt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index deb7b820325e..e617b4c335a4 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -61,7 +61,7 @@ static ssize_t platform_id_show(struct device *dev, nhlt->header.oem_revision); skl_nhlt_trim_space(platform_id); - return sprintf(buf, "%s\n", platform_id); + return sysfs_emit(buf, "%s\n", platform_id); } static DEVICE_ATTR_RO(platform_id); -- cgit v1.2.3 From 628d0f72d5828611cae353bd8b49d7647711c283 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Aug 2022 19:01:06 +0200 Subject: ASoC: core: Replace sprintf() with sysfs_emit() For sysfs outputs, it's safer to use a new helper, sysfs_emit(), instead of the raw sprintf() & co. This patch replaces the sprintf() usage straightforwardly with a new helper, sysfs_emit(). Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20220801170108.26340-7-tiwai@suse.de Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e824ff1a9fc0..e020ab49cfb1 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -72,7 +72,7 @@ static ssize_t pmdown_time_show(struct device *dev, { struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev); - return sprintf(buf, "%ld\n", rtd->pmdown_time); + return sysfs_emit(buf, "%ld\n", rtd->pmdown_time); } static ssize_t pmdown_time_store(struct device *dev, -- cgit v1.2.3 From 69f7cbfb08c7ee2ca565f532b0073b847db20bdc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Aug 2022 19:01:07 +0200 Subject: ASoC: DAPM: Replace sprintf() calls with sysfs_emit_at() For sysfs outputs, it's safer to use a new helper, sysfs_emit(), instead of the raw sprintf() & co. This patch replaces the open-code with a new helper, sysfs_emit_at(), by passing the string offset. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20220801170108.26340-8-tiwai@suse.de Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index b05231414c1d..73b8bd452ca7 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2386,11 +2386,10 @@ int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm, EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power); static ssize_t dapm_widget_show_component(struct snd_soc_component *cmpnt, - char *buf) + char *buf, int count) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); struct snd_soc_dapm_widget *w; - int count = 0; char *state = "not set"; /* card won't be set for the dummy component, as a spot fix @@ -2423,7 +2422,7 @@ static ssize_t dapm_widget_show_component(struct snd_soc_component *cmpnt, case snd_soc_dapm_pinctrl: case snd_soc_dapm_clock_supply: if (w->name) - count += sprintf(buf + count, "%s: %s\n", + count += sysfs_emit_at(buf, count, "%s: %s\n", w->name, w->power ? "On":"Off"); break; default: @@ -2445,7 +2444,7 @@ static ssize_t dapm_widget_show_component(struct snd_soc_component *cmpnt, state = "Off"; break; } - count += sprintf(buf + count, "PM State: %s\n", state); + count += sysfs_emit_at(buf, count, "PM State: %s\n", state); return count; } @@ -2463,7 +2462,7 @@ static ssize_t dapm_widget_show(struct device *dev, for_each_rtd_codec_dais(rtd, i, codec_dai) { struct snd_soc_component *cmpnt = codec_dai->component; - count += dapm_widget_show_component(cmpnt, buf + count); + count = dapm_widget_show_component(cmpnt, buf, count); } mutex_unlock(&rtd->card->dapm_mutex); -- cgit v1.2.3 From a111ae4d7f0796cf2ea0e8bf3ab6c06a401e0560 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Aug 2022 19:01:08 +0200 Subject: ASoC: omap: Replace sprintf() with sysfs_emit() For sysfs outputs, it's safer to use a new helper, sysfs_emit(), instead of the raw sprintf() & co. This patch replaces the open code with new helpers, sysfs_emit() and sysfs_emit_at(), with the proper string offset. Signed-off-by: Takashi Iwai Acked-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20220801170108.26340-9-tiwai@suse.de Signed-off-by: Mark Brown --- sound/soc/ti/omap-mcbsp-st.c | 6 +++--- sound/soc/ti/omap-mcbsp.c | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/ti/omap-mcbsp-st.c b/sound/soc/ti/omap-mcbsp-st.c index 7e8179cae92e..8163f453bf36 100644 --- a/sound/soc/ti/omap-mcbsp-st.c +++ b/sound/soc/ti/omap-mcbsp-st.c @@ -244,10 +244,10 @@ static ssize_t st_taps_show(struct device *dev, spin_lock_irq(&mcbsp->lock); for (i = 0; i < st_data->nr_taps; i++) - status += sprintf(&buf[status], (i ? ", %d" : "%d"), - st_data->taps[i]); + status += sysfs_emit_at(buf, status, (i ? ", %d" : "%d"), + st_data->taps[i]); if (i) - status += sprintf(&buf[status], "\n"); + status += sysfs_emit_at(buf, status, "\n"); spin_unlock_irq(&mcbsp->lock); return status; diff --git a/sound/soc/ti/omap-mcbsp.c b/sound/soc/ti/omap-mcbsp.c index c4ac1f30b9fe..0b377bb7737f 100644 --- a/sound/soc/ti/omap-mcbsp.c +++ b/sound/soc/ti/omap-mcbsp.c @@ -517,7 +517,7 @@ static ssize_t prop##_show(struct device *dev, \ { \ struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \ \ - return sprintf(buf, "%u\n", mcbsp->prop); \ + return sysfs_emit(buf, "%u\n", mcbsp->prop); \ } \ \ static ssize_t prop##_store(struct device *dev, \ @@ -560,11 +560,11 @@ static ssize_t dma_op_mode_show(struct device *dev, for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) { if (dma_op_mode == i) - len += sprintf(buf + len, "[%s] ", *s); + len += sysfs_emit_at(buf, len, "[%s] ", *s); else - len += sprintf(buf + len, "%s ", *s); + len += sysfs_emit_at(buf, len, "%s ", *s); } - len += sprintf(buf + len, "\n"); + len += sysfs_emit_at(buf, len, "\n"); return len; } -- cgit v1.2.3 From b79b6220a753995b80054916f1f8f037113d8d93 Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Mon, 8 Aug 2022 10:57:30 +0530 Subject: ASoC: dt-bindings: Definitions for DAI params The "convert-channels" and "convert-rate" bindings are available for audio-graph-card and are documented in the audio-graph-port.yaml and the audio-graph.yaml. There is duplication of property details at multiple places. Introduce a new schema to have common definitions for DAI params and these can be re-used in other schemas wherever applicable. Presently update audio-graph-card bindings to use these definitions. If required simple-card bindings can be extended to make use of common definitions. Signed-off-by: Sameer Pujar Cc: Kuninori Morimoto Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/1659936452-2254-2-git-send-email-spujar@nvidia.com Signed-off-by: Mark Brown --- .../bindings/sound/audio-graph-port.yaml | 13 ++++------ .../devicetree/bindings/sound/audio-graph.yaml | 7 +++-- .../devicetree/bindings/sound/dai-params.yaml | 30 ++++++++++++++++++++++ 3 files changed, 38 insertions(+), 12 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/dai-params.yaml diff --git a/Documentation/devicetree/bindings/sound/audio-graph-port.yaml b/Documentation/devicetree/bindings/sound/audio-graph-port.yaml index 5c368674d11a..fa3931be38d6 100644 --- a/Documentation/devicetree/bindings/sound/audio-graph-port.yaml +++ b/Documentation/devicetree/bindings/sound/audio-graph-port.yaml @@ -19,11 +19,10 @@ properties: description: "device name prefix" $ref: /schemas/types.yaml#/definitions/string convert-rate: - description: CPU to Codec rate convert. - $ref: /schemas/types.yaml#/definitions/uint32 + $ref: "/schemas/sound/dai-params.yaml#/$defs/dai-sample-rate" convert-channels: - description: CPU to Codec rate channels. - $ref: /schemas/types.yaml#/definitions/uint32 + $ref: "/schemas/sound/dai-params.yaml#/$defs/dai-channels" + patternProperties: "^endpoint(@[0-9a-f]+)?": $ref: /schemas/graph.yaml#/$defs/endpoint-base @@ -65,11 +64,9 @@ patternProperties: - msb - lsb convert-rate: - description: CPU to Codec rate convert. - $ref: /schemas/types.yaml#/definitions/uint32 + $ref: "/schemas/sound/dai-params.yaml#/$defs/dai-sample-rate" convert-channels: - description: CPU to Codec rate channels. - $ref: /schemas/types.yaml#/definitions/uint32 + $ref: "/schemas/sound/dai-params.yaml#/$defs/dai-channels" dai-tdm-slot-width-map: description: Mapping of sample widths to slot widths. For hardware diff --git a/Documentation/devicetree/bindings/sound/audio-graph.yaml b/Documentation/devicetree/bindings/sound/audio-graph.yaml index 4b46794e5153..ffee5c9e2a6c 100644 --- a/Documentation/devicetree/bindings/sound/audio-graph.yaml +++ b/Documentation/devicetree/bindings/sound/audio-graph.yaml @@ -27,11 +27,10 @@ properties: description: User specified audio sound widgets. $ref: /schemas/types.yaml#/definitions/non-unique-string-array convert-rate: - description: CPU to Codec rate convert. - $ref: /schemas/types.yaml#/definitions/uint32 + $ref: "/schemas/sound/dai-params.yaml#/$defs/dai-sample-rate" convert-channels: - description: CPU to Codec rate channels. - $ref: /schemas/types.yaml#/definitions/uint32 + $ref: "/schemas/sound/dai-params.yaml#/$defs/dai-channels" + pa-gpios: maxItems: 1 hp-det-gpio: diff --git a/Documentation/devicetree/bindings/sound/dai-params.yaml b/Documentation/devicetree/bindings/sound/dai-params.yaml new file mode 100644 index 000000000000..f1421a0798c4 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/dai-params.yaml @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/dai-params.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Digital Audio Interface (DAI) Stream Parameters + +maintainers: + - Kuninori Morimoto + +select: false + +$defs: + + dai-channels: + description: Number of audio channels used by DAI + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 1 + maximum: 32 + + dai-sample-rate: + description: Audio sample rate used by DAI + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 8000 + maximum: 192000 + +properties: {} + +additionalProperties: true -- cgit v1.2.3 From 955927873d82c5127e31e618703d804033a93e4f Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Mon, 8 Aug 2022 10:57:31 +0530 Subject: ASoC: dt-bindings: Add sample format conversion Presently "convert-channels" and "convert-rate" DT bindings are available for channel and rate fixups respectively. Similarly add "convert-sample-format" binding to fixup DAI sample format as well. This is added to audio-graph-card based bindings. Signed-off-by: Sameer Pujar Cc: Kuninori Morimoto Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/1659936452-2254-3-git-send-email-spujar@nvidia.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/audio-graph-port.yaml | 4 ++++ Documentation/devicetree/bindings/sound/audio-graph.yaml | 2 ++ Documentation/devicetree/bindings/sound/dai-params.yaml | 10 ++++++++++ 3 files changed, 16 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/audio-graph-port.yaml b/Documentation/devicetree/bindings/sound/audio-graph-port.yaml index fa3931be38d6..7ff7a4a104fa 100644 --- a/Documentation/devicetree/bindings/sound/audio-graph-port.yaml +++ b/Documentation/devicetree/bindings/sound/audio-graph-port.yaml @@ -22,6 +22,8 @@ properties: $ref: "/schemas/sound/dai-params.yaml#/$defs/dai-sample-rate" convert-channels: $ref: "/schemas/sound/dai-params.yaml#/$defs/dai-channels" + convert-sample-format: + $ref: "/schemas/sound/dai-params.yaml#/$defs/dai-sample-format" patternProperties: "^endpoint(@[0-9a-f]+)?": @@ -67,6 +69,8 @@ patternProperties: $ref: "/schemas/sound/dai-params.yaml#/$defs/dai-sample-rate" convert-channels: $ref: "/schemas/sound/dai-params.yaml#/$defs/dai-channels" + convert-sample-format: + $ref: "/schemas/sound/dai-params.yaml#/$defs/dai-sample-format" dai-tdm-slot-width-map: description: Mapping of sample widths to slot widths. For hardware diff --git a/Documentation/devicetree/bindings/sound/audio-graph.yaml b/Documentation/devicetree/bindings/sound/audio-graph.yaml index ffee5c9e2a6c..aaa99c2deda0 100644 --- a/Documentation/devicetree/bindings/sound/audio-graph.yaml +++ b/Documentation/devicetree/bindings/sound/audio-graph.yaml @@ -30,6 +30,8 @@ properties: $ref: "/schemas/sound/dai-params.yaml#/$defs/dai-sample-rate" convert-channels: $ref: "/schemas/sound/dai-params.yaml#/$defs/dai-channels" + convert-sample-format: + $ref: "/schemas/sound/dai-params.yaml#/$defs/dai-sample-format" pa-gpios: maxItems: 1 diff --git a/Documentation/devicetree/bindings/sound/dai-params.yaml b/Documentation/devicetree/bindings/sound/dai-params.yaml index f1421a0798c4..f5fb71f9b603 100644 --- a/Documentation/devicetree/bindings/sound/dai-params.yaml +++ b/Documentation/devicetree/bindings/sound/dai-params.yaml @@ -19,6 +19,16 @@ $defs: minimum: 1 maximum: 32 + dai-sample-format: + description: Audio sample format used by DAI + $ref: /schemas/types.yaml#/definitions/string + enum: + - s8 + - s16_le + - s24_le + - s24_3le + - s32_le + dai-sample-rate: description: Audio sample rate used by DAI $ref: /schemas/types.yaml#/definitions/uint32 -- cgit v1.2.3 From 047a05366f4bb2e32eabbd3c8990d1d91ab87c89 Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Mon, 8 Aug 2022 10:57:32 +0530 Subject: ASoC: simple-card-utils: Fixup DAI sample format Parse "convert-sample-format" DT binding and fixup the sample format as applicable. This is similar to the existing "convert-channels" and "convert-rate" properties for channels and rate fixup respectively. Signed-off-by: Sameer Pujar Cc: Kuninori Morimoto Link: https://lore.kernel.org/r/1659936452-2254-4-git-send-email-spujar@nvidia.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 1 + sound/soc/generic/simple-card-utils.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index ab55f40896e0..a0b827f0c2f6 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -39,6 +39,7 @@ struct asoc_simple_dai { struct asoc_simple_data { u32 convert_rate; u32 convert_channels; + const char *convert_sample_format; }; struct asoc_simple_jack { diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 4a29e314fa95..1b201dd09259 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -15,6 +15,33 @@ #include #include +static void asoc_simple_fixup_sample_fmt(struct asoc_simple_data *data, + struct snd_pcm_hw_params *params) +{ + int i; + struct snd_mask *mask = hw_param_mask(params, + SNDRV_PCM_HW_PARAM_FORMAT); + struct { + char *fmt; + u32 val; + } of_sample_fmt_table[] = { + { "s8", SNDRV_PCM_FORMAT_S8}, + { "s16_le", SNDRV_PCM_FORMAT_S16_LE}, + { "s24_le", SNDRV_PCM_FORMAT_S24_LE}, + { "s24_3le", SNDRV_PCM_FORMAT_S24_3LE}, + { "s32_le", SNDRV_PCM_FORMAT_S32_LE}, + }; + + for (i = 0; i < ARRAY_SIZE(of_sample_fmt_table); i++) { + if (!strcmp(data->convert_sample_format, + of_sample_fmt_table[i].fmt)) { + snd_mask_none(mask); + snd_mask_set(mask, of_sample_fmt_table[i].val); + break; + } + } +} + void asoc_simple_convert_fixup(struct asoc_simple_data *data, struct snd_pcm_hw_params *params) { @@ -30,6 +57,9 @@ void asoc_simple_convert_fixup(struct asoc_simple_data *data, if (data->convert_channels) channels->min = channels->max = data->convert_channels; + + if (data->convert_sample_format) + asoc_simple_fixup_sample_fmt(data, params); } EXPORT_SYMBOL_GPL(asoc_simple_convert_fixup); @@ -49,6 +79,10 @@ void asoc_simple_parse_convert(struct device_node *np, /* channels transfer */ snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-channels"); of_property_read_u32(np, prop, &data->convert_channels); + + /* convert sample format */ + snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-sample-format"); + of_property_read_string(np, prop, &data->convert_sample_format); } EXPORT_SYMBOL_GPL(asoc_simple_parse_convert); -- cgit v1.2.3 From 98c17a01bc5965047890bd30c95966007234e6d1 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 6 Aug 2022 21:33:22 +0200 Subject: ASoC: tlv320adcx140: Fix a typo in a comment s/TLV320ADCX104/TLV320ADCX140/ Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/63efe8fe4e25a8ac386762d2d7cfe9bb9482333f.1659814389.git.christophe.jaillet@wanadoo.fr Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320adcx140.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/tlv320adcx140.h b/sound/soc/codecs/tlv320adcx140.h index d7d4e3a88b5c..795b5f7194e6 100644 --- a/sound/soc/codecs/tlv320adcx140.h +++ b/sound/soc/codecs/tlv320adcx140.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -// TLV320ADCX104 Sound driver +// TLV320ADCX140 Sound driver // Copyright (C) 2020 Texas Instruments Incorporated - https://www.ti.com/ #ifndef _TLV320ADCX140_H -- cgit v1.2.3 From 4e6bedd3c396014ba70de2b4c9995c8e024e82b3 Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Wed, 10 Aug 2022 11:32:13 +1000 Subject: ASoC: codecs: add support for the TI SRC4392 codec The src4xxx keyword is used for future capability to integrate other codecs similar to the src4392 to the same code base. Signed-off-by: Matt Flax Link: https://lore.kernel.org/r/20220810013213.1544645-1-flatmax@flatmax.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 13 ++ sound/soc/codecs/Makefile | 4 + sound/soc/codecs/src4xxx-i2c.c | 47 ++++ sound/soc/codecs/src4xxx.c | 513 +++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/src4xxx.h | 113 +++++++++ 5 files changed, 690 insertions(+) create mode 100644 sound/soc/codecs/src4xxx-i2c.c create mode 100644 sound/soc/codecs/src4xxx.c create mode 100644 sound/soc/codecs/src4xxx.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index d16b4efb88a7..fe445465f877 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -205,6 +205,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_SIMPLE_AMPLIFIER imply SND_SOC_SIMPLE_MUX imply SND_SOC_SPDIF + imply SND_SOC_SRC4XXX_I2C imply SND_SOC_SSM2305 imply SND_SOC_SSM2518 imply SND_SOC_SSM2602_SPI @@ -1471,6 +1472,18 @@ config SND_SOC_SIMPLE_MUX config SND_SOC_SPDIF tristate "S/PDIF CODEC" +config SND_SOC_SRC4XXX_I2C + tristate "Texas Instruments SRC4XXX DIR/DIT and SRC codecs" + depends on I2C + select SND_SOC_SRC4XXX + help + Enable support for the TI SRC4XXX family of codecs. These include the + scr4392 which has digital receivers, transmitters, and + a sample rate converter, including numerous ports. + +config SND_SOC_SRC4XXX + tristate + config SND_SOC_SSM2305 tristate "Analog Devices SSM2305 Class-D Amplifier" help diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 92fd441d426a..a599b727c65b 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -231,6 +231,8 @@ snd-soc-sigmadsp-regmap-objs := sigmadsp-regmap.o snd-soc-si476x-objs := si476x.o snd-soc-spdif-tx-objs := spdif_transmitter.o snd-soc-spdif-rx-objs := spdif_receiver.o +snd-soc-src4xxx-objs := src4xxx.o +snd-soc-src4xxx-i2c-objs := src4xxx-i2c.o snd-soc-ssm2305-objs := ssm2305.o snd-soc-ssm2518-objs := ssm2518.o snd-soc-ssm2602-objs := ssm2602.o @@ -579,6 +581,8 @@ obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o obj-$(CONFIG_SND_SOC_SIGMADSP_REGMAP) += snd-soc-sigmadsp-regmap.o obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o +obj-$(CONFIG_SND_SOC_SRC4XXX) += snd-soc-src4xxx.o +obj-$(CONFIG_SND_SOC_SRC4XXX_I2C) += snd-soc-src4xxx-i2c.o obj-$(CONFIG_SND_SOC_SSM2305) += snd-soc-ssm2305.o obj-$(CONFIG_SND_SOC_SSM2518) += snd-soc-ssm2518.o obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o diff --git a/sound/soc/codecs/src4xxx-i2c.c b/sound/soc/codecs/src4xxx-i2c.c new file mode 100644 index 000000000000..43daa9dc8ab5 --- /dev/null +++ b/sound/soc/codecs/src4xxx-i2c.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Driver for SRC4XXX codecs +// +// Copyright 2021-2022 Deqx Pty Ltd +// Author: Matt Flax + +#include +#include +#include +#include + +#include "src4xxx.h" + +static int src4xxx_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + return src4xxx_probe(&i2c->dev, + devm_regmap_init_i2c(i2c, &src4xxx_regmap_config), NULL); +} + +static const struct i2c_device_id src4xxx_i2c_ids[] = { + { "src4392", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, src4xxx_i2c_ids); + +static const struct of_device_id src4xxx_of_match[] = { + { .compatible = "ti,src4392", }, + { } +}; +MODULE_DEVICE_TABLE(of, src4xxx_of_match); + + +static struct i2c_driver src4xxx_i2c_driver = { + .driver = { + .name = "src4xxx", + .of_match_table = of_match_ptr(src4xxx_of_match), + }, + .probe = src4xxx_i2c_probe, + .id_table = src4xxx_i2c_ids, +}; +module_i2c_driver(src4xxx_i2c_driver); + +MODULE_DESCRIPTION("ASoC SRC4392 CODEC I2C driver"); +MODULE_AUTHOR("Matt Flax "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/src4xxx.c b/sound/soc/codecs/src4xxx.c new file mode 100644 index 000000000000..a8f143057b41 --- /dev/null +++ b/sound/soc/codecs/src4xxx.c @@ -0,0 +1,513 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// TI SRC4xxx Audio Codec driver +// +// Copyright 2021-2022 Deqx Pty Ltd +// Author: Matt Flax + +#include + +#include +#include + +#include "src4xxx.h" + +struct src4xxx { + struct regmap *regmap; + bool master[2]; + int mclk_hz; + struct device *dev; +}; + +enum {SRC4XXX_PORTA, SRC4XXX_PORTB}; + +/* SRC attenuation */ +static const DECLARE_TLV_DB_SCALE(src_tlv, -12750, 50, 0); + +static const struct snd_kcontrol_new src4xxx_controls[] = { + SOC_DOUBLE_R_TLV("SRC Volume", + SRC4XXX_SCR_CTL_30, SRC4XXX_SCR_CTL_31, 0, 255, 1, src_tlv), +}; + +/* I2S port control */ +static const char * const port_out_src_text[] = { + "loopback", "other_port", "DIR", "SRC" +}; +static SOC_ENUM_SINGLE_DECL(porta_out_src_enum, SRC4XXX_PORTA_CTL_03, 4, + port_out_src_text); +static SOC_ENUM_SINGLE_DECL(portb_out_src_enum, SRC4XXX_PORTB_CTL_05, 4, + port_out_src_text); +static const struct snd_kcontrol_new porta_out_control = + SOC_DAPM_ENUM("Port A source select", porta_out_src_enum); +static const struct snd_kcontrol_new portb_out_control = + SOC_DAPM_ENUM("Port B source select", portb_out_src_enum); + +/* Digital audio transmitter control */ +static const char * const dit_mux_text[] = {"Port A", "Port B", "DIR", "SRC"}; +static SOC_ENUM_SINGLE_DECL(dit_mux_enum, SRC4XXX_TX_CTL_07, 3, dit_mux_text); +static const struct snd_kcontrol_new dit_mux_control = + SOC_DAPM_ENUM("DIT source", dit_mux_enum); + +/* SRC control */ +static const char * const src_in_text[] = {"Port A", "Port B", "DIR"}; +static SOC_ENUM_SINGLE_DECL(src_in_enum, SRC4XXX_SCR_CTL_2D, 0, src_in_text); +static const struct snd_kcontrol_new src_in_control = + SOC_DAPM_ENUM("SRC source select", src_in_enum); + +/* DIR control */ +static const char * const dir_in_text[] = {"Ch 1", "Ch 2", "Ch 3", "Ch 4"}; +static SOC_ENUM_SINGLE_DECL(dir_in_enum, SRC4XXX_RCV_CTL_0D, 0, dir_in_text); +static const struct snd_kcontrol_new dir_in_control = + SOC_DAPM_ENUM("Digital Input", dir_in_enum); + +static const struct snd_soc_dapm_widget src4xxx_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("loopback_A"), + SND_SOC_DAPM_INPUT("other_port_A"), + SND_SOC_DAPM_INPUT("DIR_A"), + SND_SOC_DAPM_INPUT("SRC_A"), + SND_SOC_DAPM_MUX("Port A source", + SND_SOC_NOPM, 0, 0, &porta_out_control), + + SND_SOC_DAPM_INPUT("loopback_B"), + SND_SOC_DAPM_INPUT("other_port_B"), + SND_SOC_DAPM_INPUT("DIR_B"), + SND_SOC_DAPM_INPUT("SRC_B"), + SND_SOC_DAPM_MUX("Port B source", + SND_SOC_NOPM, 0, 0, &portb_out_control), + + SND_SOC_DAPM_INPUT("Port_A"), + SND_SOC_DAPM_INPUT("Port_B"), + SND_SOC_DAPM_INPUT("DIR_"), + + /* Digital audio receivers and transmitters */ + SND_SOC_DAPM_OUTPUT("DIR_OUT"), + SND_SOC_DAPM_OUTPUT("SRC_OUT"), + SND_SOC_DAPM_MUX("DIT Out Src", SRC4XXX_PWR_RST_01, + SRC4XXX_ENABLE_DIT_SHIFT, 1, &dit_mux_control), + + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("AIF_A_RX", "Playback A", 0, + SRC4XXX_PWR_RST_01, SRC4XXX_ENABLE_PORT_A_SHIFT, 1), + SND_SOC_DAPM_AIF_OUT("AIF_A_TX", "Capture A", 0, + SRC4XXX_PWR_RST_01, SRC4XXX_ENABLE_PORT_A_SHIFT, 1), + SND_SOC_DAPM_AIF_IN("AIF_B_RX", "Playback B", 0, + SRC4XXX_PWR_RST_01, SRC4XXX_ENABLE_PORT_B_SHIFT, 1), + SND_SOC_DAPM_AIF_OUT("AIF_B_TX", "Capture B", 0, + SRC4XXX_PWR_RST_01, SRC4XXX_ENABLE_PORT_B_SHIFT, 1), + + SND_SOC_DAPM_MUX("SRC source", SND_SOC_NOPM, 0, 0, &src_in_control), + + SND_SOC_DAPM_INPUT("MCLK"), + SND_SOC_DAPM_INPUT("RXMCLKI"), + SND_SOC_DAPM_INPUT("RXMCLKO"), + + SND_SOC_DAPM_INPUT("RX1"), + SND_SOC_DAPM_INPUT("RX2"), + SND_SOC_DAPM_INPUT("RX3"), + SND_SOC_DAPM_INPUT("RX4"), + SND_SOC_DAPM_MUX("Digital Input", SRC4XXX_PWR_RST_01, + SRC4XXX_ENABLE_DIR_SHIFT, 1, &dir_in_control), +}; + +static const struct snd_soc_dapm_route src4xxx_audio_routes[] = { + /* I2S Input to Output Routing */ + {"Port A source", "loopback", "loopback_A"}, + {"Port A source", "other_port", "other_port_A"}, + {"Port A source", "DIR", "DIR_A"}, + {"Port A source", "SRC", "SRC_A"}, + {"Port B source", "loopback", "loopback_B"}, + {"Port B source", "other_port", "other_port_B"}, + {"Port B source", "DIR", "DIR_B"}, + {"Port B source", "SRC", "SRC_B"}, + /* DIT muxing */ + {"DIT Out Src", "Port A", "Capture A"}, + {"DIT Out Src", "Port B", "Capture B"}, + {"DIT Out Src", "DIR", "DIR_OUT"}, + {"DIT Out Src", "SRC", "SRC_OUT"}, + + /* SRC input selection */ + {"SRC source", "Port A", "Port_A"}, + {"SRC source", "Port B", "Port_B"}, + {"SRC source", "DIR", "DIR_"}, + /* SRC mclk selection */ + {"SRC mclk source", "Master (MCLK)", "MCLK"}, + {"SRC mclk source", "Master (RXCLKI)", "RXMCLKI"}, + {"SRC mclk source", "Recovered receiver clk", "RXMCLKO"}, + /* DIR input selection */ + {"Digital Input", "Ch 1", "RX1"}, + {"Digital Input", "Ch 2", "RX2"}, + {"Digital Input", "Ch 3", "RX3"}, + {"Digital Input", "Ch 4", "RX4"}, +}; + + +static const struct snd_soc_component_driver src4xxx_driver = { + .controls = src4xxx_controls, + .num_controls = ARRAY_SIZE(src4xxx_controls), + + .dapm_widgets = src4xxx_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(src4xxx_dapm_widgets), + .dapm_routes = src4xxx_audio_routes, + .num_dapm_routes = ARRAY_SIZE(src4xxx_audio_routes), +}; + +static int src4xxx_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + struct src4xxx *src4xxx = snd_soc_component_get_drvdata(component); + unsigned int ctrl; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + ctrl = SRC4XXX_BUS_MASTER; + src4xxx->master[dai->id] = true; + break; + case SND_SOC_DAIFMT_CBS_CFS: + ctrl = 0; + src4xxx->master[dai->id] = false; + break; + default: + return -EINVAL; + break; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + ctrl |= SRC4XXX_BUS_I2S; + break; + case SND_SOC_DAIFMT_LEFT_J: + ctrl |= SRC4XXX_BUS_LEFT_J; + break; + case SND_SOC_DAIFMT_RIGHT_J: + ctrl |= SRC4XXX_BUS_RIGHT_J_24; + break; + default: + return -EINVAL; + break; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + default: + return -EINVAL; + break; + } + + regmap_update_bits(src4xxx->regmap, SRC4XXX_BUS_FMT(dai->id), + SRC4XXX_BUS_FMT_MS_MASK, ctrl); + + return 0; +} + +static int src4xxx_set_mclk_hz(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_component *component = codec_dai->component; + struct src4xxx *src4xxx = snd_soc_component_get_drvdata(component); + + dev_info(component->dev, "changing mclk rate from %d to %d Hz\n", + src4xxx->mclk_hz, freq); + src4xxx->mclk_hz = freq; + + return 0; +} + +static int src4xxx_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 src4xxx *src4xxx = snd_soc_component_get_drvdata(component); + unsigned int mclk_div; + int val, pj, jd, d; + int reg; + int ret; + + switch (dai->id) { + case SRC4XXX_PORTB: + reg = SRC4XXX_PORTB_CTL_06; + break; + default: + reg = SRC4XXX_PORTA_CTL_04; + break; + } + + if (src4xxx->master[dai->id]) { + mclk_div = src4xxx->mclk_hz/params_rate(params); + if (src4xxx->mclk_hz != mclk_div*params_rate(params)) { + dev_err(component->dev, + "mclk %d / rate %d has a remainder.\n", + src4xxx->mclk_hz, params_rate(params)); + return -EINVAL; + } + + val = ((int)mclk_div - 128) / 128; + if ((val < 0) | (val > 3)) { + dev_err(component->dev, + "div register setting %d is out of range\n", + val); + dev_err(component->dev, + "unsupported sample rate %d Hz for the master clock of %d Hz\n", + params_rate(params), src4xxx->mclk_hz); + return -EINVAL; + } + + /* set the TX DIV */ + ret = regmap_update_bits(src4xxx->regmap, + SRC4XXX_TX_CTL_07, SRC4XXX_TX_MCLK_DIV_MASK, + val<dev, + "Couldn't set the TX's div register to %d << %d = 0x%x\n", + val, SRC4XXX_TX_MCLK_DIV_SHIFT, + val<mclk_hz) { + case 24576000: + pj = 0x22; + jd = 0x00; + d = 0x00; + break; + case 22579200: + pj = 0x22; + jd = 0x1b; + d = 0xa3; + break; + default: + /* don't error out here, + * other parts of the chip are still functional + */ + dev_info(component->dev, + "Couldn't set the RCV PLL as this master clock rate is unknown\n"); + break; + } + ret = regmap_write(src4xxx->regmap, SRC4XXX_RCV_PLL_0F, pj); + if (ret < 0) + dev_err(component->dev, + "Failed to update PLL register 0x%x\n", + SRC4XXX_RCV_PLL_0F); + ret = regmap_write(src4xxx->regmap, SRC4XXX_RCV_PLL_10, jd); + if (ret < 0) + dev_err(component->dev, + "Failed to update PLL register 0x%x\n", + SRC4XXX_RCV_PLL_10); + ret = regmap_write(src4xxx->regmap, SRC4XXX_RCV_PLL_11, d); + if (ret < 0) + dev_err(component->dev, + "Failed to update PLL register 0x%x\n", + SRC4XXX_RCV_PLL_11); + + ret = regmap_update_bits(src4xxx->regmap, + SRC4XXX_TX_CTL_07, SRC4XXX_TX_MCLK_DIV_MASK, + val<dev, + "Couldn't set the TX's div register to %d << %d = 0x%x\n", + val, SRC4XXX_TX_MCLK_DIV_SHIFT, + val<regmap, reg, + SRC4XXX_MCLK_DIV_MASK, val); + } else { + dev_info(dai->dev, "not setting up MCLK as not master\n"); + } + + return 0; +}; + +static const struct snd_soc_dai_ops src4xxx_dai_ops = { + .hw_params = src4xxx_hw_params, + .set_sysclk = src4xxx_set_mclk_hz, + .set_fmt = src4xxx_set_dai_fmt, +}; + +#define SRC4XXX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE) +#define SRC4XXX_RATES (SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000|\ + SNDRV_PCM_RATE_88200|\ + SNDRV_PCM_RATE_96000|\ + SNDRV_PCM_RATE_176400|\ + SNDRV_PCM_RATE_192000) + +static struct snd_soc_dai_driver src4xxx_dai_driver[] = { + { + .id = SRC4XXX_PORTA, + .name = "src4xxx-portA", + .playback = { + .stream_name = "Playback A", + .channels_min = 2, + .channels_max = 2, + .rates = SRC4XXX_RATES, + .formats = SRC4XXX_FORMATS, + }, + .capture = { + .stream_name = "Capture A", + .channels_min = 2, + .channels_max = 2, + .rates = SRC4XXX_RATES, + .formats = SRC4XXX_FORMATS, + }, + .ops = &src4xxx_dai_ops, + }, + { + .id = SRC4XXX_PORTB, + .name = "src4xxx-portB", + .playback = { + .stream_name = "Playback B", + .channels_min = 2, + .channels_max = 2, + .rates = SRC4XXX_RATES, + .formats = SRC4XXX_FORMATS, + }, + .capture = { + .stream_name = "Capture B", + .channels_min = 2, + .channels_max = 2, + .rates = SRC4XXX_RATES, + .formats = SRC4XXX_FORMATS, + }, + .ops = &src4xxx_dai_ops, + }, +}; + +static const struct reg_default src4xxx_reg_defaults[] = { + { SRC4XXX_PWR_RST_01, 0x00 }, /* all powered down intially */ + { SRC4XXX_PORTA_CTL_03, 0x00 }, + { SRC4XXX_PORTA_CTL_04, 0x00 }, + { SRC4XXX_PORTB_CTL_05, 0x00 }, + { SRC4XXX_PORTB_CTL_06, 0x00 }, + { SRC4XXX_TX_CTL_07, 0x00 }, + { SRC4XXX_TX_CTL_08, 0x00 }, + { SRC4XXX_TX_CTL_09, 0x00 }, + { SRC4XXX_SRC_DIT_IRQ_MSK_0B, 0x00 }, + { SRC4XXX_SRC_DIT_IRQ_MODE_0C, 0x00 }, + { SRC4XXX_RCV_CTL_0D, 0x00 }, + { SRC4XXX_RCV_CTL_0E, 0x00 }, + { SRC4XXX_RCV_PLL_0F, 0x00 }, /* not spec. in the datasheet */ + { SRC4XXX_RCV_PLL_10, 0xff }, /* not spec. in the datasheet */ + { SRC4XXX_RCV_PLL_11, 0xff }, /* not spec. in the datasheet */ + { SRC4XXX_RVC_IRQ_MSK_16, 0x00 }, + { SRC4XXX_RVC_IRQ_MSK_17, 0x00 }, + { SRC4XXX_RVC_IRQ_MODE_18, 0x00 }, + { SRC4XXX_RVC_IRQ_MODE_19, 0x00 }, + { SRC4XXX_RVC_IRQ_MODE_1A, 0x00 }, + { SRC4XXX_GPIO_1_1B, 0x00 }, + { SRC4XXX_GPIO_2_1C, 0x00 }, + { SRC4XXX_GPIO_3_1D, 0x00 }, + { SRC4XXX_GPIO_4_1E, 0x00 }, + { SRC4XXX_SCR_CTL_2D, 0x00 }, + { SRC4XXX_SCR_CTL_2E, 0x00 }, + { SRC4XXX_SCR_CTL_2F, 0x00 }, + { SRC4XXX_SCR_CTL_30, 0x00 }, + { SRC4XXX_SCR_CTL_31, 0x00 }, +}; + +int src4xxx_probe(struct device *dev, struct regmap *regmap, + void (*switch_mode)(struct device *dev)) +{ + struct src4xxx *src4xxx; + int ret; + + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + src4xxx = devm_kzalloc(dev, sizeof(*src4xxx), GFP_KERNEL); + if (!src4xxx) + return -ENOMEM; + + src4xxx->regmap = regmap; + src4xxx->dev = dev; + src4xxx->mclk_hz = 0; /* mclk has not been configured yet */ + dev_set_drvdata(dev, src4xxx); + + ret = regmap_write(regmap, SRC4XXX_PWR_RST_01, SRC4XXX_RESET); + if (ret < 0) + dev_err(dev, "Failed to issue reset: %d\n", ret); + usleep_range(1, 500); /* sleep for more then 500 ns */ + ret = regmap_write(regmap, SRC4XXX_PWR_RST_01, SRC4XXX_POWER_DOWN); + if (ret < 0) + dev_err(dev, "Failed to decommission reset: %d\n", ret); + usleep_range(500, 1000); /* sleep for 500 us or more */ + + ret = regmap_update_bits(src4xxx->regmap, SRC4XXX_PWR_RST_01, + SRC4XXX_POWER_ENABLE, SRC4XXX_POWER_ENABLE); + if (ret < 0) + dev_err(dev, "Failed to port A and B : %d\n", ret); + + /* set receiver to use master clock (rcv mclk is most likely jittery) */ + ret = regmap_update_bits(src4xxx->regmap, SRC4XXX_RCV_CTL_0D, + SRC4XXX_RXCLK_MCLK, SRC4XXX_RXCLK_MCLK); + if (ret < 0) + dev_err(dev, + "Failed to enable mclk as the PLL1 DIR reference : %d\n", ret); + + /* default to leaving the PLL2 running on loss of lock, divide by 8 */ + ret = regmap_update_bits(src4xxx->regmap, SRC4XXX_RCV_CTL_0E, + SRC4XXX_PLL2_DIV_8 | SRC4XXX_REC_MCLK_EN | SRC4XXX_PLL2_LOL, + SRC4XXX_PLL2_DIV_8 | SRC4XXX_REC_MCLK_EN | SRC4XXX_PLL2_LOL); + if (ret < 0) + dev_err(dev, "Failed to enable mclk rec and div : %d\n", ret); + + ret = devm_snd_soc_register_component(dev, &src4xxx_driver, + src4xxx_dai_driver, ARRAY_SIZE(src4xxx_dai_driver)); + if (ret == 0) + dev_info(dev, "src4392 probe ok %d\n", ret); + return ret; +} +EXPORT_SYMBOL_GPL(src4xxx_probe); + +static bool src4xxx_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case SRC4XXX_RES_00: + case SRC4XXX_GLOBAL_ITR_STS_02: + case SRC4XXX_SRC_DIT_STS_0A: + case SRC4XXX_NON_AUDIO_D_12: + case SRC4XXX_RVC_STS_13: + case SRC4XXX_RVC_STS_14: + case SRC4XXX_RVC_STS_15: + case SRC4XXX_SUB_CODE_1F: + case SRC4XXX_SUB_CODE_20: + case SRC4XXX_SUB_CODE_21: + case SRC4XXX_SUB_CODE_22: + case SRC4XXX_SUB_CODE_23: + case SRC4XXX_SUB_CODE_24: + case SRC4XXX_SUB_CODE_25: + case SRC4XXX_SUB_CODE_26: + case SRC4XXX_SUB_CODE_27: + case SRC4XXX_SUB_CODE_28: + case SRC4XXX_PC_PREAMBLE_HI_29: + case SRC4XXX_PC_PREAMBLE_LO_2A: + case SRC4XXX_PD_PREAMBLE_HI_2B: + case SRC4XXX_PC_PREAMBLE_LO_2C: + case SRC4XXX_IO_RATIO_32: + case SRC4XXX_IO_RATIO_33: + return true; + } + + if (reg > SRC4XXX_IO_RATIO_33 && reg < SRC4XXX_PAGE_SEL_7F) + return true; + + return false; +} + +const struct regmap_config src4xxx_regmap_config = { + .val_bits = 8, + .reg_bits = 8, + .max_register = SRC4XXX_IO_RATIO_33, + + .reg_defaults = src4xxx_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(src4xxx_reg_defaults), + .volatile_reg = src4xxx_volatile_register, + .cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(src4xxx_regmap_config); + +MODULE_DESCRIPTION("ASoC SRC4XXX CODEC driver"); +MODULE_AUTHOR("Matt Flax "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/src4xxx.h b/sound/soc/codecs/src4xxx.h new file mode 100644 index 000000000000..5bf778fb9945 --- /dev/null +++ b/sound/soc/codecs/src4xxx.h @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// src4xxx.h -- SRC4XXX ALSA SoC audio driver +// +// Copyright 2021-2022 Deqx Pty Ltd +// Author: Matt R Flax + +#ifndef __SRC4XXX_H__ +#define __SRC4XXX_H__ + +#define SRC4XXX_RES_00 0x00 +#define SRC4XXX_PWR_RST_01 0x01 +#define SRC4XXX_RESET 0x80 +#define SRC4XXX_POWER_DOWN 0x00 +#define SRC4XXX_POWER_ENABLE 0x20 +#define SRC4XXX_ENABLE_SRC 0x1 +#define SRC4XXX_ENABLE_SRC_SHIFT 0 +#define SRC4XXX_ENABLE_DIR 0x2 +#define SRC4XXX_ENABLE_DIR_SHIFT 1 +#define SRC4XXX_ENABLE_DIT 0x4 +#define SRC4XXX_ENABLE_DIT_SHIFT 2 +#define SRC4XXX_ENABLE_PORT_B 0x8 +#define SRC4XXX_ENABLE_PORT_B_SHIFT 3 +#define SRC4XXX_ENABLE_PORT_A 0x10 +#define SRC4XXX_ENABLE_PORT_A_SHIFT 4 + +#define SRC4XXX_PORTA_CTL_03 0x03 +#define SRC4XXX_BUS_MASTER 0x8 +#define SRC4XXX_BUS_LEFT_J 0x0 +#define SRC4XXX_BUS_I2S 0x1 +#define SRC4XXX_BUS_RIGHT_J_16 0x4 +#define SRC4XXX_BUS_RIGHT_J_18 0x5 +#define SRC4XXX_BUS_RIGHT_J_20 0x6 +#define SRC4XXX_BUS_RIGHT_J_24 0x7 +#define SRC4XXX_BUS_FMT_MS_MASK 0xf + +#define SRC4XXX_PORTA_CTL_04 0x04 +#define SRC4XXX_MCLK_DIV_MASK 0x3 + +#define SRC4XXX_BUS_FMT(id) (SRC4XXX_PORTA_CTL_03+2*id) +#define SRC4XXX_BUS_CLK(id) (SRC4XXX_PORTA_CTL_04+2*id) + +#define SRC4XXX_PORTB_CTL_05 0x05 +#define SRC4XXX_PORTB_CTL_06 0x06 + +#define SRC4XXX_TX_CTL_07 0x07 +#define SRC4XXX_TX_MCLK_DIV_MASK 0x60 +#define SRC4XXX_TX_MCLK_DIV_SHIFT 5 + +#define SRC4XXX_TX_CTL_08 0x08 +#define SRC4XXX_TX_CTL_09 0x09 +#define SRC4XXX_SRC_DIT_IRQ_MSK_0B 0x0B +#define SRC4XXX_SRC_BTI_EN 0x01 +#define SRC4XXX_SRC_TSLIP_EN 0x02 +#define SRC4XXX_SRC_DIT_IRQ_MODE_0C 0x0C +#define SRC4XXX_RCV_CTL_0D 0x0D +#define SRC4XXX_RXCLK_RXCKI 0x0 +#define SRC4XXX_RXCLK_MCLK 0x8 +#define SRC4XXX_RCV_CTL_0E 0x0E +#define SRC4XXX_REC_MCLK_EN 0x1 +#define SRC4XXX_PLL2_DIV_0 (0x0<<1) +#define SRC4XXX_PLL2_DIV_2 (0x1<<1) +#define SRC4XXX_PLL2_DIV_4 (0x2<<1) +#define SRC4XXX_PLL2_DIV_8 (0x3<<1) +#define SRC4XXX_PLL2_LOL 0x8 +#define SRC4XXX_RCV_PLL_0F 0x0F +#define SRC4XXX_RCV_PLL_10 0x10 +#define SRC4XXX_RCV_PLL_11 0x11 +#define SRC4XXX_RVC_IRQ_MSK_16 0x16 +#define SRC4XXX_RVC_IRQ_MSK_17 0x17 +#define SRC4XXX_RVC_IRQ_MODE_18 0x18 +#define SRC4XXX_RVC_IRQ_MODE_19 0x19 +#define SRC4XXX_RVC_IRQ_MODE_1A 0x1A +#define SRC4XXX_GPIO_1_1B 0x1B +#define SRC4XXX_GPIO_2_1C 0x1C +#define SRC4XXX_GPIO_3_1D 0x1D +#define SRC4XXX_GPIO_4_1E 0x1E +#define SRC4XXX_SCR_CTL_2D 0x2D +#define SRC4XXX_SCR_CTL_2E 0x2E +#define SRC4XXX_SCR_CTL_2F 0x2F +#define SRC4XXX_SCR_CTL_30 0x30 +#define SRC4XXX_SCR_CTL_31 0x31 +#define SRC4XXX_PAGE_SEL_7F 0x7F + +// read only registers +#define SRC4XXX_GLOBAL_ITR_STS_02 0x02 +#define SRC4XXX_SRC_DIT_STS_0A 0x0A +#define SRC4XXX_NON_AUDIO_D_12 0x12 +#define SRC4XXX_RVC_STS_13 0x13 +#define SRC4XXX_RVC_STS_14 0x14 +#define SRC4XXX_RVC_STS_15 0x15 +#define SRC4XXX_SUB_CODE_1F 0x1F +#define SRC4XXX_SUB_CODE_20 0x20 +#define SRC4XXX_SUB_CODE_21 0x21 +#define SRC4XXX_SUB_CODE_22 0x22 +#define SRC4XXX_SUB_CODE_23 0x23 +#define SRC4XXX_SUB_CODE_24 0x24 +#define SRC4XXX_SUB_CODE_25 0x25 +#define SRC4XXX_SUB_CODE_26 0x26 +#define SRC4XXX_SUB_CODE_27 0x27 +#define SRC4XXX_SUB_CODE_28 0x28 +#define SRC4XXX_PC_PREAMBLE_HI_29 0x29 +#define SRC4XXX_PC_PREAMBLE_LO_2A 0x2A +#define SRC4XXX_PD_PREAMBLE_HI_2B 0x2B +#define SRC4XXX_PC_PREAMBLE_LO_2C 0x2C +#define SRC4XXX_IO_RATIO_32 0x32 +#define SRC4XXX_IO_RATIO_33 0x33 + +int src4xxx_probe(struct device *dev, struct regmap *regmap, + void (*switch_mode)(struct device *dev)); +extern const struct regmap_config src4xxx_regmap_config; + +#endif /* __SRC4XXX_H__ */ -- cgit v1.2.3 From d563336877b21ede46053103c726f50a0206d155 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Tue, 2 Aug 2022 20:29:54 +0800 Subject: ASoC: dt-bindings: fsl,sai: Convert format to json-schema Convert the NXP SAI binding to DT schema format using json-schema. The Synchronous Audio Interface (SAI) provides an interface that supports full-duplex serial interfaces with frame synchronization formats such as I2S, AC97, TDM, and codec/DSP interfaces. Beside conversion, 'fsl,shared-interrupt' and '#sound-dai-cells' are added for they are already used by some dts. Signed-off-by: Shengjiu Wang Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/1659443394-9838-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/fsl,sai.yaml | 216 +++++++++++++++++++++ .../devicetree/bindings/sound/fsl-sai.txt | 95 --------- 2 files changed, 216 insertions(+), 95 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/fsl,sai.yaml delete mode 100644 Documentation/devicetree/bindings/sound/fsl-sai.txt diff --git a/Documentation/devicetree/bindings/sound/fsl,sai.yaml b/Documentation/devicetree/bindings/sound/fsl,sai.yaml new file mode 100644 index 000000000000..70c4111d59c7 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/fsl,sai.yaml @@ -0,0 +1,216 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/fsl,sai.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale Synchronous Audio Interface (SAI). + +maintainers: + - Shengjiu Wang + +description: | + The SAI is based on I2S module that used communicating with audio codecs, + which provides a synchronous audio interface that supports fullduplex + serial interfaces with frame synchronization such as I2S, AC97, TDM, and + codec/DSP interfaces. + +properties: + compatible: + oneOf: + - enum: + - fsl,vf610-sai + - fsl,imx6sx-sai + - fsl,imx6ul-sai + - fsl,imx7ulp-sai + - fsl,imx8mq-sai + - fsl,imx8qm-sai + - fsl,imx8ulp-sai + - items: + - enum: + - fsl,imx8mm-sai + - fsl,imx8mn-sai + - fsl,imx8mp-sai + - const: fsl,imx8mq-sai + + reg: + maxItems: 1 + + interrupts: + items: + - description: receive and transmit interrupt + + dmas: + maxItems: 2 + + dma-names: + maxItems: 2 + + clocks: + items: + - description: The ipg clock for register access + - description: master clock source 0 (obsoleted) + - description: master clock source 1 + - description: master clock source 2 + - description: master clock source 3 + - description: PLL clock source for 8kHz series + - description: PLL clock source for 11kHz series + minItems: 4 + + clock-names: + oneOf: + - items: + - const: bus + - const: mclk0 + - const: mclk1 + - const: mclk2 + - const: mclk3 + - const: pll8k + - const: pll11k + minItems: 4 + - items: + - const: bus + - const: mclk1 + - const: mclk2 + - const: mclk3 + - const: pll8k + - const: pll11k + minItems: 4 + + lsb-first: + description: | + Configures whether the LSB or the MSB is transmitted + first for the fifo data. If this property is absent, + the MSB is transmitted first as default, or the LSB + is transmitted first. + type: boolean + + big-endian: + description: | + required if all the SAI registers are big-endian rather than little-endian. + type: boolean + + fsl,sai-synchronous-rx: + description: | + SAI will work in the synchronous mode (sync Tx with Rx) which means + both the transmitter and the receiver will send and receive data by + following receiver's bit clocks and frame sync clocks. + type: boolean + + fsl,sai-asynchronous: + description: | + SAI will work in the asynchronous mode, which means both transmitter + and receiver will send and receive data by following their own bit clocks + and frame sync clocks separately. + If both fsl,sai-asynchronous and fsl,sai-synchronous-rx are absent, the + default synchronous mode (sync Rx with Tx) will be used, which means both + transmitter and receiver will send and receive data by following clocks + of transmitter. + type: boolean + + fsl,dataline: + $ref: /schemas/types.yaml#/definitions/uint32-matrix + description: | + Configure the dataline. It has 3 value for each configuration + maxItems: 16 + items: + items: + - description: format Default(0), I2S(1) or PDM(2) + enum: [0, 1, 2] + - description: dataline mask for 'rx' + - description: dataline mask for 'tx' + + fsl,sai-mclk-direction-output: + description: SAI will output the SAI MCLK clock. + type: boolean + + fsl,shared-interrupt: + description: Interrupt is shared with other modules. + type: boolean + + "#sound-dai-cells": + const: 0 + description: optional, some dts node didn't add it. + +allOf: + - if: + properties: + compatible: + contains: + const: fsl,vf610-sai + then: + properties: + dmas: + items: + - description: DMA controller phandle and request line for TX + - description: DMA controller phandle and request line for RX + dma-names: + items: + - const: tx + - const: rx + else: + properties: + dmas: + items: + - description: DMA controller phandle and request line for RX + - description: DMA controller phandle and request line for TX + dma-names: + items: + - const: rx + - const: tx + - if: + required: + - fsl,sai-asynchronous + then: + properties: + fsl,sai-synchronous-rx: false + +required: + - compatible + - reg + - interrupts + - dmas + - dma-names + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + #include + #include + sai2: sai@40031000 { + compatible = "fsl,vf610-sai"; + reg = <0x40031000 0x1000>; + interrupts = <86 IRQ_TYPE_LEVEL_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sai2_1>; + clocks = <&clks VF610_CLK_PLATFORM_BUS>, + <&clks VF610_CLK_SAI2>, + <&clks 0>, <&clks 0>; + clock-names = "bus", "mclk1", "mclk2", "mclk3"; + dma-names = "tx", "rx"; + dmas = <&edma0 0 21>, + <&edma0 0 20>; + big-endian; + lsb-first; + }; + + - | + #include + #include + sai1: sai@30010000 { + compatible = "fsl,imx8mm-sai", "fsl,imx8mq-sai"; + reg = <0x30010000 0x10000>; + interrupts = ; + clocks = <&clk IMX8MM_CLK_SAI1_IPG>, + <&clk IMX8MM_CLK_DUMMY>, + <&clk IMX8MM_CLK_SAI1_ROOT>, + <&clk IMX8MM_CLK_DUMMY>, <&clk IMX8MM_CLK_DUMMY>; + clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3"; + dmas = <&sdma2 0 2 0>, <&sdma2 1 2 0>; + dma-names = "rx", "tx"; + fsl,dataline = <1 0xff 0xff 2 0xff 0x11>; + #sound-dai-cells = <0>; + }; diff --git a/Documentation/devicetree/bindings/sound/fsl-sai.txt b/Documentation/devicetree/bindings/sound/fsl-sai.txt deleted file mode 100644 index fbdefc3fade7..000000000000 --- a/Documentation/devicetree/bindings/sound/fsl-sai.txt +++ /dev/null @@ -1,95 +0,0 @@ -Freescale Synchronous Audio Interface (SAI). - -The SAI is based on I2S module that used communicating with audio codecs, -which provides a synchronous audio interface that supports fullduplex -serial interfaces with frame synchronization such as I2S, AC97, TDM, and -codec/DSP interfaces. - -Required properties: - - - compatible : Compatible list, contains "fsl,vf610-sai", - "fsl,imx6sx-sai", "fsl,imx6ul-sai", - "fsl,imx7ulp-sai", "fsl,imx8mq-sai", - "fsl,imx8qm-sai", "fsl,imx8mm-sai", - "fsl,imx8mn-sai", "fsl,imx8mp-sai", or - "fsl,imx8ulp-sai". - - - reg : Offset and length of the register set for the device. - - - clocks : Must contain an entry for each entry in clock-names. - - - clock-names : Must include the "bus" for register access and - "mclk1", "mclk2", "mclk3" for bit clock and frame - clock providing. - "pll8k", "pll11k" are optional, they are the clock - source for root clock, one is for 8kHz series rates - another one is for 11kHz series rates. - - dmas : Generic dma devicetree binding as described in - Documentation/devicetree/bindings/dma/dma.txt. - - - dma-names : Two dmas have to be defined, "tx" and "rx". - - - pinctrl-names : Must contain a "default" entry. - - - pinctrl-NNN : One property must exist for each entry in - pinctrl-names. See ../pinctrl/pinctrl-bindings.txt - for details of the property values. - - - lsb-first : Configures whether the LSB or the MSB is transmitted - first for the fifo data. If this property is absent, - the MSB is transmitted first as default, or the LSB - is transmitted first. - - - fsl,sai-synchronous-rx: This is a boolean property. If present, indicating - that SAI will work in the synchronous mode (sync Tx - with Rx) which means both the transmitter and the - receiver will send and receive data by following - receiver's bit clocks and frame sync clocks. - - - fsl,sai-asynchronous: This is a boolean property. If present, indicating - that SAI will work in the asynchronous mode, which - means both transmitter and receiver will send and - receive data by following their own bit clocks and - frame sync clocks separately. - - - fsl,dataline : configure the dataline. it has 3 value for each configuration - first one means the type: I2S(1) or PDM(2) - second one is dataline mask for 'rx' - third one is dataline mask for 'tx'. - for example: fsl,dataline = <1 0xff 0xff 2 0xff 0x11>; - it means I2S type rx mask is 0xff, tx mask is 0xff, PDM type - rx mask is 0xff, tx mask is 0x11 (dataline 1 and 4 enabled). - -Optional properties: - - - big-endian : Boolean property, required if all the SAI - registers are big-endian rather than little-endian. - -Optional properties (for mx6ul): - - - fsl,sai-mclk-direction-output: This is a boolean property. If present, - indicates that SAI will output the SAI MCLK clock. - -Note: -- If both fsl,sai-asynchronous and fsl,sai-synchronous-rx are absent, the - default synchronous mode (sync Rx with Tx) will be used, which means both - transmitter and receiver will send and receive data by following clocks - of transmitter. -- fsl,sai-asynchronous and fsl,sai-synchronous-rx are exclusive. - -Example: -sai2: sai@40031000 { - compatible = "fsl,vf610-sai"; - reg = <0x40031000 0x1000>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_sai2_1>; - clocks = <&clks VF610_CLK_PLATFORM_BUS>, - <&clks VF610_CLK_SAI2>, - <&clks 0>, <&clks 0>; - clock-names = "bus", "mclk1", "mclk2", "mclk3"; - dma-names = "tx", "rx"; - dmas = <&edma0 0 VF610_EDMA_MUXID0_SAI2_TX>, - <&edma0 0 VF610_EDMA_MUXID0_SAI2_RX>; - big-endian; - lsb-first; -}; -- cgit v1.2.3 From eab9100d9898cbd37882b04415b12156f8942f18 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 9 Aug 2022 18:08:09 -0700 Subject: ASoC: mchp-spdiftx: Fix clang -Wbitfield-constant-conversion A recent change in clang strengthened its -Wbitfield-constant-conversion to warn when 1 is assigned to a 1-bit signed integer bitfield, as it can only be 0 or -1, not 1: sound/soc/atmel/mchp-spdiftx.c:505:20: error: implicit truncation from 'int' to bit-field changes value from 1 to -1 [-Werror,-Wbitfield-constant-conversion] dev->gclk_enabled = 1; ^ ~ 1 error generated. The actual value of the field is never checked, just that it is not zero, so there is not a real bug here. However, it is simple enough to silence the warning by making the bitfield unsigned, which matches the mchp-spdifrx driver. Fixes: 06ca24e98e6b ("ASoC: mchp-spdiftx: add driver for S/PDIF TX Controller") Link: https://github.com/ClangBuiltLinux/linux/issues/1686 Link: https://github.com/llvm/llvm-project/commit/82afc9b169a67e8b8a1862fb9c41a2cd974d6691 Signed-off-by: Nathan Chancellor Reviewed-by: Nick Desaulniers Link: https://lore.kernel.org/r/20220810010809.2024482-1-nathan@kernel.org Signed-off-by: Mark Brown --- sound/soc/atmel/mchp-spdiftx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/atmel/mchp-spdiftx.c b/sound/soc/atmel/mchp-spdiftx.c index 4850a177803d..ab2d7a791f39 100644 --- a/sound/soc/atmel/mchp-spdiftx.c +++ b/sound/soc/atmel/mchp-spdiftx.c @@ -196,7 +196,7 @@ struct mchp_spdiftx_dev { struct clk *pclk; struct clk *gclk; unsigned int fmt; - int gclk_enabled:1; + unsigned int gclk_enabled:1; }; static inline int mchp_spdiftx_is_running(struct mchp_spdiftx_dev *dev) -- cgit v1.2.3 From b9f0a8ffd6265e7d8c7464a7990330da85ee07ef Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 3 Aug 2022 12:09:00 +0300 Subject: ASoC: mediatek: mt8186: remove unnecessary NULL check The "i2s_priv" pointer cannot be NULL. Some NULL checks were deleted in commit d7bffbe9cbd3 ("ASoC: mediatek: mt8186: remove unnecessary judgments") but this one was accidentally left behind. Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/Yuo7LGPk8KnBW6ac@kili Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8186/mt8186-dai-i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c b/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c index ec79e2f2a54d..d7a227169548 100644 --- a/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c +++ b/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c @@ -968,7 +968,7 @@ static int mtk_dai_i2s_config(struct mtk_base_afe *afe, } /* set share i2s */ - if (i2s_priv && i2s_priv->share_i2s_id >= 0) { + if (i2s_priv->share_i2s_id >= 0) { ret = mtk_dai_i2s_config(afe, params, i2s_priv->share_i2s_id); if (ret) return ret; -- cgit v1.2.3 From 1b5efeabf75a74043f1eb509ca3ac183b3ffaf89 Mon Sep 17 00:00:00 2001 From: Xin Gao Date: Mon, 8 Aug 2022 23:39:10 +0800 Subject: ASoC: Variable type completion 'unsigned int' is better than 'unsigned'. Signed-off-by: Xin Gao Link: https://lore.kernel.org/r/20220808153910.59545-1-gaoxin@cdjrlc.com Signed-off-by: Mark Brown --- sound/soc/codecs/uda134x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 2db3d8a60c7a..1a62bec94005 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -450,7 +450,7 @@ static int uda134x_soc_probe(struct snd_soc_component *component) struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component); struct uda134x_platform_data *pd = uda134x->pd; const struct snd_soc_dapm_widget *widgets; - unsigned num_widgets; + unsigned int num_widgets; int ret; printk(KERN_INFO "UDA134X SoC Audio Codec\n"); -- cgit v1.2.3 From 1ca726424a12962f2c2656cc9cdd0b8668117e8f Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Mon, 1 Aug 2022 10:40:34 +0100 Subject: ASoC: Intel: cirrus-common: Use UID to map correct amp to prefix Since the order of the amps in the ACPI determines the device name, and the ACPI order may change depending on hardware configuration, use UID to dynamically compute the dai links, allowing dynamic assignment of the name_prefix. The UIDs for these amps in ACPI are fixed, and map to a name_prefix, where: UID 0x0 -> WL UID 0x1 -> WR UID 0x2 -> TL UID 0x3 -> TR Signed-off-by: Stefan Binding Signed-off-by: Vitaly Rodionov Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220801094034.3927841-1-sbinding@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_cirrus_common.c | 92 ++++++++++++++++-------------- 1 file changed, 49 insertions(+), 43 deletions(-) diff --git a/sound/soc/intel/boards/sof_cirrus_common.c b/sound/soc/intel/boards/sof_cirrus_common.c index f4192df962d6..6e39eda77385 100644 --- a/sound/soc/intel/boards/sof_cirrus_common.c +++ b/sound/soc/intel/boards/sof_cirrus_common.c @@ -10,6 +10,9 @@ #include "../../codecs/cs35l41.h" #include "sof_cirrus_common.h" +#define CS35L41_HID "CSC3541" +#define CS35L41_MAX_AMPS 4 + /* * Cirrus Logic CS35L41/CS35L53 */ @@ -35,50 +38,12 @@ static const struct snd_soc_dapm_route cs35l41_dapm_routes[] = { {"TR Spk", NULL, "TR SPK"}, }; -static struct snd_soc_dai_link_component cs35l41_components[] = { - { - .name = CS35L41_DEV0_NAME, - .dai_name = CS35L41_CODEC_DAI, - }, - { - .name = CS35L41_DEV1_NAME, - .dai_name = CS35L41_CODEC_DAI, - }, - { - .name = CS35L41_DEV2_NAME, - .dai_name = CS35L41_CODEC_DAI, - }, - { - .name = CS35L41_DEV3_NAME, - .dai_name = CS35L41_CODEC_DAI, - }, -}; +static struct snd_soc_dai_link_component cs35l41_components[CS35L41_MAX_AMPS]; /* * Mapping between ACPI instance id and speaker position. - * - * Four speakers: - * 0: Tweeter left, 1: Woofer left - * 2: Tweeter right, 3: Woofer right */ -static struct snd_soc_codec_conf cs35l41_codec_conf[] = { - { - .dlc = COMP_CODEC_CONF(CS35L41_DEV0_NAME), - .name_prefix = "TL", - }, - { - .dlc = COMP_CODEC_CONF(CS35L41_DEV1_NAME), - .name_prefix = "WL", - }, - { - .dlc = COMP_CODEC_CONF(CS35L41_DEV2_NAME), - .name_prefix = "TR", - }, - { - .dlc = COMP_CODEC_CONF(CS35L41_DEV3_NAME), - .name_prefix = "WR", - }, -}; +static struct snd_soc_codec_conf cs35l41_codec_conf[CS35L41_MAX_AMPS]; static int cs35l41_init(struct snd_soc_pcm_runtime *rtd) { @@ -117,10 +82,10 @@ static int cs35l41_init(struct snd_soc_pcm_runtime *rtd) static const struct { unsigned int rx[2]; } cs35l41_channel_map[] = { - {.rx = {0, 1}}, /* TL */ {.rx = {0, 1}}, /* WL */ - {.rx = {1, 0}}, /* TR */ {.rx = {1, 0}}, /* WR */ + {.rx = {0, 1}}, /* TL */ + {.rx = {1, 0}}, /* TR */ }; static int cs35l41_hw_params(struct snd_pcm_substream *substream, @@ -175,10 +140,51 @@ static const struct snd_soc_ops cs35l41_ops = { .hw_params = cs35l41_hw_params, }; +static const char * const cs35l41_name_prefixes[] = { "WL", "WR", "TL", "TR" }; + +/* + * Expected UIDs are integers (stored as strings). + * UID Mapping is fixed: + * UID 0x0 -> WL + * UID 0x1 -> WR + * UID 0x2 -> TL + * UID 0x3 -> TR + * Note: If there are less than 4 Amps, UIDs still map to WL/WR/TL/TR. Dynamic code will only create + * dai links for UIDs which exist, and ignore non-existant ones. Only 2 or 4 amps are expected. + * Return number of codecs found. + */ +static int cs35l41_compute_codec_conf(void) +{ + const char * const uid_strings[] = { "0", "1", "2", "3" }; + unsigned int uid, sz = 0; + struct acpi_device *adev; + struct device *physdev; + + for (uid = 0; uid < CS35L41_MAX_AMPS; uid++) { + adev = acpi_dev_get_first_match_dev(CS35L41_HID, uid_strings[uid], -1); + if (!adev) { + pr_devel("Cannot find match for HID %s UID %u (%s)\n", CS35L41_HID, uid, + cs35l41_name_prefixes[uid]); + continue; + } + physdev = get_device(acpi_get_first_physical_node(adev)); + cs35l41_components[sz].name = dev_name(physdev); + cs35l41_components[sz].dai_name = CS35L41_CODEC_DAI; + cs35l41_codec_conf[sz].dlc.name = dev_name(physdev); + cs35l41_codec_conf[sz].name_prefix = cs35l41_name_prefixes[uid]; + acpi_dev_put(adev); + sz++; + } + + if (sz != 2 && sz != 4) + pr_warn("Invalid number of cs35l41 amps found: %d, expected 2 or 4\n", sz); + return sz; +} + void cs35l41_set_dai_link(struct snd_soc_dai_link *link) { + link->num_codecs = cs35l41_compute_codec_conf(); link->codecs = cs35l41_components; - link->num_codecs = ARRAY_SIZE(cs35l41_components); link->init = cs35l41_init; link->ops = &cs35l41_ops; } -- cgit v1.2.3 From 51eea3a6fb4d39c2cc71824e6eee5949d7ae4d1c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 11 Aug 2022 14:01:26 +0300 Subject: ASoC: mt6359: fix tests for platform_get_irq() failure The platform_get_irq() returns negative error codes. It can't actually return zero, but if it did that should be treated as success. Fixes: eef07b9e0925 ("ASoC: mediatek: mt6359: add MT6359 accdet jack driver") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/YvThhr86N3qQM2EO@kili Signed-off-by: Mark Brown --- sound/soc/codecs/mt6359-accdet.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/mt6359-accdet.c b/sound/soc/codecs/mt6359-accdet.c index c190628e2905..7f624854948c 100644 --- a/sound/soc/codecs/mt6359-accdet.c +++ b/sound/soc/codecs/mt6359-accdet.c @@ -965,7 +965,7 @@ static int mt6359_accdet_probe(struct platform_device *pdev) mutex_init(&priv->res_lock); priv->accdet_irq = platform_get_irq(pdev, 0); - if (priv->accdet_irq) { + if (priv->accdet_irq >= 0) { ret = devm_request_threaded_irq(&pdev->dev, priv->accdet_irq, NULL, mt6359_accdet_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, @@ -979,7 +979,7 @@ static int mt6359_accdet_probe(struct platform_device *pdev) if (priv->caps & ACCDET_PMIC_EINT0) { priv->accdet_eint0 = platform_get_irq(pdev, 1); - if (priv->accdet_eint0) { + if (priv->accdet_eint0 >= 0) { ret = devm_request_threaded_irq(&pdev->dev, priv->accdet_eint0, NULL, mt6359_accdet_irq, @@ -994,7 +994,7 @@ static int mt6359_accdet_probe(struct platform_device *pdev) } } else if (priv->caps & ACCDET_PMIC_EINT1) { priv->accdet_eint1 = platform_get_irq(pdev, 2); - if (priv->accdet_eint1) { + if (priv->accdet_eint1 >= 0) { ret = devm_request_threaded_irq(&pdev->dev, priv->accdet_eint1, NULL, mt6359_accdet_irq, -- cgit v1.2.3 From 020adbfb2edae4dd90d7774d08936261e218c171 Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Mon, 15 Aug 2022 08:22:18 +1000 Subject: ASoC: codecs: dt bind. doc for the new TI SRC4392 codec Signed-off-by: Matt Flax Link: https://lore.kernel.org/r/20220814222218.119786-1-flatmax@flatmax.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/ti,src4xxx.yaml | 48 ++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/ti,src4xxx.yaml diff --git a/Documentation/devicetree/bindings/sound/ti,src4xxx.yaml b/Documentation/devicetree/bindings/sound/ti,src4xxx.yaml new file mode 100644 index 000000000000..9681b72b4918 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ti,src4xxx.yaml @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/ti,src4xxx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments SRC4392 Device Tree Bindings + +description: | + The SRC4392 is a digital audio codec that can be connected via + I2C or SPI. Currently, only I2C bus is supported. + +maintainers: + - Matt Flax + +allOf: + - $ref: name-prefix.yaml# + +properties: + compatible: + const: ti,src4392 + + "#sound-dai-cells": + const: 0 + + reg: + maxItems: 1 + +required: + - "#sound-dai-cells" + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + audio-codec@70 { + #sound-dai-cells = <0>; + compatible = "ti,src4392"; + reg = <0x70>; + }; + }; +... -- cgit v1.2.3 From 7d67657cb472a80d54457362bc421f2b57ee250b Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 6 Aug 2022 07:45:48 +0200 Subject: ASoC: sam9g20_wm8731: Simplify some error message dev_err_probe() already prints the error code in a human readable way, so there is no need to duplicate it as a numerical value at the end of the message. Fixes: 29f4078f777f ("ASoC: sam9g20_wm8731: Use dev_err_probe() for snd_soc_register_card()") Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/fb959b3bda689aa47e1fbe9948de957b77530b24.1659764734.git.christophe.jaillet@wanadoo.fr Signed-off-by: Mark Brown --- sound/soc/atmel/sam9g20_wm8731.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index 4d25fb61c652..1430642c8433 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -172,7 +172,7 @@ static int at91sam9g20ek_audio_probe(struct platform_device *pdev) ret = snd_soc_register_card(card); if (ret) { dev_err_probe(&pdev->dev, ret, - "snd_soc_register_card() failed: %d\n", ret); + "snd_soc_register_card() failed\n"); goto err; } -- cgit v1.2.3 From 088f115c6ff664c8afe003bd542e1e662a72aaed Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 3 Aug 2022 11:02:28 +0800 Subject: ASoC: imx-rpmsg: Support configure sysclk for codec dai Some codecs need to configure the sysclk even with slave mode, otherwise it may not work properly with some case. wm8960 is the one that need sysclk be configured, so add late_probe() to call the snd_soc_dai_set_sysclk() of codec Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1659495748-10876-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/imx-rpmsg.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/sound/soc/fsl/imx-rpmsg.c b/sound/soc/fsl/imx-rpmsg.c index 2e117311e582..4d99f4858a14 100644 --- a/sound/soc/fsl/imx-rpmsg.c +++ b/sound/soc/fsl/imx-rpmsg.c @@ -19,6 +19,7 @@ struct imx_rpmsg { struct snd_soc_dai_link dai; struct snd_soc_card card; + unsigned long sysclk; }; static const struct snd_soc_dapm_widget imx_rpmsg_dapm_widgets[] = { @@ -28,6 +29,27 @@ static const struct snd_soc_dapm_widget imx_rpmsg_dapm_widgets[] = { SND_SOC_DAPM_MIC("Main MIC", NULL), }; +static int imx_rpmsg_late_probe(struct snd_soc_card *card) +{ + struct imx_rpmsg *data = snd_soc_card_get_drvdata(card); + struct snd_soc_pcm_runtime *rtd = list_first_entry(&card->rtd_list, + struct snd_soc_pcm_runtime, list); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct device *dev = card->dev; + int ret; + + if (!data->sysclk) + return 0; + + ret = snd_soc_dai_set_sysclk(codec_dai, 0, data->sysclk, SND_SOC_CLOCK_IN); + if (ret && ret != -ENOTSUPP) { + dev_err(dev, "failed to set sysclk in %s\n", __func__); + return ret; + } + + return 0; +} + static int imx_rpmsg_probe(struct platform_device *pdev) { struct snd_soc_dai_link_component *dlc; @@ -72,12 +94,18 @@ static int imx_rpmsg_probe(struct platform_device *pdev) data->dai.codecs->dai_name = "snd-soc-dummy-dai"; data->dai.codecs->name = "snd-soc-dummy"; } else { + struct clk *clk; + data->dai.codecs->of_node = args.np; ret = snd_soc_get_dai_name(&args, &data->dai.codecs->dai_name); if (ret) { dev_err(&pdev->dev, "Unable to get codec_dai_name\n"); goto fail; } + + clk = devm_get_clk_from_child(&pdev->dev, args.np, NULL); + if (!IS_ERR(clk)) + data->sysclk = clk_get_rate(clk); } data->dai.cpus->dai_name = dev_name(&rpmsg_pdev->dev); @@ -103,6 +131,7 @@ static int imx_rpmsg_probe(struct platform_device *pdev) data->card.owner = THIS_MODULE; data->card.dapm_widgets = imx_rpmsg_dapm_widgets; data->card.num_dapm_widgets = ARRAY_SIZE(imx_rpmsg_dapm_widgets); + data->card.late_probe = imx_rpmsg_late_probe; /* * Inoder to use common api to get card name and audio routing. * Use parent of_node for this device, revert it after finishing using -- cgit v1.2.3 From efe30e2cb6ff87467389cece8ce604f6601059f9 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 15 Aug 2022 12:33:46 +0100 Subject: ASoC: soc-utils: Improve kerneldoc for snd_soc_tdm_params_to_bclk() The statement that snd_soc_tdm_params_to_bclk() is equivalent to snd_soc_params_to_bclk() if tdm_width==tdm_slots==0 is not accurate, it is only true is slot_multiple is also <2. However, the description of special-case behaviour in terms of pairs of tdm_width and tdm_slot values is not particularly helpful so we might as well take the opportunity to rework the description to say the same thing in a simpler way. The behaviour of a pair of values is obvious from a description of each argument. At the same time make a few edits to clarify the rest of the description. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20220815113346.3805075-1-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/soc-utils.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index 70c380c0ac7b..a3b6df2378b4 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -56,23 +56,24 @@ EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk); /** * snd_soc_tdm_params_to_bclk - calculate bclk from params and tdm slot info. * - * Calculate the bclk from the params sample rate and the tdm slot count and - * tdm slot width. Either or both of tdm_width and tdm_slots can be 0. + * Calculate the bclk from the params sample rate, the tdm slot count and the + * tdm slot width. Optionally round-up the slot count to a given multiple. + * Either or both of tdm_width and tdm_slots can be 0. * - * If tdm_width == 0 and tdm_slots > 0: the params_width will be used. - * If tdm_width > 0 and tdm_slots == 0: the params_channels will be used - * as the slot count. - * Both tdm_width and tdm_slots are 0: this is equivalent to calling - * snd_soc_params_to_bclk(). + * If tdm_width == 0: use params_width() as the slot width. + * If tdm_slots == 0: use params_channels() as the slot count. * - * If slot_multiple > 1 the slot count (or params_channels if tdm_slots == 0) - * will be rounded up to a multiple of this value. This is mainly useful for + * If slot_multiple > 1 the slot count (or params_channels() if tdm_slots == 0) + * will be rounded up to a multiple of slot_multiple. This is mainly useful for * I2S mode, which has a left and right phase so the number of slots is always * a multiple of 2. * + * If tdm_width == 0 && tdm_slots == 0 && slot_multiple < 2, this is equivalent + * to calling snd_soc_params_to_bclk(). + * * @params: Pointer to struct_pcm_hw_params. - * @tdm_width: Width in bits of the tdm slots. - * @tdm_slots: Number of tdm slots per frame. + * @tdm_width: Width in bits of the tdm slots. Must be >= 0. + * @tdm_slots: Number of tdm slots per frame. Must be >= 0. * @slot_multiple: If >1 roundup slot count to a multiple of this value. * * Return: bclk frequency in Hz, else a negative error code if params format -- cgit v1.2.3 From 7c32710c8be4be8a2999a648bcb4e899e12f9a4b Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Mon, 15 Aug 2022 18:58:15 +0200 Subject: ASoC: Intel: hsw_rt5640: Rename module Change kernel module name from snd_soc_sst_haswell to snd_soc_hsw_rt5640 to better reflect its purpose. Reviewed-by: Kai Vehmanen Reviewed-by: Pierre-Louis Bossart Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20220815165818.3050649-2-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index eea1e26acfda..c1e532c47e5c 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-soc-sst-haswell-objs := hsw_rt5640.o +snd-soc-hsw-rt5640-objs := hsw_rt5640.o snd-soc-sst-bdw-rt5650-mach-objs := bdw-rt5650.o snd-soc-sst-bdw-rt5677-mach-objs := bdw-rt5677.o snd-soc-sst-broadwell-objs := bdw_rt286.o @@ -47,7 +47,7 @@ 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_HASWELL_MACH) += snd-soc-hsw-rt5640.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 obj-$(CONFIG_SND_SOC_INTEL_SOF_PCM512x_MACH) += snd-soc-sst-sof-pcm512x.o -- cgit v1.2.3 From efbaa66852ee98fbd661beef8663d2992cfa901a Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Mon, 15 Aug 2022 18:58:16 +0200 Subject: ASoC: Intel: bdw_rt286: Rename module Change kernel module name from snd_soc_sst_broadwell to snd_soc_bdw_rt286 to better reflect its purpose. Reviewed-by: Kai Vehmanen Reviewed-by: Pierre-Louis Bossart Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20220815165818.3050649-3-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index c1e532c47e5c..53458e748191 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -2,7 +2,7 @@ snd-soc-hsw-rt5640-objs := hsw_rt5640.o snd-soc-sst-bdw-rt5650-mach-objs := bdw-rt5650.o snd-soc-sst-bdw-rt5677-mach-objs := bdw-rt5677.o -snd-soc-sst-broadwell-objs := bdw_rt286.o +snd-soc-bdw-rt286-objs := bdw_rt286.o snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o snd-soc-sst-bxt-rt298-objs := bxt_rt298.o snd-soc-sst-sof-pcm512x-objs := sof_pcm512x.o @@ -53,7 +53,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o obj-$(CONFIG_SND_SOC_INTEL_SOF_PCM512x_MACH) += snd-soc-sst-sof-pcm512x.o obj-$(CONFIG_SND_SOC_INTEL_SOF_WM8804_MACH) += snd-soc-sst-sof-wm8804.o obj-$(CONFIG_SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH) += snd-soc-sst-glk-rt5682_max98357a.o -obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o +obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-bdw-rt286.o obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5650_MACH) += snd-soc-sst-bdw-rt5650-mach.o obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH) += snd-soc-sst-bdw-rt5677-mach.o obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o -- cgit v1.2.3 From 02f29be6a553e4ebee5b718165b01cc4f17dffa8 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Mon, 15 Aug 2022 18:58:17 +0200 Subject: ASoC: Intel: catpt: Drop SND_SOC_ACPI_INTEL_MATCH dependency catpt-driver does not make use of most of the fields found in the descriptor table and is the sole user of haswell machines list. Move the tables to local directory and clean them up so it's clear what's actually used by the solution. Reviewed-by: Kai Vehmanen Reviewed-by: Pierre-Louis Bossart Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20220815165818.3050649-4-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 2 +- sound/soc/intel/catpt/device.c | 33 ++++++++++++++++++++++++++++++--- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index ded903f95b67..d2ca710ac3fa 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -23,7 +23,7 @@ config SND_SOC_INTEL_CATPT depends on ACPI || COMPILE_TEST depends on DMADEVICES && SND_DMA_SGBUF select DW_DMAC_CORE - select SND_SOC_ACPI_INTEL_MATCH + select SND_SOC_ACPI if ACPI select WANT_DEV_COREDUMP select SND_INTEL_DSP_CONFIG help diff --git a/sound/soc/intel/catpt/device.c b/sound/soc/intel/catpt/device.c index d48a71d2cf1e..d5d08bd766c7 100644 --- a/sound/soc/intel/catpt/device.c +++ b/sound/soc/intel/catpt/device.c @@ -22,7 +22,6 @@ #include #include #include -#include #include "core.h" #include "registers.h" @@ -310,8 +309,36 @@ static int catpt_acpi_remove(struct platform_device *pdev) return 0; } +static struct snd_soc_acpi_mach lpt_machines[] = { + { + .id = "INT33CA", + .drv_name = "hsw_rt5640", + }, + {} +}; + +static struct snd_soc_acpi_mach wpt_machines[] = { + { + .id = "INT33CA", + .drv_name = "hsw_rt5640", + }, + { + .id = "INT343A", + .drv_name = "bdw_rt286", + }, + { + .id = "10EC5650", + .drv_name = "bdw-rt5650", + }, + { + .id = "RT5677CE", + .drv_name = "bdw-rt5677", + }, + {} +}; + static struct catpt_spec lpt_desc = { - .machines = snd_soc_acpi_intel_haswell_machines, + .machines = lpt_machines, .core_id = 0x01, .host_dram_offset = 0x000000, .host_iram_offset = 0x080000, @@ -326,7 +353,7 @@ static struct catpt_spec lpt_desc = { }; static struct catpt_spec wpt_desc = { - .machines = snd_soc_acpi_intel_broadwell_machines, + .machines = wpt_machines, .core_id = 0x02, .host_dram_offset = 0x000000, .host_iram_offset = 0x0A0000, -- cgit v1.2.3 From a25e1183ea2d0feb068794adf0249919ea7e0d8c Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Mon, 15 Aug 2022 18:58:18 +0200 Subject: ASoC: Intel: Drop legacy HSW/BDW board-match information With board-matching information for legacy solution moved to local directory, there is no need to expose it globally. Reviewed-by: Kai Vehmanen Reviewed-by: Pierre-Louis Bossart Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20220815165818.3050649-5-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- include/sound/soc-acpi-intel-match.h | 1 - sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c | 15 --------------- 2 files changed, 16 deletions(-) diff --git a/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h index bc7fd46ec2bc..14d783952548 100644 --- a/include/sound/soc-acpi-intel-match.h +++ b/include/sound/soc-acpi-intel-match.h @@ -14,7 +14,6 @@ * these tables are not constants, some fields can be used for * pdata or machine ops */ -extern struct snd_soc_acpi_mach snd_soc_acpi_intel_haswell_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[]; diff --git a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c index cbcb649604e5..6daf60b1edf1 100644 --- a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c @@ -9,40 +9,25 @@ #include #include -struct snd_soc_acpi_mach snd_soc_acpi_intel_haswell_machines[] = { - { - .id = "INT33CA", - .drv_name = "hsw_rt5640", - .fw_filename = "intel/IntcSST1.bin", - .sof_tplg_filename = "sof-hsw.tplg", - }, - {} -}; -EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_haswell_machines); - struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = { { .id = "INT343A", .drv_name = "bdw_rt286", - .fw_filename = "intel/IntcSST2.bin", .sof_tplg_filename = "sof-bdw-rt286.tplg", }, { .id = "10EC5650", .drv_name = "bdw-rt5650", - .fw_filename = "intel/IntcSST2.bin", .sof_tplg_filename = "sof-bdw-rt5650.tplg", }, { .id = "RT5677CE", .drv_name = "bdw-rt5677", - .fw_filename = "intel/IntcSST2.bin", .sof_tplg_filename = "sof-bdw-rt5677.tplg", }, { .id = "INT33CA", .drv_name = "hsw_rt5640", - .fw_filename = "intel/IntcSST2.bin", .sof_tplg_filename = "sof-bdw-rt5640.tplg", }, {} -- cgit v1.2.3 From 8c6789f4e2d4ee7d6c8c60daa88ea7a4c4cf6779 Mon Sep 17 00:00:00 2001 From: Zhu Ning Date: Tue, 16 Aug 2022 10:44:55 +0800 Subject: ASoC: dt-bindings: Add Everest ES8326 audio CODEC Add device tree binding documentation for Everest ES8326 ---- v5 tested by dtschema Signed-off-by: David Yang Signed-off-by: Zhu Ning Link: https://lore.kernel.org/r/20220816024456.4475-1-zhuning0077@gmail.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/everest,es8326.yaml | 116 +++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100755 Documentation/devicetree/bindings/sound/everest,es8326.yaml diff --git a/Documentation/devicetree/bindings/sound/everest,es8326.yaml b/Documentation/devicetree/bindings/sound/everest,es8326.yaml new file mode 100755 index 000000000000..07781408e788 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/everest,es8326.yaml @@ -0,0 +1,116 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/everest,es8326.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Everest ES8326 audio CODEC + +maintainers: + - David Yang + +properties: + compatible: + const: everest,es8326 + + reg: + maxItems: 1 + + clocks: + items: + - description: clock for master clock (MCLK) + + clock-names: + items: + - const: mclk + + "#sound-dai-cells": + const: 0 + + everest,jack-pol: + $ref: /schemas/types.yaml#/definitions/uint8 + description: | + just the value of reg 57. Bit(3) decides whether the jack polarity is inverted. + Bit(2) decides whether the button on the headset is inverted. + Bit(1)/(0) decides the mic properity to be OMTP/CTIA or auto. + minimum: 0x00 + maximum: 0x0f + default: 0x0f + + everest,mic1-src: + $ref: /schemas/types.yaml#/definitions/uint8 + description: + the value of reg 2A when headset plugged. + minimum: 0x00 + maximum: 0x77 + default: 0x22 + + everest,mic2-src: + $ref: /schemas/types.yaml#/definitions/uint8 + description: + the value of reg 2A when headset unplugged. + minimum: 0x00 + maximum: 0x77 + default: 0x44 + + everest,jack-detect-inverted: + $ref: /schemas/types.yaml#/definitions/flag + description: + Defined to invert the jack detection. + + everest,interrupt-src: + $ref: /schemas/types.yaml#/definitions/uint8 + description: | + value of reg 0x58, Defines the interrupt source. + Bit(2) 1 means button press triggers irq, 0 means not. + Bit(3) 1 means PIN9 is the irq source for jack detection. When set to 0, + bias change on PIN9 do not triggers irq. + Bit(4) 1 means PIN27 is the irq source for jack detection. + Bit(5) 1 means PIN9 is the irq source after MIC detect. + Bit(6) 1 means PIN27 is the irq source after MIC detect. + minimum: 0 + maximum: 0x3c + default: 0x08 + + everest,interrupt-clk: + $ref: /schemas/types.yaml#/definitions/uint8 + description: | + value of reg 0x59, Defines the interrupt output behavior. + Bit(0-3) 0 means irq pulse equals 512*internal clock + 1 means irq pulse equals 1024*internal clock + 2 means ... + 7 means irq pulse equals 65536*internal clock + 8 means irq mutes PA + 9 means irq mutes PA and DAC output + Bit(4) 1 means we invert the interrupt output. + Bit(6) 1 means the chip do not detect jack type after button released. + 0 means the chip detect jack type again after button released. + minimum: 0 + maximum: 0x7f + default: 0x45 + +required: + - compatible + - reg + - "#sound-dai-cells" + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + es8326: codec@19 { + compatible = "everest,es8326"; + reg = <0x19>; + clocks = <&clks 10>; + clock-names = "mclk"; + #sound-dai-cells = <0>; + everest,mic1-src = [22]; + everest,mic2-src = [44]; + everest,jack-pol = [0e]; + everest,interrupt-src = [08]; + everest,interrupt-clk = [45]; + }; + }; -- cgit v1.2.3 From 5c439937775d77a334696a98fb2a25dee72ffa2d Mon Sep 17 00:00:00 2001 From: Zhu Ning Date: Tue, 16 Aug 2022 10:44:56 +0800 Subject: ASoC: codecs: add support for ES8326 The ES8326 codec is not compatible with ES8316 and requires a dedicated driver. ------ v6 remove rate 96000 remove HEX suffix Signed-off-by: David Yang Signed-off-by: Zhu Ning Link: https://lore.kernel.org/r/20220816024456.4475-2-zhuning0077@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/es8326.c | 905 ++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/es8326.h | 182 ++++++++++ 4 files changed, 1094 insertions(+) create mode 100755 sound/soc/codecs/es8326.c create mode 100755 sound/soc/codecs/es8326.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index fe445465f877..5926b33ba09e 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -98,6 +98,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_DA9055 imply SND_SOC_DMIC imply SND_SOC_ES8316 + imply SND_SOC_ES8326 imply SND_SOC_ES8328_SPI imply SND_SOC_ES8328_I2C imply SND_SOC_ES7134 @@ -914,6 +915,10 @@ config SND_SOC_ES8316 tristate "Everest Semi ES8316 CODEC" depends on I2C +config SND_SOC_ES8326 + tristate "Everest Semi ES8326 CODEC" + depends on I2C + config SND_SOC_ES8328 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index a599b727c65b..16a01635dd04 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -100,6 +100,7 @@ snd-soc-dmic-objs := dmic.o snd-soc-es7134-objs := es7134.o snd-soc-es7241-objs := es7241.o snd-soc-es8316-objs := es8316.o +snd-soc-es8326-objs := es8326.o snd-soc-es8328-objs := es8328.o snd-soc-es8328-i2c-objs := es8328-i2c.o snd-soc-es8328-spi-objs := es8328-spi.o @@ -457,6 +458,7 @@ obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o obj-$(CONFIG_SND_SOC_ES7134) += snd-soc-es7134.o obj-$(CONFIG_SND_SOC_ES7241) += snd-soc-es7241.o obj-$(CONFIG_SND_SOC_ES8316) += snd-soc-es8316.o +obj-$(CONFIG_SND_SOC_ES8326) += snd-soc-es8326.o obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c new file mode 100755 index 000000000000..975302b2a61d --- /dev/null +++ b/sound/soc/codecs/es8326.c @@ -0,0 +1,905 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// es8326.c -- es8326 ALSA SoC audio driver +// Copyright Everest Semiconductor Co., Ltd +// +// Authors: David Yang +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "es8326.h" + +struct es8326_priv { + struct clk *mclk; + struct i2c_client *i2c; + struct regmap *regmap; + struct snd_soc_component *component; + struct delayed_work jack_detect_work; + struct delayed_work button_press_work; + struct snd_soc_jack *jack; + int irq; + /* The lock protects the situation that an irq is generated + * while enabling or disabling or during an irq. + */ + struct mutex lock; + u8 mic1_src; + u8 mic2_src; + u8 jack_pol; + u8 interrupt_src; + u8 interrupt_clk; + bool jd_inverted; + unsigned int sysclk; +}; + +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(dac_vol_tlv, -9550, 50, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_vol_tlv, -9550, 50, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_analog_pga_tlv, 0, 300, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_pga_tlv, 0, 600, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(softramp_rate, 0, 100, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(drc_target_tlv, -3200, 200, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(drc_recovery_tlv, -125, 250, 0); + +static const char *const winsize[] = { + "0.25db/2 LRCK", + "0.25db/4 LRCK", + "0.25db/8 LRCK", + "0.25db/16 LRCK", + "0.25db/32 LRCK", + "0.25db/64 LRCK", + "0.25db/128 LRCK", + "0.25db/256 LRCK", + "0.25db/512 LRCK", + "0.25db/1024 LRCK", + "0.25db/2048 LRCK", + "0.25db/4096 LRCK", + "0.25db/8192 LRCK", + "0.25db/16384 LRCK", + "0.25db/32768 LRCK", + "0.25db/65536 LRCK", +}; + +static const char *const dacpol_txt[] = { + "Normal", "R Invert", "L Invert", "L + R Invert" }; + +static const struct soc_enum dacpol = + SOC_ENUM_SINGLE(ES8326_DAC_DSM, 4, 4, dacpol_txt); +static const struct soc_enum alc_winsize = + SOC_ENUM_SINGLE(ES8326_ADC_RAMPRATE, 4, 16, winsize); +static const struct soc_enum drc_winsize = + SOC_ENUM_SINGLE(ES8326_DRC_WINSIZE, 4, 16, winsize); + +static const struct snd_kcontrol_new es8326_snd_controls[] = { + SOC_SINGLE_TLV("DAC Playback Volume", ES8326_DAC_VOL, 0, 0xbf, 0, dac_vol_tlv), + SOC_ENUM("Playback Polarity", dacpol), + SOC_SINGLE_TLV("DAC Ramp Rate", ES8326_DAC_RAMPRATE, 0, 0x0f, 0, softramp_rate), + SOC_SINGLE_TLV("DRC Recovery Level", ES8326_DRC_RECOVERY, 0, 4, 0, drc_recovery_tlv), + SOC_ENUM("DRC Winsize", drc_winsize), + SOC_SINGLE_TLV("DRC Target Level", ES8326_DRC_WINSIZE, 0, 0x0f, 0, drc_target_tlv), + + SOC_DOUBLE_R_TLV("ADC Capture Volume", ES8326_ADC1_VOL, ES8326_ADC2_VOL, 0, 0xff, 0, + adc_vol_tlv), + SOC_DOUBLE_TLV("ADC PGA Volume", ES8326_ADC_SCALE, 4, 0, 5, 0, adc_pga_tlv), + SOC_SINGLE_TLV("ADC PGA Gain Volume", ES8326_PGAGAIN, 0, 10, 0, adc_analog_pga_tlv), + SOC_SINGLE_TLV("ADC Ramp Rate", ES8326_ADC_RAMPRATE, 0, 0x0f, 0, softramp_rate), + SOC_SINGLE("ALC Capture Switch", ES8326_ALC_RECOVERY, 3, 1, 0), + SOC_SINGLE_TLV("ALC Capture Recovery Level", ES8326_ALC_LEVEL, + 0, 4, 0, drc_recovery_tlv), + SOC_ENUM("ALC Capture Winsize", alc_winsize), + SOC_SINGLE_TLV("ALC Capture Target Level", ES8326_ALC_LEVEL, + 0, 0x0f, 0, drc_target_tlv), + +}; + +static const struct snd_soc_dapm_widget es8326_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("MIC1"), + SND_SOC_DAPM_INPUT("MIC2"), + SND_SOC_DAPM_INPUT("MIC3"), + SND_SOC_DAPM_INPUT("MIC4"), + + SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0), + + /* Digital Interface */ + SND_SOC_DAPM_AIF_OUT("I2S OUT", "I2S1 Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("I2S IN", "I2S1 Playback", 0, SND_SOC_NOPM, 0, 0), + + /* ADC Digital Mute */ + SND_SOC_DAPM_PGA("ADC L1", ES8326_ADC_MUTE, 0, 1, NULL, 0), + SND_SOC_DAPM_PGA("ADC R1", ES8326_ADC_MUTE, 1, 1, NULL, 0), + SND_SOC_DAPM_PGA("ADC L2", ES8326_ADC_MUTE, 2, 1, NULL, 0), + SND_SOC_DAPM_PGA("ADC R2", ES8326_ADC_MUTE, 3, 1, NULL, 0), + + /* Analog Power Supply*/ + SND_SOC_DAPM_DAC("Right DAC", NULL, ES8326_ANA_PDN, 0, 1), + SND_SOC_DAPM_DAC("Left DAC", NULL, ES8326_ANA_PDN, 1, 1), + SND_SOC_DAPM_SUPPLY("Analog Power", ES8326_ANA_PDN, 7, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("IBias Power", ES8326_ANA_PDN, 6, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC Vref", ES8326_ANA_PDN, 5, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC Vref", ES8326_ANA_PDN, 4, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("Vref Power", ES8326_ANA_PDN, 3, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("MICBIAS1", ES8326_ANA_MICBIAS, 2, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MICBIAS2", ES8326_ANA_MICBIAS, 3, 0, NULL, 0), + + SND_SOC_DAPM_PGA("LHPMIX", ES8326_DAC2HPMIX, 7, 0, NULL, 0), + SND_SOC_DAPM_PGA("RHPMIX", ES8326_DAC2HPMIX, 3, 0, NULL, 0), + + /* Headphone Charge Pump and Output */ + SND_SOC_DAPM_SUPPLY("HPOR Cal", ES8326_HP_CAL, 7, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("HPOL Cal", ES8326_HP_CAL, 3, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("Headphone Charge Pump", ES8326_HP_DRIVER, + 3, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("Headphone Driver Bias", ES8326_HP_DRIVER, + 2, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("Headphone LDO", ES8326_HP_DRIVER, + 1, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("Headphone Reference", ES8326_HP_DRIVER, + 0, 1, NULL, 0), + SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOR Supply", ES8326_HP_CAL, + ES8326_HPOR_SHIFT, 7, 7, 0), + SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOL Supply", ES8326_HP_CAL, + 0, 7, 7, 0), + + SND_SOC_DAPM_OUTPUT("HPOL"), + SND_SOC_DAPM_OUTPUT("HPOR"), +}; + +static const struct snd_soc_dapm_route es8326_dapm_routes[] = { + {"ADC L1", NULL, "MIC1"}, + {"ADC R1", NULL, "MIC2"}, + {"ADC L2", NULL, "MIC3"}, + {"ADC R2", NULL, "MIC4"}, + + {"ADC L", NULL, "ADC L1"}, + {"ADC R", NULL, "ADC R1"}, + {"ADC L", NULL, "ADC L2"}, + {"ADC R", NULL, "ADC R2"}, + + {"I2S OUT", NULL, "ADC L"}, + {"I2S OUT", NULL, "ADC R"}, + + {"I2S OUT", NULL, "Analog Power"}, + {"I2S OUT", NULL, "ADC Vref"}, + {"I2S OUT", NULL, "Vref Power"}, + {"I2S OUT", NULL, "IBias Power"}, + {"I2S IN", NULL, "Analog Power"}, + {"I2S IN", NULL, "DAC Vref"}, + {"I2S IN", NULL, "Vref Power"}, + {"I2S IN", NULL, "IBias Power"}, + + {"Right DAC", NULL, "I2S IN"}, + {"Left DAC", NULL, "I2S IN"}, + + {"LHPMIX", NULL, "Left DAC"}, + {"RHPMIX", NULL, "Right DAC"}, + + {"HPOR", NULL, "HPOR Cal"}, + {"HPOL", NULL, "HPOL Cal"}, + {"HPOR", NULL, "HPOR Supply"}, + {"HPOL", NULL, "HPOL Supply"}, + {"HPOL", NULL, "Headphone Charge Pump"}, + {"HPOR", NULL, "Headphone Charge Pump"}, + {"HPOL", NULL, "Headphone Driver Bias"}, + {"HPOR", NULL, "Headphone Driver Bias"}, + {"HPOL", NULL, "Headphone LDO"}, + {"HPOR", NULL, "Headphone LDO"}, + {"HPOL", NULL, "Headphone Reference"}, + {"HPOR", NULL, "Headphone Reference"}, + + {"HPOL", NULL, "LHPMIX"}, + {"HPOR", NULL, "RHPMIX"}, +}; + +static const struct regmap_range es8326_volatile_ranges[] = { + regmap_reg_range(ES8326_HP_DETECT, ES8326_HP_DETECT), +}; + +static const struct regmap_access_table es8326_volatile_table = { + .yes_ranges = es8326_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(es8326_volatile_ranges), +}; + +const struct regmap_config es8326_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0xff, + .volatile_table = &es8326_volatile_table, + .cache_type = REGCACHE_RBTREE, +}; + +struct _coeff_div { + u16 fs; + u32 rate; + u32 mclk; + u8 reg4; + u8 reg5; + u8 reg6; + u8 reg7; + u8 reg8; + u8 reg9; + u8 rega; + u8 regb; +}; + +/* codec hifi mclk clock divider coefficients */ +/* {ratio, LRCK, MCLK, REG04, REG05, REG06, REG07, REG08, REG09, REG10, REG11} */ +static const struct _coeff_div coeff_div[] = { + {32, 8000, 256000, 0x60, 0x00, 0x0F, 0x75, 0x0A, 0x1B, 0x1F, 0x7F}, + {32, 16000, 512000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x3F}, + {32, 44100, 1411200, 0x00, 0x00, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {32, 48000, 1536000, 0x00, 0x00, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {36, 8000, 288000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x23, 0x47}, + {36, 16000, 576000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x23, 0x47}, + {48, 8000, 384000, 0x60, 0x02, 0x1F, 0x75, 0x0A, 0x1B, 0x1F, 0x7F}, + {48, 16000, 768000, 0x20, 0x02, 0x0F, 0x75, 0x0A, 0x1B, 0x1F, 0x3F}, + {48, 48000, 2304000, 0x00, 0x02, 0x0D, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {64, 8000, 512000, 0x60, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F}, + {64, 16000, 1024000, 0x20, 0x00, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x3F}, + + {64, 44100, 2822400, 0x00, 0x00, 0x11, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {64, 48000, 3072000, 0x00, 0x00, 0x11, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {72, 8000, 576000, 0x20, 0x00, 0x13, 0x35, 0x0A, 0x1B, 0x23, 0x47}, + {72, 16000, 1152000, 0x20, 0x00, 0x05, 0x75, 0x0A, 0x1B, 0x23, 0x47}, + {96, 8000, 768000, 0x60, 0x02, 0x1D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F}, + {96, 16000, 1536000, 0x20, 0x02, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x3F}, + {100, 48000, 4800000, 0x04, 0x04, 0x3F, 0x6D, 0x38, 0x08, 0x4f, 0x1f}, + {125, 48000, 6000000, 0x04, 0x04, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27}, + {128, 8000, 1024000, 0x60, 0x00, 0x13, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, + {128, 16000, 2048000, 0x20, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, + + {128, 44100, 5644800, 0x00, 0x00, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {128, 48000, 6144000, 0x00, 0x00, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {144, 8000, 1152000, 0x20, 0x00, 0x03, 0x35, 0x0A, 0x1B, 0x23, 0x47}, + {144, 16000, 2304000, 0x20, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x23, 0x47}, + {192, 8000, 1536000, 0x60, 0x02, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F}, + {192, 16000, 3072000, 0x20, 0x02, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x3F}, + {200, 48000, 9600000, 0x04, 0x04, 0x0F, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {250, 48000, 12000000, 0x04, 0x04, 0x0F, 0x2D, 0x0A, 0x0A, 0x27, 0x27}, + {256, 8000, 2048000, 0x60, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, + {256, 16000, 4096000, 0x20, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, + + {256, 44100, 11289600, 0x00, 0x00, 0x10, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {256, 48000, 12288000, 0x00, 0x00, 0x30, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {288, 8000, 2304000, 0x20, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x23, 0x47}, + {384, 8000, 3072000, 0x60, 0x02, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x7F}, + {384, 16000, 6144000, 0x20, 0x02, 0x03, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, + {384, 48000, 18432000, 0x00, 0x02, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {400, 48000, 19200000, 0x09, 0x04, 0x0f, 0x6d, 0x3a, 0x0A, 0x4F, 0x1F}, + {500, 48000, 24000000, 0x18, 0x04, 0x1F, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {512, 8000, 4096000, 0x60, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, + {512, 16000, 8192000, 0x20, 0x00, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, + + {512, 44100, 22579200, 0x00, 0x00, 0x00, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {512, 48000, 24576000, 0x00, 0x00, 0x00, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {768, 8000, 6144000, 0x60, 0x02, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, + {768, 16000, 12288000, 0x20, 0x02, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, + {800, 48000, 38400000, 0x00, 0x18, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, + {1024, 8000, 8192000, 0x60, 0x00, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, + {1024, 16000, 16384000, 0x20, 0x00, 0x00, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, + {1152, 16000, 18432000, 0x20, 0x08, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, + {1536, 8000, 12288000, 0x60, 0x02, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, + + {1536, 16000, 24576000, 0x20, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, + {1625, 8000, 13000000, 0x0C, 0x18, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27}, + {1625, 16000, 26000000, 0x0C, 0x18, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27}, + {2048, 8000, 16384000, 0x60, 0x00, 0x00, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, + {2304, 8000, 18432000, 0x40, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x5F}, + {3072, 8000, 24576000, 0x60, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, + {3250, 8000, 26000000, 0x0C, 0x18, 0x0F, 0x2D, 0x0A, 0x0A, 0x27, 0x27}, + +}; + +static inline int get_coeff(int mclk, int rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { + if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) + return i; + } + + return -EINVAL; +} + +static int es8326_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_component *codec = codec_dai->component; + struct es8326_priv *es8326 = snd_soc_component_get_drvdata(codec); + + es8326->sysclk = freq; + + return 0; +} + +static int es8326_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_component *component = codec_dai->component; + u8 iface = 0; + + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFP: + snd_soc_component_update_bits(component, ES8326_RESET, + ES8326_MASTER_MODE_EN, ES8326_MASTER_MODE_EN); + break; + case SND_SOC_DAIFMT_CBC_CFC: + break; + default: + return -EINVAL; + } + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + case SND_SOC_DAIFMT_RIGHT_J: + dev_err(component->dev, "Codec driver does not support right justified\n"); + return -EINVAL; + case SND_SOC_DAIFMT_LEFT_J: + iface |= ES8326_DAIFMT_LEFT_J; + break; + case SND_SOC_DAIFMT_DSP_A: + iface |= ES8326_DAIFMT_DSP_A; + break; + case SND_SOC_DAIFMT_DSP_B: + iface |= ES8326_DAIFMT_DSP_B; + break; + default: + return -EINVAL; + } + + snd_soc_component_update_bits(component, ES8326_FMT, ES8326_DAIFMT_MASK, iface); + + return 0; +} + +static int es8326_pcm_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 es8326_priv *es8326 = snd_soc_component_get_drvdata(component); + u8 srate = 0; + int coeff; + + coeff = get_coeff(es8326->sysclk, params_rate(params)); + /* bit size */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + srate |= ES8326_S16_LE; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + srate |= ES8326_S20_3_LE; + break; + case SNDRV_PCM_FORMAT_S18_3LE: + srate |= ES8326_S18_LE; + break; + case SNDRV_PCM_FORMAT_S24_LE: + srate |= ES8326_S24_LE; + break; + case SNDRV_PCM_FORMAT_S32_LE: + srate |= ES8326_S32_LE; + break; + default: + return -EINVAL; + } + + /* set iface & srate */ + snd_soc_component_update_bits(component, ES8326_FMT, ES8326_DATA_LEN_MASK, srate); + + if (coeff >= 0) { + regmap_write(es8326->regmap, ES8326_CLK_DIV1, + coeff_div[coeff].reg4); + regmap_write(es8326->regmap, ES8326_CLK_DIV2, + coeff_div[coeff].reg5); + regmap_write(es8326->regmap, ES8326_CLK_DLL, + coeff_div[coeff].reg6); + regmap_write(es8326->regmap, ES8326_CLK_MUX, + coeff_div[coeff].reg7); + regmap_write(es8326->regmap, ES8326_CLK_ADC_SEL, + coeff_div[coeff].reg8); + regmap_write(es8326->regmap, ES8326_CLK_DAC_SEL, + coeff_div[coeff].reg9); + regmap_write(es8326->regmap, ES8326_CLK_ADC_OSR, + coeff_div[coeff].rega); + regmap_write(es8326->regmap, ES8326_CLK_DAC_OSR, + coeff_div[coeff].regb); + } else { + dev_warn(component->dev, "Clock coefficients do not match"); + } + + return 0; +} + +static int es8326_set_bias_level(struct snd_soc_component *codec, + enum snd_soc_bias_level level) +{ + struct es8326_priv *es8326 = snd_soc_component_get_drvdata(codec); + int ret; + + switch (level) { + case SND_SOC_BIAS_ON: + ret = clk_prepare_enable(es8326->mclk); + if (ret) + return ret; + regmap_write(es8326->regmap, ES8326_RESET, ES8326_PWRUP_SEQ_EN); + regmap_write(es8326->regmap, ES8326_INTOUT_IO, 0x45); + regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, + (ES8326_IO_DMIC_CLK << ES8326_SDINOUT1_SHIFT)); + regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT); + regmap_write(es8326->regmap, ES8326_CLK_RESAMPLE, 0x05); + regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x02); + regmap_write(es8326->regmap, ES8326_PGA_PDN, 0x40); + regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0xAA); + regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_ON); + break; + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + break; + case SND_SOC_BIAS_OFF: + clk_disable_unprepare(es8326->mclk); + regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x11); + regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_OFF); + regmap_write(es8326->regmap, ES8326_PGA_PDN, 0xF8); + regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x00); + regmap_write(es8326->regmap, ES8326_INT_SOURCE, 0x08); + regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, ES8326_IO_INPUT); + regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT); + regmap_write(es8326->regmap, ES8326_RESET, + ES8326_CODEC_RESET | ES8326_PWRUP_SEQ_EN); + break; + } + + return 0; +} + +#define es8326_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE) + +static const struct snd_soc_dai_ops es8326_ops = { + .hw_params = es8326_pcm_hw_params, + .set_fmt = es8326_set_dai_fmt, + .set_sysclk = es8326_set_dai_sysclk, +}; + +static struct snd_soc_dai_driver es8326_dai = { + .name = "ES8326 HiFi", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = es8326_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = es8326_FORMATS, + }, + .ops = &es8326_ops, + .symmetric_rate = 1, +}; + +static void es8326_enable_micbias(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + + snd_soc_dapm_mutex_lock(dapm); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS1"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS2"); + snd_soc_dapm_sync_unlocked(dapm); + snd_soc_dapm_mutex_unlock(dapm); +} + +static void es8326_disable_micbias(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + + snd_soc_dapm_mutex_lock(dapm); + snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS1"); + snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS2"); + snd_soc_dapm_sync_unlocked(dapm); + snd_soc_dapm_mutex_unlock(dapm); +} + +/* + * For button detection, set the following in soundcard + * snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + * snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); + * snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); + */ +static void es8326_jack_button_handler(struct work_struct *work) +{ + struct es8326_priv *es8326 = + container_of(work, struct es8326_priv, button_press_work.work); + struct snd_soc_component *comp = es8326->component; + unsigned int iface; + static int button_to_report, press_count; + static int prev_button, cur_button; + + if (!(es8326->jack->status & SND_JACK_HEADSET)) /* Jack unplugged */ + return; + + mutex_lock(&es8326->lock); + iface = snd_soc_component_read(comp, ES8326_HP_DETECT); + switch (iface) { + case 0x93: + /* pause button detected */ + cur_button = SND_JACK_BTN_0; + break; + case 0x6f: + /* button volume up */ + cur_button = SND_JACK_BTN_1; + break; + case 0x27: + /* button volume down */ + cur_button = SND_JACK_BTN_2; + break; + case 0x1e: + /* button released or not pressed */ + cur_button = 0; + break; + default: + break; + } + + if ((prev_button == cur_button) && (cur_button != 0)) { + press_count++; + if (press_count > 10) { + /* report a press every 500ms */ + snd_soc_jack_report(es8326->jack, cur_button, + SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2); + press_count = 0; + } + button_to_report = cur_button; + queue_delayed_work(system_wq, &es8326->button_press_work, + msecs_to_jiffies(50)); + } else if (prev_button != cur_button) { + /* mismatch, detect again */ + prev_button = cur_button; + queue_delayed_work(system_wq, &es8326->button_press_work, + msecs_to_jiffies(50)); + } else { + /* released or no pressed */ + if (button_to_report != 0) { + snd_soc_jack_report(es8326->jack, button_to_report, + SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2); + snd_soc_jack_report(es8326->jack, 0, + SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2); + button_to_report = 0; + } + } + mutex_unlock(&es8326->lock); +} + +static void es8326_jack_detect_handler(struct work_struct *work) +{ + struct es8326_priv *es8326 = + container_of(work, struct es8326_priv, jack_detect_work.work); + struct snd_soc_component *comp = es8326->component; + unsigned int iface; + + mutex_lock(&es8326->lock); + iface = snd_soc_component_read(comp, ES8326_HP_DETECT); + dev_dbg(comp->dev, "gpio flag %#04x", iface); + if ((iface & ES8326_HPINSERT_FLAG) == 0) { + /* Jack unplugged or spurious IRQ */ + dev_dbg(comp->dev, "No headset detected"); + if (es8326->jack->status & SND_JACK_HEADPHONE) { + snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET); + snd_soc_component_write(comp, ES8326_ADC1_SRC, es8326->mic2_src); + es8326_disable_micbias(comp); + } + } else if ((iface & ES8326_HPINSERT_FLAG) == ES8326_HPINSERT_FLAG) { + if (es8326->jack->status & SND_JACK_HEADSET) { + /* detect button */ + queue_delayed_work(system_wq, &es8326->button_press_work, 10); + } else { + if ((iface & ES8326_HPBUTTON_FLAG) == 0x00) { + dev_dbg(comp->dev, "Headset detected"); + snd_soc_jack_report(es8326->jack, + SND_JACK_HEADSET, SND_JACK_HEADSET); + snd_soc_component_write(comp, + ES8326_ADC1_SRC, es8326->mic1_src); + } else { + dev_dbg(comp->dev, "Headphone detected"); + snd_soc_jack_report(es8326->jack, + SND_JACK_HEADPHONE, SND_JACK_HEADSET); + } + } + } + mutex_unlock(&es8326->lock); +} + +static irqreturn_t es8326_irq(int irq, void *dev_id) +{ + struct es8326_priv *es8326 = dev_id; + struct snd_soc_component *comp = es8326->component; + + if (!es8326->jack) + goto out; + + es8326_enable_micbias(comp); + + if (es8326->jack->status & SND_JACK_HEADSET) + queue_delayed_work(system_wq, &es8326->jack_detect_work, + msecs_to_jiffies(10)); + else + queue_delayed_work(system_wq, &es8326->jack_detect_work, + msecs_to_jiffies(300)); + +out: + return IRQ_HANDLED; +} + +static int es8326_resume(struct snd_soc_component *component) +{ + struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); + unsigned int reg; + + regcache_cache_only(es8326->regmap, false); + regcache_sync(es8326->regmap); + + regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_ON); + /* Two channel ADC */ + regmap_write(es8326->regmap, ES8326_PULLUP_CTL, 0x02); + regmap_write(es8326->regmap, ES8326_CLK_INV, 0x00); + regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC, 0x1F); + regmap_write(es8326->regmap, ES8326_CLK_VMIDS1, 0xC8); + regmap_write(es8326->regmap, ES8326_CLK_VMIDS2, 0x88); + regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME, 0x20); + regmap_write(es8326->regmap, ES8326_SYS_BIAS, 0x08); + regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x22); + regmap_write(es8326->regmap, ES8326_ADC1_SRC, es8326->mic1_src); + regmap_write(es8326->regmap, ES8326_ADC2_SRC, es8326->mic2_src); + regmap_write(es8326->regmap, ES8326_HPJACK_TIMER, 0x88); + regmap_write(es8326->regmap, ES8326_HP_DET, + ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol); + regmap_write(es8326->regmap, ES8326_INT_SOURCE, es8326->interrupt_src); + regmap_write(es8326->regmap, ES8326_INTOUT_IO, es8326->interrupt_clk); + regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_ON); + snd_soc_component_update_bits(component, ES8326_PGAGAIN, + ES8326_MIC_SEL_MASK, ES8326_MIC1_SEL); + + regmap_read(es8326->regmap, ES8326_CHIP_VERSION, ®); + if ((reg & ES8326_VERSION_B) == 1) { + regmap_write(es8326->regmap, ES8326_ANA_MICBIAS, 0xDD); + regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7F); + regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x0F); + /* enable button detect */ + regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xA0); + } + + es8326_irq(es8326->irq, es8326); + return 0; +} + +static int es8326_suspend(struct snd_soc_component *component) +{ + struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); + + cancel_delayed_work_sync(&es8326->jack_detect_work); + es8326_disable_micbias(component); + + regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_OFF); + regcache_cache_only(es8326->regmap, true); + regcache_mark_dirty(es8326->regmap); + + return 0; +} + +static int es8326_probe(struct snd_soc_component *component) +{ + struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); + int ret; + + es8326->component = component; + es8326->jd_inverted = device_property_read_bool(component->dev, + "everest,jack-detect-inverted"); + + ret = device_property_read_u8(component->dev, "everest,mic1-src", &es8326->mic1_src); + if (ret != 0) { + dev_dbg(component->dev, "mic1-src return %d", ret); + es8326->mic1_src = ES8326_ADC_AMIC; + } + dev_dbg(component->dev, "mic1-src %x", es8326->mic1_src); + + ret = device_property_read_u8(component->dev, "everest,mic2-src", &es8326->mic2_src); + if (ret != 0) { + dev_dbg(component->dev, "mic2-src return %d", ret); + es8326->mic2_src = ES8326_ADC_DMIC; + } + dev_dbg(component->dev, "mic2-src %x", es8326->mic2_src); + + ret = device_property_read_u8(component->dev, "everest,jack-pol", &es8326->jack_pol); + if (ret != 0) { + dev_dbg(component->dev, "jack-pol return %d", ret); + es8326->jack_pol = ES8326_HP_DET_BUTTON_POL | ES8326_HP_TYPE_OMTP; + } + dev_dbg(component->dev, "jack-pol %x", es8326->jack_pol); + + ret = device_property_read_u8(component->dev, "everest,interrupt-src", &es8326->jack_pol); + if (ret != 0) { + dev_dbg(component->dev, "interrupt-src return %d", ret); + es8326->interrupt_src = ES8326_HP_DET_SRC_PIN9; + } + dev_dbg(component->dev, "interrupt-src %x", es8326->interrupt_src); + + ret = device_property_read_u8(component->dev, "everest,interrupt-clk", &es8326->jack_pol); + if (ret != 0) { + dev_dbg(component->dev, "interrupt-clk return %d", ret); + es8326->interrupt_clk = 0x45; + } + dev_dbg(component->dev, "interrupt-clk %x", es8326->interrupt_clk); + + es8326_resume(component); + return 0; +} + +static void es8326_enable_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack) +{ + struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); + + mutex_lock(&es8326->lock); + if (es8326->jd_inverted) + snd_soc_component_update_bits(component, ES8326_HP_DET, + ES8326_HP_DET_JACK_POL, ~es8326->jack_pol); + es8326->jack = jack; + + mutex_unlock(&es8326->lock); + es8326_irq(es8326->irq, es8326); +} + +static void es8326_disable_jack_detect(struct snd_soc_component *component) +{ + struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); + + dev_dbg(component->dev, "Enter into %s\n", __func__); + if (!es8326->jack) + return; /* Already disabled (or never enabled) */ + cancel_delayed_work_sync(&es8326->jack_detect_work); + + mutex_lock(&es8326->lock); + if (es8326->jack->status & SND_JACK_MICROPHONE) { + es8326_disable_micbias(component); + snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET); + } + es8326->jack = NULL; + mutex_unlock(&es8326->lock); +} + +static int es8326_set_jack(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *data) +{ + if (jack) + es8326_enable_jack_detect(component, jack); + else + es8326_disable_jack_detect(component); + + return 0; +} + +static void es8326_remove(struct snd_soc_component *component) +{ + es8326_disable_jack_detect(component); + es8326_set_bias_level(component, SND_SOC_BIAS_OFF); +} + +static const struct snd_soc_component_driver soc_component_dev_es8326 = { + .probe = es8326_probe, + .remove = es8326_remove, + .resume = es8326_resume, + .suspend = es8326_suspend, + .set_bias_level = es8326_set_bias_level, + .set_jack = es8326_set_jack, + .dapm_widgets = es8326_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(es8326_dapm_widgets), + .dapm_routes = es8326_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(es8326_dapm_routes), + .controls = es8326_snd_controls, + .num_controls = ARRAY_SIZE(es8326_snd_controls), + .use_pmdown_time = 1, + .endianness = 1, +}; + +static int es8326_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct es8326_priv *es8326; + int ret; + + es8326 = devm_kzalloc(&i2c->dev, sizeof(struct es8326_priv), GFP_KERNEL); + if (!es8326) + return -ENOMEM; + + i2c_set_clientdata(i2c, es8326); + es8326->i2c = i2c; + mutex_init(&es8326->lock); + es8326->regmap = devm_regmap_init_i2c(i2c, &es8326_regmap_config); + if (IS_ERR(es8326->regmap)) { + ret = PTR_ERR(es8326->regmap); + dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret); + return ret; + } + + es8326->irq = i2c->irq; + INIT_DELAYED_WORK(&es8326->jack_detect_work, + es8326_jack_detect_handler); + INIT_DELAYED_WORK(&es8326->button_press_work, + es8326_jack_button_handler); + /* ES8316 is level-based while ES8326 is edge-based */ + ret = devm_request_threaded_irq(&i2c->dev, es8326->irq, NULL, es8326_irq, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + "es8326", es8326); + if (ret) { + dev_warn(&i2c->dev, "Failed to request IRQ: %d: %d\n", + es8326->irq, ret); + es8326->irq = -ENXIO; + } + + es8326->mclk = devm_clk_get_optional(&i2c->dev, "mclk"); + if (IS_ERR(es8326->mclk)) { + dev_err(&i2c->dev, "unable to get mclk\n"); + return PTR_ERR(es8326->mclk); + } + if (!es8326->mclk) + dev_warn(&i2c->dev, "assuming static mclk\n"); + + ret = clk_prepare_enable(es8326->mclk); + if (ret) { + dev_err(&i2c->dev, "unable to enable mclk\n"); + return ret; + } + return devm_snd_soc_register_component(&i2c->dev, + &soc_component_dev_es8326, + &es8326_dai, 1); +} + +static const struct i2c_device_id es8326_i2c_id[] = { + {"es8326", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, es8326_i2c_id); + +#ifdef CONFIG_OF +static const struct of_device_id es8326_of_match[] = { + { .compatible = "everest,es8326", }, + {} +}; +MODULE_DEVICE_TABLE(of, es8326_of_match); +#endif + +#ifdef CONFIG_ACPI +static const struct acpi_device_id es8326_acpi_match[] = { + {"ESSX8326", 0}, + {}, +}; +MODULE_DEVICE_TABLE(acpi, es8326_acpi_match); +#endif + +static struct i2c_driver es8326_i2c_driver = { + .driver = { + .name = "es8326", + .acpi_match_table = ACPI_PTR(es8326_acpi_match), + .of_match_table = of_match_ptr(es8326_of_match), + }, + .probe = es8326_i2c_probe, + .id_table = es8326_i2c_id, +}; +module_i2c_driver(es8326_i2c_driver); + +MODULE_DESCRIPTION("ASoC es8326 driver"); +MODULE_AUTHOR("David Yang "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/es8326.h b/sound/soc/codecs/es8326.h new file mode 100755 index 000000000000..8e5ffe5ee10d --- /dev/null +++ b/sound/soc/codecs/es8326.h @@ -0,0 +1,182 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * es8326.h -- es8326 ALSA SoC audio driver + * Copyright Everest Semiconductor Co.,Ltd + * + * Authors: David Yang + */ + +#ifndef _ES8326_H +#define _ES8326_H + +#define CONFIG_HHTECH_MINIPMP 1 + +/* ES8326 register space */ +#define ES8326_RESET 0x00 +#define ES8326_CLK_CTL 0x01 +#define ES8326_CLK_INV 0x02 +#define ES8326_CLK_RESAMPLE 0x03 +#define ES8326_CLK_DIV1 0x04 +#define ES8326_CLK_DIV2 0x05 +#define ES8326_CLK_DLL 0x06 +#define ES8326_CLK_MUX 0x07 +#define ES8326_CLK_ADC_SEL 0x08 +#define ES8326_CLK_DAC_SEL 0x09 +#define ES8326_CLK_ADC_OSR 0x0a +#define ES8326_CLK_DAC_OSR 0x0b +#define ES8326_CLK_DIV_CPC 0x0c +#define ES8326_CLK_DIV_BCLK 0x0d +#define ES8326_CLK_TRI 0x0e +#define ES8326_CLK_DIV_LRCK 0x0f +#define ES8326_CLK_VMIDS1 0x10 +#define ES8326_CLK_VMIDS2 0x11 +#define ES8326_CLK_CAL_TIME 0x12 +#define ES8326_FMT 0x13 + +#define ES8326_DAC_MUTE 0x14 +#define ES8326_ADC_MUTE 0x15 +#define ES8326_ANA_PDN 0x16 +#define ES8326_PGA_PDN 0x17 +#define ES8326_VMIDSEL 0x18 +#define ES8326_ANA_LP 0x19 +#define ES8326_ANA_DMS 0x1a +#define ES8326_ANA_MICBIAS 0x1b +#define ES8326_ANA_VSEL 0x1c +#define ES8326_SYS_BIAS 0x1d +#define ES8326_BIAS_SW1 0x1e +#define ES8326_BIAS_SW2 0x1f +#define ES8326_BIAS_SW3 0x20 +#define ES8326_BIAS_SW4 0x21 +#define ES8326_VMIDLOW 0x22 +#define ES8326_PGAGAIN 0x23 +#define ES8326_HP_DRIVER 0x24 +#define ES8326_DAC2HPMIX 0x25 +#define ES8326_HP_VOL 0x26 +#define ES8326_HP_CAL 0x27 +#define ES8326_HP_DRIVER_REF 0x28 +#define ES8326_ADC_SCALE 0x29 +#define ES8326_ADC1_SRC 0x2a +#define ES8326_ADC2_SRC 0x2b +#define ES8326_ADC1_VOL 0x2c +#define ES8326_ADC2_VOL 0x2d +#define ES8326_ADC_RAMPRATE 0x2e +#define ES8326_ALC_RECOVERY 0x32 +#define ES8326_ALC_LEVEL 0x33 +#define ES8326_ADC_HPFS1 0x34 +#define ES8326_ADC_HPFS2 0x35 +#define ES8326_ADC_EQ 0x36 +#define ES8326_HP_OFFSET_CAL 0x4A +#define ES8326_HPL_OFFSET_INI 0x4B +#define ES8326_HPR_OFFSET_INI 0x4C +#define ES8326_DAC_DSM 0x4D +#define ES8326_DAC_RAMPRATE 0x4E +#define ES8326_DAC_VPPSCALE 0x4F +#define ES8326_DAC_VOL 0x50 +#define ES8326_DRC_RECOVERY 0x53 +#define ES8326_DRC_WINSIZE 0x54 +#define ES8326_HPJACK_TIMER 0x56 +#define ES8326_HP_DET 0x57 +#define ES8326_INT_SOURCE 0x58 +#define ES8326_INTOUT_IO 0x59 +#define ES8326_SDINOUT1_IO 0x5A +#define ES8326_SDINOUT23_IO 0x5B +#define ES8326_JACK_PULSE 0x5C + +#define ES8326_PULLUP_CTL 0xF9 +#define ES8326_HP_DETECT 0xFB +#define ES8326_CHIP_ID1 0xFD +#define ES8326_CHIP_ID2 0xFE +#define ES8326_CHIP_VERSION 0xFF + +/* ES8326_RESET */ +#define ES8326_CSM_ON (1 << 7) +#define ES8326_MASTER_MODE_EN (1 << 6) +#define ES8326_PWRUP_SEQ_EN (1 << 5) +#define ES8326_CODEC_RESET (0x0f << 0) +#define ES8326_CSM_OFF (0 << 7) + +/* ES8326_CLK_CTL */ +#define ES8326_CLK_ON (0x7f << 0) +#define ES8326_CLK_OFF (0 << 0) + +/* ES8326_CLK_INV */ +#define ES8326_BCLK_AS_MCLK (1 << 3) + +/* ES8326_FMT */ +#define ES8326_S24_LE (0 << 2) +#define ES8326_S20_3_LE (1 << 2) +#define ES8326_S18_LE (2 << 2) +#define ES8326_S16_LE (3 << 2) +#define ES8326_S32_LE (4 << 2) +#define ES8326_DATA_LEN_MASK (7 << 2) + +#define ES8326_DAIFMT_MASK ((1 << 5) | (3 << 0)) +#define ES8326_DAIFMT_I2S 0 +#define ES8326_DAIFMT_LEFT_J (1 << 0) +#define ES8326_DAIFMT_DSP_A (3 << 0) +#define ES8326_DAIFMT_DSP_B ((1 << 5) | (3 << 0)) + +/* ES8326_PGAGAIN */ +#define ES8326_MIC_SEL_MASK (3 << 4) +#define ES8326_MIC1_SEL (1 << 4) +#define ES8326_MIC2_SEL (1 << 5) + +/* ES8326_HP_CAL */ +#define ES8326_HPOR_SHIFT 4 + +/* ES8326_ADC1_SRC */ +#define ES8326_ADC1_SHIFT 0 +#define ES8326_ADC2_SHIFT 4 +#define ES8326_ADC_SRC_ANA 0 +#define ES8326_ADC_SRC_ANA_INV_SW0 1 +#define ES8326_ADC_SRC_ANA_INV_SW1 2 +#define ES8326_ADC_SRC_DMIC_MCLK 3 +#define ES8326_ADC_SRC_DMIC_SDIN2 4 +#define ES8326_ADC_SRC_DMIC_SDIN2_INV 5 +#define ES8326_ADC_SRC_DMIC_SDIN3 6 +#define ES8326_ADC_SRC_DMIC_SDIN3_INV 7 + +#define ES8326_ADC_AMIC ((ES8326_ADC_SRC_ANA_INV_SW1 << ES8326_ADC2_SHIFT) \ + | (ES8326_ADC_SRC_ANA_INV_SW1 << ES8326_ADC1_SHIFT)) +#define ES8326_ADC_DMIC ((ES8326_ADC_SRC_DMIC_SDIN2 << ES8326_ADC2_SHIFT) \ + | (ES8326_ADC_SRC_DMIC_SDIN2 << ES8326_ADC1_SHIFT)) +/* ES8326_ADC2_SRC */ +#define ES8326_ADC3_SHIFT 0 +#define ES8326_ADC4_SHIFT 3 + +/* ES8326_HP_DET */ +#define ES8326_HP_DET_SRC_PIN27 (1 << 5) +#define ES8326_HP_DET_SRC_PIN9 (1 << 4) +#define ES8326_HP_DET_JACK_POL (1 << 3) +#define ES8326_HP_DET_BUTTON_POL (1 << 2) +#define ES8326_HP_TYPE_OMTP (3 << 0) +#define ES8326_HP_TYPE_CTIA (2 << 0) +#define ES8326_HP_TYPE_AUTO (1 << 0) +#define ES8326_HP_TYPE_AUTO_INV (0 << 0) + +/* ES8326_SDINOUT1_IO */ +#define ES8326_IO_INPUT (0 << 0) +#define ES8326_IO_SDIN_SLOT0 (1 << 0) +#define ES8326_IO_SDIN_SLOT1 (2 << 0) +#define ES8326_IO_SDIN_SLOT2 (3 << 0) +#define ES8326_IO_SDIN_SLOT7 (8 << 0) +#define ES8326_IO_DMIC_CLK (9 << 0) +#define ES8326_IO_DMIC_CLK_INV (0x0a << 0) +#define ES8326_IO_SDOUT2 (0x0b << 0) +#define ES8326_IO_LOW (0x0e << 0) +#define ES8326_IO_HIGH (0x0f << 0) +#define ES8326_ADC2DAC (1 << 3) +#define ES8326_SDINOUT1_SHIFT 4 + +/* ES8326_SDINOUT23_IO */ +#define ES8326_SDINOUT2_SHIFT 4 +#define ES8326_SDINOUT3_SHIFT 0 + +/* ES8326_HP_DETECT */ +#define ES8326_HPINSERT_FLAG (1 << 1) +#define ES8326_HPBUTTON_FLAG (1 << 0) + +/* ES8326_CHIP_VERSION 0xFF */ +#define ES8326_VERSION_B (1 << 0) + +#endif -- cgit v1.2.3 From 3b43a713f6b09ffbca468847000dabeaf92492df Mon Sep 17 00:00:00 2001 From: Pieterjan Camerlynck Date: Sat, 13 Aug 2022 10:33:52 +0200 Subject: ASoC: fsl_sai: fix incorrect mclk number in error message In commit c3ecef21c3f26 ("ASoC: fsl_sai: add sai master mode support") the loop was changed to start iterating from 1 instead of 0. The error message however was not updated, reporting the wrong clock to the user. Signed-off-by: Pieterjan Camerlynck Acked-by: Shengjiu Wang Link: https://lore.kernel.org/r/20220813083353.8959-1-pieterjan.camerlynck@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 7523bb944b21..d430eece1d6b 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -1306,7 +1306,7 @@ static int fsl_sai_probe(struct platform_device *pdev) sai->mclk_clk[i] = devm_clk_get(dev, tmp); if (IS_ERR(sai->mclk_clk[i])) { dev_err(dev, "failed to get mclk%d clock: %ld\n", - i + 1, PTR_ERR(sai->mclk_clk[i])); + i, PTR_ERR(sai->mclk_clk[i])); sai->mclk_clk[i] = NULL; } } -- cgit v1.2.3 From 5f3db54cfbc21772d984372fdcc5bb17b57f425f Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 16 Aug 2022 16:05:09 +0300 Subject: ASoC: Intel: common: add ACPI matching tables for Raptor Lake Initial support for RPL w/ RT711 Signed-off-by: Kai Vehmanen Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Tested-by: Gopal Vamshi Krishna Link: https://lore.kernel.org/r/20220816130510.190427-1-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- include/sound/soc-acpi-intel-match.h | 2 + sound/soc/intel/common/Makefile | 2 +- sound/soc/intel/common/soc-acpi-intel-rpl-match.c | 51 +++++++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 sound/soc/intel/common/soc-acpi-intel-rpl-match.c diff --git a/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h index bc7fd46ec2bc..ac750afa7bc6 100644 --- a/include/sound/soc-acpi-intel-match.h +++ b/include/sound/soc-acpi-intel-match.h @@ -30,6 +30,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_sdw_machines[]; @@ -38,6 +39,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[]; /* diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index 8ca8f872ec80..41054cf09ec9 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -9,7 +9,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m soc-acpi-intel-cml-match.o soc-acpi-intel-icl-match.o \ soc-acpi-intel-tgl-match.o soc-acpi-intel-ehl-match.o \ soc-acpi-intel-jsl-match.o soc-acpi-intel-adl-match.o \ - soc-acpi-intel-mtl-match.o \ + soc-acpi-intel-rpl-match.o soc-acpi-intel-mtl-match.o \ soc-acpi-intel-hda-match.o \ soc-acpi-intel-sdw-mockup-match.o diff --git a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c new file mode 100644 index 000000000000..0b77401e4e6f --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * soc-apci-intel-rpl-match.c - tables and support for RPL ACPI enumeration. + * + * Copyright (c) 2022 Intel Corporation. + */ + +#include +#include + +static const struct snd_soc_acpi_endpoint single_endpoint = { + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, +}; + +static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { + { + .adr = 0x000020025D071100ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt711" + } +}; + +static const struct snd_soc_acpi_link_adr rpl_rvp[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_0_adr), + .adr_d = rt711_0_adr, + }, + {} +}; + +struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = { + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_rpl_machines); + +/* this table is used when there is no I2S codec present */ +struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_sdw_machines[] = { + { + .link_mask = 0x1, /* link0 required */ + .links = rpl_rvp, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-rpl-rt711.tplg", + }, + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_rpl_sdw_machines); -- cgit v1.2.3 From 63d375b9f2a99bb111e3fb5f3e2442a391988949 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 16 Aug 2022 16:05:10 +0300 Subject: ASoC: SOF: Intel: pci-tgl: use RPL specific firmware definitions Split out firmware definitions for Intel Raptor Lake platforms. Signed-off-by: Kai Vehmanen Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Suggested-by: Gopal Vamshi Krishna Link: https://lore.kernel.org/r/20220816130510.190427-2-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/pci-tgl.c | 62 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c index ccc44ba3ad94..aac47cd007e8 100644 --- a/sound/soc/sof/intel/pci-tgl.c +++ b/sound/soc/sof/intel/pci-tgl.c @@ -159,6 +159,62 @@ static const struct sof_dev_desc adl_desc = { .ops_init = sof_tgl_ops_init, }; +static const struct sof_dev_desc rpls_desc = { + .machines = snd_soc_acpi_intel_rpl_machines, + .alt_machines = snd_soc_acpi_intel_rpl_sdw_machines, + .use_acpi_target_states = true, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .chip_info = &adls_chip_info, + .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4), + .ipc_default = SOF_IPC, + .default_fw_path = { + [SOF_IPC] = "intel/sof", + [SOF_INTEL_IPC4] = "intel/avs/rpl-s", + }, + .default_tplg_path = { + [SOF_IPC] = "intel/sof-tplg", + [SOF_INTEL_IPC4] = "intel/avs-tplg", + }, + .default_fw_filename = { + [SOF_IPC] = "sof-rpl-s.ri", + [SOF_INTEL_IPC4] = "dsp_basefw.bin", + }, + .nocodec_tplg_filename = "sof-rpl-nocodec.tplg", + .ops = &sof_tgl_ops, + .ops_init = sof_tgl_ops_init, +}; + +static const struct sof_dev_desc rpl_desc = { + .machines = snd_soc_acpi_intel_rpl_machines, + .alt_machines = snd_soc_acpi_intel_rpl_sdw_machines, + .use_acpi_target_states = true, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .chip_info = &tgl_chip_info, + .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4), + .ipc_default = SOF_IPC, + .default_fw_path = { + [SOF_IPC] = "intel/sof", + [SOF_INTEL_IPC4] = "intel/avs/rpl", + }, + .default_tplg_path = { + [SOF_IPC] = "intel/sof-tplg", + [SOF_INTEL_IPC4] = "intel/avs-tplg", + }, + .default_fw_filename = { + [SOF_IPC] = "sof-rpl.ri", + [SOF_INTEL_IPC4] = "dsp_basefw.bin", + }, + .nocodec_tplg_filename = "sof-rpl-nocodec.tplg", + .ops = &sof_tgl_ops, + .ops_init = sof_tgl_ops_init, +}; + /* PCI IDs */ static const struct pci_device_id sof_pci_ids[] = { { PCI_DEVICE(0x8086, 0xa0c8), /* TGL-LP */ @@ -172,7 +228,7 @@ static const struct pci_device_id sof_pci_ids[] = { { PCI_DEVICE(0x8086, 0x7ad0), /* ADL-S */ .driver_data = (unsigned long)&adls_desc}, { PCI_DEVICE(0x8086, 0x7a50), /* RPL-S */ - .driver_data = (unsigned long)&adls_desc}, + .driver_data = (unsigned long)&rpls_desc}, { PCI_DEVICE(0x8086, 0x51c8), /* ADL-P */ .driver_data = (unsigned long)&adl_desc}, { PCI_DEVICE(0x8086, 0x51cd), /* ADL-P */ @@ -180,9 +236,9 @@ static const struct pci_device_id sof_pci_ids[] = { { PCI_DEVICE(0x8086, 0x51c9), /* ADL-PS */ .driver_data = (unsigned long)&adl_desc}, { PCI_DEVICE(0x8086, 0x51ca), /* RPL-P */ - .driver_data = (unsigned long)&adl_desc}, + .driver_data = (unsigned long)&rpl_desc}, { PCI_DEVICE(0x8086, 0x51cb), /* RPL-P */ - .driver_data = (unsigned long)&adl_desc}, + .driver_data = (unsigned long)&rpl_desc}, { PCI_DEVICE(0x8086, 0x51cc), /* ADL-M */ .driver_data = (unsigned long)&adl_desc}, { PCI_DEVICE(0x8086, 0x54c8), /* ADL-N */ -- cgit v1.2.3 From bab10ec9fd9dc1537b705d0dd3862dd5982b921f Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 17 Aug 2022 11:05:26 +0300 Subject: ASoC: SOF: compress: Remove byte offset computation Byte offset is the offset in the ring buffer to the DSP while posn_offset is an offset inside the stream_box where we keep position information. Reviewed-by: Paul Olaru Reviewed-by: Pierre-Louis Bossart Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20220817080529.10864-2-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/compress.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sof/compress.c b/sound/soc/sof/compress.c index 67139e15f862..760d6a4a5253 100644 --- a/sound/soc/sof/compress.c +++ b/sound/soc/sof/compress.c @@ -237,7 +237,6 @@ static int sof_compr_set_params(struct snd_soc_component *component, goto out; } - tstamp->byte_offset = sdev->stream_box.offset + ipc_params_reply.posn_offset; tstamp->sampling_rate = params->codec.sample_rate; spcm->prepared[cstream->direction] = true; -- cgit v1.2.3 From e3091f0a3f563ad1c9b60c290752e1190b67ea97 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 17 Aug 2022 11:05:27 +0300 Subject: ASoC: SOF: compress: Introduce sof_compr_stream This will keep SOF compress stream private data. So far we used snd_compr_tstamp to hold the private data but this is no longer enough as we need to hold other info like number of channels or sample bytes. Reviewed-by: Paul Olaru Reviewed-by: Pierre-Louis Bossart Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20220817080529.10864-3-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/compress.c | 40 ++++++++++++++++++++-------------------- sound/soc/sof/sof-priv.h | 5 +++++ 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/sound/soc/sof/compress.c b/sound/soc/sof/compress.c index 760d6a4a5253..e990fa093bb5 100644 --- a/sound/soc/sof/compress.c +++ b/sound/soc/sof/compress.c @@ -11,20 +11,20 @@ #include "sof-priv.h" #include "sof-utils.h" -static void sof_set_transferred_bytes(struct snd_compr_tstamp *tstamp, +static void sof_set_transferred_bytes(struct sof_compr_stream *sstream, u64 host_pos, u64 buffer_size) { u64 prev_pos; unsigned int copied; - div64_u64_rem(tstamp->copied_total, buffer_size, &prev_pos); + div64_u64_rem(sstream->copied_total, buffer_size, &prev_pos); if (host_pos < prev_pos) copied = (buffer_size - prev_pos) + host_pos; else copied = host_pos - prev_pos; - tstamp->copied_total += copied; + sstream->copied_total += copied; } static void snd_sof_compr_fragment_elapsed_work(struct work_struct *work) @@ -49,7 +49,7 @@ void snd_sof_compr_fragment_elapsed(struct snd_compr_stream *cstream) struct snd_soc_pcm_runtime *rtd; struct snd_compr_runtime *crtd; struct snd_soc_component *component; - struct snd_compr_tstamp *tstamp; + struct sof_compr_stream *sstream; struct snd_sof_pcm *spcm; if (!cstream) @@ -57,7 +57,7 @@ void snd_sof_compr_fragment_elapsed(struct snd_compr_stream *cstream) rtd = cstream->private_data; crtd = cstream->runtime; - tstamp = crtd->private_data; + sstream = crtd->private_data; component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); spcm = snd_sof_find_spcm_dai(component, rtd); @@ -67,7 +67,7 @@ void snd_sof_compr_fragment_elapsed(struct snd_compr_stream *cstream) return; } - sof_set_transferred_bytes(tstamp, spcm->stream[cstream->direction].posn.host_posn, + sof_set_transferred_bytes(sstream, spcm->stream[cstream->direction].posn.host_posn, crtd->buffer_size); /* use the same workqueue-based solution as for PCM, cf. snd_sof_pcm_elapsed */ @@ -96,24 +96,24 @@ static int sof_compr_open(struct snd_soc_component *component, { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_compr_runtime *crtd = cstream->runtime; - struct snd_compr_tstamp *tstamp; + struct sof_compr_stream *sstream; struct snd_sof_pcm *spcm; int dir; - tstamp = kzalloc(sizeof(*tstamp), GFP_KERNEL); - if (!tstamp) + sstream = kzalloc(sizeof(*sstream), GFP_KERNEL); + if (!sstream) return -ENOMEM; spcm = snd_sof_find_spcm_dai(component, rtd); if (!spcm) { - kfree(tstamp); + kfree(sstream); return -EINVAL; } dir = cstream->direction; if (spcm->stream[dir].cstream) { - kfree(tstamp); + kfree(sstream); return -EBUSY; } @@ -122,7 +122,7 @@ static int sof_compr_open(struct snd_soc_component *component, spcm->stream[dir].posn.dai_posn = 0; spcm->prepared[dir] = false; - crtd->private_data = tstamp; + crtd->private_data = sstream; return 0; } @@ -131,7 +131,7 @@ static int sof_compr_free(struct snd_soc_component *component, struct snd_compr_stream *cstream) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); - struct snd_compr_tstamp *tstamp = cstream->runtime->private_data; + struct sof_compr_stream *sstream = cstream->runtime->private_data; struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct sof_ipc_stream stream; struct sof_ipc_reply reply; @@ -155,7 +155,7 @@ static int sof_compr_free(struct snd_soc_component *component, cancel_work_sync(&spcm->stream[cstream->direction].period_elapsed_work); spcm->stream[cstream->direction].cstream = NULL; - kfree(tstamp); + kfree(sstream); return ret; } @@ -169,7 +169,7 @@ static int sof_compr_set_params(struct snd_soc_component *component, struct sof_ipc_pcm_params_reply ipc_params_reply; struct sof_ipc_fw_ready *ready = &sdev->fw_ready; struct sof_ipc_fw_version *v = &ready->version; - struct snd_compr_tstamp *tstamp; + struct sof_compr_stream *sstream; struct sof_ipc_pcm_params *pcm; struct snd_sof_pcm *spcm; size_t ext_data_size; @@ -184,7 +184,7 @@ static int sof_compr_set_params(struct snd_soc_component *component, return -EINVAL; } - tstamp = crtd->private_data; + sstream = crtd->private_data; spcm = snd_sof_find_spcm_dai(component, rtd); @@ -237,7 +237,7 @@ static int sof_compr_set_params(struct snd_soc_component *component, goto out; } - tstamp->sampling_rate = params->codec.sample_rate; + sstream->sampling_rate = params->codec.sample_rate; spcm->prepared[cstream->direction] = true; @@ -325,10 +325,10 @@ static int sof_compr_pointer(struct snd_soc_component *component, struct snd_compr_stream *cstream, struct snd_compr_tstamp *tstamp) { - struct snd_compr_tstamp *pstamp = cstream->runtime->private_data; + struct sof_compr_stream *sstream = cstream->runtime->private_data; - tstamp->sampling_rate = pstamp->sampling_rate; - tstamp->copied_total = pstamp->copied_total; + tstamp->sampling_rate = sstream->sampling_rate; + tstamp->copied_total = sstream->copied_total; return 0; } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 823583086279..42f112030fb8 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -105,6 +105,11 @@ enum sof_debugfs_access_type { SOF_DEBUGFS_ACCESS_D0_ONLY, }; +struct sof_compr_stream { + u64 copied_total; + u32 sampling_rate; +}; + struct snd_sof_dev; struct snd_sof_ipc_msg; struct snd_sof_ipc; -- cgit v1.2.3 From 3ccbe6887747679d15e5c9524b23754281a24d9e Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Wed, 17 Aug 2022 11:05:28 +0300 Subject: ASoC: SOF: compress: Save channel count and sample bytes The purpose of this change is to enable the saving of the channel count and sample container bytes format parameters for later use to compute the timestamps. This is done when setting the compress stream parameters (in sof_compr_set_params). Reviewed-by: Paul Olaru Reviewed-by: Pierre-Louis Bossart Signed-off-by: Laurentiu Mihalcea Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20220817080529.10864-4-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/compress.c | 2 ++ sound/soc/sof/sof-priv.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/sound/soc/sof/compress.c b/sound/soc/sof/compress.c index e990fa093bb5..ac79b46ce3b9 100644 --- a/sound/soc/sof/compress.c +++ b/sound/soc/sof/compress.c @@ -238,6 +238,8 @@ static int sof_compr_set_params(struct snd_soc_component *component, } sstream->sampling_rate = params->codec.sample_rate; + sstream->channels = params->codec.ch_out; + sstream->sample_container_bytes = pcm->params.sample_container_bytes; spcm->prepared[cstream->direction] = true; diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 42f112030fb8..33165299a20f 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -108,6 +108,8 @@ enum sof_debugfs_access_type { struct sof_compr_stream { u64 copied_total; u32 sampling_rate; + u16 channels; + u16 sample_container_bytes; }; struct snd_sof_dev; -- cgit v1.2.3 From c1a731c71359407eae4fd0a5fd675ef25a582764 Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Wed, 17 Aug 2022 11:05:29 +0300 Subject: ASoC: SOF: compress: Add support for computing timestamps We compute the number of pcm_io_frames by dividing the dai position to size of a frame (channels * sample size). Reviewed-by: Paul Olaru Reviewed-by: Pierre-Louis Bossart Signed-off-by: Laurentiu Mihalcea Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20220817080529.10864-5-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/compress.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/soc/sof/compress.c b/sound/soc/sof/compress.c index ac79b46ce3b9..174b3d8e67dd 100644 --- a/sound/soc/sof/compress.c +++ b/sound/soc/sof/compress.c @@ -327,10 +327,21 @@ static int sof_compr_pointer(struct snd_soc_component *component, struct snd_compr_stream *cstream, struct snd_compr_tstamp *tstamp) { + u64 dai_posn; + struct snd_sof_pcm *spcm; + struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct sof_compr_stream *sstream = cstream->runtime->private_data; + spcm = snd_sof_find_spcm_dai(component, rtd); + if (!spcm) + return -EINVAL; + + dai_posn = spcm->stream[cstream->direction].posn.dai_posn; + tstamp->sampling_rate = sstream->sampling_rate; tstamp->copied_total = sstream->copied_total; + tstamp->pcm_io_frames = div_u64(spcm->stream[cstream->direction].posn.dai_posn, + sstream->channels * sstream->sample_container_bytes); return 0; } -- cgit v1.2.3 From 5c69f11ce85d4a8ea985a6d266574577e94c6506 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 17 Aug 2022 17:15:19 +0800 Subject: ASoC: codecs: es8326: change es8326_regmap_config to static es8326_regmap_config is only used in es8326.c now, change it to static. Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20220817091519.2487385-1-yangyingliang@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8326.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index 975302b2a61d..87c1cc16592b 100755 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -207,7 +207,7 @@ static const struct regmap_access_table es8326_volatile_table = { .n_yes_ranges = ARRAY_SIZE(es8326_volatile_ranges), }; -const struct regmap_config es8326_regmap_config = { +static const struct regmap_config es8326_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = 0xff, -- cgit v1.2.3 From 43a70fb51b6a5e35ac5be5e3a86df6a203b1fce1 Mon Sep 17 00:00:00 2001 From: Xin Gao Date: Wed, 17 Aug 2022 01:51:05 +0800 Subject: ASoC: Variable type completion 'unsigned int' is better than 'unsigned'. Signed-off-by: Xin Gao Link: https://lore.kernel.org/r/20220816175105.8084-1-gaoxin@cdjrlc.com Signed-off-by: Mark Brown --- sound/soc/soc-ac97.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/soc-ac97.c b/sound/soc/soc-ac97.c index 5f49e3dec3fc..32c5be61e2ec 100644 --- a/sound/soc/soc-ac97.c +++ b/sound/soc/soc-ac97.c @@ -57,7 +57,7 @@ static inline struct snd_soc_component *gpio_to_component(struct gpio_chip *chip return gpio_priv->component; } -static int snd_soc_ac97_gpio_request(struct gpio_chip *chip, unsigned offset) +static int snd_soc_ac97_gpio_request(struct gpio_chip *chip, unsigned int offset) { if (offset >= AC97_NUM_GPIOS) return -EINVAL; @@ -66,7 +66,7 @@ static int snd_soc_ac97_gpio_request(struct gpio_chip *chip, unsigned offset) } static int snd_soc_ac97_gpio_direction_in(struct gpio_chip *chip, - unsigned offset) + unsigned int offset) { struct snd_soc_component *component = gpio_to_component(chip); @@ -75,7 +75,7 @@ static int snd_soc_ac97_gpio_direction_in(struct gpio_chip *chip, 1 << offset, 1 << offset); } -static int snd_soc_ac97_gpio_get(struct gpio_chip *chip, unsigned offset) +static int snd_soc_ac97_gpio_get(struct gpio_chip *chip, unsigned int offset) { struct snd_soc_component *component = gpio_to_component(chip); int ret; @@ -88,7 +88,7 @@ static int snd_soc_ac97_gpio_get(struct gpio_chip *chip, unsigned offset) return !!(ret & (1 << offset)); } -static void snd_soc_ac97_gpio_set(struct gpio_chip *chip, unsigned offset, +static void snd_soc_ac97_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) { struct snd_ac97_gpio_priv *gpio_priv = gpiochip_get_data(chip); -- cgit v1.2.3 From ea15d3bd3cd6e9483bb8aa664954c0a8cde253eb Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 16 Aug 2022 18:01:18 +0100 Subject: ASoC: qcom: qdsp6: q6prm: add new clocks Add support to new clocks that are added in Q6DSP as part of newer version of LPASS support on SM8450 and SC8280XP. Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220816170118.13470-1-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h | 18 ++++++++++++++++++ sound/soc/qcom/qdsp6/q6prm-clocks.c | 9 +++++++++ sound/soc/qcom/qdsp6/q6prm.h | 19 +++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h b/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h index 0d3276c8fc11..9f7c5103bc82 100644 --- a/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h +++ b/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h @@ -193,6 +193,24 @@ #define LPASS_CLK_ID_RX_CORE_MCLK 59 #define LPASS_CLK_ID_RX_CORE_NPL_MCLK 60 #define LPASS_CLK_ID_VA_CORE_2X_MCLK 61 +/* Clock ID for MCLK for WSA2 core */ +#define LPASS_CLK_ID_WSA2_CORE_MCLK 62 +/* Clock ID for NPL MCLK for WSA2 core */ +#define LPASS_CLK_ID_WSA2_CORE_2X_MCLK 63 +/* Clock ID for RX Core TX MCLK */ +#define LPASS_CLK_ID_RX_CORE_TX_MCLK 64 +/* Clock ID for RX CORE TX 2X MCLK */ +#define LPASS_CLK_ID_RX_CORE_TX_2X_MCLK 65 +/* Clock ID for WSA core TX MCLK */ +#define LPASS_CLK_ID_WSA_CORE_TX_MCLK 66 +/* Clock ID for WSA core TX 2X MCLK */ +#define LPASS_CLK_ID_WSA_CORE_TX_2X_MCLK 67 +/* Clock ID for WSA2 core TX MCLK */ +#define LPASS_CLK_ID_WSA2_CORE_TX_MCLK 68 +/* Clock ID for WSA2 core TX 2X MCLK */ +#define LPASS_CLK_ID_WSA2_CORE_TX_2X_MCLK 69 +/* Clock ID for RX CORE MCLK2 2X MCLK */ +#define LPASS_CLK_ID_RX_CORE_MCLK2_2X_MCLK 70 #define LPASS_HW_AVTIMER_VOTE 101 #define LPASS_HW_MACRO_VOTE 102 diff --git a/sound/soc/qcom/qdsp6/q6prm-clocks.c b/sound/soc/qcom/qdsp6/q6prm-clocks.c index a26cda5140c1..73b0cbac73d4 100644 --- a/sound/soc/qcom/qdsp6/q6prm-clocks.c +++ b/sound/soc/qcom/qdsp6/q6prm-clocks.c @@ -50,6 +50,15 @@ static const struct q6dsp_clk_init q6prm_clks[] = { Q6PRM_CLK(LPASS_CLK_ID_RX_CORE_MCLK), Q6PRM_CLK(LPASS_CLK_ID_RX_CORE_NPL_MCLK), Q6PRM_CLK(LPASS_CLK_ID_VA_CORE_2X_MCLK), + Q6PRM_CLK(LPASS_CLK_ID_WSA2_CORE_MCLK), + Q6PRM_CLK(LPASS_CLK_ID_WSA2_CORE_2X_MCLK), + Q6PRM_CLK(LPASS_CLK_ID_RX_CORE_TX_MCLK), + Q6PRM_CLK(LPASS_CLK_ID_RX_CORE_TX_2X_MCLK), + Q6PRM_CLK(LPASS_CLK_ID_WSA_CORE_TX_MCLK), + Q6PRM_CLK(LPASS_CLK_ID_WSA_CORE_TX_2X_MCLK), + Q6PRM_CLK(LPASS_CLK_ID_WSA2_CORE_TX_MCLK), + Q6PRM_CLK(LPASS_CLK_ID_WSA2_CORE_TX_2X_MCLK), + Q6PRM_CLK(LPASS_CLK_ID_RX_CORE_MCLK2_2X_MCLK), Q6DSP_VOTE_CLK(LPASS_HW_MACRO_VOTE, Q6PRM_HW_CORE_ID_LPASS, "LPASS_HW_MACRO"), Q6DSP_VOTE_CLK(LPASS_HW_DCODEC_VOTE, Q6PRM_HW_CORE_ID_DCODEC, diff --git a/sound/soc/qcom/qdsp6/q6prm.h b/sound/soc/qcom/qdsp6/q6prm.h index fea4d1954bc1..a988a32086fe 100644 --- a/sound/soc/qcom/qdsp6/q6prm.h +++ b/sound/soc/qcom/qdsp6/q6prm.h @@ -64,6 +64,25 @@ #define Q6PRM_LPASS_CLK_ID_RX_CORE_MCLK 0x30e #define Q6PRM_LPASS_CLK_ID_RX_CORE_NPL_MCLK 0x30f +/* Clock ID for MCLK for WSA2 core */ +#define Q6PRM_LPASS_CLK_ID_WSA2_CORE_MCLK 0x310 +/* Clock ID for NPL MCLK for WSA2 core */ +#define Q6PRM_LPASS_CLK_ID_WSA2_CORE_2X_MCLK 0x311 +/* Clock ID for RX Core TX MCLK */ +#define Q6PRM_LPASS_CLK_ID_RX_CORE_TX_MCLK 0x312 +/* Clock ID for RX CORE TX 2X MCLK */ +#define Q6PRM_LPASS_CLK_ID_RX_CORE_TX_2X_MCLK 0x313 +/* Clock ID for WSA core TX MCLK */ +#define Q6PRM_LPASS_CLK_ID_WSA_CORE_TX_MCLK 0x314 +/* Clock ID for WSA core TX 2X MCLK */ +#define Q6PRM_LPASS_CLK_ID_WSA_CORE_TX_2X_MCLK 0x315 +/* Clock ID for WSA2 core TX MCLK */ +#define Q6PRM_LPASS_CLK_ID_WSA2_CORE_TX_MCLK 0x316 +/* Clock ID for WSA2 core TX 2X MCLK */ +#define Q6PRM_LPASS_CLK_ID_WSA2_CORE_TX_2X_MCLK 0x317 +/* Clock ID for RX CORE MCLK2 2X MCLK */ +#define Q6PRM_LPASS_CLK_ID_RX_CORE_MCLK2_2X_MCLK 0x318 + #define Q6PRM_LPASS_CLK_SRC_INTERNAL 1 #define Q6PRM_LPASS_CLK_ROOT_DEFAULT 0 #define Q6PRM_HW_CORE_ID_LPASS 1 -- cgit v1.2.3 From 4e82971f7b556cff3491c867e8840e7d788693b9 Mon Sep 17 00:00:00 2001 From: Kevin Lu Date: Mon, 15 Aug 2022 19:27:15 +0800 Subject: ASoC: tlv320adcx140: Add a new kcontrol Add a new kcontrol for phase calib Signed-off-by: Kevin Lu Link: https://lore.kernel.org/r/20220815112715.21617-1-luminlong@139.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320adcx140.c | 59 ++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/tlv320adcx140.h | 1 + 2 files changed, 60 insertions(+) diff --git a/sound/soc/codecs/tlv320adcx140.c b/sound/soc/codecs/tlv320adcx140.c index 2844a9d2bc4a..91a22d927915 100644 --- a/sound/soc/codecs/tlv320adcx140.c +++ b/sound/soc/codecs/tlv320adcx140.c @@ -31,6 +31,7 @@ struct adcx140_priv { struct device *dev; bool micbias_vg; + bool phase_calib_on; unsigned int dai_fmt; unsigned int slot_width; @@ -592,6 +593,52 @@ static const struct snd_soc_dapm_route adcx140_audio_map[] = { {"MIC4M Input Mux", "Digital", "MIC4M"}, }; +#define ADCX140_PHASE_CALIB_SWITCH(xname) {\ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\ + .info = adcx140_phase_calib_info, \ + .get = adcx140_phase_calib_get, \ + .put = adcx140_phase_calib_put} + +static int adcx140_phase_calib_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int adcx140_phase_calib_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct snd_soc_component *codec = + snd_soc_kcontrol_component(kcontrol); + struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(codec); + + value->value.integer.value[0] = adcx140->phase_calib_on ? 1 : 0; + + + return 0; +} + +static int adcx140_phase_calib_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct snd_soc_component *codec + = snd_soc_kcontrol_component(kcontrol); + struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(codec); + + bool v = value->value.integer.value[0] ? true : false; + + if (adcx140->phase_calib_on != v) { + adcx140->phase_calib_on = v; + return 1; + } + return 0; +} + static const struct snd_kcontrol_new adcx140_snd_controls[] = { SOC_SINGLE_TLV("Analog CH1 Mic Gain Volume", ADCX140_CH1_CFG1, 2, 42, 0, adc_tlv), @@ -628,6 +675,7 @@ static const struct snd_kcontrol_new adcx140_snd_controls[] = { 0, 0xff, 0, dig_vol_tlv), SOC_SINGLE_TLV("Digital CH8 Out Volume", ADCX140_CH8_CFG2, 0, 0xff, 0, dig_vol_tlv), + ADCX140_PHASE_CALIB_SWITCH("Phase Calibration Switch"), }; static int adcx140_reset(struct adcx140_priv *adcx140) @@ -653,6 +701,8 @@ static int adcx140_reset(struct adcx140_priv *adcx140) static void adcx140_pwr_ctrl(struct adcx140_priv *adcx140, bool power_state) { int pwr_ctrl = 0; + int ret = 0; + struct snd_soc_component *component = adcx140->component; if (power_state) pwr_ctrl = ADCX140_PWR_CFG_ADC_PDZ | ADCX140_PWR_CFG_PLL_PDZ; @@ -660,6 +710,14 @@ static void adcx140_pwr_ctrl(struct adcx140_priv *adcx140, bool power_state) if (adcx140->micbias_vg && power_state) pwr_ctrl |= ADCX140_PWR_CFG_BIAS_PDZ; + if (pwr_ctrl) { + ret = regmap_write(adcx140->regmap, ADCX140_PHASE_CALIB, + adcx140->phase_calib_on ? 0x00 : 0x40); + if (ret) + dev_err(component->dev, "%s: register write error %d\n", + __func__, ret); + } + regmap_update_bits(adcx140->regmap, ADCX140_PWR_CFG, ADCX140_PWR_CTRL_MSK, pwr_ctrl); } @@ -1095,6 +1153,7 @@ static int adcx140_i2c_probe(struct i2c_client *i2c) if (!adcx140) return -ENOMEM; + adcx140->phase_calib_on = false; adcx140->dev = &i2c->dev; adcx140->gpio_reset = devm_gpiod_get_optional(adcx140->dev, diff --git a/sound/soc/codecs/tlv320adcx140.h b/sound/soc/codecs/tlv320adcx140.h index 795b5f7194e6..fd80fac8b327 100644 --- a/sound/soc/codecs/tlv320adcx140.h +++ b/sound/soc/codecs/tlv320adcx140.h @@ -90,6 +90,7 @@ #define ADCX140_PWR_CFG 0x75 #define ADCX140_DEV_STS0 0x76 #define ADCX140_DEV_STS1 0x77 +#define ADCX140_PHASE_CALIB 0X7b #define ADCX140_RESET BIT(0) -- cgit v1.2.3 From 26bdcc4ba12351642cd94339aa6996f96434dd47 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 16 Aug 2022 18:21:29 +0100 Subject: ASoC: core: remove setting platform_max in kcontrol macros platform_max should not be set by the driver, its intended for machine drivers or DT to override the max value for platform specific reasons. So remove setting this from Kcontrol macros. Setting this to max in these macros would limit the range when min value is less then zero. Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220816172129.6661-1-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- include/sound/soc.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index aad24a1d3276..4351d86eedf6 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -31,31 +31,31 @@ #define SOC_DOUBLE_VALUE(xreg, shift_left, shift_right, xmax, xinvert, xautodisable) \ ((unsigned long)&(struct soc_mixer_control) \ {.reg = xreg, .rreg = xreg, .shift = shift_left, \ - .rshift = shift_right, .max = xmax, .platform_max = xmax, \ + .rshift = shift_right, .max = xmax, \ .invert = xinvert, .autodisable = xautodisable}) #define SOC_DOUBLE_S_VALUE(xreg, shift_left, shift_right, xmin, xmax, xsign_bit, xinvert, xautodisable) \ ((unsigned long)&(struct soc_mixer_control) \ {.reg = xreg, .rreg = xreg, .shift = shift_left, \ - .rshift = shift_right, .min = xmin, .max = xmax, .platform_max = xmax, \ + .rshift = shift_right, .min = xmin, .max = xmax, \ .sign_bit = xsign_bit, .invert = xinvert, .autodisable = xautodisable}) #define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert, xautodisable) \ SOC_DOUBLE_VALUE(xreg, xshift, xshift, xmax, xinvert, xautodisable) #define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \ ((unsigned long)&(struct soc_mixer_control) \ - {.reg = xreg, .max = xmax, .platform_max = xmax, .invert = xinvert}) + {.reg = xreg, .max = xmax, .invert = xinvert}) #define SOC_DOUBLE_R_VALUE(xlreg, xrreg, xshift, xmax, xinvert) \ ((unsigned long)&(struct soc_mixer_control) \ {.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \ - .max = xmax, .platform_max = xmax, .invert = xinvert}) + .max = xmax, .invert = xinvert}) #define SOC_DOUBLE_R_S_VALUE(xlreg, xrreg, xshift, xmin, xmax, xsign_bit, xinvert) \ ((unsigned long)&(struct soc_mixer_control) \ {.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \ - .max = xmax, .min = xmin, .platform_max = xmax, .sign_bit = xsign_bit, \ + .max = xmax, .min = xmin, .sign_bit = xsign_bit, \ .invert = xinvert}) #define SOC_DOUBLE_R_RANGE_VALUE(xlreg, xrreg, xshift, xmin, xmax, xinvert) \ ((unsigned long)&(struct soc_mixer_control) \ {.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \ - .min = xmin, .max = xmax, .platform_max = xmax, .invert = xinvert}) + .min = xmin, .max = xmax, .invert = xinvert}) #define SOC_SINGLE(xname, reg, shift, max, invert) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ @@ -68,7 +68,7 @@ .private_value = (unsigned long)&(struct soc_mixer_control) \ {.reg = xreg, .rreg = xreg, .shift = xshift, \ .rshift = xshift, .min = xmin, .max = xmax, \ - .platform_max = xmax, .invert = xinvert} } + .invert = xinvert} } #define SOC_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ @@ -99,7 +99,7 @@ .private_value = (unsigned long)&(struct soc_mixer_control) \ {.reg = xreg, .rreg = xreg, .shift = xshift, \ .rshift = xshift, .min = xmin, .max = xmax, \ - .platform_max = xmax, .invert = xinvert} } + .invert = xinvert} } #define SOC_DOUBLE(xname, reg, shift_left, shift_right, max, invert) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \ @@ -199,7 +199,7 @@ .put = snd_soc_put_volsw, \ .private_value = (unsigned long)&(struct soc_mixer_control) \ {.reg = xreg, .rreg = xreg, \ - .min = xmin, .max = xmax, .platform_max = xmax, \ + .min = xmin, .max = xmax, \ .sign_bit = 7,} } #define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ @@ -273,7 +273,7 @@ .private_value = (unsigned long)&(struct soc_mixer_control) \ {.reg = xreg, .rreg = xreg, .shift = xshift, \ .rshift = xshift, .min = xmin, .max = xmax, \ - .platform_max = xmax, .invert = xinvert} } + .invert = xinvert} } #define SOC_DOUBLE_EXT_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert,\ xhandler_get, xhandler_put, tlv_array) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ -- cgit v1.2.3 From 874de459488b8741afc0e9888d39f2e15a962b3d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 14 Jul 2022 09:10:40 +0800 Subject: soundwire: add read_ping_status helper definition in manager ops The existing manager ops provide callbacks to transfer read/write commands, but don't allow for direct access to PING status register. This is accessible in all existing IP, and would help diagnose timeouts or resume issues by reporting the 'true' status instead of the internal status reported by the IP. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Acked-By: Vinod Koul Link: https://lore.kernel.org/r/20220714011043.46059-2-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- include/linux/soundwire/sdw.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 39058c841469..eb840a07c25c 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -839,6 +839,8 @@ struct sdw_defer { * @set_bus_conf: Set the bus configuration * @pre_bank_switch: Callback for pre bank switch * @post_bank_switch: Callback for post bank switch + * @read_ping_status: Read status from PING frames, reported with two bits per Device. + * Bits 31:24 are reserved. */ struct sdw_master_ops { int (*read_prop)(struct sdw_bus *bus); @@ -855,6 +857,7 @@ struct sdw_master_ops { struct sdw_bus_params *params); int (*pre_bank_switch)(struct sdw_bus *bus); int (*post_bank_switch)(struct sdw_bus *bus); + u32 (*read_ping_status)(struct sdw_bus *bus); }; -- cgit v1.2.3 From 133547a1ef16cbdadb5c0023e5917924ae326dcc Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 14 Jul 2022 09:10:41 +0800 Subject: soundwire: intel/cadence: expose PING status in manager ops Simple indirection to existing register. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Acked-By: Vinod Koul Link: https://lore.kernel.org/r/20220714011043.46059-3-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- drivers/soundwire/cadence_master.c | 8 ++++++++ drivers/soundwire/cadence_master.h | 2 ++ drivers/soundwire/intel.c | 1 + 3 files changed, 11 insertions(+) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 4fbb19557f5e..615b0b63a3e1 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -756,6 +756,14 @@ cdns_reset_page_addr(struct sdw_bus *bus, unsigned int dev_num) } EXPORT_SYMBOL(cdns_reset_page_addr); +u32 cdns_read_ping_status(struct sdw_bus *bus) +{ + struct sdw_cdns *cdns = bus_to_cdns(bus); + + return cdns_readl(cdns, CDNS_MCP_SLAVE_STAT); +} +EXPORT_SYMBOL(cdns_read_ping_status); + /* * IRQ handling */ diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h index 595d72c15d97..ca9e805bab88 100644 --- a/drivers/soundwire/cadence_master.h +++ b/drivers/soundwire/cadence_master.h @@ -177,6 +177,8 @@ enum sdw_command_response cdns_xfer_msg_defer(struct sdw_bus *bus, struct sdw_msg *msg, struct sdw_defer *defer); +u32 cdns_read_ping_status(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, diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 89d1d0d021fc..a5965e8827b9 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1262,6 +1262,7 @@ static struct sdw_master_ops sdw_intel_ops = { .set_bus_conf = cdns_bus_conf, .pre_bank_switch = intel_pre_bank_switch, .post_bank_switch = intel_post_bank_switch, + .read_ping_status = cdns_read_ping_status, }; static int intel_init(struct sdw_intel *sdw) -- cgit v1.2.3 From 79fe02cb7547fcc09e83b850cfd32896d7dc6289 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 14 Jul 2022 09:10:42 +0800 Subject: soundwire: add sdw_show_ping_status() helper This helper provides an optional delay parameter to wait for devices to resync in case of errors, and checks that devices are indeed attached on the bus. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Acked-By: Vinod Koul Link: https://lore.kernel.org/r/20220714011043.46059-4-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- drivers/soundwire/bus.c | 32 ++++++++++++++++++++++++++++++++ include/linux/soundwire/sdw.h | 2 ++ 2 files changed, 34 insertions(+) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 8d4000664fa3..d95b07896a3e 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -297,6 +297,38 @@ int sdw_transfer(struct sdw_bus *bus, struct sdw_msg *msg) return ret; } +/** + * sdw_show_ping_status() - Direct report of PING status, to be used by Peripheral drivers + * @bus: SDW bus + * @sync_delay: Delay before reading status + */ +void sdw_show_ping_status(struct sdw_bus *bus, bool sync_delay) +{ + u32 status; + + if (!bus->ops->read_ping_status) + return; + + /* + * wait for peripheral to sync if desired. 10-15ms should be more than + * enough in most cases. + */ + if (sync_delay) + usleep_range(10000, 15000); + + mutex_lock(&bus->msg_lock); + + status = bus->ops->read_ping_status(bus); + + mutex_unlock(&bus->msg_lock); + + if (!status) + dev_warn(bus->dev, "%s: no peripherals attached\n", __func__); + else + dev_dbg(bus->dev, "PING status: %#x\n", status); +} +EXPORT_SYMBOL(sdw_show_ping_status); + /** * sdw_transfer_defer() - Asynchronously transfer message to a SDW Slave device * @bus: SDW bus diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index eb840a07c25c..822599957b35 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -922,6 +922,8 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, struct fwnode_handle *fwnode); void sdw_bus_master_delete(struct sdw_bus *bus); +void sdw_show_ping_status(struct sdw_bus *bus, bool sync_delay); + /** * sdw_port_config: Master or Slave Port configuration * -- cgit v1.2.3 From 917df025e1db1286afb6e46914ae3e8b40241568 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 14 Jul 2022 09:10:43 +0800 Subject: ASoC: codecs: show PING status on resume failures This helper should help identify cases where devices fall off the bus and don't resync. BugLink: https://github.com/thesofproject/linux/issues/3638 Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Acked-By: Vinod Koul Link: https://lore.kernel.org/r/20220714011043.46059-5-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- 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-sdw.c | 2 ++ sound/soc/codecs/rt711-sdca-sdw.c | 2 ++ sound/soc/codecs/rt715-sdca-sdw.c | 2 ++ sound/soc/codecs/rt715-sdw.c | 2 ++ 8 files changed, 16 insertions(+) diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c index 97b64477dde6..899965b19d12 100644 --- a/sound/soc/codecs/max98373-sdw.c +++ b/sound/soc/codecs/max98373-sdw.c @@ -281,6 +281,8 @@ static __maybe_unused int max98373_resume(struct device *dev) msecs_to_jiffies(MAX98373_PROBE_TIMEOUT)); if (!time) { dev_err(dev, "Initialization not complete, timed out\n"); + sdw_show_ping_status(slave->bus, true); + return -ETIMEDOUT; } diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index 0be6e72ff5a9..5c29416aa781 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -749,6 +749,8 @@ static int __maybe_unused rt1308_dev_resume(struct device *dev) msecs_to_jiffies(RT1308_PROBE_TIMEOUT)); if (!time) { dev_err(&slave->dev, "Initialization not complete, timed out\n"); + sdw_show_ping_status(slave->bus, true); + return -ETIMEDOUT; } diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c index e53396606a1c..ed0a11436362 100644 --- a/sound/soc/codecs/rt1316-sdw.c +++ b/sound/soc/codecs/rt1316-sdw.c @@ -734,6 +734,8 @@ static int __maybe_unused rt1316_dev_resume(struct device *dev) msecs_to_jiffies(RT1316_PROBE_TIMEOUT)); if (!time) { dev_err(&slave->dev, "Initialization not complete, timed out\n"); + sdw_show_ping_status(slave->bus, true); + return -ETIMEDOUT; } diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index f04e18c32489..c1a94229dc7e 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -793,6 +793,8 @@ static int __maybe_unused rt5682_dev_resume(struct device *dev) msecs_to_jiffies(RT5682_PROBE_TIMEOUT)); if (!time) { dev_err(&slave->dev, "Initialization not complete, timed out\n"); + sdw_show_ping_status(slave->bus, true); + return -ETIMEDOUT; } diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c index f7439e40ca8b..96fc5f36d0d0 100644 --- a/sound/soc/codecs/rt700-sdw.c +++ b/sound/soc/codecs/rt700-sdw.c @@ -542,6 +542,8 @@ static int __maybe_unused rt700_dev_resume(struct device *dev) msecs_to_jiffies(RT700_PROBE_TIMEOUT)); if (!time) { dev_err(&slave->dev, "Initialization not complete, timed out\n"); + sdw_show_ping_status(slave->bus, true); + return -ETIMEDOUT; } diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c index a085b2f530aa..4120842fe699 100644 --- a/sound/soc/codecs/rt711-sdca-sdw.c +++ b/sound/soc/codecs/rt711-sdca-sdw.c @@ -449,6 +449,8 @@ static int __maybe_unused rt711_sdca_dev_resume(struct device *dev) msecs_to_jiffies(RT711_PROBE_TIMEOUT)); if (!time) { dev_err(&slave->dev, "Initialization not complete, timed out\n"); + sdw_show_ping_status(slave->bus, true); + return -ETIMEDOUT; } diff --git a/sound/soc/codecs/rt715-sdca-sdw.c b/sound/soc/codecs/rt715-sdca-sdw.c index 13e731d16675..3f981a9e7fb6 100644 --- a/sound/soc/codecs/rt715-sdca-sdw.c +++ b/sound/soc/codecs/rt715-sdca-sdw.c @@ -244,6 +244,8 @@ static int __maybe_unused rt715_dev_resume(struct device *dev) msecs_to_jiffies(RT715_PROBE_TIMEOUT)); if (!time) { dev_err(&slave->dev, "Enumeration not complete, timed out\n"); + sdw_show_ping_status(slave->bus, true); + return -ETIMEDOUT; } diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c index b047bf87a100..4e61e16470ed 100644 --- a/sound/soc/codecs/rt715-sdw.c +++ b/sound/soc/codecs/rt715-sdw.c @@ -562,6 +562,8 @@ static int __maybe_unused rt715_dev_resume(struct device *dev) msecs_to_jiffies(RT715_PROBE_TIMEOUT)); if (!time) { dev_err(&slave->dev, "Initialization not complete, timed out\n"); + sdw_show_ping_status(slave->bus, true); + return -ETIMEDOUT; } -- cgit v1.2.3 From 8ccaa7eb76742579864ddf834a8ea9c036c2cc5a Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 17 Aug 2022 13:23:43 +0100 Subject: ASoC: cs42l42: Don't include kernel.h kernel.h includes a lot of other headers that we don't need. Replace with an include of types.h. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20220817122347.1356773-2-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index d545a593a251..c212112cf87e 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include -- cgit v1.2.3 From b48d1da00fc8f32f7f75b8a34eb484f08b39ffaa Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 17 Aug 2022 13:23:44 +0100 Subject: ASoC: cs42l42: Add include dependencies to cs42l42.h Make cs42l42.h include the other headers it depends on instead of assuming that the .c file already included them. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20220817122347.1356773-3-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index 5f50970375d4..1d53e0e050ee 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -12,7 +12,12 @@ #ifndef __CS42L42_H__ #define __CS42L42_H__ +#include +#include +#include #include +#include +#include #include #include -- cgit v1.2.3 From dbd231732c99e336c2ece4a70896139e7f5a51a7 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 17 Aug 2022 13:23:45 +0100 Subject: ASoC: cs42l42: Move cs42l42_supply_names to .c file The array of supply name strings doesn't need to be in the header file. Move it to the .c file. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20220817122347.1356773-4-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 9 +++++++++ sound/soc/codecs/cs42l42.h | 8 -------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index c212112cf87e..abe3f91274fb 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -37,6 +37,14 @@ #include "cs42l42.h" #include "cirrus_legacy.h" +static const char * const cs42l42_supply_names[] = { + "VA", + "VP", + "VCP", + "VD_FILT", + "VL", +}; + static const struct reg_default cs42l42_reg_defaults[] = { { CS42L42_FRZ_CTL, 0x00 }, { CS42L42_SRC_CTL, 0x10 }, @@ -2214,6 +2222,7 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client) return ret; } + BUILD_BUG_ON(ARRAY_SIZE(cs42l42_supply_names) != ARRAY_SIZE(cs42l42->supplies)); for (i = 0; i < ARRAY_SIZE(cs42l42->supplies); i++) cs42l42->supplies[i].supply = cs42l42_supply_names[i]; diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index 1d53e0e050ee..50299c9f283a 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -21,14 +21,6 @@ #include #include -static const char *const cs42l42_supply_names[CS42L42_NUM_SUPPLIES] = { - "VA", - "VP", - "VCP", - "VD_FILT", - "VL", -}; - struct cs42l42_private { struct regmap *regmap; struct device *dev; -- cgit v1.2.3 From db568aab37c1af80057c12c97e6af049495c3e4a Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 17 Aug 2022 13:23:46 +0100 Subject: ASoC: cs42l42: Fix comment typo in cs42l42_slow_start_put() Fix "much change together" to "must change together". It's probably obvious what was meant but it's nice to fix it. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20220817122347.1356773-5-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index abe3f91274fb..40d5a2d98f2f 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -403,7 +403,7 @@ static int cs42l42_slow_start_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); u8 val; - /* all bits of SLOW_START_EN much change together */ + /* all bits of SLOW_START_EN must change together */ switch (ucontrol->value.integer.value[0]) { case 0: val = 0; -- cgit v1.2.3 From c2683ecfd1850cc99829691b2e1d90f1a6d75b8b Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 17 Aug 2022 13:23:47 +0100 Subject: ASoC: cs42l42: Use snd_soc_tdm_params_to_bclk() Use the new snd_soc_tdm_params_to_bclk() helper function to calculate the bclk. This function handles most of the previous manipulation and makes the code tidier. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20220817122347.1356773-6-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 40d5a2d98f2f..de1e276bdf7d 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -893,22 +893,21 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream, struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component); unsigned int channels = params_channels(params); unsigned int width = (params_width(params) / 8) - 1; + unsigned int slot_width = 0; unsigned int val = 0; int ret; cs42l42->srate = params_rate(params); - cs42l42->bclk = snd_soc_params_to_bclk(params); - - /* I2S frame always has 2 channels even for mono audio */ - if (channels == 1) - cs42l42->bclk *= 2; /* * Assume 24-bit samples are in 32-bit slots, to prevent SCLK being * more than assumed (which would result in overclocking). */ if (params_width(params) == 24) - cs42l42->bclk = (cs42l42->bclk / 3) * 4; + slot_width = 32; + + /* I2S frame always has multiple of 2 channels */ + cs42l42->bclk = snd_soc_tdm_params_to_bclk(params, slot_width, 0, 2); switch (substream->stream) { case SNDRV_PCM_STREAM_CAPTURE: -- cgit v1.2.3 From e32e23a2b588424aec0c4c4435530f8022318b8f Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 17 Aug 2022 13:55:08 +0100 Subject: ASoC: soc-utils-test: Add test for snd_soc_params_to_bclk() snd_soc_params_to_bclk() calculates the BCLK from only the information in snd_pcm_hw_params. It is therefore a subset of the functionality of snd_soc_tdm_params_to_bclk() so can use a subset of the test case table. Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20220817125508.1406651-1-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/soc-utils-test.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/sound/soc/soc-utils-test.c b/sound/soc/soc-utils-test.c index 5ad8e23af49a..616d2c926dd1 100644 --- a/sound/soc/soc-utils-test.c +++ b/sound/soc/soc-utils-test.c @@ -170,8 +170,54 @@ static void test_tdm_params_to_bclk(struct kunit *test) } } +static void test_snd_soc_params_to_bclk_one(struct kunit *test, + unsigned int rate, snd_pcm_format_t fmt, + unsigned int channels, + unsigned int expected_bclk) +{ + struct snd_pcm_hw_params params; + int got_bclk; + + _snd_pcm_hw_params_any(¶ms); + snd_mask_none(hw_param_mask(¶ms, SNDRV_PCM_HW_PARAM_FORMAT)); + hw_param_interval(¶ms, SNDRV_PCM_HW_PARAM_RATE)->min = rate; + hw_param_interval(¶ms, SNDRV_PCM_HW_PARAM_RATE)->max = rate; + hw_param_interval(¶ms, SNDRV_PCM_HW_PARAM_CHANNELS)->min = channels; + hw_param_interval(¶ms, SNDRV_PCM_HW_PARAM_CHANNELS)->max = channels; + params_set_format(¶ms, fmt); + + got_bclk = snd_soc_params_to_bclk(¶ms); + pr_debug("%s: r=%u sb=%u ch=%u expected=%u got=%d\n", + __func__, + rate, params_width(¶ms), channels, expected_bclk, got_bclk); + KUNIT_ASSERT_EQ(test, expected_bclk, (unsigned int)got_bclk); +} + +static void test_snd_soc_params_to_bclk(struct kunit *test) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(tdm_params_to_bclk_cases); ++i) { + /* + * snd_soc_params_to_bclk() is all the test cases where + * snd_pcm_hw_params values are not overridden. + */ + if (tdm_params_to_bclk_cases[i].tdm_width | + tdm_params_to_bclk_cases[i].tdm_slots | + tdm_params_to_bclk_cases[i].slot_multiple) + continue; + + test_snd_soc_params_to_bclk_one(test, + tdm_params_to_bclk_cases[i].rate, + tdm_params_to_bclk_cases[i].fmt, + tdm_params_to_bclk_cases[i].channels, + tdm_params_to_bclk_cases[i].bclk); + } +} + static struct kunit_case soc_utils_test_cases[] = { KUNIT_CASE(test_tdm_params_to_bclk), + KUNIT_CASE(test_snd_soc_params_to_bclk), {} }; -- cgit v1.2.3 From cb225ac125a9c82889f4796a6092dd0bed39720a Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 17 Aug 2022 13:24:27 +0800 Subject: ASoC: fsl_sai: Remove unnecessary FIFO reset in ISR The FIFO reset drops the words in the FIFO, which may cause channel swap when SAI module is running, especially when the DMA speed is low. So it is not good to do FIFO reset in ISR, then remove the operation. Fixes: e2681a1bf5ae ("ASoC: fsl_sai: Add isr to deal with error flag") Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1660713867-26921-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index d430eece1d6b..a7fa6f0bf83d 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -114,11 +114,8 @@ static irqreturn_t fsl_sai_isr(int irq, void *devid) if (flags & FSL_SAI_CSR_SEF) dev_dbg(dev, "isr: Tx Frame sync error detected\n"); - if (flags & FSL_SAI_CSR_FEF) { + if (flags & FSL_SAI_CSR_FEF) dev_dbg(dev, "isr: Transmit underrun detected\n"); - /* FIFO reset for safety */ - xcsr |= FSL_SAI_CSR_FR; - } if (flags & FSL_SAI_CSR_FWF) dev_dbg(dev, "isr: Enabled transmit FIFO is empty\n"); @@ -148,11 +145,8 @@ irq_rx: if (flags & FSL_SAI_CSR_SEF) dev_dbg(dev, "isr: Rx Frame sync error detected\n"); - if (flags & FSL_SAI_CSR_FEF) { + if (flags & FSL_SAI_CSR_FEF) dev_dbg(dev, "isr: Receive overflow detected\n"); - /* FIFO reset for safety */ - xcsr |= FSL_SAI_CSR_FR; - } if (flags & FSL_SAI_CSR_FWF) dev_dbg(dev, "isr: Enabled receive FIFO is full\n"); -- cgit v1.2.3 From e4746d94d00c52918461bc169e009b6784a38e21 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 16 Aug 2022 13:17:22 +0200 Subject: ASoC: Intel: Skylake: Introduce HDA codec init and exit routines Preliminary step in making snd_hda_codec_device_init() the only constructor for struct hda_codec instances. To do that, existing usage of hdac_ext equivalents has to be dropped. Reviewed-by: Kai Vehmanen Reviewed-by: Pierre-Louis Bossart Signed-off-by: Cezary Rojewski Acked-by: Mark Brown Link: https://lore.kernel.org/r/20220816111727.3218543-2-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai --- sound/soc/intel/skylake/skl.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index aeca58246fc7..33b0ed6b0534 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -689,6 +689,35 @@ static void load_codec_module(struct hda_codec *codec) #endif /* CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC */ +static void skl_codec_device_exit(struct device *dev) +{ + snd_hdac_device_exit(dev_to_hdac_dev(dev)); +} + +static __maybe_unused struct hda_codec *skl_codec_device_init(struct hdac_bus *bus, int addr) +{ + struct hda_codec *codec; + int ret; + + codec = snd_hda_codec_device_init(to_hda_bus(bus), addr, "ehdaudio%dD%d", bus->idx, addr); + if (IS_ERR(codec)) { + dev_err(bus->dev, "device init failed for hdac device\n"); + return codec; + } + + codec->core.type = HDA_DEV_ASOC; + codec->core.dev.release = skl_codec_device_exit; + + ret = snd_hdac_device_register(&codec->core); + if (ret) { + dev_err(bus->dev, "failed to register hdac device\n"); + snd_hdac_device_exit(&codec->core); + return ERR_PTR(ret); + } + + return codec; +} + /* * Probe the given codec address */ -- cgit v1.2.3 From 829c67319806009abfe3b0b82b3b8b153a2c5e32 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 16 Aug 2022 13:17:23 +0200 Subject: ASoC: SOF: Intel: Introduce HDA codec init and exit routines Preliminary step in making snd_hda_codec_device_init() the only constructor for struct hda_codec instances. To do that, existing usage of hdac_ext equivalents has to be dropped. Reviewed-by: Kai Vehmanen Reviewed-by: Pierre-Louis Bossart Signed-off-by: Cezary Rojewski Acked-by: Mark Brown Link: https://lore.kernel.org/r/20220816111727.3218543-3-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai --- sound/soc/sof/intel/hda-codec.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index 2f3f4a733d9e..4c128ba02340 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -109,6 +109,36 @@ EXPORT_SYMBOL_NS(hda_codec_jack_check, SND_SOC_SOF_HDA_AUDIO_CODEC); #define is_generic_config(x) 0 #endif +static void hda_codec_device_exit(struct device *dev) +{ + snd_hdac_device_exit(dev_to_hdac_dev(dev)); +} + +static __maybe_unused struct hda_codec * +hda_codec_device_init(struct hdac_bus *bus, int addr, int type) +{ + struct hda_codec *codec; + int ret; + + codec = snd_hda_codec_device_init(to_hda_bus(bus), addr, "ehdaudio%dD%d", bus->idx, addr); + if (IS_ERR(codec)) { + dev_err(bus->dev, "device init failed for hdac device\n"); + return codec; + } + + codec->core.type = type; + codec->core.dev.release = hda_codec_device_exit; + + ret = snd_hdac_device_register(&codec->core); + if (ret) { + dev_err(bus->dev, "failed to register hdac device\n"); + snd_hdac_device_exit(&codec->core); + return ERR_PTR(ret); + } + + return codec; +} + /* probe individual codec */ static int hda_codec_probe(struct snd_sof_dev *sdev, int address, bool hda_codec_use_common_hdmi) -- cgit v1.2.3 From 3fd63658caed9494cca1d4789a66d3d2def2a0ab Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 16 Aug 2022 13:17:24 +0200 Subject: ASoC: Intel: Drop hdac_ext usage for codec device creation To make snd_hda_codec_device_init() the only constructor for struct hda_codec instances remaining tasks are: 1) no struct may wrap struct hda_codec as its base type 2) bus drivers (skylake and sof) which are the current hdac_ext users need to be adjusted to make use of newly added codec init and exit routines instead 3) as bus drivers (skylake and sof) are to be responsible for creating codec device and assigning it to hdac_hda_priv->codec, hdac_hda_dev_probe() has to be freed of that job To keep git bisect happy, all of these in made in one-go. Reviewed-by: Kai Vehmanen Reviewed-by: Pierre-Louis Bossart Signed-off-by: Cezary Rojewski Acked-by: Mark Brown Link: https://lore.kernel.org/r/20220816111727.3218543-4-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai --- sound/soc/codecs/hdac_hda.c | 26 ++++++++++--------------- sound/soc/codecs/hdac_hda.h | 2 +- sound/soc/intel/boards/hda_dsp_common.c | 2 +- sound/soc/intel/boards/skl_hda_dsp_generic.c | 2 +- sound/soc/intel/skylake/skl.c | 26 +++++++++++-------------- sound/soc/sof/intel/hda-codec.c | 29 ++++++++++++---------------- 6 files changed, 36 insertions(+), 51 deletions(-) diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index 8debcee59224..77df4c5b274a 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -246,7 +246,7 @@ static int hdac_hda_dai_hw_free(struct snd_pcm_substream *substream, return -EINVAL; hda_stream = &pcm->stream[substream->stream]; - snd_hda_codec_cleanup(&hda_pvt->codec, hda_stream, substream); + snd_hda_codec_cleanup(hda_pvt->codec, hda_stream, substream); return 0; } @@ -264,7 +264,7 @@ static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream, int ret = 0; hda_pvt = snd_soc_component_get_drvdata(component); - hdev = &hda_pvt->codec.core; + hdev = &hda_pvt->codec->core; pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai); if (!pcm) return -EINVAL; @@ -274,7 +274,7 @@ static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream, stream = hda_pvt->pcm[dai->id].stream_tag[substream->stream]; format_val = hda_pvt->pcm[dai->id].format_val[substream->stream]; - ret = snd_hda_codec_prepare(&hda_pvt->codec, hda_stream, + ret = snd_hda_codec_prepare(hda_pvt->codec, hda_stream, stream, format_val, substream); if (ret < 0) dev_err(&hdev->dev, "codec prepare failed %d\n", ret); @@ -299,7 +299,7 @@ static int hdac_hda_dai_open(struct snd_pcm_substream *substream, hda_stream = &pcm->stream[substream->stream]; - return hda_stream->ops.open(hda_stream, &hda_pvt->codec, substream); + return hda_stream->ops.open(hda_stream, hda_pvt->codec, substream); } static void hdac_hda_dai_close(struct snd_pcm_substream *substream, @@ -317,7 +317,7 @@ static void hdac_hda_dai_close(struct snd_pcm_substream *substream, hda_stream = &pcm->stream[substream->stream]; - hda_stream->ops.close(hda_stream, &hda_pvt->codec, substream); + hda_stream->ops.close(hda_stream, hda_pvt->codec, substream); snd_hda_codec_pcm_put(pcm); } @@ -325,7 +325,7 @@ static void hdac_hda_dai_close(struct snd_pcm_substream *substream, static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt, struct snd_soc_dai *dai) { - struct hda_codec *hcodec = &hda_pvt->codec; + struct hda_codec *hcodec = hda_pvt->codec; struct hda_pcm *cpcm; const char *pcm_name; @@ -394,8 +394,8 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) snd_soc_component_get_drvdata(component); struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); - struct hdac_device *hdev = &hda_pvt->codec.core; - struct hda_codec *hcodec = &hda_pvt->codec; + struct hdac_device *hdev = &hda_pvt->codec->core; + struct hda_codec *hcodec = hda_pvt->codec; struct hdac_ext_link *hlink; hda_codec_patch_t patch; int ret; @@ -515,8 +515,8 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component) { struct hdac_hda_priv *hda_pvt = snd_soc_component_get_drvdata(component); - struct hdac_device *hdev = &hda_pvt->codec.core; - struct hda_codec *codec = &hda_pvt->codec; + struct hdac_device *hdev = &hda_pvt->codec->core; + struct hda_codec *codec = hda_pvt->codec; struct hdac_ext_link *hlink = NULL; hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev)); @@ -584,7 +584,6 @@ static const struct snd_soc_component_driver hdac_hda_codec = { static int hdac_hda_dev_probe(struct hdac_device *hdev) { struct hdac_ext_link *hlink; - struct hdac_hda_priv *hda_pvt; int ret; /* hold the ref while we probe */ @@ -595,10 +594,6 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev) } snd_hdac_ext_bus_link_get(hdev->bus, hlink); - hda_pvt = hdac_to_hda_priv(hdev); - if (!hda_pvt) - return -ENOMEM; - /* ASoC specific initialization */ ret = devm_snd_soc_register_component(&hdev->dev, &hdac_hda_codec, hdac_hda_dais, @@ -608,7 +603,6 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev) return ret; } - dev_set_drvdata(&hdev->dev, hda_pvt); snd_hdac_ext_bus_link_put(hdev->bus, hlink); return ret; diff --git a/sound/soc/codecs/hdac_hda.h b/sound/soc/codecs/hdac_hda.h index d0efc5e254ae..fc19c34ca00e 100644 --- a/sound/soc/codecs/hdac_hda.h +++ b/sound/soc/codecs/hdac_hda.h @@ -23,7 +23,7 @@ struct hdac_hda_pcm { }; struct hdac_hda_priv { - struct hda_codec codec; + struct hda_codec *codec; struct hdac_hda_pcm pcm[HDAC_LAST_DAI_ID]; bool need_display_power; }; diff --git a/sound/soc/intel/boards/hda_dsp_common.c b/sound/soc/intel/boards/hda_dsp_common.c index 83c7dfbccd9d..04b7d4f7f9e2 100644 --- a/sound/soc/intel/boards/hda_dsp_common.c +++ b/sound/soc/intel/boards/hda_dsp_common.c @@ -54,7 +54,7 @@ int hda_dsp_hdmi_build_controls(struct snd_soc_card *card, return -EINVAL; hda_pvt = snd_soc_component_get_drvdata(comp); - hcodec = &hda_pvt->codec; + hcodec = hda_pvt->codec; list_for_each_entry(hpcm, &hcodec->pcm_list_head, list) { spcm = hda_dsp_hdmi_pcm_handle(card, i); diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index 81144efb4b44..879ebba52832 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -190,7 +190,7 @@ static void skl_set_hda_codec_autosuspend_delay(struct snd_soc_card *card) * all codecs are on the same bus, so it's sufficient * to look up only the first one */ - snd_hda_set_power_save(hda_pvt->codec.bus, + snd_hda_set_power_save(hda_pvt->codec->bus, HDA_CODEC_AUTOSUSPEND_DELAY_MS); break; } diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 33b0ed6b0534..c7c1cad2a753 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -694,7 +694,7 @@ static void skl_codec_device_exit(struct device *dev) snd_hdac_device_exit(dev_to_hdac_dev(dev)); } -static __maybe_unused struct hda_codec *skl_codec_device_init(struct hdac_bus *bus, int addr) +static struct hda_codec *skl_codec_device_init(struct hdac_bus *bus, int addr) { struct hda_codec *codec; int ret; @@ -729,9 +729,8 @@ static int probe_codec(struct hdac_bus *bus, int addr) struct skl_dev *skl = bus_to_skl(bus); #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) struct hdac_hda_priv *hda_codec; - int err; #endif - struct hdac_device *hdev; + struct hda_codec *codec; mutex_lock(&bus->cmd_mutex); snd_hdac_bus_send_cmd(bus, cmd); @@ -747,25 +746,22 @@ static int probe_codec(struct hdac_bus *bus, int addr) if (!hda_codec) return -ENOMEM; - hda_codec->codec.bus = skl_to_hbus(skl); - hdev = &hda_codec->codec.core; + codec = skl_codec_device_init(bus, addr); + if (IS_ERR(codec)) + return PTR_ERR(codec); - err = snd_hdac_ext_bus_device_init(bus, addr, hdev, HDA_DEV_ASOC); - if (err < 0) - return err; + hda_codec->codec = codec; + dev_set_drvdata(&codec->core.dev, hda_codec); /* use legacy bus only for HDA codecs, idisp uses ext bus */ if ((res & 0xFFFF0000) != IDISP_INTEL_VENDOR_ID) { - hdev->type = HDA_DEV_LEGACY; - load_codec_module(&hda_codec->codec); + codec->core.type = HDA_DEV_LEGACY; + load_codec_module(hda_codec->codec); } return 0; #else - hdev = devm_kzalloc(&skl->pci->dev, sizeof(*hdev), GFP_KERNEL); - if (!hdev) - return -ENOMEM; - - return snd_hdac_ext_bus_device_init(bus, addr, hdev, HDA_DEV_ASOC); + codec = skl_codec_device_init(bus, addr); + return PTR_ERR_OR_ZERO(codec); #endif /* CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC */ } diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index 4c128ba02340..73336648cd25 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -114,8 +114,7 @@ static void hda_codec_device_exit(struct device *dev) snd_hdac_device_exit(dev_to_hdac_dev(dev)); } -static __maybe_unused struct hda_codec * -hda_codec_device_init(struct hdac_bus *bus, int addr, int type) +static struct hda_codec *hda_codec_device_init(struct hdac_bus *bus, int addr, int type) { struct hda_codec *codec; int ret; @@ -145,11 +144,10 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address, { #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) struct hdac_hda_priv *hda_priv; - struct hda_codec *codec; int type = HDA_DEV_LEGACY; #endif struct hda_bus *hbus = sof_to_hbus(sdev); - struct hdac_device *hdev; + struct hda_codec *codec; u32 hda_cmd = (address << 28) | (AC_NODE_ROOT << 20) | (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; u32 resp = -1; @@ -172,20 +170,20 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address, if (!hda_priv) return -ENOMEM; - hda_priv->codec.bus = hbus; - hdev = &hda_priv->codec.core; - codec = &hda_priv->codec; - /* only probe ASoC codec drivers for HDAC-HDMI */ if (!hda_codec_use_common_hdmi && (resp & 0xFFFF0000) == IDISP_VID_INTEL) type = HDA_DEV_ASOC; - ret = snd_hdac_ext_bus_device_init(&hbus->core, address, hdev, type); + codec = hda_codec_device_init(&hbus->core, address, type); + ret = PTR_ERR_OR_ZERO(codec); if (ret < 0) return ret; + hda_priv->codec = codec; + dev_set_drvdata(&codec->core.dev, hda_priv); + if ((resp & 0xFFFF0000) == IDISP_VID_INTEL) { - if (!hdev->bus->audio_component) { + if (!hbus->core.audio_component) { dev_dbg(sdev->dev, "iDisp hw present but no driver\n"); ret = -ENOENT; @@ -211,15 +209,12 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address, out: if (ret < 0) { - snd_hdac_device_unregister(hdev); - put_device(&hdev->dev); + snd_hdac_device_unregister(&codec->core); + put_device(&codec->core.dev); } #else - hdev = devm_kzalloc(sdev->dev, sizeof(*hdev), GFP_KERNEL); - if (!hdev) - return -ENOMEM; - - ret = snd_hdac_ext_bus_device_init(&hbus->core, address, hdev, HDA_DEV_ASOC); + codec = hda_codec_device_init(&hbus->core, address); + ret = PTR_ERR_OR_ZERO(codec); #endif return ret; -- cgit v1.2.3 From 0c5c29cafcea20f1f6a9943640e4a5a790e259ee Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 16 Aug 2022 13:17:25 +0200 Subject: ALSA: hda: Always free codec on the device release With all HDAudio drivers aligned to make use of the same constructor, have codec freed on the device release regardless of its type. Reviewed-by: Kai Vehmanen Reviewed-by: Pierre-Louis Bossart Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20220816111727.3218543-5-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 384426d7e9dd..aa7a362be290 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -883,13 +883,7 @@ static void snd_hda_codec_dev_release(struct device *dev) snd_hda_sysfs_clear(codec); kfree(codec->modelname); kfree(codec->wcaps); - - /* - * In the case of ASoC HD-audio, hda_codec is device managed. - * It will be freed when the ASoC device is removed. - */ - if (codec->core.type == HDA_DEV_LEGACY) - kfree(codec); + kfree(codec); } #define DEV_NAME_LEN 31 -- cgit v1.2.3 From fb5987844808bf9abeb23f695e94b75b439daa42 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 16 Aug 2022 13:17:26 +0200 Subject: ALSA: hda: Remove codec init and exit routines There are no users for snd_hdac_ext_bus_device_init() and snd_hdac_ext_bus_device_exit(). While at it, remove hdac_to_hda_priv() too for the exact same reason. Reviewed-by: Kai Vehmanen Reviewed-by: Pierre-Louis Bossart Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20220816111727.3218543-6-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai --- include/sound/hda_codec.h | 2 -- include/sound/hdaudio_ext.h | 3 --- sound/hda/ext/hdac_ext_bus.c | 53 -------------------------------------------- 3 files changed, 58 deletions(-) diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h index 6d3c82c4b6ac..2a8fe7240f10 100644 --- a/include/sound/hda_codec.h +++ b/include/sound/hda_codec.h @@ -293,8 +293,6 @@ struct hda_codec { #define dev_to_hda_codec(_dev) container_of(_dev, struct hda_codec, core.dev) #define hda_codec_dev(_dev) (&(_dev)->core.dev) -#define hdac_to_hda_priv(_hdac) \ - container_of(_hdac, struct hdac_hda_priv, codec.core) #define hdac_to_hda_codec(_hdac) container_of(_hdac, struct hda_codec, core) #define list_for_each_codec(c, bus) \ diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h index d26234f9ee46..88ebb64fd8a5 100644 --- a/include/sound/hdaudio_ext.h +++ b/include/sound/hdaudio_ext.h @@ -11,9 +11,6 @@ int snd_hdac_ext_bus_init(struct hdac_bus *bus, struct device *dev, const struct hdac_ext_bus_ops *ext_ops); void snd_hdac_ext_bus_exit(struct hdac_bus *bus); -int snd_hdac_ext_bus_device_init(struct hdac_bus *bus, int addr, - struct hdac_device *hdev, int type); -void snd_hdac_ext_bus_device_exit(struct hdac_device *hdev); void snd_hdac_ext_bus_device_remove(struct hdac_bus *bus); #define HDA_CODEC_REV_EXT_ENTRY(_vid, _rev, _name, drv_data) \ diff --git a/sound/hda/ext/hdac_ext_bus.c b/sound/hda/ext/hdac_ext_bus.c index 765c40a6ccba..6004ea1c373e 100644 --- a/sound/hda/ext/hdac_ext_bus.c +++ b/sound/hda/ext/hdac_ext_bus.c @@ -60,59 +60,6 @@ void snd_hdac_ext_bus_exit(struct hdac_bus *bus) } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_exit); -static void default_release(struct device *dev) -{ - snd_hdac_ext_bus_device_exit(dev_to_hdac_dev(dev)); -} - -/** - * snd_hdac_ext_bus_device_init - initialize the HDA extended codec base device - * @bus: hdac bus to attach to - * @addr: codec address - * @hdev: hdac device to init - * @type: codec type (HDAC_DEV_*) to use for this device - * - * Returns zero for success or a negative error code. - */ -int snd_hdac_ext_bus_device_init(struct hdac_bus *bus, int addr, - struct hdac_device *hdev, int type) -{ - char name[15]; - int ret; - - hdev->bus = bus; - - snprintf(name, sizeof(name), "ehdaudio%dD%d", bus->idx, addr); - - ret = snd_hdac_device_init(hdev, bus, name, addr); - if (ret < 0) { - dev_err(bus->dev, "device init failed for hdac device\n"); - return ret; - } - hdev->type = type; - hdev->dev.release = default_release; - - ret = snd_hdac_device_register(hdev); - if (ret) { - dev_err(bus->dev, "failed to register hdac device\n"); - snd_hdac_ext_bus_device_exit(hdev); - return ret; - } - - return 0; -} -EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_init); - -/** - * snd_hdac_ext_bus_device_exit - clean up a HD-audio extended codec base device - * @hdev: hdac device to clean up - */ -void snd_hdac_ext_bus_device_exit(struct hdac_device *hdev) -{ - snd_hdac_device_exit(hdev); -} -EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_exit); - /** * snd_hdac_ext_bus_device_remove - remove HD-audio extended codec base devices * -- cgit v1.2.3 From f2bd1c5ae2cb0cf9525c9bffc0038c12dd7e1338 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 16 Aug 2022 13:17:27 +0200 Subject: ALSA: hda: Fix page fault in snd_hda_codec_shutdown() If early probe of HDAudio bus driver fails e.g.: due to missing firmware file, snd_hda_codec_shutdown() ends in manipulating uninitialized codec->pcm_list_head causing page fault. Initialization of HDAudio codec in ASoC is split in two: - snd_hda_codec_device_init() - snd_hda_codec_device_new() snd_hda_codec_device_init() is called during probe_codecs() by HDAudio bus driver while snd_hda_codec_device_new() is called by codec-component's ->probe(). The second call will not happen until all components required by related sound card are present within the ASoC framework. With firmware failing to load during the PCI's deferred initialization i.e.: probe_work(), no platform components are ever registered. HDAudio codec enumeration is done at that point though, so the codec components became registered to ASoC framework, calling snd_hda_codec_device_init() in the process. Now, during platform reboot snd_hda_codec_shutdown() is called for every codec found on the HDAudio bus causing oops if any of them has not completed both of their initialization steps. Relocating field initialization fixes the issue. Reviewed-by: Kai Vehmanen Reviewed-by: Pierre-Louis Bossart Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20220816111727.3218543-7-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index aa7a362be290..b4d1e658c556 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -925,8 +925,28 @@ snd_hda_codec_device_init(struct hda_bus *bus, unsigned int codec_addr, } codec->bus = bus; + codec->depop_delay = -1; + codec->fixup_id = HDA_FIXUP_ID_NOT_SET; + codec->core.dev.release = snd_hda_codec_dev_release; + codec->core.exec_verb = codec_exec_verb; codec->core.type = HDA_DEV_LEGACY; + mutex_init(&codec->spdif_mutex); + mutex_init(&codec->control_mutex); + snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32); + snd_array_init(&codec->nids, sizeof(struct hda_nid_item), 32); + snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16); + snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16); + snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8); + snd_array_init(&codec->spdif_out, sizeof(struct hda_spdif_out), 16); + snd_array_init(&codec->jacktbl, sizeof(struct hda_jack_tbl), 16); + snd_array_init(&codec->verbs, sizeof(struct hda_verb *), 8); + INIT_LIST_HEAD(&codec->conn_list); + INIT_LIST_HEAD(&codec->pcm_list_head); + INIT_DELAYED_WORK(&codec->jackpoll_work, hda_jackpoll_work); + refcount_set(&codec->pcm_ref, 1); + init_waitqueue_head(&codec->remove_sleep); + return codec; } EXPORT_SYMBOL_GPL(snd_hda_codec_device_init); @@ -979,29 +999,8 @@ int snd_hda_codec_device_new(struct hda_bus *bus, struct snd_card *card, if (snd_BUG_ON(codec_addr > HDA_MAX_CODEC_ADDRESS)) return -EINVAL; - codec->core.dev.release = snd_hda_codec_dev_release; - codec->core.exec_verb = codec_exec_verb; - codec->card = card; codec->addr = codec_addr; - mutex_init(&codec->spdif_mutex); - mutex_init(&codec->control_mutex); - snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32); - snd_array_init(&codec->nids, sizeof(struct hda_nid_item), 32); - snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16); - snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16); - snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8); - snd_array_init(&codec->spdif_out, sizeof(struct hda_spdif_out), 16); - snd_array_init(&codec->jacktbl, sizeof(struct hda_jack_tbl), 16); - snd_array_init(&codec->verbs, sizeof(struct hda_verb *), 8); - INIT_LIST_HEAD(&codec->conn_list); - INIT_LIST_HEAD(&codec->pcm_list_head); - refcount_set(&codec->pcm_ref, 1); - init_waitqueue_head(&codec->remove_sleep); - - INIT_DELAYED_WORK(&codec->jackpoll_work, hda_jackpoll_work); - codec->depop_delay = -1; - codec->fixup_id = HDA_FIXUP_ID_NOT_SET; #ifdef CONFIG_PM codec->power_jiffies = jiffies; -- cgit v1.2.3 From 3cab69d99db754a2d3407fa2f5a80e6a2beb8440 Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Thu, 18 Aug 2022 16:15:14 +0200 Subject: ALSA: hda: Move stream-register polling macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Polling stream registers doesn't really have anything to do with extended HDA registers, so move it to basic HDA header. This will allow for use in HDA framework. Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20220818141517.109280-2-amadeuszx.slawinski@linux.intel.com Signed-off-by: Takashi Iwai --- include/sound/hdaudio.h | 7 +++++++ include/sound/hdaudio_ext.h | 6 ------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index 797bf67a164d..6e74aeafeda4 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -589,6 +590,12 @@ int snd_hdac_get_stream_stripe_ctl(struct hdac_bus *bus, snd_hdac_reg_readw((dev)->bus, (dev)->sd_addr + AZX_REG_ ## reg) #define snd_hdac_stream_readb(dev, reg) \ snd_hdac_reg_readb((dev)->bus, (dev)->sd_addr + AZX_REG_ ## reg) +#define snd_hdac_stream_readb_poll(dev, reg, val, cond, delay_us, timeout_us) \ + readb_poll_timeout((dev)->sd_addr + AZX_REG_ ## reg, val, cond, \ + delay_us, timeout_us) +#define snd_hdac_stream_readl_poll(dev, reg, val, cond, delay_us, timeout_us) \ + readl_poll_timeout((dev)->sd_addr + AZX_REG_ ## reg, val, cond, \ + delay_us, timeout_us) /* update a register, pass without AZX_REG_ prefix */ #define snd_hdac_stream_updatel(dev, reg, mask, val) \ diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h index 88ebb64fd8a5..07231f0b93b5 100644 --- a/include/sound/hdaudio_ext.h +++ b/include/sound/hdaudio_ext.h @@ -185,12 +185,6 @@ void snd_hdac_ext_bus_link_power(struct hdac_device *codec, bool enable); #define snd_hdac_adsp_readq_poll(chip, reg, val, cond, delay_us, timeout_us) \ readq_poll_timeout((chip)->dsp_ba + (reg), val, cond, \ delay_us, timeout_us) -#define snd_hdac_stream_readb_poll(strm, reg, val, cond, delay_us, timeout_us) \ - readb_poll_timeout((strm)->sd_addr + AZX_REG_ ## reg, val, cond, \ - delay_us, timeout_us) -#define snd_hdac_stream_readl_poll(strm, reg, val, cond, delay_us, timeout_us) \ - readl_poll_timeout((strm)->sd_addr + AZX_REG_ ## reg, val, cond, \ - delay_us, timeout_us) struct hdac_ext_device; -- cgit v1.2.3 From d91857059defe6acb443d8a25691b43a0f9390e8 Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Thu, 18 Aug 2022 16:15:15 +0200 Subject: ALSA: hda: Rework snd_hdac_stream_reset() to use macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can use existing macros to poll and update register values instead of open coding the functionality. Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20220818141517.109280-3-amadeuszx.slawinski@linux.intel.com Signed-off-by: Takashi Iwai --- sound/hda/hdac_stream.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c index f3582012d22f..bdf6d4db6769 100644 --- a/sound/hda/hdac_stream.c +++ b/sound/hda/hdac_stream.c @@ -165,7 +165,6 @@ EXPORT_SYMBOL_GPL(snd_hdac_stop_streams_and_chip); void snd_hdac_stream_reset(struct hdac_stream *azx_dev) { unsigned char val; - int timeout; int dma_run_state; snd_hdac_stream_clear(azx_dev); @@ -173,30 +172,17 @@ void snd_hdac_stream_reset(struct hdac_stream *azx_dev) dma_run_state = snd_hdac_stream_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START; snd_hdac_stream_updateb(azx_dev, SD_CTL, 0, SD_CTL_STREAM_RESET); - udelay(3); - timeout = 300; - do { - val = snd_hdac_stream_readb(azx_dev, SD_CTL) & - SD_CTL_STREAM_RESET; - if (val) - break; - } while (--timeout); + + /* wait for hardware to report that the stream entered reset */ + snd_hdac_stream_readb_poll(azx_dev, SD_CTL, val, (val & SD_CTL_STREAM_RESET), 3, 300); if (azx_dev->bus->dma_stop_delay && dma_run_state) udelay(azx_dev->bus->dma_stop_delay); - val &= ~SD_CTL_STREAM_RESET; - snd_hdac_stream_writeb(azx_dev, SD_CTL, val); - udelay(3); + snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_CTL_STREAM_RESET, 0); - timeout = 300; - /* waiting for hardware to report that the stream is out of reset */ - do { - val = snd_hdac_stream_readb(azx_dev, SD_CTL) & - SD_CTL_STREAM_RESET; - if (!val) - break; - } while (--timeout); + /* wait for hardware to report that the stream is out of reset */ + snd_hdac_stream_readb_poll(azx_dev, SD_CTL, val, !(val & SD_CTL_STREAM_RESET), 3, 300); /* reset first position - may not be synced with hw at this time */ if (azx_dev->posbuf) -- cgit v1.2.3 From 21b3d4f58401350cc73e67717366d1127caa6f7f Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Thu, 18 Aug 2022 16:15:16 +0200 Subject: ALSA: hda: Remove unused MAX_PIN_CONFIGS constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since it was introduced around v2.6.30 it was never used. Also HDA specification does not mention any limitation on number of PIN configurations. Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20220818141517.109280-4-amadeuszx.slawinski@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_sysfs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/pci/hda/hda_sysfs.c b/sound/pci/hda/hda_sysfs.c index bf951c10ae61..69ebc37a4d6f 100644 --- a/sound/pci/hda/hda_sysfs.c +++ b/sound/pci/hda/hda_sysfs.c @@ -375,8 +375,6 @@ static ssize_t user_pin_configs_show(struct device *dev, return pin_configs_show(codec, &codec->user_pins, buf); } -#define MAX_PIN_CONFIGS 32 - static int parse_user_pin_configs(struct hda_codec *codec, const char *buf) { int nid, cfg, err; -- cgit v1.2.3 From da9d635f07f21b07ceda13a2ac815a058995f113 Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Thu, 18 Aug 2022 16:15:17 +0200 Subject: ALSA: hda: Remove unused defines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no need to keep unused defines in file. Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20220818141517.109280-5-amadeuszx.slawinski@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index a77165bd92a9..7720978dc132 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -86,9 +86,6 @@ enum { #define INTEL_SCH_HDA_DEVC 0x78 #define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11) -/* Define VIA HD Audio Device ID*/ -#define VIA_HDAC_DEVICE_ID 0x3288 - /* max number of SDs */ /* ICH, ATI and VIA have 4 playback and 4 capture */ #define ICH6_NUM_CAPTURE 4 @@ -102,10 +99,6 @@ enum { #define ATIHDMI_NUM_CAPTURE 0 #define ATIHDMI_NUM_PLAYBACK 8 -/* TERA has 4 playback and 3 capture */ -#define TERA_NUM_CAPTURE 3 -#define TERA_NUM_PLAYBACK 4 - static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; -- cgit v1.2.3 From 3c15abbed0ab99bac2e075ad38d43a7004778e91 Mon Sep 17 00:00:00 2001 From: Chunxu Li Date: Thu, 18 Aug 2022 10:51:11 +0800 Subject: ASoC: mediatek: mt8186: support DSP downlink 1. add DSP downlink link widget 2. add DSP to I2S route path Signed-off-by: Chunxu Li Link: https://lore.kernel.org/r/20220818025113.17144-2-chunxu.li@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8186/mt8186-afe-pcm.c | 3 +++ sound/soc/mediatek/mt8186/mt8186-dai-i2s.c | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c b/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c index eb729ab00f5a..d7e94e6a19c7 100644 --- a/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c +++ b/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c @@ -1359,6 +1359,9 @@ static const struct snd_soc_dapm_widget mt8186_memif_widgets[] = { SND_SOC_DAPM_MUX("UL5_IN_MUX", SND_SOC_NOPM, 0, 0, &ul5_in_mux_control), + SND_SOC_DAPM_MIXER("DSP_DL1_VIRT", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("DSP_DL2_VIRT", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_INPUT("UL1_VIRTUAL_INPUT"), SND_SOC_DAPM_INPUT("UL2_VIRTUAL_INPUT"), SND_SOC_DAPM_INPUT("UL3_VIRTUAL_INPUT"), diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c b/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c index d7a227169548..e553a555d168 100644 --- a/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c +++ b/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c @@ -658,9 +658,15 @@ static const struct snd_soc_dapm_route mtk_dai_i2s_routes[] = { {"I2S1_CH1", "DL1_CH1 Switch", "DL1"}, {"I2S1_CH2", "DL1_CH2 Switch", "DL1"}, + {"I2S1_CH1", "DL1_CH1 Switch", "DSP_DL1_VIRT"}, + {"I2S1_CH2", "DL1_CH2 Switch", "DSP_DL1_VIRT"}, + {"I2S1_CH1", "DL2_CH1 Switch", "DL2"}, {"I2S1_CH2", "DL2_CH2 Switch", "DL2"}, + {"I2S1_CH1", "DL2_CH1 Switch", "DSP_DL2_VIRT"}, + {"I2S1_CH2", "DL2_CH2 Switch", "DSP_DL2_VIRT"}, + {"I2S1_CH1", "DL3_CH1 Switch", "DL3"}, {"I2S1_CH2", "DL3_CH2 Switch", "DL3"}, @@ -728,9 +734,15 @@ static const struct snd_soc_dapm_route mtk_dai_i2s_routes[] = { {"I2S3_CH1", "DL1_CH1 Switch", "DL1"}, {"I2S3_CH2", "DL1_CH2 Switch", "DL1"}, + {"I2S3_CH1", "DL1_CH1 Switch", "DSP_DL1_VIRT"}, + {"I2S3_CH2", "DL1_CH2 Switch", "DSP_DL1_VIRT"}, + {"I2S3_CH1", "DL2_CH1 Switch", "DL2"}, {"I2S3_CH2", "DL2_CH2 Switch", "DL2"}, + {"I2S3_CH1", "DL2_CH1 Switch", "DSP_DL2_VIRT"}, + {"I2S3_CH2", "DL2_CH2 Switch", "DSP_DL2_VIRT"}, + {"I2S3_CH1", "DL3_CH1 Switch", "DL3"}, {"I2S3_CH2", "DL3_CH2 Switch", "DL3"}, -- cgit v1.2.3 From 4be34e1b70ac72415a55e02683cd847436424588 Mon Sep 17 00:00:00 2001 From: Chunxu Li Date: Thu, 18 Aug 2022 10:51:12 +0800 Subject: ASoC: mediatek: mt8186: add SOF support on mt8186-mt6366-rt1019-rt5682s 1. Add widgets, routes and dai-links required by SOF 2. Only when adsp phandle could be retrieved from DTS, the SOF related part of machine driver is executed. 3. Support 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: Chunxu Li Link: https://lore.kernel.org/r/20220818025113.17144-3-chunxu.li@mediatek.com Signed-off-by: Mark Brown --- .../mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c | 168 +++++++++++++++++++-- 1 file changed, 155 insertions(+), 13 deletions(-) diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c index 891146fd6c2b..6c41706a5621 100644 --- a/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c +++ b/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c @@ -19,6 +19,8 @@ #include "../../codecs/mt6358.h" #include "../../codecs/rt5682.h" #include "../common/mtk-afe-platform-driver.h" +#include "../common/mtk-dsp-sof-common.h" +#include "../common/mtk-soc-card.h" #include "mt8186-afe-common.h" #include "mt8186-afe-clk.h" #include "mt8186-afe-gpio.h" @@ -30,6 +32,11 @@ #define RT5682S_CODEC_DAI "rt5682s-aif1" #define RT5682S_DEV0_NAME "rt5682s.5-001a" +#define SOF_DMA_DL1 "SOF_DMA_DL1" +#define SOF_DMA_DL2 "SOF_DMA_DL2" +#define SOF_DMA_UL1 "SOF_DMA_UL1" +#define SOF_DMA_UL2 "SOF_DMA_UL2" + struct mt8186_mt6366_rt1019_rt5682s_priv { struct snd_soc_jack headset_jack, hdmi_jack; }; @@ -51,8 +58,9 @@ static struct snd_soc_codec_conf mt8186_mt6366_rt1019_rt5682s_codec_conf[] = { static int mt8186_rt5682s_init(struct snd_soc_pcm_runtime *rtd) { - struct mt8186_mt6366_rt1019_rt5682s_priv *priv = + struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card); + struct mt8186_mt6366_rt1019_rt5682s_priv *priv = soc_card_data->mach_priv; struct snd_soc_jack *jack = &priv->headset_jack; struct snd_soc_component *cmpnt_codec = asoc_rtd_to_codec(rtd, 0)->component; @@ -130,8 +138,9 @@ static int mt8186_mt6366_rt1019_rt5682s_hdmi_init(struct snd_soc_pcm_runtime *rt { struct snd_soc_component *cmpnt_codec = asoc_rtd_to_codec(rtd, 0)->component; - struct mt8186_mt6366_rt1019_rt5682s_priv *priv = + struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card); + struct mt8186_mt6366_rt1019_rt5682s_priv *priv = soc_card_data->mach_priv; int ret; ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT, &priv->hdmi_jack); @@ -177,6 +186,24 @@ static int mt8186_it6505_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return mt8186_hw_params_fixup(rtd, params, SNDRV_PCM_FORMAT_S32_LE); } +/* fixup the BE DAI link to match any values from topology */ +static int mt8186_sof_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + int ret; + + ret = mtk_sof_dai_link_fixup(rtd, params); + + if (!strcmp(rtd->dai_link->name, "I2S0") || + !strcmp(rtd->dai_link->name, "I2S1") || + !strcmp(rtd->dai_link->name, "I2S2")) + mt8186_i2s_hw_params_fixup(rtd, params); + else if (!strcmp(rtd->dai_link->name, "I2S3")) + mt8186_it6505_i2s_hw_params_fixup(rtd, params); + + return ret; +} + static int mt8186_mt6366_rt1019_rt5682s_playback_startup(struct snd_pcm_substream *substream) { static const unsigned int rates[] = { @@ -450,6 +477,33 @@ SND_SOC_DAILINK_DEFS(hostless_src_aaudio, DAILINK_COMP_ARRAY(COMP_CPU("Hostless SRC AAudio DAI")), DAILINK_COMP_ARRAY(COMP_DUMMY()), DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(AFE_SOF_DL1, + DAILINK_COMP_ARRAY(COMP_CPU("SOF_DL1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + 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_UL1, + DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(AFE_SOF_UL2, + DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +static const struct sof_conn_stream g_sof_conn_streams[] = { + { "I2S1", "AFE_SOF_DL1", SOF_DMA_DL1, SNDRV_PCM_STREAM_PLAYBACK}, + { "I2S3", "AFE_SOF_DL2", SOF_DMA_DL2, SNDRV_PCM_STREAM_PLAYBACK}, + { "Primary Codec", "AFE_SOF_UL1", SOF_DMA_UL1, SNDRV_PCM_STREAM_CAPTURE}, + { "I2S0", "AFE_SOF_UL2", SOF_DMA_UL2, SNDRV_PCM_STREAM_CAPTURE}, +}; + static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { /* Front End DAI links */ { @@ -824,12 +878,41 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_ul6), }, + /* SOF BE */ + { + .name = "AFE_SOF_DL1", + .no_pcm = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(AFE_SOF_DL1), + }, + { + .name = "AFE_SOF_DL2", + .no_pcm = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(AFE_SOF_DL2), + }, + { + .name = "AFE_SOF_UL1", + .no_pcm = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(AFE_SOF_UL1), + }, + { + .name = "AFE_SOF_UL2", + .no_pcm = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(AFE_SOF_UL2), + }, }; static const struct snd_soc_dapm_widget mt8186_mt6366_rt1019_rt5682s_widgets[] = { SND_SOC_DAPM_SPK("Speakers", NULL), SND_SOC_DAPM_OUTPUT("HDMI1"), + SND_SOC_DAPM_MIXER(SOF_DMA_DL1, SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER(SOF_DMA_DL2, SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER(SOF_DMA_UL1, SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER(SOF_DMA_UL2, SND_SOC_NOPM, 0, 0, NULL, 0), }; static const struct snd_soc_dapm_route @@ -838,6 +921,14 @@ mt8186_mt6366_rt1019_rt5682s_routes[] = { { "Speakers", NULL, "Speaker" }, /* HDMI */ { "HDMI1", NULL, "TX" }, + /* SOF Uplink */ + {SOF_DMA_UL1, NULL, "UL1_CH1"}, + {SOF_DMA_UL1, NULL, "UL1_CH2"}, + {SOF_DMA_UL2, NULL, "UL2_CH1"}, + {SOF_DMA_UL2, NULL, "UL2_CH2"}, + /* SOF Downlink */ + {"DSP_DL1_VIRT", NULL, SOF_DMA_DL1}, + {"DSP_DL2_VIRT", NULL, SOF_DMA_DL2}, }; static const struct snd_kcontrol_new @@ -865,8 +956,10 @@ static int mt8186_mt6366_rt1019_rt5682s_dev_probe(struct platform_device *pdev) { struct snd_soc_card *card; struct snd_soc_dai_link *dai_link; - struct mt8186_mt6366_rt1019_rt5682s_priv *priv; - struct device_node *platform_node, *headset_codec, *playback_codec; + struct mtk_soc_card_data *soc_card_data; + struct mt8186_mt6366_rt1019_rt5682s_priv *mach_priv; + struct device_node *platform_node, *headset_codec, *playback_codec, *adsp_node; + int sof_on = 0; int ret, i; card = (struct snd_soc_card *)device_get_match_data(&pdev->dev); @@ -874,11 +967,60 @@ static int mt8186_mt6366_rt1019_rt5682s_dev_probe(struct platform_device *pdev) return -EINVAL; card->dev = &pdev->dev; + soc_card_data = devm_kzalloc(&pdev->dev, sizeof(*soc_card_data), GFP_KERNEL); + if (!soc_card_data) + return -ENOMEM; + mach_priv = devm_kzalloc(&pdev->dev, sizeof(*mach_priv), GFP_KERNEL); + if (!mach_priv) + return -ENOMEM; + + soc_card_data->mach_priv = mach_priv; + + adsp_node = of_parse_phandle(pdev->dev.of_node, "mediatek,adsp", 0); + if (adsp_node) { + struct mtk_sof_priv *sof_priv; + + sof_priv = devm_kzalloc(&pdev->dev, sizeof(*sof_priv), GFP_KERNEL); + if (!sof_priv) { + ret = -ENOMEM; + goto err_adsp_node; + } + sof_priv->conn_streams = g_sof_conn_streams; + sof_priv->num_streams = ARRAY_SIZE(g_sof_conn_streams); + sof_priv->sof_dai_link_fixup = mt8186_sof_dai_link_fixup; + soc_card_data->sof_priv = sof_priv; + card->probe = mtk_sof_card_probe; + card->late_probe = mtk_sof_card_late_probe; + if (!card->topology_shortname_created) { + snprintf(card->topology_shortname, 32, "sof-%s", card->name); + card->topology_shortname_created = true; + } + card->name = card->topology_shortname; + sof_on = 1; + } else { + dev_info(&pdev->dev, "Probe without adsp\n"); + } + + if (of_property_read_bool(pdev->dev.of_node, "mediatek,dai-link")) { + ret = mtk_sof_dailink_parse_of(card, pdev->dev.of_node, + "mediatek,dai-link", + mt8186_mt6366_rt1019_rt5682s_dai_links, + ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_dai_links)); + if (ret) { + dev_dbg(&pdev->dev, "Parse dai-link fail\n"); + goto err_adsp_node; + } + } else { + if (!sof_on) + card->num_links = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_dai_links) + - ARRAY_SIZE(g_sof_conn_streams); + } + platform_node = of_parse_phandle(pdev->dev.of_node, "mediatek,platform", 0); if (!platform_node) { ret = -EINVAL; dev_err_probe(&pdev->dev, ret, "Property 'platform' missing or invalid\n"); - return ret; + goto err_platform_node; } playback_codec = of_get_child_by_name(pdev->dev.of_node, "playback-codecs"); @@ -917,17 +1059,14 @@ static int mt8186_mt6366_rt1019_rt5682s_dev_probe(struct platform_device *pdev) goto err_probe; } - if (!dai_link->platforms->name) - dai_link->platforms->of_node = platform_node; - } + if (!strncmp(dai_link->name, "AFE_SOF", strlen("AFE_SOF")) && sof_on) + dai_link->platforms->of_node = adsp_node; - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - ret = -ENOMEM; - goto err_probe; + if (!dai_link->platforms->name && !dai_link->platforms->of_node) + dai_link->platforms->of_node = platform_node; } - snd_soc_card_set_drvdata(card, priv); + snd_soc_card_set_drvdata(card, soc_card_data); ret = mt8186_afe_gpio_init(&pdev->dev); if (ret) { @@ -945,6 +1084,9 @@ err_headset_codec: of_node_put(playback_codec); err_playback_codec: of_node_put(platform_node); +err_platform_node: +err_adsp_node: + of_node_put(adsp_node); return ret; } -- cgit v1.2.3 From 9398381a3904d8849691fb3ec173b48f077c185e Mon Sep 17 00:00:00 2001 From: Chunxu Li Date: Thu, 18 Aug 2022 10:51:13 +0800 Subject: ASoC: mediatek: mt8186: add SOF support on mt8186-mt6366-da7219-max98357 1. Add widgets, routes and dai-links required by SOF 2. Only when adsp phandle could be retrieved from DTS, the SOF related part of machine driver is executed. 3. Support 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: Chunxu Li Link: https://lore.kernel.org/r/20220818025113.17144-4-chunxu.li@mediatek.com Signed-off-by: Mark Brown --- .../mt8186/mt8186-mt6366-da7219-max98357.c | 168 +++++++++++++++++++-- 1 file changed, 155 insertions(+), 13 deletions(-) diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c index 387f25cad809..84ee5d95a9f0 100644 --- a/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c +++ b/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c @@ -18,6 +18,8 @@ #include "../../codecs/da7219.h" #include "../../codecs/mt6358.h" #include "../common/mtk-afe-platform-driver.h" +#include "../common/mtk-dsp-sof-common.h" +#include "../common/mtk-soc-card.h" #include "mt8186-afe-common.h" #include "mt8186-afe-clk.h" #include "mt8186-afe-gpio.h" @@ -26,6 +28,11 @@ #define DA7219_CODEC_DAI "da7219-hifi" #define DA7219_DEV_NAME "da7219.5-001a" +#define SOF_DMA_DL1 "SOF_DMA_DL1" +#define SOF_DMA_DL2 "SOF_DMA_DL2" +#define SOF_DMA_UL1 "SOF_DMA_UL1" +#define SOF_DMA_UL2 "SOF_DMA_UL2" + struct mt8186_mt6366_da7219_max98357_priv { struct snd_soc_jack headset_jack, hdmi_jack; }; @@ -47,8 +54,9 @@ static struct snd_soc_codec_conf mt8186_mt6366_da7219_max98357_codec_conf[] = { static int mt8186_da7219_init(struct snd_soc_pcm_runtime *rtd) { - struct mt8186_mt6366_da7219_max98357_priv *priv = + struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card); + struct mt8186_mt6366_da7219_max98357_priv *priv = soc_card_data->mach_priv; struct snd_soc_jack *jack = &priv->headset_jack; struct snd_soc_component *cmpnt_codec = asoc_rtd_to_codec(rtd, 0)->component; @@ -154,8 +162,9 @@ static int mt8186_mt6366_da7219_max98357_hdmi_init(struct snd_soc_pcm_runtime *r { struct snd_soc_component *cmpnt_codec = asoc_rtd_to_codec(rtd, 0)->component; - struct mt8186_mt6366_da7219_max98357_priv *priv = + struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card); + struct mt8186_mt6366_da7219_max98357_priv *priv = soc_card_data->mach_priv; int ret; ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT, &priv->hdmi_jack); @@ -201,6 +210,24 @@ static int mt8186_anx7625_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return mt8186_hw_params_fixup(rtd, params, SNDRV_PCM_FORMAT_S24_LE); } +/* fixup the BE DAI link to match any values from topology */ +static int mt8186_sof_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + int ret; + + ret = mtk_sof_dai_link_fixup(rtd, params); + + if (!strcmp(rtd->dai_link->name, "I2S0") || + !strcmp(rtd->dai_link->name, "I2S1") || + !strcmp(rtd->dai_link->name, "I2S2")) + mt8186_i2s_hw_params_fixup(rtd, params); + else if (!strcmp(rtd->dai_link->name, "I2S3")) + mt8186_anx7625_i2s_hw_params_fixup(rtd, params); + + return ret; +} + static int mt8186_mt6366_da7219_max98357_playback_startup(struct snd_pcm_substream *substream) { static const unsigned int rates[] = { @@ -474,6 +501,33 @@ SND_SOC_DAILINK_DEFS(hostless_src_aaudio, DAILINK_COMP_ARRAY(COMP_CPU("Hostless SRC AAudio DAI")), DAILINK_COMP_ARRAY(COMP_DUMMY()), DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(AFE_SOF_DL1, + DAILINK_COMP_ARRAY(COMP_CPU("SOF_DL1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + 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_UL1, + DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(AFE_SOF_UL2, + DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +static const struct sof_conn_stream g_sof_conn_streams[] = { + { "I2S1", "AFE_SOF_DL1", SOF_DMA_DL1, SNDRV_PCM_STREAM_PLAYBACK}, + { "I2S3", "AFE_SOF_DL2", SOF_DMA_DL2, SNDRV_PCM_STREAM_PLAYBACK}, + { "Primary Codec", "AFE_SOF_UL1", SOF_DMA_UL1, SNDRV_PCM_STREAM_CAPTURE}, + { "I2S0", "AFE_SOF_UL2", SOF_DMA_UL2, SNDRV_PCM_STREAM_CAPTURE}, +}; + static struct snd_soc_dai_link mt8186_mt6366_da7219_max98357_dai_links[] = { /* Front End DAI links */ { @@ -848,12 +902,41 @@ static struct snd_soc_dai_link mt8186_mt6366_da7219_max98357_dai_links[] = { .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_ul6), }, + /* SOF BE */ + { + .name = "AFE_SOF_DL1", + .no_pcm = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(AFE_SOF_DL1), + }, + { + .name = "AFE_SOF_DL2", + .no_pcm = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(AFE_SOF_DL2), + }, + { + .name = "AFE_SOF_UL1", + .no_pcm = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(AFE_SOF_UL1), + }, + { + .name = "AFE_SOF_UL2", + .no_pcm = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(AFE_SOF_UL2), + }, }; static const struct snd_soc_dapm_widget mt8186_mt6366_da7219_max98357_widgets[] = { SND_SOC_DAPM_SPK("Speakers", NULL), SND_SOC_DAPM_OUTPUT("HDMI1"), + SND_SOC_DAPM_MIXER(SOF_DMA_DL1, SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER(SOF_DMA_DL2, SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER(SOF_DMA_UL1, SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER(SOF_DMA_UL2, SND_SOC_NOPM, 0, 0, NULL, 0), }; static const struct snd_soc_dapm_route @@ -862,6 +945,14 @@ mt8186_mt6366_da7219_max98357_routes[] = { { "Speakers", NULL, "Speaker"}, /* HDMI */ { "HDMI1", NULL, "TX"}, + /* SOF Uplink */ + {SOF_DMA_UL1, NULL, "UL1_CH1"}, + {SOF_DMA_UL1, NULL, "UL1_CH2"}, + {SOF_DMA_UL2, NULL, "UL2_CH1"}, + {SOF_DMA_UL2, NULL, "UL2_CH2"}, + /* SOF Downlink */ + {"DSP_DL1_VIRT", NULL, SOF_DMA_DL1}, + {"DSP_DL2_VIRT", NULL, SOF_DMA_DL2}, }; static const struct snd_kcontrol_new @@ -889,8 +980,10 @@ static int mt8186_mt6366_da7219_max98357_dev_probe(struct platform_device *pdev) { struct snd_soc_card *card; struct snd_soc_dai_link *dai_link; - struct mt8186_mt6366_da7219_max98357_priv *priv; - struct device_node *platform_node, *headset_codec, *playback_codec; + struct mtk_soc_card_data *soc_card_data; + struct mt8186_mt6366_da7219_max98357_priv *mach_priv; + struct device_node *platform_node, *headset_codec, *playback_codec, *adsp_node; + int sof_on = 0; int ret, i; card = (struct snd_soc_card *)device_get_match_data(&pdev->dev); @@ -898,11 +991,60 @@ static int mt8186_mt6366_da7219_max98357_dev_probe(struct platform_device *pdev) return -EINVAL; card->dev = &pdev->dev; + soc_card_data = devm_kzalloc(&pdev->dev, sizeof(*soc_card_data), GFP_KERNEL); + if (!soc_card_data) + return -ENOMEM; + mach_priv = devm_kzalloc(&pdev->dev, sizeof(*mach_priv), GFP_KERNEL); + if (!mach_priv) + return -ENOMEM; + + soc_card_data->mach_priv = mach_priv; + + adsp_node = of_parse_phandle(pdev->dev.of_node, "mediatek,adsp", 0); + if (adsp_node) { + struct mtk_sof_priv *sof_priv; + + sof_priv = devm_kzalloc(&pdev->dev, sizeof(*sof_priv), GFP_KERNEL); + if (!sof_priv) { + ret = -ENOMEM; + goto err_adsp_node; + } + sof_priv->conn_streams = g_sof_conn_streams; + sof_priv->num_streams = ARRAY_SIZE(g_sof_conn_streams); + sof_priv->sof_dai_link_fixup = mt8186_sof_dai_link_fixup; + soc_card_data->sof_priv = sof_priv; + card->probe = mtk_sof_card_probe; + card->late_probe = mtk_sof_card_late_probe; + if (!card->topology_shortname_created) { + snprintf(card->topology_shortname, 32, "sof-%s", card->name); + card->topology_shortname_created = true; + } + card->name = card->topology_shortname; + sof_on = 1; + } else { + dev_info(&pdev->dev, "Probe without adsp\n"); + } + + if (of_property_read_bool(pdev->dev.of_node, "mediatek,dai-link")) { + ret = mtk_sof_dailink_parse_of(card, pdev->dev.of_node, + "mediatek,dai-link", + mt8186_mt6366_da7219_max98357_dai_links, + ARRAY_SIZE(mt8186_mt6366_da7219_max98357_dai_links)); + if (ret) { + dev_dbg(&pdev->dev, "Parse dai-link fail\n"); + goto err_adsp_node; + } + } else { + if (!sof_on) + card->num_links = ARRAY_SIZE(mt8186_mt6366_da7219_max98357_dai_links) + - ARRAY_SIZE(g_sof_conn_streams); + } + platform_node = of_parse_phandle(pdev->dev.of_node, "mediatek,platform", 0); if (!platform_node) { ret = -EINVAL; dev_err_probe(&pdev->dev, ret, "Property 'platform' missing or invalid\n"); - return ret; + goto err_platform_node; } playback_codec = of_get_child_by_name(pdev->dev.of_node, "playback-codecs"); @@ -941,17 +1083,14 @@ static int mt8186_mt6366_da7219_max98357_dev_probe(struct platform_device *pdev) goto err_probe; } - if (!dai_link->platforms->name) - dai_link->platforms->of_node = platform_node; - } + if (!strncmp(dai_link->name, "AFE_SOF", strlen("AFE_SOF")) && sof_on) + dai_link->platforms->of_node = adsp_node; - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - ret = -ENOMEM; - goto err_probe; + if (!dai_link->platforms->name && !dai_link->platforms->of_node) + dai_link->platforms->of_node = platform_node; } - snd_soc_card_set_drvdata(card, priv); + snd_soc_card_set_drvdata(card, soc_card_data); ret = mt8186_afe_gpio_init(&pdev->dev); if (ret) { @@ -969,6 +1108,9 @@ err_headset_codec: of_node_put(playback_codec); err_playback_codec: of_node_put(platform_node); +err_platform_node: +err_adsp_node: + of_node_put(adsp_node); return ret; } -- cgit v1.2.3 From ee6c42ba5c7670c6f8c17c7bcedbcdaf7b8eb72e Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Thu, 18 Aug 2022 09:53:53 +0800 Subject: dt-bindings: dsp: fsl: Add SOF compatile string for i.MX8ULP Add SOF compatile string "fsl,imx8ulp-dsp" for supporting DSP device on i.MX8ULP platform. Signed-off-by: Shengjiu Wang Acked-by: Rob Herring Reviewed-by: Daniel Baluta Link: https://lore.kernel.org/r/1660787634-28550-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/dsp/fsl,dsp.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/dsp/fsl,dsp.yaml b/Documentation/devicetree/bindings/dsp/fsl,dsp.yaml index e66ef2da7879..9af40da5688e 100644 --- a/Documentation/devicetree/bindings/dsp/fsl,dsp.yaml +++ b/Documentation/devicetree/bindings/dsp/fsl,dsp.yaml @@ -20,6 +20,7 @@ properties: - fsl,imx8qxp-dsp - fsl,imx8qm-dsp - fsl,imx8mp-dsp + - fsl,imx8ulp-dsp - fsl,imx8qxp-hifi4 - fsl,imx8qm-hifi4 - fsl,imx8mp-hifi4 -- cgit v1.2.3 From fb5319af6ad8616b772761ed926ca57e10f30ea4 Mon Sep 17 00:00:00 2001 From: Zhang Peng Date: Thu, 18 Aug 2022 09:53:54 +0800 Subject: ASoC: SOF: imx: Add i.MX8ULP HW support This adds skeleton support for the audio DSP hardware found on NXP i.MX8ULP platform. On i.MX8ULP resources (clocks, power, etc) are managed by the System Integration Module in LPAV domain and XRDC which is handled by arm trusted firmware. Signed-off-by: Zhang Peng Signed-off-by: Shengjiu Wang Reviewed-by: Daniel Baluta Link: https://lore.kernel.org/r/1660787634-28550-2-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/imx/Kconfig | 9 + sound/soc/sof/imx/Makefile | 2 + sound/soc/sof/imx/imx8ulp.c | 514 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 525 insertions(+) create mode 100644 sound/soc/sof/imx/imx8ulp.c diff --git a/sound/soc/sof/imx/Kconfig b/sound/soc/sof/imx/Kconfig index cc6e695f913a..4751b04d5e6f 100644 --- a/sound/soc/sof/imx/Kconfig +++ b/sound/soc/sof/imx/Kconfig @@ -41,4 +41,13 @@ config SND_SOC_SOF_IMX8M Say Y if you have such a device. If unsure select "N". +config SND_SOC_SOF_IMX8ULP + tristate "SOF support for i.MX8ULP" + depends on IMX_DSP + select SND_SOC_SOF_IMX_COMMON + help + This adds support for Sound Open Firmware for NXP i.MX8ULP platforms. + Say Y if you have such a device. + If unsure select "N". + endif ## SND_SOC_SOF_IMX_TOPLEVEL diff --git a/sound/soc/sof/imx/Makefile b/sound/soc/sof/imx/Makefile index dba93c3466ec..798b43a415bf 100644 --- a/sound/soc/sof/imx/Makefile +++ b/sound/soc/sof/imx/Makefile @@ -1,9 +1,11 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) snd-sof-imx8-objs := imx8.o snd-sof-imx8m-objs := imx8m.o +snd-sof-imx8ulp-objs := imx8ulp.o snd-sof-imx-common-objs := imx-common.o obj-$(CONFIG_SND_SOC_SOF_IMX8) += snd-sof-imx8.o obj-$(CONFIG_SND_SOC_SOF_IMX8M) += snd-sof-imx8m.o +obj-$(CONFIG_SND_SOC_SOF_IMX8ULP) += snd-sof-imx8ulp.o obj-$(CONFIG_SND_SOC_SOF_IMX_COMMON) += imx-common.o diff --git a/sound/soc/sof/imx/imx8ulp.c b/sound/soc/sof/imx/imx8ulp.c new file mode 100644 index 000000000000..02b496165acc --- /dev/null +++ b/sound/soc/sof/imx/imx8ulp.c @@ -0,0 +1,514 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// Copyright 2021-2022 NXP +// +// Author: Peng Zhang +// +// Hardware interface for audio DSP on i.MX8ULP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "../ops.h" +#include "../sof-of-dev.h" +#include "imx-common.h" + +#define FSL_SIP_HIFI_XRDC 0xc200000e + +/* SIM Domain register */ +#define SYSCTRL0 0x8 +#define EXECUTE_BIT BIT(13) +#define RESET_BIT BIT(16) +#define HIFI4_CLK_BIT BIT(17) +#define PB_CLK_BIT BIT(18) +#define PLAT_CLK_BIT BIT(19) +#define DEBUG_LOGIC_BIT BIT(25) + +#define MBOX_OFFSET 0x800000 +#define MBOX_SIZE 0x1000 + +static struct clk_bulk_data imx8ulp_dsp_clks[] = { + { .id = "core" }, + { .id = "ipg" }, + { .id = "ocram" }, + { .id = "mu" }, +}; + +struct imx8ulp_priv { + struct device *dev; + struct snd_sof_dev *sdev; + + /* DSP IPC handler */ + struct imx_dsp_ipc *dsp_ipc; + struct platform_device *ipc_dev; + + struct regmap *regmap; + struct imx_clocks *clks; +}; + +static void imx8ulp_sim_lpav_start(struct imx8ulp_priv *priv) +{ + /* Controls the HiFi4 DSP Reset: 1 in reset, 0 out of reset */ + regmap_update_bits(priv->regmap, SYSCTRL0, RESET_BIT, 0); + + /* Reset HiFi4 DSP Debug logic: 1 debug reset, 0 out of reset*/ + regmap_update_bits(priv->regmap, SYSCTRL0, DEBUG_LOGIC_BIT, 0); + + /* Stall HIFI4 DSP Execution: 1 stall, 0 run */ + regmap_update_bits(priv->regmap, SYSCTRL0, EXECUTE_BIT, 0); +} + +static int imx8ulp_get_mailbox_offset(struct snd_sof_dev *sdev) +{ + return MBOX_OFFSET; +} + +static int imx8ulp_get_window_offset(struct snd_sof_dev *sdev, u32 id) +{ + return MBOX_OFFSET; +} + +static void imx8ulp_dsp_handle_reply(struct imx_dsp_ipc *ipc) +{ + struct imx8ulp_priv *priv = imx_dsp_get_data(ipc); + unsigned long flags; + + spin_lock_irqsave(&priv->sdev->ipc_lock, flags); + + snd_sof_ipc_process_reply(priv->sdev, 0); + + spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags); +} + +static void imx8ulp_dsp_handle_request(struct imx_dsp_ipc *ipc) +{ + struct imx8ulp_priv *priv = imx_dsp_get_data(ipc); + u32 p; /* panic code */ + + /* Read the message from the debug box. */ + sof_mailbox_read(priv->sdev, priv->sdev->debug_box.offset + 4, &p, sizeof(p)); + + /* 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, true); + else + snd_sof_ipc_msgs_rx(priv->sdev); +} + +static struct imx_dsp_ops dsp_ops = { + .handle_reply = imx8ulp_dsp_handle_reply, + .handle_request = imx8ulp_dsp_handle_request, +}; + +static int imx8ulp_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +{ + struct imx8ulp_priv *priv = sdev->pdata->hw_pdata; + + sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, + msg->msg_size); + imx_dsp_ring_doorbell(priv->dsp_ipc, 0); + + return 0; +} + +static int imx8ulp_run(struct snd_sof_dev *sdev) +{ + struct imx8ulp_priv *priv = sdev->pdata->hw_pdata; + + imx8ulp_sim_lpav_start(priv); + + return 0; +} + +static int imx8ulp_reset(struct snd_sof_dev *sdev) +{ + struct imx8ulp_priv *priv = sdev->pdata->hw_pdata; + struct arm_smccc_res smc_resource; + + /* HiFi4 Platform Clock Enable: 1 enabled, 0 disabled */ + regmap_update_bits(priv->regmap, SYSCTRL0, PLAT_CLK_BIT, PLAT_CLK_BIT); + + /* HiFi4 PBCLK clock enable: 1 enabled, 0 disabled */ + regmap_update_bits(priv->regmap, SYSCTRL0, PB_CLK_BIT, PB_CLK_BIT); + + /* HiFi4 Clock Enable: 1 enabled, 0 disabled */ + regmap_update_bits(priv->regmap, SYSCTRL0, HIFI4_CLK_BIT, HIFI4_CLK_BIT); + + regmap_update_bits(priv->regmap, SYSCTRL0, RESET_BIT, RESET_BIT); + usleep_range(1, 2); + + /* Stall HIFI4 DSP Execution: 1 stall, 0 not stall */ + regmap_update_bits(priv->regmap, SYSCTRL0, EXECUTE_BIT, EXECUTE_BIT); + usleep_range(1, 2); + + arm_smccc_smc(FSL_SIP_HIFI_XRDC, 0, 0, 0, 0, 0, 0, 0, &smc_resource); + + return 0; +} + +static int imx8ulp_probe(struct snd_sof_dev *sdev) +{ + struct platform_device *pdev = + container_of(sdev->dev, struct platform_device, dev); + struct device_node *np = pdev->dev.of_node; + struct device_node *res_node; + struct resource *mmio; + struct imx8ulp_priv *priv; + struct resource res; + u32 base, size; + int ret = 0; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->clks = devm_kzalloc(&pdev->dev, sizeof(*priv->clks), GFP_KERNEL); + if (!priv->clks) + return -ENOMEM; + + sdev->num_cores = 1; + sdev->pdata->hw_pdata = priv; + priv->dev = sdev->dev; + priv->sdev = sdev; + + /* System integration module(SIM) control dsp configuration */ + priv->regmap = syscon_regmap_lookup_by_phandle(np, "fsl,dsp-ctrl"); + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); + + priv->ipc_dev = platform_device_register_data(sdev->dev, "imx-dsp", + PLATFORM_DEVID_NONE, + pdev, sizeof(*pdev)); + if (IS_ERR(priv->ipc_dev)) + return PTR_ERR(priv->ipc_dev); + + priv->dsp_ipc = dev_get_drvdata(&priv->ipc_dev->dev); + if (!priv->dsp_ipc) { + /* DSP IPC driver not probed yet, try later */ + ret = -EPROBE_DEFER; + dev_err(sdev->dev, "Failed to get drvdata\n"); + goto exit_pdev_unregister; + } + + imx_dsp_set_data(priv->dsp_ipc, priv); + priv->dsp_ipc->ops = &dsp_ops; + + /* DSP base */ + mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (mmio) { + base = mmio->start; + size = resource_size(mmio); + } else { + dev_err(sdev->dev, "error: failed to get DSP base at idx 0\n"); + ret = -EINVAL; + 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", + base, size); + ret = -ENODEV; + goto exit_pdev_unregister; + } + sdev->mmio_bar = SOF_FW_BLK_TYPE_IRAM; + + res_node = of_parse_phandle(np, "memory-reserved", 0); + if (!res_node) { + dev_err(&pdev->dev, "failed to get memory region node\n"); + ret = -ENODEV; + goto exit_pdev_unregister; + } + + ret = of_address_to_resource(res_node, 0, &res); + if (ret) { + dev_err(&pdev->dev, "failed to get reserved region address\n"); + goto exit_pdev_unregister; + } + + sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, res.start, + resource_size(&res)); + if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) { + dev_err(sdev->dev, "failed to ioremap mem 0x%x size 0x%x\n", + base, size); + ret = -ENOMEM; + goto exit_pdev_unregister; + } + sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM; + + /* set default mailbox offset for FW ready message */ + sdev->dsp_box.offset = MBOX_OFFSET; + + ret = of_reserved_mem_device_init(sdev->dev); + if (ret) { + dev_err(&pdev->dev, "failed to init reserved memory region %d\n", ret); + goto exit_pdev_unregister; + } + + priv->clks->dsp_clks = imx8ulp_dsp_clks; + priv->clks->num_dsp_clks = ARRAY_SIZE(imx8ulp_dsp_clks); + + ret = imx8_parse_clocks(sdev, priv->clks); + if (ret < 0) + goto exit_pdev_unregister; + + ret = imx8_enable_clocks(sdev, priv->clks); + if (ret < 0) + goto exit_pdev_unregister; + + return 0; + +exit_pdev_unregister: + platform_device_unregister(priv->ipc_dev); + + return ret; +} + +static int imx8ulp_remove(struct snd_sof_dev *sdev) +{ + struct imx8ulp_priv *priv = sdev->pdata->hw_pdata; + + imx8_disable_clocks(sdev, priv->clks); + platform_device_unregister(priv->ipc_dev); + + return 0; +} + +/* on i.MX8 there is 1 to 1 match between type and BAR idx */ +static int imx8ulp_get_bar_index(struct snd_sof_dev *sdev, u32 type) +{ + return type; +} + +static int imx8ulp_suspend(struct snd_sof_dev *sdev) +{ + int i; + struct imx8ulp_priv *priv = (struct imx8ulp_priv *)sdev->pdata->hw_pdata; + + /*Stall DSP, release in .run() */ + regmap_update_bits(priv->regmap, SYSCTRL0, EXECUTE_BIT, EXECUTE_BIT); + + for (i = 0; i < DSP_MU_CHAN_NUM; i++) + imx_dsp_free_channel(priv->dsp_ipc, i); + + imx8_disable_clocks(sdev, priv->clks); + + return 0; +} + +static int imx8ulp_resume(struct snd_sof_dev *sdev) +{ + struct imx8ulp_priv *priv = (struct imx8ulp_priv *)sdev->pdata->hw_pdata; + int i; + + imx8_enable_clocks(sdev, priv->clks); + + for (i = 0; i < DSP_MU_CHAN_NUM; i++) + imx_dsp_request_channel(priv->dsp_ipc, i); + + return 0; +} + +static int imx8ulp_dsp_runtime_resume(struct snd_sof_dev *sdev) +{ + const struct sof_dsp_power_state target_dsp_state = { + .state = SOF_DSP_PM_D0, + .substate = 0, + }; + + imx8ulp_resume(sdev); + + return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); +} + +static int imx8ulp_dsp_runtime_suspend(struct snd_sof_dev *sdev) +{ + const struct sof_dsp_power_state target_dsp_state = { + .state = SOF_DSP_PM_D3, + .substate = 0, + }; + + imx8ulp_suspend(sdev); + + return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); +} + +static int imx8ulp_dsp_suspend(struct snd_sof_dev *sdev, unsigned int target_state) +{ + const struct sof_dsp_power_state target_dsp_state = { + .state = target_state, + .substate = 0, + }; + + if (!pm_runtime_suspended(sdev->dev)) + imx8ulp_suspend(sdev); + + return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); +} + +static int imx8ulp_dsp_resume(struct snd_sof_dev *sdev) +{ + const struct sof_dsp_power_state target_dsp_state = { + .state = SOF_DSP_PM_D0, + .substate = 0, + }; + + imx8ulp_resume(sdev); + + 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 imx8ulp_dai[] = { + { + .name = "sai5", + .playback = { + .channels_min = 1, + .channels_max = 32, + }, + .capture = { + .channels_min = 1, + .channels_max = 32, + }, + }, + { + .name = "sai6", + .playback = { + .channels_min = 1, + .channels_max = 32, + }, + .capture = { + .channels_min = 1, + .channels_max = 32, + }, + }, +}; + +static int imx8ulp_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_imx8ulp_ops = { + /* probe and remove */ + .probe = imx8ulp_probe, + .remove = imx8ulp_remove, + /* DSP core boot */ + .run = imx8ulp_run, + .reset = imx8ulp_reset, + + /* Block IO */ + .block_read = sof_block_read, + .block_write = sof_block_write, + + /* Module IO */ + .read64 = sof_io_read64, + + /* Mailbox IO */ + .mailbox_read = sof_mailbox_read, + .mailbox_write = sof_mailbox_write, + + /* ipc */ + .send_msg = imx8ulp_send_msg, + .get_mailbox_offset = imx8ulp_get_mailbox_offset, + .get_window_offset = imx8ulp_get_window_offset, + + .ipc_msg_data = sof_ipc_msg_data, + .set_stream_data_offset = sof_set_stream_data_offset, + + /* stream callbacks */ + .pcm_open = sof_stream_pcm_open, + .pcm_close = sof_stream_pcm_close, + + /* module loading */ + .get_bar_index = imx8ulp_get_bar_index, + /* firmware loading */ + .load_firmware = snd_sof_load_firmware_memcpy, + + /* Debug information */ + .dbg_dump = imx8_dump, + + /* Firmware ops */ + .dsp_arch_ops = &sof_xtensa_arch_ops, + + /* DAI drivers */ + .drv = imx8ulp_dai, + .num_drv = ARRAY_SIZE(imx8ulp_dai), + + /* 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, + + /* PM */ + .runtime_suspend = imx8ulp_dsp_runtime_suspend, + .runtime_resume = imx8ulp_dsp_runtime_resume, + + .suspend = imx8ulp_dsp_suspend, + .resume = imx8ulp_dsp_resume, + + .set_power_state = imx8ulp_dsp_set_power_state, +}; + +static struct sof_dev_desc sof_of_imx8ulp_desc = { + .ipc_supported_mask = BIT(SOF_IPC), + .ipc_default = SOF_IPC, + .default_fw_path = { + [SOF_IPC] = "imx/sof", + }, + .default_tplg_path = { + [SOF_IPC] = "imx/sof-tplg", + }, + .default_fw_filename = { + [SOF_IPC] = "sof-imx8ulp.ri", + }, + .nocodec_tplg_filename = "sof-imx8ulp-nocodec.tplg", + .ops = &sof_imx8ulp_ops, +}; + +static const struct of_device_id sof_of_imx8ulp_ids[] = { + { .compatible = "fsl,imx8ulp-dsp", .data = &sof_of_imx8ulp_desc}, + { } +}; +MODULE_DEVICE_TABLE(of, sof_of_imx8ulp_ids); + +/* DT driver definition */ +static struct platform_driver snd_sof_of_imx8ulp_driver = { + .probe = sof_of_probe, + .remove = sof_of_remove, + .driver = { + .name = "sof-audio-of-imx8ulp", + .pm = &sof_of_pm, + .of_match_table = sof_of_imx8ulp_ids, + }, +}; +module_platform_driver(snd_sof_of_imx8ulp_driver); + +MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); +MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3 From 6a4ce20fd776d2fd19ffaf85cf34a53761e2c888 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Fri, 19 Aug 2022 15:37:56 +0800 Subject: ASoC: amd: acp: add missing platform_device_unregister() in acp_pci_probe() Add missing platform_device_unregister() in error path in acp_pci_probe(). Fixes: c49f5e74a11e ("ASoC: amd: acp: Add error handling cases") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20220819073758.1273160-1-yangyingliang@huawei.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c index 2c8e960cc9a6..5bb23ebe1216 100644 --- a/sound/soc/amd/acp/acp-pci.c +++ b/sound/soc/amd/acp/acp-pci.c @@ -104,6 +104,7 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id addr = pci_resource_start(pci, 0); chip->base = devm_ioremap(&pci->dev, addr, pci_resource_len(pci, 0)); if (!chip->base) { + platform_device_unregister(dmic_dev); ret = -ENOMEM; goto release_regions; } -- cgit v1.2.3 From f89a8c5bb3489e43ff87b5f91acc8db66a168e8e Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Fri, 19 Aug 2022 15:37:57 +0800 Subject: ASoC: amd: acp: switch to use dev_err_probe() Use dev_err_probe() to simplify code and print error code. Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20220819073758.1273160-2-yangyingliang@huawei.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-pci.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c index 5bb23ebe1216..691350646f1b 100644 --- a/sound/soc/amd/acp/acp-pci.c +++ b/sound/soc/amd/acp/acp-pci.c @@ -62,10 +62,9 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id if (!chip) return -ENOMEM; - if (pci_enable_device(pci)) { - dev_err(&pci->dev, "pci_enable_device failed\n"); - return -ENODEV; - } + if (pci_enable_device(pci)) + return dev_err_probe(&pci->dev, -ENODEV, + "pci_enable_device failed\n"); ret = pci_request_regions(pci, "AMD ACP3x audio"); if (ret < 0) { -- cgit v1.2.3 From fd8ec75207588f85c622ee49e5f32267d2406d92 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Fri, 19 Aug 2022 15:37:58 +0800 Subject: ASoC: amd: acp: add a label to make error path more clean Move platform_device_unregister() to a new label to make code more clean. Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20220819073758.1273160-3-yangyingliang@huawei.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-pci.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c index 691350646f1b..ef2ce083521e 100644 --- a/sound/soc/amd/acp/acp-pci.c +++ b/sound/soc/amd/acp/acp-pci.c @@ -103,16 +103,14 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id addr = pci_resource_start(pci, 0); chip->base = devm_ioremap(&pci->dev, addr, pci_resource_len(pci, 0)); if (!chip->base) { - platform_device_unregister(dmic_dev); ret = -ENOMEM; - goto release_regions; + goto unregister_dmic_dev; } res = devm_kzalloc(&pci->dev, sizeof(struct resource) * num_res, GFP_KERNEL); if (!res) { - platform_device_unregister(dmic_dev); ret = -ENOMEM; - goto release_regions; + goto unregister_dmic_dev; } for (i = 0; i < num_res; i++, res_acp++) { @@ -139,13 +137,14 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id pdev = platform_device_register_full(&pdevinfo); if (IS_ERR(pdev)) { dev_err(&pci->dev, "cannot register %s device\n", pdevinfo.name); - platform_device_unregister(dmic_dev); ret = PTR_ERR(pdev); - goto release_regions; + goto unregister_dmic_dev; } return ret; +unregister_dmic_dev: + platform_device_unregister(dmic_dev); release_regions: pci_release_regions(pci); disable_pci: -- cgit v1.2.3 From ceff365a29aaf275c0cd1bb7edaf57dcf254bc77 Mon Sep 17 00:00:00 2001 From: Martin Povišer Date: Thu, 18 Aug 2022 18:53:36 +0200 Subject: ASoC: Change handling of unimplemented set_bclk_ratio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a 'set_bclk_ratio' call is attempted on a DAI not implementing the method, make it an -ENOSUPP error instead of -EINVAL. Assume the DAI can still be okay with the ratio, just does not care to register a handler. No current in-tree users of snd_soc_dai_set_bclk_ratio seem to inspect the return value, but -ENOSUPP disables an error print from within the common soc_dai_ret return filter. With the new behavior a machine driver can do a blanket 'set_bclk_ratio' on all DAIs on a bus, some of which may care about the ratio, some of which may not. Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220818165336.76403-1-povik+lin@cutebit.org Signed-off-by: Mark Brown --- sound/soc/soc-dai.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index d530e8c2b77b..49752af0e205 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -124,7 +124,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll); */ int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) { - int ret = -EINVAL; + int ret = -ENOTSUPP; if (dai->driver->ops && dai->driver->ops->set_bclk_ratio) -- cgit v1.2.3 From a74ec0bf5b67eae87317646571116ce4b4166d95 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 19 Aug 2022 08:23:09 +0300 Subject: ASoC: amd: acp: remove unnecessary NULL checks The list iterator can never be NULL. Delete the bogus NULL checks. Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/Yv8ePUuBfzaRu6xV@kili Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-platform.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/amd/acp/acp-platform.c b/sound/soc/amd/acp/acp-platform.c index beee53aedeaf..85a81add4ef9 100644 --- a/sound/soc/amd/acp/acp-platform.c +++ b/sound/soc/amd/acp/acp-platform.c @@ -106,14 +106,14 @@ static irqreturn_t i2s_irq_handler(int irq, void *data) spin_lock(&adata->acp_lock); list_for_each_entry(stream, &adata->stream_list, list) { - if (stream && (ext_intr_stat & stream->irq_bit)) { + if (ext_intr_stat & stream->irq_bit) { writel(stream->irq_bit, ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used)); snd_pcm_period_elapsed(stream->substream); i2s_flag = 1; } if (adata->rsrc->no_of_ctrls == 2) { - if (stream && (ext_intr_stat1 & stream->irq_bit)) { + if (ext_intr_stat1 & stream->irq_bit) { writel(stream->irq_bit, ACP_EXTERNAL_INTR_STAT(adata, (rsrc->irqp_used - 1))); snd_pcm_period_elapsed(stream->substream); -- cgit v1.2.3 From 1cda83e42bf66beb06bf61c7a78951ec0c028898 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Fri, 19 Aug 2022 14:47:40 +0200 Subject: ASoC: SOF: Fix compilation when HDA_AUDIO_CODEC config is disabled hda_codec_device_init() expects three parameters, not two. Fixes: 3fd63658caed ("ASoC: Intel: Drop hdac_ext usage for codec device creation") Reported-by: kernel test robot Signed-off-by: Cezary Rojewski Acked-by: Mark Brown Link: https://lore.kernel.org/r/20220819124740.3564862-1-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai --- sound/soc/sof/intel/hda-codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index 73336648cd25..1e9afc48394c 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -213,7 +213,7 @@ out: put_device(&codec->core.dev); } #else - codec = hda_codec_device_init(&hbus->core, address); + codec = hda_codec_device_init(&hbus->core, address, HDA_DEV_ASOC); ret = PTR_ERR_OR_ZERO(codec); #endif -- cgit v1.2.3 From b01104fc62b6194c852124f6c6df1c0a5c031fc1 Mon Sep 17 00:00:00 2001 From: Conner Knox Date: Thu, 18 Aug 2022 17:14:33 -0300 Subject: ALSA: usb-audio: Add quirk to enable Avid Mbox 3 support Add support for Avid Mbox3 USB audio interface at 48kHz Signed-off-by: Conner Knox Link: https://lore.kernel.org/r/20220818201433.16360-1-mbarriolinares@gmail.com Signed-off-by: Takashi Iwai --- sound/usb/quirks-table.h | 76 ++++++++++++ sound/usb/quirks.c | 302 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 378 insertions(+) diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index f93201a830b5..06dfdd45cff8 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -2985,6 +2985,82 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, +/* DIGIDESIGN MBOX 3 */ +{ + USB_DEVICE(0x0dba, 0x5000), + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Digidesign", + .product_name = "Mbox 3", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 4, + .iface = 2, + .altsetting = 1, + .altset_idx = 1, + .attributes = 0x00, + .endpoint = 0x01, + .ep_attr = USB_ENDPOINT_XFER_ISOC | + USB_ENDPOINT_SYNC_ASYNC, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .nr_rates = 1, + .rate_table = (unsigned int[]) { + 48000 + } + } + }, + { + .ifnum = 3, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 4, + .iface = 3, + .altsetting = 1, + .altset_idx = 1, + .endpoint = 0x81, + .attributes = 0x00, + .ep_attr = USB_ENDPOINT_XFER_ISOC | + USB_ENDPOINT_SYNC_ASYNC, + .maxpacksize = 0x009c, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .nr_rates = 1, + .rate_table = (unsigned int[]) { + 48000 + } + } + }, + { + .ifnum = 4, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = &(const struct snd_usb_midi_endpoint_info) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } + } + } +}, { /* Tascam US122 MKII - playback-only support */ USB_DEVICE_VENDOR_SPEC(0x0644, 0x8021), diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 168fd802d70b..1b05b0220fad 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1020,6 +1020,304 @@ static int snd_usb_axefx3_boot_quirk(struct usb_device *dev) return 0; } +static void mbox3_setup_48_24_magic(struct usb_device *dev) +{ + /* The Mbox 3 is "little endian" */ + /* max volume is: 0x0000. */ + /* min volume is: 0x0080 (shown in little endian form) */ + + + /* Load 48000Hz rate into buffer */ + u8 com_buff[4] = {0x80, 0xbb, 0x00, 0x00}; + + /* Set 48000Hz sample rate */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 0x01, 0x21, 0x0100, 0x0001, &com_buff, 4); //Is this really needed? + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 0x01, 0x21, 0x0100, 0x8101, &com_buff, 4); + + /* Deactivate Tuner */ + /* on = 0x01*/ + /* off = 0x00*/ + com_buff[0] = 0x00; + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 0x01, 0x21, 0x0003, 0x2001, &com_buff, 1); + + /* Set clock source to Internal (as opposed to S/PDIF) */ + com_buff[0] = 0x01; + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0100, 0x8001, &com_buff, 1); + + /* Mute the hardware loopbacks to start the device in a known state. */ + com_buff[0] = 0x00; + com_buff[1] = 0x80; + /* Analogue input 1 left channel: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0110, 0x4001, &com_buff, 2); + /* Analogue input 1 right channel: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0111, 0x4001, &com_buff, 2); + /* Analogue input 2 left channel: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0114, 0x4001, &com_buff, 2); + /* Analogue input 2 right channel: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0115, 0x4001, &com_buff, 2); + /* Analogue input 3 left channel: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0118, 0x4001, &com_buff, 2); + /* Analogue input 3 right channel: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0119, 0x4001, &com_buff, 2); + /* Analogue input 4 left channel: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x011c, 0x4001, &com_buff, 2); + /* Analogue input 4 right channel: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x011d, 0x4001, &com_buff, 2); + + /* Set software sends to output */ + com_buff[0] = 0x00; + com_buff[1] = 0x00; + /* Analogue software return 1 left channel: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0100, 0x4001, &com_buff, 2); + com_buff[0] = 0x00; + com_buff[1] = 0x80; + /* Analogue software return 1 right channel: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0101, 0x4001, &com_buff, 2); + com_buff[0] = 0x00; + com_buff[1] = 0x80; + /* Analogue software return 2 left channel: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0104, 0x4001, &com_buff, 2); + com_buff[0] = 0x00; + com_buff[1] = 0x00; + /* Analogue software return 2 right channel: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0105, 0x4001, &com_buff, 2); + + com_buff[0] = 0x00; + com_buff[1] = 0x80; + /* Analogue software return 3 left channel: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0108, 0x4001, &com_buff, 2); + /* Analogue software return 3 right channel: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0109, 0x4001, &com_buff, 2); + /* Analogue software return 4 left channel: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x010c, 0x4001, &com_buff, 2); + /* Analogue software return 4 right channel: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x010d, 0x4001, &com_buff, 2); + + /* Return to muting sends */ + com_buff[0] = 0x00; + com_buff[1] = 0x80; + /* Analogue fx return left channel: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0120, 0x4001, &com_buff, 2); + /* Analogue fx return right channel: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0121, 0x4001, &com_buff, 2); + + /* Analogue software input 1 fx send: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0100, 0x4201, &com_buff, 2); + /* Analogue software input 2 fx send: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0101, 0x4201, &com_buff, 2); + /* Analogue software input 3 fx send: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0102, 0x4201, &com_buff, 2); + /* Analogue software input 4 fx send: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0103, 0x4201, &com_buff, 2); + /* Analogue input 1 fx send: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0104, 0x4201, &com_buff, 2); + /* Analogue input 2 fx send: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0105, 0x4201, &com_buff, 2); + /* Analogue input 3 fx send: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0106, 0x4201, &com_buff, 2); + /* Analogue input 4 fx send: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0107, 0x4201, &com_buff, 2); + + /* Toggle allowing host control */ + com_buff[0] = 0x02; + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 3, 0x21, 0x0000, 0x2001, &com_buff, 1); + + /* Do not dim fx returns */ + com_buff[0] = 0x00; + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 3, 0x21, 0x0002, 0x2001, &com_buff, 1); + + /* Do not set fx returns to mono */ + com_buff[0] = 0x00; + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 3, 0x21, 0x0001, 0x2001, &com_buff, 1); + + /* Mute the S/PDIF hardware loopback + * same odd volume logic here as above + */ + com_buff[0] = 0x00; + com_buff[1] = 0x80; + /* S/PDIF hardware input 1 left channel */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0112, 0x4001, &com_buff, 2); + /* S/PDIF hardware input 1 right channel */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0113, 0x4001, &com_buff, 2); + /* S/PDIF hardware input 2 left channel */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0116, 0x4001, &com_buff, 2); + /* S/PDIF hardware input 2 right channel */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0117, 0x4001, &com_buff, 2); + /* S/PDIF hardware input 3 left channel */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x011a, 0x4001, &com_buff, 2); + /* S/PDIF hardware input 3 right channel */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x011b, 0x4001, &com_buff, 2); + /* S/PDIF hardware input 4 left channel */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x011e, 0x4001, &com_buff, 2); + /* S/PDIF hardware input 4 right channel */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x011f, 0x4001, &com_buff, 2); + /* S/PDIF software return 1 left channel */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0102, 0x4001, &com_buff, 2); + /* S/PDIF software return 1 right channel */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0103, 0x4001, &com_buff, 2); + /* S/PDIF software return 2 left channel */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0106, 0x4001, &com_buff, 2); + /* S/PDIF software return 2 right channel */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0107, 0x4001, &com_buff, 2); + + com_buff[0] = 0x00; + com_buff[1] = 0x00; + /* S/PDIF software return 3 left channel */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x010a, 0x4001, &com_buff, 2); + + com_buff[0] = 0x00; + com_buff[1] = 0x80; + /* S/PDIF software return 3 right channel */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x010b, 0x4001, &com_buff, 2); + /* S/PDIF software return 4 left channel */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x010e, 0x4001, &com_buff, 2); + + com_buff[0] = 0x00; + com_buff[1] = 0x00; + /* S/PDIF software return 4 right channel */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x010f, 0x4001, &com_buff, 2); + + com_buff[0] = 0x00; + com_buff[1] = 0x80; + /* S/PDIF fx returns left channel */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0122, 0x4001, &com_buff, 2); + /* S/PDIF fx returns right channel */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0123, 0x4001, &com_buff, 2); + + /* Set the dropdown "Effect" to the first option */ + /* Room1 = 0x00 */ + /* Room2 = 0x01 */ + /* Room3 = 0x02 */ + /* Hall 1 = 0x03 */ + /* Hall 2 = 0x04 */ + /* Plate = 0x05 */ + /* Delay = 0x06 */ + /* Echo = 0x07 */ + com_buff[0] = 0x00; + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0200, 0x4301, &com_buff, 1); /* max is 0xff */ + /* min is 0x00 */ + + + /* Set the effect duration to 0 */ + /* max is 0xffff */ + /* min is 0x0000 */ + com_buff[0] = 0x00; + com_buff[1] = 0x00; + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0400, 0x4301, &com_buff, 2); + + /* Set the effect volume and feedback to 0 */ + /* max is 0xff */ + /* min is 0x00 */ + com_buff[0] = 0x00; + /* feedback: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0500, 0x4301, &com_buff, 1); + /* volume: */ + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 1, 0x21, 0x0300, 0x4301, &com_buff, 1); + + /* Set soft button hold duration */ + /* 0x03 = 250ms */ + /* 0x05 = 500ms DEFAULT */ + /* 0x08 = 750ms */ + /* 0x0a = 1sec */ + com_buff[0] = 0x05; + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 3, 0x21, 0x0005, 0x2001, &com_buff, 1); + + /* Use dim LEDs for button of state */ + com_buff[0] = 0x00; + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 3, 0x21, 0x0004, 0x2001, &com_buff, 1); +} + +#define MBOX3_DESCRIPTOR_SIZE 464 + +static int snd_usb_mbox3_boot_quirk(struct usb_device *dev) +{ + struct usb_host_config *config = dev->actconfig; + int err; + int descriptor_size; + + descriptor_size = le16_to_cpu(get_cfg_desc(config)->wTotalLength); + + if (descriptor_size != MBOX3_DESCRIPTOR_SIZE) { + dev_err(&dev->dev, "Invalid descriptor size=%d.\n", descriptor_size); + return -ENODEV; + } + + dev_dbg(&dev->dev, "device initialised!\n"); + + err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, + &dev->descriptor, sizeof(dev->descriptor)); + config = dev->actconfig; + if (err < 0) + dev_dbg(&dev->dev, "error usb_get_descriptor: %d\n", err); + + err = usb_reset_configuration(dev); + if (err < 0) + dev_dbg(&dev->dev, "error usb_reset_configuration: %d\n", err); + dev_dbg(&dev->dev, "mbox3_boot: new boot length = %d\n", + le16_to_cpu(get_cfg_desc(config)->wTotalLength)); + + mbox3_setup_48_24_magic(dev); + dev_info(&dev->dev, "Digidesign Mbox 3: 24bit 48kHz"); + + return 0; /* Successful boot */ +} #define MICROBOOK_BUF_SIZE 128 @@ -1324,6 +1622,10 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev, case USB_ID(0x0dba, 0x3000): /* Digidesign Mbox 2 */ return snd_usb_mbox2_boot_quirk(dev); + case USB_ID(0x0dba, 0x5000): + /* Digidesign Mbox 3 */ + return snd_usb_mbox3_boot_quirk(dev); + case USB_ID(0x1235, 0x0010): /* Focusrite Novation Saffire 6 USB */ case USB_ID(0x1235, 0x0018): /* Focusrite Novation Twitch */ -- cgit v1.2.3 From 4d45d944e885e1bf4341a8cbb9b69584477880e3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 22 Aug 2022 02:46:25 +0000 Subject: ASoC: soc-pcm.c: summarize related settings at soc_new_pcm() soc_new_pcm() sets pcm->no_device_suspend, but it sets other pcm->xxx at the same function with different timing. pcm->no_device_suspend setup timing has no effect. This patch tidyup it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87bksdgflq.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 4f60c0a83311..209dfa437cb4 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2907,6 +2907,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) rtd->pcm = pcm; pcm->nonatomic = rtd->dai_link->nonatomic; pcm->private_data = rtd; + pcm->no_device_suspend = true; if (rtd->dai_link->no_pcm || rtd->dai_link->params) { if (playback) @@ -2961,8 +2962,6 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) ret = snd_soc_pcm_component_new(rtd); if (ret < 0) return ret; - - pcm->no_device_suspend = true; out: dev_dbg(rtd->card->dev, "%s <-> %s mapping ok\n", soc_codec_dai_name(rtd), soc_cpu_dai_name(rtd)); -- cgit v1.2.3 From 94f072748337424c9cf92cd018532a34db3a5516 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 21 Aug 2022 17:09:14 +0100 Subject: ASoC: samsung: Use iio_get_channel_type() accessor. struct iio_chan_spec is meant to be opaque to IIO consumer drivers which should only use the interfaces in linux/iio/consumer.h. Use the provided accessor function to find get the type of the channel instead of directly reading it form the structure. Signed-off-by: Jonathan Cameron Cc: Krzysztof Kozlowski Cc: Sylwester Nawrocki Link: https://lore.kernel.org/r/20220821160914.2207116-1-jic23@kernel.org Signed-off-by: Mark Brown --- sound/soc/samsung/aries_wm8994.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/soc/samsung/aries_wm8994.c b/sound/soc/samsung/aries_wm8994.c index e7d52d27132e..0fbbf3b02c09 100644 --- a/sound/soc/samsung/aries_wm8994.c +++ b/sound/soc/samsung/aries_wm8994.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ #include #include -#include #include #include #include @@ -543,6 +542,7 @@ static int aries_audio_probe(struct platform_device *pdev) struct aries_wm8994_data *priv; struct snd_soc_dai_link *dai_link; const struct of_device_id *match; + enum iio_chan_type channel_type; int ret, i; if (!np) @@ -594,7 +594,11 @@ static int aries_audio_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(priv->adc), "Failed to get ADC channel"); - if (priv->adc->channel->type != IIO_VOLTAGE) + ret = iio_get_channel_type(priv->adc, &channel_type); + if (ret) + return dev_err_probe(dev, ret, + "Failed to get ADC channel type"); + if (channel_type != IIO_VOLTAGE) return -EINVAL; priv->gpio_headset_key = devm_gpiod_get(dev, "headset-key", -- cgit v1.2.3 From 18afcf90d8807fef66d1fd428eeb2b407df90fa8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 22 Aug 2022 21:00:44 +0200 Subject: ALSA: hda: cleanup definitions for multi-link registers For some reason two masks are used without the AZX prefix, and the pattern MLCLT should be ML_LCTL for consistency. Pure rename, no functionality change. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20220822190044.170495-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- include/sound/hda_register.h | 20 +++++++++++--------- sound/hda/ext/hdac_ext_controller.c | 16 ++++++++-------- sound/pci/hda/hda_intel.c | 14 +++++++------- 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/include/sound/hda_register.h b/include/sound/hda_register.h index ad8b71b1dbb6..d37cf43546eb 100644 --- a/include/sound/hda_register.h +++ b/include/sound/hda_register.h @@ -260,7 +260,18 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define AZX_REG_ML_LCAP 0x00 #define AZX_REG_ML_LCTL 0x04 + +#define AZX_ML_LCTL_CPA BIT(23) +#define AZX_ML_LCTL_CPA_SHIFT 23 +#define AZX_ML_LCTL_SPA BIT(16) +#define AZX_ML_LCTL_SPA_SHIFT 16 +#define AZX_ML_LCTL_SCF GENMASK(3, 0) + #define AZX_REG_ML_LOSIDV 0x08 + +/* bit0 is reserved, with BIT(1) mapping to stream1 */ +#define AZX_ML_LOSIDV_STREAM_MASK 0xFFFE + #define AZX_REG_ML_LSDIID 0x0C #define AZX_REG_ML_LPSOO 0x10 #define AZX_REG_ML_LPSIO 0x12 @@ -268,15 +279,6 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define AZX_REG_ML_LOUTPAY 0x20 #define AZX_REG_ML_LINPAY 0x30 -/* bit0 is reserved, with BIT(1) mapping to stream1 */ -#define ML_LOSIDV_STREAM_MASK 0xFFFE - -#define ML_LCTL_SCF_MASK 0xF -#define AZX_MLCTL_SPA (0x1 << 16) -#define AZX_MLCTL_CPA (0x1 << 23) -#define AZX_MLCTL_SPA_SHIFT 16 -#define AZX_MLCTL_CPA_SHIFT 23 - /* registers for DMA Resume Capability Structure */ #define AZX_DRSM_CAP_ID 0x5 #define AZX_REG_DRSM_CTL 0x4 diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c index a42f66f561f5..80876b9a87f4 100644 --- a/sound/hda/ext/hdac_ext_controller.c +++ b/sound/hda/ext/hdac_ext_controller.c @@ -170,7 +170,7 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable) { int timeout; u32 val; - int mask = (1 << AZX_MLCTL_CPA_SHIFT); + int mask = (1 << AZX_ML_LCTL_CPA_SHIFT); udelay(3); timeout = 150; @@ -178,10 +178,10 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable) do { val = readl(link->ml_addr + AZX_REG_ML_LCTL); if (enable) { - if (((val & mask) >> AZX_MLCTL_CPA_SHIFT)) + if (((val & mask) >> AZX_ML_LCTL_CPA_SHIFT)) return 0; } else { - if (!((val & mask) >> AZX_MLCTL_CPA_SHIFT)) + if (!((val & mask) >> AZX_ML_LCTL_CPA_SHIFT)) return 0; } udelay(3); @@ -197,7 +197,7 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable) int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link) { snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL, - AZX_MLCTL_SPA, AZX_MLCTL_SPA); + AZX_ML_LCTL_SPA, AZX_ML_LCTL_SPA); return check_hdac_link_power_active(link, true); } @@ -209,7 +209,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_up); */ int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link) { - snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL, AZX_MLCTL_SPA, 0); + snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL, AZX_ML_LCTL_SPA, 0); return check_hdac_link_power_active(link, false); } @@ -226,7 +226,7 @@ int snd_hdac_ext_bus_link_power_up_all(struct hdac_bus *bus) list_for_each_entry(hlink, &bus->hlink_list, list) { snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, - AZX_MLCTL_SPA, AZX_MLCTL_SPA); + AZX_ML_LCTL_SPA, AZX_ML_LCTL_SPA); ret = check_hdac_link_power_active(hlink, true); if (ret < 0) return ret; @@ -247,7 +247,7 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus) list_for_each_entry(hlink, &bus->hlink_list, list) { snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, - AZX_MLCTL_SPA, 0); + AZX_ML_LCTL_SPA, 0); ret = check_hdac_link_power_active(hlink, false); if (ret < 0) return ret; @@ -281,7 +281,7 @@ int snd_hdac_ext_bus_link_get(struct hdac_bus *bus, * clear the register to invalidate all the output streams */ snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, - ML_LOSIDV_STREAM_MASK, 0); + AZX_ML_LOSIDV_STREAM_MASK, 0); /* * wait for 521usec for codec to report status * HDA spec section 4.3 - Codec Discovery diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 7720978dc132..bf9df9bc8f1b 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -489,14 +489,14 @@ static int intel_ml_lctl_set_power(struct azx *chip, int state) * If other links are enabled for stream, they need similar fix */ val = readl(bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL); - val &= ~AZX_MLCTL_SPA; - val |= state << AZX_MLCTL_SPA_SHIFT; + val &= ~AZX_ML_LCTL_SPA; + val |= state << AZX_ML_LCTL_SPA_SHIFT; writel(val, bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL); /* wait for CPA */ timeout = 50; while (timeout) { if (((readl(bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL)) & - AZX_MLCTL_CPA) == (state << AZX_MLCTL_CPA_SHIFT)) + AZX_ML_LCTL_CPA) == (state << AZX_ML_LCTL_CPA_SHIFT)) return 0; timeout--; udelay(10); @@ -514,15 +514,15 @@ static void intel_init_lctl(struct azx *chip) /* 0. check lctl register value is correct or not */ val = readl(bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL); /* if SCF is already set, let's use it */ - if ((val & ML_LCTL_SCF_MASK) != 0) + if ((val & AZX_ML_LCTL_SCF) != 0) return; /* * Before operating on SPA, CPA must match SPA. * Any deviation may result in undefined behavior. */ - if (((val & AZX_MLCTL_SPA) >> AZX_MLCTL_SPA_SHIFT) != - ((val & AZX_MLCTL_CPA) >> AZX_MLCTL_CPA_SHIFT)) + if (((val & AZX_ML_LCTL_SPA) >> AZX_ML_LCTL_SPA_SHIFT) != + ((val & AZX_ML_LCTL_CPA) >> AZX_ML_LCTL_CPA_SHIFT)) return; /* 1. turn link down: set SPA to 0 and wait CPA to 0 */ @@ -532,7 +532,7 @@ static void intel_init_lctl(struct azx *chip) goto set_spa; /* 2. update SCF to select a properly audio clock*/ - val &= ~ML_LCTL_SCF_MASK; + val &= ~AZX_ML_LCTL_SCF; val |= intel_get_lctl_scf(chip); writel(val, bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL); -- cgit v1.2.3 From e8ee449bd7a45e871fc84fe51c773f7a6e68a02f Mon Sep 17 00:00:00 2001 From: "chunxu.li" Date: Tue, 23 Aug 2022 17:07:35 +0800 Subject: ASoC: mediatek: mt8186: rename sound card name The field 'topology_shortname' in 'snd_soc_card' is defined as char[32], Current card name will be truncated when SOF is enabled, so rename the sound card name. Signed-off-by: chunxu.li Link: https://lore.kernel.org/r/20220823090735.12176-1-chunxu.li@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c | 2 +- sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c index 84ee5d95a9f0..17a15bec41da 100644 --- a/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c +++ b/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c @@ -962,7 +962,7 @@ mt8186_mt6366_da7219_max98357_controls[] = { }; static struct snd_soc_card mt8186_mt6366_da7219_max98357_soc_card = { - .name = "mt8186_mt6366_da7219_max98357", + .name = "mt8186_da7219_max98357", .owner = THIS_MODULE, .dai_link = mt8186_mt6366_da7219_max98357_dai_links, .num_links = ARRAY_SIZE(mt8186_mt6366_da7219_max98357_dai_links), diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c index 6c41706a5621..393d179d61de 100644 --- a/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c +++ b/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c @@ -938,7 +938,7 @@ mt8186_mt6366_rt1019_rt5682s_controls[] = { }; static struct snd_soc_card mt8186_mt6366_rt1019_rt5682s_soc_card = { - .name = "mt8186_mt6366_rt1019_rt5682s", + .name = "mt8186_rt1019_rt5682s", .owner = THIS_MODULE, .dai_link = mt8186_mt6366_rt1019_rt5682s_dai_links, .num_links = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_dai_links), -- cgit v1.2.3 From 62bd431bac942c90d908b1681d04f0c577f6c70f Mon Sep 17 00:00:00 2001 From: ye xingchen Date: Tue, 23 Aug 2022 07:53:35 +0000 Subject: ASoC: atmel_ssc_dai: Remove the unneeded result variable Return the value from asoc_ssc_init() directly instead of storing it in another redundant variable. Reported-by: Zeal Robot Signed-off-by: ye xingchen Link: https://lore.kernel.org/r/20220823075335.209072-1-ye.xingchen@zte.com.cn Signed-off-by: Mark Brown --- sound/soc/atmel/atmel_ssc_dai.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index e868b7e028d6..3763454436c1 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -891,7 +891,6 @@ static int asoc_ssc_init(struct device *dev) int atmel_ssc_set_audio(int ssc_id) { struct ssc_device *ssc; - int ret; /* If we can grab the SSC briefly to parent the DAI device off it */ ssc = ssc_request(ssc_id); @@ -903,9 +902,7 @@ int atmel_ssc_set_audio(int ssc_id) ssc_info[ssc_id].ssc = ssc; } - ret = asoc_ssc_init(&ssc->pdev->dev); - - return ret; + return asoc_ssc_init(&ssc->pdev->dev); } EXPORT_SYMBOL_GPL(atmel_ssc_set_audio); -- cgit v1.2.3 From d45f552a1e44e2885c4b7551564241959d8138be Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Mon, 22 Aug 2022 20:49:37 +0300 Subject: ASoC: SOF: compress: Remove dai_posn variable dai_posn is set but never used. Initial intention was to use dai_posn to shorthen one code line but it looks fine without it too. Fixes: c1a731c71359 ("ASoC: SOF: compress: Add support for computing timestamps") Reported-by: kernel test robot Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20220822174937.254873-1-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/compress.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/sof/compress.c b/sound/soc/sof/compress.c index 174b3d8e67dd..c8ae778a50d1 100644 --- a/sound/soc/sof/compress.c +++ b/sound/soc/sof/compress.c @@ -327,7 +327,6 @@ static int sof_compr_pointer(struct snd_soc_component *component, struct snd_compr_stream *cstream, struct snd_compr_tstamp *tstamp) { - u64 dai_posn; struct snd_sof_pcm *spcm; struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct sof_compr_stream *sstream = cstream->runtime->private_data; @@ -336,8 +335,6 @@ static int sof_compr_pointer(struct snd_soc_component *component, if (!spcm) return -EINVAL; - dai_posn = spcm->stream[cstream->direction].posn.dai_posn; - tstamp->sampling_rate = sstream->sampling_rate; tstamp->copied_total = sstream->copied_total; tstamp->pcm_io_frames = div_u64(spcm->stream[cstream->direction].posn.dai_posn, -- cgit v1.2.3 From 88630575406fdf2a7853545a884484bd55dab8a0 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Tue, 23 Aug 2022 09:36:13 +0800 Subject: ASoC: fsl_sai: Add support multi fifo sdma script With disabling combine mode, the multiple successive FIFO registers or non successive FIFO registers of SAI module can work with the sdma multi fifo script. This patch is to configure the necessary information to the SDMA engine driver for support multi fifo script. 'words_per_fifo' is the channels for each dataline 'n_fifos_src' and 'n_fifos_dst' are the fifo number 'stride_fifos_src' and 'stride_fifos_dst' are the stride between enable FIFOs 'maxburst' is the multiply of datalines Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1661218573-2154-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 37 ++++++++++++++++++++++++++++++++++++- sound/soc/fsl/fsl_sai.h | 3 +++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index a7fa6f0bf83d..0f92906d7a29 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -527,6 +527,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, u32 slot_width = word_width; int adir = tx ? RX : TX; u32 pins, bclk; + u32 watermark; int ret, i; if (sai->slots) @@ -619,7 +620,15 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, FSL_SAI_CR5_FBT_MASK, val_cr5); } - if (hweight8(dl_cfg[dl_cfg_idx].mask[tx]) <= 1) + /* + * Combine mode has limation: + * - Can't used for singel dataline/FIFO case except the FIFO0 + * - Can't used for multi dataline/FIFO case except the enabled FIFOs + * are successive and start from FIFO0 + * + * So for common usage, all multi fifo case disable the combine mode. + */ + if (hweight8(dl_cfg[dl_cfg_idx].mask[tx]) <= 1 || sai->is_multi_fifo_dma) regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), FSL_SAI_CR4_FCOMB_MASK, 0); else @@ -630,6 +639,26 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, dma_params->addr = sai->res->start + FSL_SAI_xDR0(tx) + dl_cfg[dl_cfg_idx].start_off[tx] * 0x4; + if (sai->is_multi_fifo_dma) { + sai->audio_config[tx].words_per_fifo = min(slots, channels); + if (tx) { + sai->audio_config[tx].n_fifos_dst = pins; + sai->audio_config[tx].stride_fifos_dst = dl_cfg[dl_cfg_idx].next_off[tx]; + } else { + sai->audio_config[tx].n_fifos_src = pins; + sai->audio_config[tx].stride_fifos_src = dl_cfg[dl_cfg_idx].next_off[tx]; + } + dma_params->maxburst = sai->audio_config[tx].words_per_fifo * pins; + dma_params->peripheral_config = &sai->audio_config[tx]; + dma_params->peripheral_size = sizeof(sai->audio_config[tx]); + + watermark = tx ? (sai->soc_data->fifo_depth - dma_params->maxburst) : + (dma_params->maxburst - 1); + regmap_update_bits(sai->regmap, FSL_SAI_xCR1(tx, ofs), + FSL_SAI_CR1_RFW_MASK(sai->soc_data->fifo_depth), + watermark); + } + /* Find a proper tcre setting */ for (i = 0; i < sai->soc_data->pins; i++) { trce_mask = (1 << (i + 1)) - 1; @@ -1257,6 +1286,7 @@ static int fsl_sai_probe(struct platform_device *pdev) char tmp[8]; int irq, ret, i; int index; + u32 dmas[4]; sai = devm_kzalloc(dev, sizeof(*sai), GFP_KERNEL); if (!sai) @@ -1313,6 +1343,11 @@ static int fsl_sai_probe(struct platform_device *pdev) fsl_asoc_get_pll_clocks(&pdev->dev, &sai->pll8k_clk, &sai->pll11k_clk); + /* Use Multi FIFO mode depending on the support from SDMA script */ + ret = of_property_read_u32_array(np, "dmas", dmas, 4); + if (!sai->soc_data->use_edma && !ret && dmas[2] == IMX_DMATYPE_MULTI_SAI) + sai->is_multi_fifo_dma = true; + /* read dataline mask for rx and tx*/ ret = fsl_sai_read_dlcfg(sai); if (ret < 0) { diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 17956b5731dc..697f6690068c 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -6,6 +6,7 @@ #ifndef __FSL_SAI_H #define __FSL_SAI_H +#include #include #define FSL_SAI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ @@ -281,6 +282,7 @@ struct fsl_sai { bool is_lsb_first; bool is_dsp_mode; bool is_pdm_mode; + bool is_multi_fifo_dma; bool synchronous[2]; struct fsl_sai_dl_cfg *dl_cfg; unsigned int dl_cfg_cnt; @@ -300,6 +302,7 @@ struct fsl_sai { struct pm_qos_request pm_qos_req; struct pinctrl *pinctrl; struct pinctrl_state *pins_state; + struct sdma_peripheral_config audio_config[2]; }; #define TX 1 -- cgit v1.2.3 From 43a03d247091e1fcd3065dae3407b959e8921c16 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 12 Jul 2022 15:57:33 +0300 Subject: ASoC: SOF: Intel: hda-loader: Use the FSR state definitions during bootup Switch to use the newly added FSR (Firmware State Register) definitions for DSP state handling and targeting. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220712125734.30512-3-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-loader.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index eb22eb3f6fee..98812d51b31c 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -177,14 +177,13 @@ int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot) * - IMR boot: wait for ROM firmware entered (firmware booted up from IMR) */ if (imr_boot) - target_status = HDA_DSP_ROM_FW_ENTERED; + target_status = FSR_STATE_FW_ENTERED; else - target_status = HDA_DSP_ROM_INIT; + target_status = FSR_STATE_INIT_DONE; ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, chip->rom_status_reg, status, - ((status & HDA_DSP_ROM_STS_MASK) - == target_status), + (FSR_TO_STATE_CODE(status) == target_status), HDA_DSP_REG_POLL_INTERVAL_US, chip->rom_init_timeout * USEC_PER_MSEC); @@ -292,8 +291,7 @@ int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream status = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, chip->rom_status_reg, reg, - ((reg & HDA_DSP_ROM_STS_MASK) - == HDA_DSP_ROM_FW_ENTERED), + (FSR_TO_STATE_CODE(reg) == FSR_STATE_FW_ENTERED), HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_BASEFW_TIMEOUT_US); -- cgit v1.2.3 From 8613753a681e7a5c63313dea9b04bf103d601368 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 12 Jul 2022 15:57:34 +0300 Subject: ASoC: SOF: Intel: hda: Drop no longer used ROM state definitions All code have been switched to use the new FSR defines and macros for ROM/FW state tracking. The old definitions can be dropped now. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220712125734.30512-4-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 5ef3e8775e36..ba6feb1b0d3b 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -251,12 +251,6 @@ #define FSR_STATE_BRINGUP_FW_ENTERED FSR_STATE_FW_ENTERED /* ROM status/error values */ -#define HDA_DSP_ROM_STS_MASK GENMASK(23, 0) -#define HDA_DSP_ROM_INIT 0x1 -#define HDA_DSP_ROM_FW_MANIFEST_LOADED 0x3 -#define HDA_DSP_ROM_FW_FW_LOADED 0x4 -#define HDA_DSP_ROM_FW_ENTERED 0x5 -#define HDA_DSP_ROM_RFW_START 0xf #define HDA_DSP_ROM_CSE_ERROR 40 #define HDA_DSP_ROM_CSE_WRONG_RESPONSE 41 #define HDA_DSP_ROM_IMR_TO_SMALL 42 -- cgit v1.2.3 From 6ace85b9838dc0162b474dbbbb6b388e7561f6a7 Mon Sep 17 00:00:00 2001 From: Chunxu Li Date: Fri, 5 Aug 2022 15:04:48 +0800 Subject: ASoC: SOF: Introduce function sof_of_machine_select From current design in sof_machine_check and snd_sof_new_platform_drv, the SOF can only support ACPI type machine. 1. In sof_machine_check if there is no ACPI machine exist, the function will return -ENODEV directly, that's we don't expected if we do not base on ACPI machine. 2. In snd_sof_new_platform_drv the component driver need a driver name to do ignore_machine, currently the driver name is obtained from machine->drv_name, and the type of machine is snd_soc_acpi_mach. So we add a new function named sof_of_machine_select that we can pass sof_machine_check and obtain info required by snd_sof_new_platform_drv. Signed-off-by: Chunxu Li Link: https://lore.kernel.org/r/20220805070449.6611-2-chunxu.li@mediatek.com Signed-off-by: Mark Brown --- include/sound/sof.h | 2 ++ sound/soc/sof/pcm.c | 8 +++++++- sound/soc/sof/sof-audio.c | 1 + sound/soc/sof/sof-of-dev.h | 7 +++++++ 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/include/sound/sof.h b/include/sound/sof.h index 367dccfea7ad..341fef19e612 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -89,6 +89,7 @@ struct snd_sof_pdata { /* machine */ struct platform_device *pdev_mach; const struct snd_soc_acpi_mach *machine; + const struct snd_sof_of_mach *of_machine; void *hw_pdata; @@ -102,6 +103,7 @@ struct snd_sof_pdata { struct sof_dev_desc { /* list of machines using this configuration */ struct snd_soc_acpi_mach *machines; + struct snd_sof_of_mach *of_machines; /* alternate list of machines using this configuration */ struct snd_soc_acpi_mach *alt_machines; diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 6cb6a432be5e..49f7cb049f62 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -13,6 +13,7 @@ #include #include #include +#include "sof-of-dev.h" #include "sof-priv.h" #include "sof-audio.h" #include "sof-utils.h" @@ -655,7 +656,12 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) struct snd_sof_pdata *plat_data = sdev->pdata; const char *drv_name; - drv_name = plat_data->machine->drv_name; + if (plat_data->machine) + drv_name = plat_data->machine->drv_name; + else if (plat_data->of_machine) + drv_name = plat_data->of_machine->drv_name; + else + drv_name = NULL; pd->name = "sof-audio-component"; pd->probe = sof_pcm_probe; diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 28976098a89e..c18e723435bd 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -10,6 +10,7 @@ #include #include "sof-audio.h" +#include "sof-of-dev.h" #include "ops.h" static void sof_reset_route_setup_status(struct snd_sof_dev *sdev, struct snd_sof_widget *widget) diff --git a/sound/soc/sof/sof-of-dev.h b/sound/soc/sof/sof-of-dev.h index fd950a222ba4..2948b3a0d9fe 100644 --- a/sound/soc/sof/sof-of-dev.h +++ b/sound/soc/sof/sof-of-dev.h @@ -9,6 +9,13 @@ #ifndef __SOUND_SOC_SOF_OF_H #define __SOUND_SOC_SOF_OF_H +struct snd_sof_of_mach { + const char *compatible; + const char *drv_name; + const char *fw_filename; + const char *sof_tplg_filename; +}; + extern const struct dev_pm_ops sof_of_pm; int sof_of_probe(struct platform_device *pdev); -- cgit v1.2.3 From 2dec9e09e955dfc4b7843fa4f9c09e7ee8931b1d Mon Sep 17 00:00:00 2001 From: Chunxu Li Date: Fri, 5 Aug 2022 15:04:49 +0800 Subject: ASoC: SOF: mediatek: Add sof_mt8186_machs for mt8186 Add .of_machines field sof_mt8186_machs for mt8186 Signed-off-by: Chunxu Li Link: https://lore.kernel.org/r/20220805070449.6611-3-chunxu.li@mediatek.com Signed-off-by: Mark Brown --- sound/soc/sof/mediatek/mt8186/mt8186.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c index e006532caf2f..014afe33b3d9 100644 --- a/sound/soc/sof/mediatek/mt8186/mt8186.c +++ b/sound/soc/sof/mediatek/mt8186/mt8186.c @@ -515,7 +515,16 @@ static struct snd_sof_dsp_ops sof_mt8186_ops = { SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, }; +static struct snd_sof_of_mach sof_mt8186_machs[] = { + { + .compatible = "mediatek,mt8186", + .sof_tplg_filename = "sof-mt8186.tplg", + }, + {} +}; + static const struct sof_dev_desc sof_of_mt8186_desc = { + .of_machines = sof_mt8186_machs, .ipc_supported_mask = BIT(SOF_IPC), .ipc_default = SOF_IPC, .default_fw_path = { -- cgit v1.2.3 From 837b40293de66a5b96f883f540512ec5c3867610 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 5 Aug 2022 14:45:26 +0800 Subject: ASoC: fsl_sai: Update slots number according to bclk_ratio The bclk_ratio is set by .set_bclk_ratio API. bclk_ratio = slots * slot_width So if slots is not set by .set_tdm_slot, then it can be calculated by bclk_ratio. Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1659681926-13493-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 0f92906d7a29..81f89f6767a2 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -530,12 +530,14 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, u32 watermark; int ret, i; - if (sai->slots) - slots = sai->slots; - if (sai->slot_width) slot_width = sai->slot_width; + if (sai->slots) + slots = sai->slots; + else if (sai->bclk_ratio) + slots = sai->bclk_ratio / slot_width; + pins = DIV_ROUND_UP(channels, slots); /* -- cgit v1.2.3 From 1332d2078a839b371b3d541c3653a800d12a763d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 23 Aug 2022 17:40:27 +0200 Subject: ASoC: SOF: imx: imx8ulp: declare ops structure as static Sparse warning: sound/soc/sof/imx/imx8ulp.c:416:24: error: symbol 'sof_imx8ulp_ops' was not declared. Should it be static? Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220823154027.762889-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/imx/imx8ulp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/imx/imx8ulp.c b/sound/soc/sof/imx/imx8ulp.c index 02b496165acc..afab7feab5fb 100644 --- a/sound/soc/sof/imx/imx8ulp.c +++ b/sound/soc/sof/imx/imx8ulp.c @@ -413,7 +413,7 @@ static int imx8ulp_dsp_set_power_state(struct snd_sof_dev *sdev, } /* i.MX8 ops */ -struct snd_sof_dsp_ops sof_imx8ulp_ops = { +static struct snd_sof_dsp_ops sof_imx8ulp_ops = { /* probe and remove */ .probe = imx8ulp_probe, .remove = imx8ulp_remove, -- cgit v1.2.3 From a337c2012774d588fcab318c42edc2601d90e549 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 23 Aug 2022 15:42:19 +0300 Subject: ASoC: SOF: ipc4-loader: Verify ext manifest magic number Firmware image must start with an extended manifest. Add a check to make sure that the image does contain it. The magic number (the first u32 of a firmware image if manifest is present) for an IPC4 image must be 0x31454124 (ASCI "$AE1"). Signed-off-by: Peter Ujfalusi Reviewed-by: Rander Wang Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20220823124219.927-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-loader.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/soc/sof/ipc4-loader.c b/sound/soc/sof/ipc4-loader.c index 9fadae8fd011..8bd2132b4f41 100644 --- a/sound/soc/sof/ipc4-loader.c +++ b/sound/soc/sof/ipc4-loader.c @@ -40,6 +40,17 @@ static size_t sof_ipc4_fw_parse_ext_man(struct snd_sof_dev *sdev) ext_man_hdr = (struct sof_ext_manifest4_hdr *)fw->data; + /* + * At the start of the firmware image we must have an extended manifest. + * Verify that the magic number is correct. + */ + if (ext_man_hdr->id != SOF_EXT_MAN4_MAGIC_NUMBER) { + dev_err(sdev->dev, + "Unexpected extended manifest magic number: %#x\n", + ext_man_hdr->id); + return -EINVAL; + } + fw_hdr_offset = ipc4_data->manifest_fw_hdr_offset; if (!fw_hdr_offset) return -EINVAL; -- cgit v1.2.3 From 9e10a1ded6a1b7ffacbb2d9c75fe6aa91623051b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 23 Aug 2022 09:56:39 -0500 Subject: ASoC: dt-bindings: Add missing (unevaluated|additional)Properties on child nodes In order to ensure only documented properties are present, node schemas must have unevaluatedProperties or additionalProperties set to false (typically). Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220823145649.3118479-8-robh@kernel.org Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/amlogic,gx-sound-card.yaml | 2 ++ .../devicetree/bindings/sound/audio-graph-port.yaml | 2 ++ .../devicetree/bindings/sound/google,sc7180-trogdor.yaml | 4 ++++ .../devicetree/bindings/sound/imx-audio-card.yaml | 2 ++ .../bindings/sound/mt8192-mt6359-rt1015-rt5682.yaml | 4 ++++ Documentation/devicetree/bindings/sound/qcom,sm8250.yaml | 6 ++++++ Documentation/devicetree/bindings/sound/renesas,rsnd.yaml | 14 ++++++++++++-- .../devicetree/bindings/sound/samsung,aries-wm8994.yaml | 2 ++ .../devicetree/bindings/sound/samsung,midas-audio.yaml | 2 ++ Documentation/devicetree/bindings/sound/samsung,snow.yaml | 2 ++ Documentation/devicetree/bindings/sound/st,stm32-sai.yaml | 1 + 11 files changed, 39 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml b/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml index b4b35edcb493..5b8d59245f82 100644 --- a/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml +++ b/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml @@ -40,6 +40,7 @@ properties: patternProperties: "^dai-link-[0-9]+$": type: object + additionalProperties: false description: |- dai-link child nodes: Container for dai-link level properties and the CODEC sub-nodes. @@ -63,6 +64,7 @@ patternProperties: patternProperties: "^codec-[0-9]+$": type: object + additionalProperties: false description: |- Codecs: dai-link representing backend links should have at least one subnode. diff --git a/Documentation/devicetree/bindings/sound/audio-graph-port.yaml b/Documentation/devicetree/bindings/sound/audio-graph-port.yaml index 7ff7a4a104fa..bc46a95ed840 100644 --- a/Documentation/devicetree/bindings/sound/audio-graph-port.yaml +++ b/Documentation/devicetree/bindings/sound/audio-graph-port.yaml @@ -28,6 +28,8 @@ properties: patternProperties: "^endpoint(@[0-9a-f]+)?": $ref: /schemas/graph.yaml#/$defs/endpoint-base + unevaluatedProperties: false + properties: mclk-fs: description: | diff --git a/Documentation/devicetree/bindings/sound/google,sc7180-trogdor.yaml b/Documentation/devicetree/bindings/sound/google,sc7180-trogdor.yaml index 233caa0ade87..67ccddd44489 100644 --- a/Documentation/devicetree/bindings/sound/google,sc7180-trogdor.yaml +++ b/Documentation/devicetree/bindings/sound/google,sc7180-trogdor.yaml @@ -61,6 +61,8 @@ patternProperties: cpu: description: Holds subnode which indicates cpu dai. type: object + additionalProperties: false + properties: sound-dai: maxItems: 1 @@ -68,6 +70,8 @@ patternProperties: codec: description: Holds subnode which indicates codec dai. type: object + additionalProperties: false + properties: sound-dai: maxItems: 1 diff --git a/Documentation/devicetree/bindings/sound/imx-audio-card.yaml b/Documentation/devicetree/bindings/sound/imx-audio-card.yaml index bb3a435722c7..b6f5d486600e 100644 --- a/Documentation/devicetree/bindings/sound/imx-audio-card.yaml +++ b/Documentation/devicetree/bindings/sound/imx-audio-card.yaml @@ -58,6 +58,7 @@ patternProperties: cpu: description: Holds subnode which indicates cpu dai. type: object + additionalProperties: false properties: sound-dai: maxItems: 1 @@ -65,6 +66,7 @@ patternProperties: codec: description: Holds subnode which indicates codec dai. type: object + additionalProperties: false properties: sound-dai: minItems: 1 diff --git a/Documentation/devicetree/bindings/sound/mt8192-mt6359-rt1015-rt5682.yaml b/Documentation/devicetree/bindings/sound/mt8192-mt6359-rt1015-rt5682.yaml index 4fa179909c62..478be7e3fa29 100644 --- a/Documentation/devicetree/bindings/sound/mt8192-mt6359-rt1015-rt5682.yaml +++ b/Documentation/devicetree/bindings/sound/mt8192-mt6359-rt1015-rt5682.yaml @@ -30,6 +30,8 @@ properties: headset-codec: type: object + additionalProperties: false + properties: sound-dai: $ref: /schemas/types.yaml#/definitions/phandle @@ -38,6 +40,8 @@ properties: speaker-codecs: type: object + additionalProperties: false + properties: sound-dai: minItems: 1 diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index e6e27d09783e..a3a4289f713e 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -71,6 +71,8 @@ patternProperties: cpu: description: Holds subnode which indicates cpu dai. type: object + additionalProperties: false + properties: sound-dai: maxItems: 1 @@ -78,6 +80,8 @@ patternProperties: platform: description: Holds subnode which indicates platform dai. type: object + additionalProperties: false + properties: sound-dai: maxItems: 1 @@ -85,6 +89,8 @@ patternProperties: codec: description: Holds subnode which indicates codec dai. type: object + additionalProperties: false + properties: sound-dai: minItems: 1 diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml b/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml index e17c0245f77a..268895c90bd5 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml @@ -129,6 +129,8 @@ properties: patternProperties: "^dvc-[0-1]$": type: object + additionalProperties: false + properties: dmas: maxItems: 1 @@ -145,7 +147,7 @@ properties: patternProperties: "^mix-[0-1]$": type: object - # no properties + additionalProperties: false additionalProperties: false rcar_sound,ctu: @@ -154,7 +156,7 @@ properties: patternProperties: "^ctu-[0-7]$": type: object - # no properties + additionalProperties: false additionalProperties: false rcar_sound,src: @@ -163,6 +165,8 @@ properties: patternProperties: "^src-[0-9]$": type: object + additionalProperties: false + properties: interrupts: maxItems: 1 @@ -186,6 +190,8 @@ properties: patternProperties: "^ssiu-[0-9]+$": type: object + additionalProperties: false + properties: dmas: maxItems: 2 @@ -206,6 +212,8 @@ properties: patternProperties: "^ssi-[0-9]$": type: object + additionalProperties: false + properties: interrupts: maxItems: 1 @@ -243,6 +251,8 @@ properties: patternProperties: "^dai([0-9]+)?$": type: object + additionalProperties: false + properties: playback: $ref: /schemas/types.yaml#/definitions/phandle-array diff --git a/Documentation/devicetree/bindings/sound/samsung,aries-wm8994.yaml b/Documentation/devicetree/bindings/sound/samsung,aries-wm8994.yaml index a01c4ad929b8..447e013f6e17 100644 --- a/Documentation/devicetree/bindings/sound/samsung,aries-wm8994.yaml +++ b/Documentation/devicetree/bindings/sound/samsung,aries-wm8994.yaml @@ -23,6 +23,7 @@ properties: cpu: type: object + additionalProperties: false properties: sound-dai: minItems: 2 @@ -34,6 +35,7 @@ properties: - sound-dai codec: + additionalProperties: false type: object properties: sound-dai: diff --git a/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml b/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml index ec50bcb4af5f..31095913e330 100644 --- a/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml +++ b/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml @@ -19,6 +19,7 @@ properties: cpu: type: object + additionalProperties: false properties: sound-dai: maxItems: 1 @@ -28,6 +29,7 @@ properties: codec: type: object + additionalProperties: false properties: sound-dai: maxItems: 1 diff --git a/Documentation/devicetree/bindings/sound/samsung,snow.yaml b/Documentation/devicetree/bindings/sound/samsung,snow.yaml index 51a83d3c7274..3d49aa4c9be2 100644 --- a/Documentation/devicetree/bindings/sound/samsung,snow.yaml +++ b/Documentation/devicetree/bindings/sound/samsung,snow.yaml @@ -19,6 +19,7 @@ properties: codec: type: object + additionalProperties: false properties: sound-dai: description: List of phandles to the CODEC and HDMI IP nodes. @@ -30,6 +31,7 @@ properties: cpu: type: object + additionalProperties: false properties: sound-dai: description: Phandle to the Samsung I2S controller. diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.yaml b/Documentation/devicetree/bindings/sound/st,stm32-sai.yaml index fe2e15504ebc..1a3abc949505 100644 --- a/Documentation/devicetree/bindings/sound/st,stm32-sai.yaml +++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.yaml @@ -60,6 +60,7 @@ required: patternProperties: "^audio-controller@[0-9a-f]+$": type: object + additionalProperties: false description: Two subnodes corresponding to SAI sub-block instances A et B can be defined. Subnode can be omitted for unsused sub-block. -- cgit v1.2.3 From 3b99852f4c874062295704dd483b03cab61301fe Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 23 Aug 2022 15:43:59 +0300 Subject: ASoC: SOF: Intel: hda: Skip IMR boot after a firmware crash or boot failure To make sure that we start from a clean state next time when the DSP is powered up after a firmware crash or boot failure we must skip the IMR booting attempt. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220823124359.24865-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dsp.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index eddfd77ad90f..671c3e02d7df 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -620,8 +620,13 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) /* * The memory used for IMR boot loses its content in deeper than S3 state * We must not try IMR boot on next power up (as it will fail). + * + * In case of firmware crash or boot failure set the skip_imr_boot to true + * as well in order to try to re-load the firmware to do a 'cold' boot. */ - if (sdev->system_suspend_target > SOF_SUSPEND_S3) + if (sdev->system_suspend_target > SOF_SUSPEND_S3 || + sdev->fw_state == SOF_FW_CRASHED || + sdev->fw_state == SOF_FW_BOOT_FAILED) hda->skip_imr_boot = true; hda_sdw_int_enable(sdev, false); -- cgit v1.2.3 From 7d3ac70d82080f7a934402d66c5238e1d99be412 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 23 Aug 2022 08:19:40 -0700 Subject: ASoC: codes: src4xxx: Avoid clang -Wsometimes-uninitialized in src4xxx_hw_params() Clang warns: sound/soc/codecs/src4xxx.c:280:3: error: variable 'd' is used uninitialized whenever switch default is taken [-Werror,-Wsometimes-uninitialized] default: ^~~~~~~ sound/soc/codecs/src4xxx.c:298:59: note: uninitialized use occurs here ret = regmap_write(src4xxx->regmap, SRC4XXX_RCV_PLL_11, d); ^ sound/soc/codecs/src4xxx.c:223:20: note: initialize the variable 'd' to silence this warning int val, pj, jd, d; ^ = 0 sound/soc/codecs/src4xxx.c:280:3: error: variable 'jd' is used uninitialized whenever switch default is taken [-Werror,-Wsometimes-uninitialized] default: ^~~~~~~ sound/soc/codecs/src4xxx.c:293:59: note: uninitialized use occurs here ret = regmap_write(src4xxx->regmap, SRC4XXX_RCV_PLL_10, jd); ^~ sound/soc/codecs/src4xxx.c:223:17: note: initialize the variable 'jd' to silence this warning int val, pj, jd, d; ^ = 0 sound/soc/codecs/src4xxx.c:280:3: error: variable 'pj' is used uninitialized whenever switch default is taken [-Werror,-Wsometimes-uninitialized] default: ^~~~~~~ sound/soc/codecs/src4xxx.c:288:59: note: uninitialized use occurs here ret = regmap_write(src4xxx->regmap, SRC4XXX_RCV_PLL_0F, pj); ^~ sound/soc/codecs/src4xxx.c:223:13: note: initialize the variable 'pj' to silence this warning int val, pj, jd, d; ^ = 0 3 errors generated. The datasheet does not have any default values for these regmap values so pick some arbitrary values and print to the user that this is the case to silence the warnings. Link: https://github.com/ClangBuiltLinux/linux/issues/1691 Reported-by: kernel test robot Reported-by: "Sudip Mukherjee (Codethink)" Suggested-by: Matt Flax Signed-off-by: Nathan Chancellor Reviewed-by: Matt Flax Link: https://lore.kernel.org/r/20220823151939.2493697-1-nathan@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/src4xxx.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/src4xxx.c b/sound/soc/codecs/src4xxx.c index a8f143057b41..db4e280dd055 100644 --- a/sound/soc/codecs/src4xxx.c +++ b/sound/soc/codecs/src4xxx.c @@ -280,9 +280,14 @@ static int src4xxx_hw_params(struct snd_pcm_substream *substream, default: /* don't error out here, * other parts of the chip are still functional + * Dummy initialize variables to avoid + * -Wsometimes-uninitialized from clang. */ dev_info(component->dev, - "Couldn't set the RCV PLL as this master clock rate is unknown\n"); + "Couldn't set the RCV PLL as this master clock rate is unknown. Chosen regmap values may not match real world values.\n"); + pj = 0x0; + jd = 0xff; + d = 0xff; break; } ret = regmap_write(src4xxx->regmap, SRC4XXX_RCV_PLL_0F, pj); -- cgit v1.2.3 From a5ed0c547d50d30a60d67b0911b4ec2c85c54310 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 23 Aug 2022 13:57:36 +0200 Subject: ALSA: vx: Drop superfluous GFP setup The extra setup with GFP_DMA32 is superfluous for this driver. The whole operation is a simple copy loop, and there is no memory address restriction at all. Drop the useless GFP setup. Link: https://lore.kernel.org/r/20220823115740.14123-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/drivers/vx/vx_pcm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index 3924f5283745..ceaeb257003b 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c @@ -1215,8 +1215,7 @@ int snd_vx_pcm_new(struct vx_core *chip) if (ins) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &vx_pcm_capture_ops); snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, - snd_dma_continuous_data(GFP_KERNEL | GFP_DMA32), - 0, 0); + NULL, 0, 0); pcm->private_data = chip; pcm->private_free = snd_vx_pcm_free; -- cgit v1.2.3 From 63bfc84672bbdfc19e54ce181d094fc1aab09e8c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 23 Aug 2022 13:57:37 +0200 Subject: ALSA: pdaudiocf: Drop superfluous GFP setup The extra setup with GFP_DMA32 is superfluous for this driver. The whole operation is a simple copy loop, and there is no memory address restriction at all. Drop the useless GFP setup. Link: https://lore.kernel.org/r/20220823115740.14123-3-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c index dfc4295b69c4..aaa82ec36540 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c @@ -257,8 +257,7 @@ int snd_pdacf_pcm_new(struct snd_pdacf *chip) return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pdacf_pcm_capture_ops); - snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, - snd_dma_continuous_data(GFP_KERNEL | GFP_DMA32), + snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0); pcm->private_data = chip; -- cgit v1.2.3 From 97557ec97a2473ffb9ca5d2e19d21e4807f43fb1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 23 Aug 2022 13:57:38 +0200 Subject: ASoC: Intel: sst: Switch to standard device pages ASoC Atom SST driver is using the continuous RAM pages with GFP_DMA flag for its PCM buffer, but this should work fine with the standard DMA pages. As a part of cleanup work, this patch replaces the buffer allocation to the standard device pages with SNDRV_DMA_TYPE_DEV. Link: https://lore.kernel.org/r/20220823115740.14123-4-tiwai@suse.de Signed-off-by: Takashi Iwai Reviewed-by: Cezary Rojewski --- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index a56dd48c045f..c75616a5fd0a 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -676,10 +676,9 @@ static int sst_soc_pcm_new(struct snd_soc_component *component, if (dai->driver->playback.channels_min || dai->driver->capture.channels_min) { - snd_pcm_set_managed_buffer_all(pcm, - SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_DMA), - SST_MIN_BUFFER, SST_MAX_BUFFER); + snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, + pcm->card->dev, + SST_MIN_BUFFER, SST_MAX_BUFFER); } return 0; } -- cgit v1.2.3 From dd164fbfdc20ccf17be9186b1a5a4b2bc11b6a97 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 23 Aug 2022 13:57:39 +0200 Subject: ALSA: memalloc: Drop special handling of GFP for CONTINUOUS allocation Now that all users of snd_dma_continuous_data() is gone, let's drop this ugly (and dangerous) way. After this commit, SNDRV_DMA_TYPE_CONTINUOUS may take the standard device pointer instead of the hacked pointer by the macro above, and the memalloc core refers to the coherent_dma_mask of the given device like other SNDRV_DMA_TYPE. It's still allowed to pass NULL there, and in that case, the allocation is performed always in the normal zone. For SNDRV_DMA_TYPE_VMALLOC, the device pointer is simply ignored. Link: https://lore.kernel.org/r/20220823115740.14123-5-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/memalloc.h | 3 -- sound/core/memalloc.c | 113 ++++++++++++++++++++--------------------------- 2 files changed, 48 insertions(+), 68 deletions(-) diff --git a/include/sound/memalloc.h b/include/sound/memalloc.h index 8d79cebf95f3..43d524580bd2 100644 --- a/include/sound/memalloc.h +++ b/include/sound/memalloc.h @@ -26,9 +26,6 @@ struct snd_dma_device { struct device *dev; /* generic device */ }; -#define snd_dma_continuous_data(x) ((struct device *)(__force unsigned long)(x)) - - /* * buffer types */ diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index b665ac66ccbe..39561faef6e9 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -18,25 +18,18 @@ #include #include "memalloc_local.h" +#define DEFAULT_GFP \ + (GFP_KERNEL | \ + __GFP_COMP | /* compound page lets parts be mapped */ \ + __GFP_NORETRY | /* don't trigger OOM-killer */ \ + __GFP_NOWARN) /* no stack trace print - this call is non-critical */ + static const struct snd_malloc_ops *snd_dma_get_ops(struct snd_dma_buffer *dmab); #ifdef CONFIG_SND_DMA_SGBUF -static void *do_alloc_fallback_pages(struct device *dev, size_t size, - dma_addr_t *addr, bool wc); -static void do_free_fallback_pages(void *p, size_t size, bool wc); static void *snd_dma_sg_fallback_alloc(struct snd_dma_buffer *dmab, size_t size); #endif -/* a cast to gfp flag from the dev pointer; for CONTINUOUS and VMALLOC types */ -static inline gfp_t snd_mem_get_gfp_flags(const struct snd_dma_buffer *dmab, - gfp_t default_gfp) -{ - if (!dmab->dev.dev) - return default_gfp; - else - return (__force gfp_t)(unsigned long)dmab->dev.dev; -} - static void *__snd_dma_alloc_pages(struct snd_dma_buffer *dmab, size_t size) { const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab); @@ -284,24 +277,54 @@ EXPORT_SYMBOL(snd_sgbuf_get_chunk_size); /* * Continuous pages allocator */ -static void *do_alloc_pages(size_t size, dma_addr_t *addr, gfp_t gfp) +static void *do_alloc_pages(struct device *dev, size_t size, dma_addr_t *addr, + bool wc) { - void *p = alloc_pages_exact(size, gfp); + void *p; + gfp_t gfp = GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN; - if (p) - *addr = page_to_phys(virt_to_page(p)); + again: + p = alloc_pages_exact(size, gfp); + if (!p) + return NULL; + *addr = page_to_phys(virt_to_page(p)); + if (!dev) + return p; + if ((*addr + size - 1) & ~dev->coherent_dma_mask) { + if (IS_ENABLED(CONFIG_ZONE_DMA32) && !(gfp & GFP_DMA32)) { + gfp |= GFP_DMA32; + goto again; + } + if (IS_ENABLED(CONFIG_ZONE_DMA) && !(gfp & GFP_DMA)) { + gfp = (gfp & ~GFP_DMA32) | GFP_DMA; + goto again; + } + } +#ifdef CONFIG_X86 + if (wc) + set_memory_wc((unsigned long)(p), size >> PAGE_SHIFT); +#endif return p; } +static void do_free_pages(void *p, size_t size, bool wc) +{ +#ifdef CONFIG_X86 + if (wc) + set_memory_wb((unsigned long)(p), size >> PAGE_SHIFT); +#endif + free_pages_exact(p, size); +} + + static void *snd_dma_continuous_alloc(struct snd_dma_buffer *dmab, size_t size) { - return do_alloc_pages(size, &dmab->addr, - snd_mem_get_gfp_flags(dmab, GFP_KERNEL)); + return do_alloc_pages(dmab->dev.dev, size, &dmab->addr, false); } static void snd_dma_continuous_free(struct snd_dma_buffer *dmab) { - free_pages_exact(dmab->area, dmab->bytes); + do_free_pages(dmab->area, dmab->bytes, false); } static int snd_dma_continuous_mmap(struct snd_dma_buffer *dmab, @@ -324,9 +347,7 @@ static const struct snd_malloc_ops snd_dma_continuous_ops = { */ static void *snd_dma_vmalloc_alloc(struct snd_dma_buffer *dmab, size_t size) { - gfp_t gfp = snd_mem_get_gfp_flags(dmab, GFP_KERNEL | __GFP_HIGHMEM); - - return __vmalloc(size, gfp); + return vmalloc(size); } static void snd_dma_vmalloc_free(struct snd_dma_buffer *dmab) @@ -440,12 +461,6 @@ static const struct snd_malloc_ops snd_dma_iram_ops = { }; #endif /* CONFIG_GENERIC_ALLOCATOR */ -#define DEFAULT_GFP \ - (GFP_KERNEL | \ - __GFP_COMP | /* compound page lets parts be mapped */ \ - __GFP_NORETRY | /* don't trigger OOM-killer */ \ - __GFP_NOWARN) /* no stack trace print - this call is non-critical */ - /* * Coherent device pages allocator */ @@ -479,12 +494,12 @@ static const struct snd_malloc_ops snd_dma_dev_ops = { #ifdef CONFIG_SND_DMA_SGBUF static void *snd_dma_wc_alloc(struct snd_dma_buffer *dmab, size_t size) { - return do_alloc_fallback_pages(dmab->dev.dev, size, &dmab->addr, true); + return do_alloc_pages(dmab->dev.dev, size, &dmab->addr, true); } static void snd_dma_wc_free(struct snd_dma_buffer *dmab) { - do_free_fallback_pages(dmab->area, dmab->bytes, true); + do_free_pages(dmab->area, dmab->bytes, true); } static int snd_dma_wc_mmap(struct snd_dma_buffer *dmab, @@ -697,37 +712,6 @@ static const struct snd_malloc_ops snd_dma_sg_wc_ops = { .get_chunk_size = snd_dma_noncontig_get_chunk_size, }; -/* manual page allocations with wc setup */ -static void *do_alloc_fallback_pages(struct device *dev, size_t size, - dma_addr_t *addr, bool wc) -{ - gfp_t gfp = GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN; - void *p; - - again: - p = do_alloc_pages(size, addr, gfp); - if (!p || (*addr + size - 1) & ~dev->coherent_dma_mask) { - if (IS_ENABLED(CONFIG_ZONE_DMA32) && !(gfp & GFP_DMA32)) { - gfp |= GFP_DMA32; - goto again; - } - if (IS_ENABLED(CONFIG_ZONE_DMA) && !(gfp & GFP_DMA)) { - gfp = (gfp & ~GFP_DMA32) | GFP_DMA; - goto again; - } - } - if (p && wc) - set_memory_wc((unsigned long)(p), size >> PAGE_SHIFT); - return p; -} - -static void do_free_fallback_pages(void *p, size_t size, bool wc) -{ - if (wc) - set_memory_wb((unsigned long)(p), size >> PAGE_SHIFT); - free_pages_exact(p, size); -} - /* Fallback SG-buffer allocations for x86 */ struct snd_dma_sg_fallback { size_t count; @@ -742,7 +726,7 @@ static void __snd_dma_sg_fallback_free(struct snd_dma_buffer *dmab, size_t i; for (i = 0; i < sgbuf->count && sgbuf->pages[i]; i++) - do_free_fallback_pages(page_address(sgbuf->pages[i]), PAGE_SIZE, wc); + do_free_pages(page_address(sgbuf->pages[i]), PAGE_SIZE, wc); kvfree(sgbuf->pages); kvfree(sgbuf->addrs); kfree(sgbuf); @@ -769,8 +753,7 @@ static void *snd_dma_sg_fallback_alloc(struct snd_dma_buffer *dmab, size_t size) goto error; for (i = 0; i < count; sgbuf->count++, i++) { - p = do_alloc_fallback_pages(dmab->dev.dev, PAGE_SIZE, - &sgbuf->addrs[i], wc); + p = do_alloc_pages(dmab->dev.dev, PAGE_SIZE, &sgbuf->addrs[i], wc); if (!p) goto error; sgbuf->pages[i] = virt_to_page(p); -- cgit v1.2.3 From 0db78532ff144a52757d636a26803099d78f431e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 23 Aug 2022 13:57:40 +0200 Subject: ALSA: doc: Drop snd_dma_continuous_data() usages Update the documentation to follow the recent change of the memory allocation helpers. The macro snd_dma_continuous_data() is gone, and the driver needs to set up the coherent dma mask for allocating in the lower memory addresses, instead. Link: https://lore.kernel.org/r/20220823115740.14123-6-tiwai@suse.de Signed-off-by: Takashi Iwai --- .../sound/kernel-api/writing-an-alsa-driver.rst | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst index 176b73583b7a..07a620c5ca74 100644 --- a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst +++ b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst @@ -3565,13 +3565,17 @@ given size. The second argument (type) and the third argument (device pointer) are dependent on the bus. For normal devices, pass the device pointer (typically identical as ``card->dev``) to the third argument with -``SNDRV_DMA_TYPE_DEV`` type. For the continuous buffer unrelated to the +``SNDRV_DMA_TYPE_DEV`` type. + +For the continuous buffer unrelated to the bus can be pre-allocated with ``SNDRV_DMA_TYPE_CONTINUOUS`` type. You can pass NULL to the device pointer in that case, which is the default mode implying to allocate with ``GFP_KERNEL`` flag. -If you need a different GFP flag, you can pass it by encoding the flag -into the device pointer via a special macro -:c:func:`snd_dma_continuous_data()`. +If you need a restricted (lower) address, set up the coherent DMA mask +bits for the device, and pass the device pointer, like the normal +device memory allocations. For this type, it's still allowed to pass +NULL to the device pointer, too, if no address restriction is needed. + For the scatter-gather buffers, use ``SNDRV_DMA_TYPE_DEV_SG`` with the device pointer (see the `Non-Contiguous Buffers`_ section). @@ -3811,15 +3815,6 @@ arguments here. Since each vmalloc call should succeed at any time, we don't need to pre-allocate the buffers like other continuous pages. -If you need the 32bit DMA allocation, pass the device pointer encoded -by :c:func:`snd_dma_continuous_data()` with ``GFP_KERNEL|__GFP_DMA32`` -argument. - -:: - - snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, - snd_dma_continuous_data(GFP_KERNEL | __GFP_DMA32), 0, 0); - Proc Interface ============== -- cgit v1.2.3 From adc641f1dbce48914445efb79f302380ff10df10 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 24 Aug 2022 09:32:34 +0800 Subject: ASoC: SOF: imx8ulp: add missing of_node_put() in imx8ulp_probe() After using 'res_node' returned by of_parse_phandle(), of_node_put() need be called to decrease the refcount. Fixes: fb5319af6ad8 ("ASoC: SOF: imx: Add i.MX8ULP HW support") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20220824013234.375738-2-yangyingliang@huawei.com Signed-off-by: Mark Brown --- sound/soc/sof/imx/imx8ulp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/imx/imx8ulp.c b/sound/soc/sof/imx/imx8ulp.c index afab7feab5fb..4a562c9856e9 100644 --- a/sound/soc/sof/imx/imx8ulp.c +++ b/sound/soc/sof/imx/imx8ulp.c @@ -234,6 +234,7 @@ static int imx8ulp_probe(struct snd_sof_dev *sdev) } ret = of_address_to_resource(res_node, 0, &res); + of_node_put(res_node); if (ret) { dev_err(&pdev->dev, "failed to get reserved region address\n"); goto exit_pdev_unregister; -- cgit v1.2.3 From 0db49765ee1c45b6d4c3ddcff22a2e010739c422 Mon Sep 17 00:00:00 2001 From: "chunxu.li" Date: Wed, 24 Aug 2022 20:23:18 +0800 Subject: ASoC: mediatek: dt-bindings: modify machine bindings for SOF Add SOF related field. 1. Add a property "mediatek,adsp", Only when adsp phandle could be retrieved, from DTS, the SOF related part of machine driver is executed. 2. Add a property "mediatek,dai-link" to support dai-links could be specified from DTS Signed-off-by: chunxu.li Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220824122319.23918-2-chunxu.li@mediatek.com Signed-off-by: Mark Brown --- .../bindings/sound/mt8186-mt6366-da7219-max98357.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/mt8186-mt6366-da7219-max98357.yaml b/Documentation/devicetree/bindings/sound/mt8186-mt6366-da7219-max98357.yaml index 513cd28b2027..d427f7f623db 100644 --- a/Documentation/devicetree/bindings/sound/mt8186-mt6366-da7219-max98357.yaml +++ b/Documentation/devicetree/bindings/sound/mt8186-mt6366-da7219-max98357.yaml @@ -43,6 +43,16 @@ properties: required: - sound-dai + mediatek,adsp: + $ref: /schemas/types.yaml#/definitions/phandle + description: The phandle of MT8186 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: -- cgit v1.2.3 From 1173107d7c129ff87224814fd38fce5db023aaa0 Mon Sep 17 00:00:00 2001 From: "chunxu.li" Date: Wed, 24 Aug 2022 20:23:19 +0800 Subject: ASoC: mediatek: dt-bindings: modify machine bindings for SOF Add SOF related field. 1. Add a property "mediatek,adsp", Only when adsp phandle could be retrieved, from DTS, the SOF related part of machine driver is executed. 2. Add a property "mediatek,dai-link" to support dai-links could be specified from DTS Signed-off-by: chunxu.li Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220824122319.23918-3-chunxu.li@mediatek.com Signed-off-by: Mark Brown --- .../bindings/sound/mt8186-mt6366-rt1019-rt5682s.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/mt8186-mt6366-rt1019-rt5682s.yaml b/Documentation/devicetree/bindings/sound/mt8186-mt6366-rt1019-rt5682s.yaml index 059a7629b2d3..4fc5b045d3cf 100644 --- a/Documentation/devicetree/bindings/sound/mt8186-mt6366-rt1019-rt5682s.yaml +++ b/Documentation/devicetree/bindings/sound/mt8186-mt6366-rt1019-rt5682s.yaml @@ -43,6 +43,16 @@ properties: required: - sound-dai + mediatek,adsp: + $ref: /schemas/types.yaml#/definitions/phandle + description: The phandle of MT8186 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: -- cgit v1.2.3 From f3b75e9b56780e3bfaa910e560cb9ba4d8f38e53 Mon Sep 17 00:00:00 2001 From: Chunxu Li Date: Thu, 25 Aug 2022 14:54:09 +0800 Subject: ASoC: SOF: mediatek: Add dai driver for mt8186 Add dsp ops callback to register AFE DL1/DL2/UL1/UL2 SOF dai's with ALSA Signed-off-by: Chunxu Li Link: https://lore.kernel.org/r/20220825065411.31279-2-chunxu.li@mediatek.com Signed-off-by: Mark Brown --- sound/soc/sof/mediatek/mt8186/mt8186.c | 35 ++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c index 014afe33b3d9..b47bb7a6ba70 100644 --- a/sound/soc/sof/mediatek/mt8186/mt8186.c +++ b/sound/soc/sof/mediatek/mt8186/mt8186.c @@ -468,6 +468,37 @@ static int mt8186_ipc_msg_data(struct snd_sof_dev *sdev, return 0; } +static struct snd_soc_dai_driver mt8186_dai[] = { +{ + .name = "SOF_DL1", + .playback = { + .channels_min = 1, + .channels_max = 2, + }, +}, +{ + .name = "SOF_DL2", + .playback = { + .channels_min = 1, + .channels_max = 2, + }, +}, +{ + .name = "SOF_UL1", + .capture = { + .channels_min = 1, + .channels_max = 2, + }, +}, +{ + .name = "SOF_UL2", + .capture = { + .channels_min = 1, + .channels_max = 2, + }, +}, +}; + /* mt8186 ops */ static struct snd_sof_dsp_ops sof_mt8186_ops = { /* probe and remove */ @@ -503,6 +534,10 @@ static struct snd_sof_dsp_ops sof_mt8186_ops = { /* Firmware ops */ .dsp_arch_ops = &sof_xtensa_arch_ops, + /* DAI drivers */ + .drv = mt8186_dai, + .num_drv = ARRAY_SIZE(mt8186_dai), + /* PM */ .suspend = mt8186_dsp_suspend, .resume = mt8186_dsp_resume, -- cgit v1.2.3 From 82e93430e0ad13cc31e411cfa575e63118bb0ed4 Mon Sep 17 00:00:00 2001 From: Chunxu Li Date: Thu, 25 Aug 2022 14:54:10 +0800 Subject: ASoC: SOF: mediatek: add snd_sof_dsp_ops callbacks for pcm and mail box Use generic IPC stream and mailbox ops for mt8186 Signed-off-by: Chunxu Li Link: https://lore.kernel.org/r/20220825065411.31279-3-chunxu.li@mediatek.com Signed-off-by: Mark Brown --- sound/soc/sof/mediatek/mt8186/mt8186.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c index b47bb7a6ba70..5fc206bb0da0 100644 --- a/sound/soc/sof/mediatek/mt8186/mt8186.c +++ b/sound/soc/sof/mediatek/mt8186/mt8186.c @@ -512,6 +512,10 @@ static struct snd_sof_dsp_ops sof_mt8186_ops = { .block_read = sof_block_read, .block_write = sof_block_write, + /* Mailbox IO */ + .mailbox_read = sof_mailbox_read, + .mailbox_write = sof_mailbox_write, + /* Register IO */ .write = sof_io_write, .read = sof_io_read, @@ -528,6 +532,10 @@ static struct snd_sof_dsp_ops sof_mt8186_ops = { /* misc */ .get_bar_index = mt8186_get_bar_index, + /* stream callbacks */ + .pcm_open = sof_stream_pcm_open, + .pcm_close = sof_stream_pcm_close, + /* firmware loading */ .load_firmware = snd_sof_load_firmware_memcpy, -- cgit v1.2.3 From 059846071f468da8389dcb8b8bbb38a781b02955 Mon Sep 17 00:00:00 2001 From: Chunxu Li Date: Thu, 25 Aug 2022 14:54:11 +0800 Subject: ASoC: SOF: mediatek: Use generic implementation for .ipc_msg_data field Use generic sof_ipc_msg_data instead of specific implementation as they do the same things Signed-off-by: Chunxu Li Link: https://lore.kernel.org/r/20220825065411.31279-4-chunxu.li@mediatek.com Signed-off-by: Mark Brown --- sound/soc/sof/mediatek/mt8186/mt8186.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c index 5fc206bb0da0..a1be5d74f40b 100644 --- a/sound/soc/sof/mediatek/mt8186/mt8186.c +++ b/sound/soc/sof/mediatek/mt8186/mt8186.c @@ -460,14 +460,6 @@ static int mt8186_get_bar_index(struct snd_sof_dev *sdev, u32 type) return type; } -static int mt8186_ipc_msg_data(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream, - void *p, size_t sz) -{ - sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); - return 0; -} - static struct snd_soc_dai_driver mt8186_dai[] = { { .name = "SOF_DL1", @@ -526,7 +518,7 @@ static struct snd_sof_dsp_ops sof_mt8186_ops = { .send_msg = mt8186_send_msg, .get_mailbox_offset = mt8186_get_mailbox_offset, .get_window_offset = mt8186_get_window_offset, - .ipc_msg_data = mt8186_ipc_msg_data, + .ipc_msg_data = sof_ipc_msg_data, .set_stream_data_offset = sof_set_stream_data_offset, /* misc */ -- cgit v1.2.3 From 4bac47a7b2f9f0c84411cb06944bab8f85c08757 Mon Sep 17 00:00:00 2001 From: Zhu Ning Date: Thu, 25 Aug 2022 09:49:52 +0800 Subject: ASoC: codecs: add suspend and resume for ES8316 The registers may be lost after suspend due to powerdown. regcache_sync solves this issue. Signed-off-by: Zhu Ning Link: https://lore.kernel.org/r/20220825014952.1038508-1-zhuning0077@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8316.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index de7185f73e1e..8643014472ae 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -767,9 +767,31 @@ static void es8316_remove(struct snd_soc_component *component) clk_disable_unprepare(es8316->mclk); } +static int es8316_resume(struct snd_soc_component *component) +{ + struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); + + regcache_cache_only(es8316->regmap, false); + regcache_sync(es8316->regmap); + + return 0; +} + +static int es8316_suspend(struct snd_soc_component *component) +{ + struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); + + regcache_cache_only(es8316->regmap, true); + regcache_mark_dirty(es8316->regmap); + + return 0; +} + static const struct snd_soc_component_driver soc_component_dev_es8316 = { .probe = es8316_probe, .remove = es8316_remove, + .resume = es8316_resume, + .suspend = es8316_suspend, .set_jack = es8316_set_jack, .controls = es8316_snd_controls, .num_controls = ARRAY_SIZE(es8316_snd_controls), -- cgit v1.2.3 From 671d119e75c8dfbf25c1813a167eeb2616c8acd5 Mon Sep 17 00:00:00 2001 From: Tommaso Merciai Date: Thu, 25 Aug 2022 12:17:13 +0200 Subject: ASoC: max98088: add support for noise gate reg Add support for Noise Gate Threshold reg (ANTH reg 0x40 bit 4 to 7) References: - https://datasheets.maximintegrated.com/en/ds/MAX98089.pdf, p75 Signed-off-by: Tommaso Merciai Link: https://lore.kernel.org/r/20220825101714.81580-1-tommaso.merciai@amarulasolutions.com Signed-off-by: Mark Brown --- sound/soc/codecs/max98088.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 5435a49604cf..b208fb530a8b 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -474,6 +474,9 @@ static const struct snd_kcontrol_new max98088_snd_controls[] = { max98088_mic2pre_get, max98088_mic2pre_set, max98088_micboost_tlv), + SOC_SINGLE("Noise Gate Threshold", M98088_REG_40_MICAGC_THRESH, + 4, 15, 0), + SOC_SINGLE("INA Volume", M98088_REG_37_LVL_INA, 0, 7, 1), SOC_SINGLE("INB Volume", M98088_REG_38_LVL_INB, 0, 7, 1), -- cgit v1.2.3 From 3df5d0d972893d3c0df5aead8152fe1ad48ef45c Mon Sep 17 00:00:00 2001 From: Martin Povišer Date: Wed, 24 Aug 2022 18:07:14 +0200 Subject: ASoC: apple: mca: Start new platform driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add ASoC platform driver for the MCA peripheral found on Apple M1 and other chips. Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220824160715.95779-4-povik+lin@cutebit.org Signed-off-by: Mark Brown --- MAINTAINERS | 8 + sound/soc/Kconfig | 1 + sound/soc/Makefile | 1 + sound/soc/apple/Kconfig | 9 + sound/soc/apple/Makefile | 3 + sound/soc/apple/mca.c | 1148 ++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 1170 insertions(+) create mode 100644 sound/soc/apple/Kconfig create mode 100644 sound/soc/apple/Makefile create mode 100644 sound/soc/apple/mca.c diff --git a/MAINTAINERS b/MAINTAINERS index 8a5012ba6ff9..5f91a6b62f2f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1899,6 +1899,14 @@ F: include/dt-bindings/pinctrl/apple.h F: include/linux/apple-mailbox.h F: include/linux/soc/apple/* +ARM/APPLE MACHINE SOUND DRIVERS +M: Martin Povišer +L: asahi@lists.linux.dev +L: alsa-devel@alsa-project.org (moderated for non-subscribers) +S: Maintained +F: Documentation/devicetree/bindings/sound/apple,* +F: drivers/sound/apple/* + ARM/ARTPEC MACHINE SUPPORT M: Jesper Nilsson M: Lars Persson diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 7d4747b6bab2..848fbae26c3b 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -68,6 +68,7 @@ config SND_SOC_ACPI # All the supported SoCs source "sound/soc/adi/Kconfig" source "sound/soc/amd/Kconfig" +source "sound/soc/apple/Kconfig" source "sound/soc/atmel/Kconfig" source "sound/soc/au1x/Kconfig" source "sound/soc/bcm/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 453181ef6c94..507eaed1d6a1 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_SND_SOC_ACPI) += snd-soc-acpi.o obj-$(CONFIG_SND_SOC) += snd-soc-core.o obj-$(CONFIG_SND_SOC) += codecs/ obj-$(CONFIG_SND_SOC) += generic/ +obj-$(CONFIG_SND_SOC) += apple/ obj-$(CONFIG_SND_SOC) += adi/ obj-$(CONFIG_SND_SOC) += amd/ obj-$(CONFIG_SND_SOC) += atmel/ diff --git a/sound/soc/apple/Kconfig b/sound/soc/apple/Kconfig new file mode 100644 index 000000000000..0ba955657e98 --- /dev/null +++ b/sound/soc/apple/Kconfig @@ -0,0 +1,9 @@ +config SND_SOC_APPLE_MCA + tristate "Apple Silicon MCA driver" + depends on ARCH_APPLE || COMPILE_TEST + select SND_DMAENGINE_PCM + select COMMON_CLK + default ARCH_APPLE + help + This option enables an ASoC platform driver for MCA peripherals found + on Apple Silicon SoCs. diff --git a/sound/soc/apple/Makefile b/sound/soc/apple/Makefile new file mode 100644 index 000000000000..7a30bf452817 --- /dev/null +++ b/sound/soc/apple/Makefile @@ -0,0 +1,3 @@ +snd-soc-apple-mca-objs := mca.o + +obj-$(CONFIG_SND_SOC_APPLE_MCA) += snd-soc-apple-mca.o diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c new file mode 100644 index 000000000000..807b85469408 --- /dev/null +++ b/sound/soc/apple/mca.c @@ -0,0 +1,1148 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Apple SoCs MCA driver +// +// Copyright (C) The Asahi Linux Contributors +// +// The MCA peripheral is made up of a number of identical units called clusters. +// Each cluster has its separate clock parent, SYNC signal generator, carries +// four SERDES units and has a dedicated I2S port on the SoC's periphery. +// +// The clusters can operate independently, or can be combined together in a +// configurable manner. We mostly treat them as self-contained independent +// units and don't configure any cross-cluster connections except for the I2S +// ports. The I2S ports can be routed to any of the clusters (irrespective +// of their native cluster). We map this onto ASoC's (DPCM) notion of backend +// and frontend DAIs. The 'cluster guts' are frontends which are dynamically +// routed to backend I2S ports. +// +// DAI references in devicetree are resolved to backends. The routing between +// frontends and backends is determined by the machine driver in the DAPM paths +// it supplies. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define USE_RXB_FOR_CAPTURE + +/* Relative to cluster base */ +#define REG_STATUS 0x0 +#define STATUS_MCLK_EN BIT(0) +#define REG_MCLK_CONF 0x4 +#define MCLK_CONF_DIV GENMASK(11, 8) + +#define REG_SYNCGEN_STATUS 0x100 +#define SYNCGEN_STATUS_EN BIT(0) +#define REG_SYNCGEN_MCLK_SEL 0x104 +#define SYNCGEN_MCLK_SEL GENMASK(3, 0) +#define REG_SYNCGEN_HI_PERIOD 0x108 +#define REG_SYNCGEN_LO_PERIOD 0x10c + +#define REG_PORT_ENABLES 0x600 +#define PORT_ENABLES_CLOCKS GENMASK(2, 1) +#define PORT_ENABLES_TX_DATA BIT(3) +#define REG_PORT_CLOCK_SEL 0x604 +#define PORT_CLOCK_SEL GENMASK(11, 8) +#define REG_PORT_DATA_SEL 0x608 +#define PORT_DATA_SEL_TXA(cl) (1 << ((cl)*2)) +#define PORT_DATA_SEL_TXB(cl) (2 << ((cl)*2)) + +#define REG_INTSTATE 0x700 +#define REG_INTMASK 0x704 + +/* Bases of serdes units (relative to cluster) */ +#define CLUSTER_RXA_OFF 0x200 +#define CLUSTER_TXA_OFF 0x300 +#define CLUSTER_RXB_OFF 0x400 +#define CLUSTER_TXB_OFF 0x500 + +#define CLUSTER_TX_OFF CLUSTER_TXA_OFF + +#ifndef USE_RXB_FOR_CAPTURE +#define CLUSTER_RX_OFF CLUSTER_RXA_OFF +#else +#define CLUSTER_RX_OFF CLUSTER_RXB_OFF +#endif + +/* Relative to serdes unit base */ +#define REG_SERDES_STATUS 0x00 +#define SERDES_STATUS_EN BIT(0) +#define SERDES_STATUS_RST BIT(1) +#define REG_TX_SERDES_CONF 0x04 +#define REG_RX_SERDES_CONF 0x08 +#define SERDES_CONF_NCHANS GENMASK(3, 0) +#define SERDES_CONF_WIDTH_MASK GENMASK(8, 4) +#define SERDES_CONF_WIDTH_16BIT 0x40 +#define SERDES_CONF_WIDTH_20BIT 0x80 +#define SERDES_CONF_WIDTH_24BIT 0xc0 +#define SERDES_CONF_WIDTH_32BIT 0x100 +#define SERDES_CONF_BCLK_POL 0x400 +#define SERDES_CONF_LSB_FIRST 0x800 +#define SERDES_CONF_UNK1 BIT(12) +#define SERDES_CONF_UNK2 BIT(13) +#define SERDES_CONF_UNK3 BIT(14) +#define SERDES_CONF_NO_DATA_FEEDBACK BIT(15) +#define SERDES_CONF_SYNC_SEL GENMASK(18, 16) +#define SERDES_CONF_SOME_RST BIT(19) +#define REG_TX_SERDES_BITSTART 0x08 +#define REG_RX_SERDES_BITSTART 0x0c +#define REG_TX_SERDES_SLOTMASK 0x0c +#define REG_RX_SERDES_SLOTMASK 0x10 +#define REG_RX_SERDES_PORT 0x04 + +/* Relative to switch base */ +#define REG_DMA_ADAPTER_A(cl) (0x8000 * (cl)) +#define REG_DMA_ADAPTER_B(cl) (0x8000 * (cl) + 0x4000) +#define DMA_ADAPTER_TX_LSB_PAD GENMASK(4, 0) +#define DMA_ADAPTER_TX_NCHANS GENMASK(6, 5) +#define DMA_ADAPTER_RX_MSB_PAD GENMASK(12, 8) +#define DMA_ADAPTER_RX_NCHANS GENMASK(14, 13) +#define DMA_ADAPTER_NCHANS GENMASK(22, 20) + +#define SWITCH_STRIDE 0x8000 +#define CLUSTER_STRIDE 0x4000 + +#define MAX_NCLUSTERS 6 + +#define APPLE_MCA_FMTBITS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +struct mca_cluster { + int no; + __iomem void *base; + struct mca_data *host; + struct device *pd_dev; + struct clk *clk_parent; + struct dma_chan *dma_chans[SNDRV_PCM_STREAM_LAST + 1]; + + bool port_started[SNDRV_PCM_STREAM_LAST + 1]; + int port_driver; /* The cluster driving this cluster's port */ + + bool clocks_in_use[SNDRV_PCM_STREAM_LAST + 1]; + struct device_link *pd_link; + + unsigned int bclk_ratio; + + /* Masks etc. picked up via the set_tdm_slot method */ + int tdm_slots; + int tdm_slot_width; + unsigned int tdm_tx_mask; + unsigned int tdm_rx_mask; +}; + +struct mca_data { + struct device *dev; + + __iomem void *switch_base; + + struct device *pd_dev; + struct reset_control *rstc; + struct device_link *pd_link; + + int nclusters; + struct mca_cluster clusters[]; +}; + +static void mca_modify(struct mca_cluster *cl, int regoffset, u32 mask, u32 val) +{ + __iomem void *ptr = cl->base + regoffset; + u32 newval; + + newval = (val & mask) | (readl_relaxed(ptr) & ~mask); + writel_relaxed(newval, ptr); +} + +/* + * Get the cluster of FE or BE DAI + */ +static struct mca_cluster *mca_dai_to_cluster(struct snd_soc_dai *dai) +{ + struct mca_data *mca = snd_soc_dai_get_drvdata(dai); + /* + * FE DAIs are 0 ... nclusters - 1 + * BE DAIs are nclusters ... 2*nclusters - 1 + */ + int cluster_no = dai->id % mca->nclusters; + + return &mca->clusters[cluster_no]; +} + +/* called before PCM trigger */ +static void mca_fe_early_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct mca_cluster *cl = mca_dai_to_cluster(dai); + bool is_tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + int serdes_unit = is_tx ? CLUSTER_TX_OFF : CLUSTER_RX_OFF; + int serdes_conf = + serdes_unit + (is_tx ? REG_TX_SERDES_CONF : REG_RX_SERDES_CONF); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + mca_modify(cl, serdes_unit + REG_SERDES_STATUS, + SERDES_STATUS_EN | SERDES_STATUS_RST, + SERDES_STATUS_RST); + mca_modify(cl, serdes_conf, SERDES_CONF_SOME_RST, + SERDES_CONF_SOME_RST); + readl_relaxed(cl->base + serdes_conf); + mca_modify(cl, serdes_conf, SERDES_STATUS_RST, 0); + WARN_ON(readl_relaxed(cl->base + REG_SERDES_STATUS) & + SERDES_STATUS_RST); + break; + default: + break; + } +} + +static int mca_fe_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct mca_cluster *cl = mca_dai_to_cluster(dai); + bool is_tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + int serdes_unit = is_tx ? CLUSTER_TX_OFF : CLUSTER_RX_OFF; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + mca_modify(cl, serdes_unit + REG_SERDES_STATUS, + SERDES_STATUS_EN | SERDES_STATUS_RST, + SERDES_STATUS_EN); + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + mca_modify(cl, serdes_unit + REG_SERDES_STATUS, + SERDES_STATUS_EN, 0); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int mca_fe_enable_clocks(struct mca_cluster *cl) +{ + struct mca_data *mca = cl->host; + int ret; + + ret = clk_prepare_enable(cl->clk_parent); + if (ret) { + dev_err(mca->dev, + "cluster %d: unable to enable clock parent: %d\n", + cl->no, ret); + return ret; + } + + /* + * We can't power up the device earlier than this because + * the power state driver would error out on seeing the device + * as clock-gated. + */ + cl->pd_link = device_link_add(mca->dev, cl->pd_dev, + DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | + DL_FLAG_RPM_ACTIVE); + if (!cl->pd_link) { + dev_err(mca->dev, + "cluster %d: unable to prop-up power domain\n", cl->no); + clk_disable_unprepare(cl->clk_parent); + return -EINVAL; + } + + writel_relaxed(cl->no + 1, cl->base + REG_SYNCGEN_MCLK_SEL); + mca_modify(cl, REG_SYNCGEN_STATUS, SYNCGEN_STATUS_EN, + SYNCGEN_STATUS_EN); + mca_modify(cl, REG_STATUS, STATUS_MCLK_EN, STATUS_MCLK_EN); + + return 0; +} + +static void mca_fe_disable_clocks(struct mca_cluster *cl) +{ + mca_modify(cl, REG_SYNCGEN_STATUS, SYNCGEN_STATUS_EN, 0); + mca_modify(cl, REG_STATUS, STATUS_MCLK_EN, 0); + + device_link_del(cl->pd_link); + clk_disable_unprepare(cl->clk_parent); +} + +static bool mca_fe_clocks_in_use(struct mca_cluster *cl) +{ + struct mca_data *mca = cl->host; + struct mca_cluster *be_cl; + int stream, i; + + for (i = 0; i < mca->nclusters; i++) { + be_cl = &mca->clusters[i]; + + if (be_cl->port_driver != cl->no) + continue; + + for_each_pcm_streams(stream) + if (be_cl->clocks_in_use[stream]) + return true; + } + return false; +} + +static int mca_be_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mca_cluster *cl = mca_dai_to_cluster(dai); + struct mca_data *mca = cl->host; + struct mca_cluster *fe_cl; + int ret; + + if (cl->port_driver < 0) + return -EINVAL; + + fe_cl = &mca->clusters[cl->port_driver]; + + /* + * Typically the CODECs we are paired with will require clocks + * to be present at time of unmute with the 'mute_stream' op + * or at time of DAPM widget power-up. We need to enable clocks + * here at the latest (frontend prepare would be too late). + */ + if (!mca_fe_clocks_in_use(fe_cl)) { + ret = mca_fe_enable_clocks(fe_cl); + if (ret < 0) + return ret; + } + + cl->clocks_in_use[substream->stream] = true; + + return 0; +} + +static int mca_be_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mca_cluster *cl = mca_dai_to_cluster(dai); + struct mca_data *mca = cl->host; + struct mca_cluster *fe_cl; + + if (cl->port_driver < 0) + return -EINVAL; + + fe_cl = &mca->clusters[cl->port_driver]; + if (!mca_fe_clocks_in_use(fe_cl)) + return 0; /* Nothing to do */ + + cl->clocks_in_use[substream->stream] = false; + + if (!mca_fe_clocks_in_use(fe_cl)) + mca_fe_disable_clocks(fe_cl); + + return 0; +} + +static unsigned int mca_crop_mask(unsigned int mask, int nchans) +{ + while (hweight32(mask) > nchans) + mask &= ~(1 << __fls(mask)); + + return mask; +} + +static int mca_configure_serdes(struct mca_cluster *cl, int serdes_unit, + unsigned int mask, int slots, int nchans, + int slot_width, bool is_tx, int port) +{ + __iomem void *serdes_base = cl->base + serdes_unit; + u32 serdes_conf, serdes_conf_mask; + + serdes_conf_mask = SERDES_CONF_WIDTH_MASK | SERDES_CONF_NCHANS; + serdes_conf = FIELD_PREP(SERDES_CONF_NCHANS, max(slots, 1) - 1); + switch (slot_width) { + case 16: + serdes_conf |= SERDES_CONF_WIDTH_16BIT; + break; + case 20: + serdes_conf |= SERDES_CONF_WIDTH_20BIT; + break; + case 24: + serdes_conf |= SERDES_CONF_WIDTH_24BIT; + break; + case 32: + serdes_conf |= SERDES_CONF_WIDTH_32BIT; + break; + default: + goto err; + } + + serdes_conf_mask |= SERDES_CONF_SYNC_SEL; + serdes_conf |= FIELD_PREP(SERDES_CONF_SYNC_SEL, cl->no + 1); + + if (is_tx) { + serdes_conf_mask |= SERDES_CONF_UNK1 | SERDES_CONF_UNK2 | + SERDES_CONF_UNK3; + serdes_conf |= SERDES_CONF_UNK1 | SERDES_CONF_UNK2 | + SERDES_CONF_UNK3; + } else { + serdes_conf_mask |= SERDES_CONF_UNK1 | SERDES_CONF_UNK2 | + SERDES_CONF_UNK3 | + SERDES_CONF_NO_DATA_FEEDBACK; + serdes_conf |= SERDES_CONF_UNK1 | SERDES_CONF_UNK2 | + SERDES_CONF_NO_DATA_FEEDBACK; + } + + mca_modify(cl, + serdes_unit + + (is_tx ? REG_TX_SERDES_CONF : REG_RX_SERDES_CONF), + serdes_conf_mask, serdes_conf); + + if (is_tx) { + writel_relaxed(0xffffffff, + serdes_base + REG_TX_SERDES_SLOTMASK); + writel_relaxed(~((u32)mca_crop_mask(mask, nchans)), + serdes_base + REG_TX_SERDES_SLOTMASK + 0x4); + writel_relaxed(0xffffffff, + serdes_base + REG_TX_SERDES_SLOTMASK + 0x8); + writel_relaxed(~((u32)mask), + serdes_base + REG_TX_SERDES_SLOTMASK + 0xc); + } else { + writel_relaxed(0xffffffff, + serdes_base + REG_RX_SERDES_SLOTMASK); + writel_relaxed(~((u32)mca_crop_mask(mask, nchans)), + serdes_base + REG_RX_SERDES_SLOTMASK + 0x4); + writel_relaxed(1 << port, + serdes_base + REG_RX_SERDES_PORT); + } + + return 0; + +err: + dev_err(cl->host->dev, + "unsupported SERDES configuration requested (mask=0x%x slots=%d slot_width=%d)\n", + mask, slots, slot_width); + return -EINVAL; +} + +static int mca_fe_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct mca_cluster *cl = mca_dai_to_cluster(dai); + + cl->tdm_slots = slots; + cl->tdm_slot_width = slot_width; + cl->tdm_tx_mask = tx_mask; + cl->tdm_rx_mask = rx_mask; + + return 0; +} + +static int mca_fe_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct mca_cluster *cl = mca_dai_to_cluster(dai); + struct mca_data *mca = cl->host; + bool fpol_inv = false; + u32 serdes_conf = 0; + u32 bitstart; + + if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != + SND_SOC_DAIFMT_BP_FP) + goto err; + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + fpol_inv = 0; + bitstart = 1; + break; + case SND_SOC_DAIFMT_LEFT_J: + fpol_inv = 1; + bitstart = 0; + break; + default: + goto err; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_IF: + case SND_SOC_DAIFMT_IB_IF: + fpol_inv ^= 1; + break; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + case SND_SOC_DAIFMT_NB_IF: + serdes_conf |= SERDES_CONF_BCLK_POL; + break; + } + + if (!fpol_inv) + goto err; + + mca_modify(cl, CLUSTER_TX_OFF + REG_TX_SERDES_CONF, + SERDES_CONF_BCLK_POL, serdes_conf); + mca_modify(cl, CLUSTER_RX_OFF + REG_RX_SERDES_CONF, + SERDES_CONF_BCLK_POL, serdes_conf); + writel_relaxed(bitstart, + cl->base + CLUSTER_TX_OFF + REG_TX_SERDES_BITSTART); + writel_relaxed(bitstart, + cl->base + CLUSTER_RX_OFF + REG_RX_SERDES_BITSTART); + + return 0; + +err: + dev_err(mca->dev, "unsupported DAI format (0x%x) requested\n", fmt); + return -EINVAL; +} + +static int mca_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) +{ + struct mca_cluster *cl = mca_dai_to_cluster(dai); + + cl->bclk_ratio = ratio; + + return 0; +} + +static int mca_fe_get_port(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream); + struct snd_soc_pcm_runtime *be; + struct snd_soc_dpcm *dpcm; + + be = NULL; + for_each_dpcm_be(fe, substream->stream, dpcm) { + be = dpcm->be; + break; + } + + if (!be) + return -EINVAL; + + return mca_dai_to_cluster(asoc_rtd_to_cpu(be, 0))->no; +} + +static int mca_fe_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mca_cluster *cl = mca_dai_to_cluster(dai); + struct mca_data *mca = cl->host; + struct device *dev = mca->dev; + unsigned int samp_rate = params_rate(params); + bool is_tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + bool refine_tdm = false; + unsigned long bclk_ratio; + unsigned int tdm_slots, tdm_slot_width, tdm_mask; + u32 regval, pad; + int ret, port, nchans_ceiled; + + if (!cl->tdm_slot_width) { + /* + * We were not given TDM settings from above, set initial + * guesses which will later be refined. + */ + tdm_slot_width = params_width(params); + tdm_slots = params_channels(params); + refine_tdm = true; + } else { + tdm_slot_width = cl->tdm_slot_width; + tdm_slots = cl->tdm_slots; + tdm_mask = is_tx ? cl->tdm_tx_mask : cl->tdm_rx_mask; + } + + if (cl->bclk_ratio) + bclk_ratio = cl->bclk_ratio; + else + bclk_ratio = tdm_slot_width * tdm_slots; + + if (refine_tdm) { + int nchannels = params_channels(params); + + if (nchannels > 2) { + dev_err(dev, "missing TDM for stream with two or more channels\n"); + return -EINVAL; + } + + if ((bclk_ratio % nchannels) != 0) { + dev_err(dev, "BCLK ratio (%ld) not divisible by no. of channels (%d)\n", + bclk_ratio, nchannels); + return -EINVAL; + } + + tdm_slot_width = bclk_ratio / nchannels; + + if (tdm_slot_width > 32 && nchannels == 1) + tdm_slot_width = 32; + + if (tdm_slot_width < params_width(params)) { + dev_err(dev, "TDM slots too narrow (tdm=%d params=%d)\n", + tdm_slot_width, params_width(params)); + return -EINVAL; + } + + tdm_mask = (1 << tdm_slots) - 1; + } + + port = mca_fe_get_port(substream); + if (port < 0) + return port; + + ret = mca_configure_serdes(cl, is_tx ? CLUSTER_TX_OFF : CLUSTER_RX_OFF, + tdm_mask, tdm_slots, params_channels(params), + tdm_slot_width, is_tx, port); + if (ret) + return ret; + + pad = 32 - params_width(params); + + /* + * TODO: Here the register semantics aren't clear. + */ + nchans_ceiled = min_t(int, params_channels(params), 4); + regval = FIELD_PREP(DMA_ADAPTER_NCHANS, nchans_ceiled) | + FIELD_PREP(DMA_ADAPTER_TX_NCHANS, 0x2) | + FIELD_PREP(DMA_ADAPTER_RX_NCHANS, 0x2) | + FIELD_PREP(DMA_ADAPTER_TX_LSB_PAD, pad) | + FIELD_PREP(DMA_ADAPTER_RX_MSB_PAD, pad); + +#ifndef USE_RXB_FOR_CAPTURE + writel_relaxed(regval, mca->switch_base + REG_DMA_ADAPTER_A(cl->no)); +#else + if (is_tx) + writel_relaxed(regval, + mca->switch_base + REG_DMA_ADAPTER_A(cl->no)); + else + writel_relaxed(regval, + mca->switch_base + REG_DMA_ADAPTER_B(cl->no)); +#endif + + if (!mca_fe_clocks_in_use(cl)) { + /* + * Set up FSYNC duty cycle as even as possible. + */ + writel_relaxed((bclk_ratio / 2) - 1, + cl->base + REG_SYNCGEN_HI_PERIOD); + writel_relaxed(((bclk_ratio + 1) / 2) - 1, + cl->base + REG_SYNCGEN_LO_PERIOD); + writel_relaxed(FIELD_PREP(MCLK_CONF_DIV, 0x1), + cl->base + REG_MCLK_CONF); + + ret = clk_set_rate(cl->clk_parent, bclk_ratio * samp_rate); + if (ret) { + dev_err(mca->dev, "cluster %d: unable to set clock parent: %d\n", + cl->no, ret); + return ret; + } + } + + return 0; +} + +static const struct snd_soc_dai_ops mca_fe_ops = { + .set_fmt = mca_fe_set_fmt, + .set_bclk_ratio = mca_set_bclk_ratio, + .set_tdm_slot = mca_fe_set_tdm_slot, + .hw_params = mca_fe_hw_params, + .trigger = mca_fe_trigger, +}; + +static bool mca_be_started(struct mca_cluster *cl) +{ + int stream; + + for_each_pcm_streams(stream) + if (cl->port_started[stream]) + return true; + return false; +} + +static int mca_be_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *be = asoc_substream_to_rtd(substream); + struct snd_soc_pcm_runtime *fe; + struct mca_cluster *cl = mca_dai_to_cluster(dai); + struct mca_cluster *fe_cl; + struct mca_data *mca = cl->host; + struct snd_soc_dpcm *dpcm; + + fe = NULL; + + for_each_dpcm_fe(be, substream->stream, dpcm) { + if (fe && dpcm->fe != fe) { + dev_err(mca->dev, "many FE per one BE unsupported\n"); + return -EINVAL; + } + + fe = dpcm->fe; + } + + if (!fe) + return -EINVAL; + + fe_cl = mca_dai_to_cluster(asoc_rtd_to_cpu(fe, 0)); + + if (mca_be_started(cl)) { + /* + * Port is already started in the other direction. + * Make sure there isn't a conflict with another cluster + * driving the port. + */ + if (cl->port_driver != fe_cl->no) + return -EINVAL; + + cl->port_started[substream->stream] = true; + return 0; + } + + writel_relaxed(PORT_ENABLES_CLOCKS | PORT_ENABLES_TX_DATA, + cl->base + REG_PORT_ENABLES); + writel_relaxed(FIELD_PREP(PORT_CLOCK_SEL, fe_cl->no + 1), + cl->base + REG_PORT_CLOCK_SEL); + writel_relaxed(PORT_DATA_SEL_TXA(fe_cl->no), + cl->base + REG_PORT_DATA_SEL); + cl->port_driver = fe_cl->no; + cl->port_started[substream->stream] = true; + + return 0; +} + +static void mca_be_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mca_cluster *cl = mca_dai_to_cluster(dai); + + cl->port_started[substream->stream] = false; + + if (!mca_be_started(cl)) { + /* + * Were we the last direction to shutdown? + * Turn off the lights. + */ + writel_relaxed(0, cl->base + REG_PORT_ENABLES); + writel_relaxed(0, cl->base + REG_PORT_DATA_SEL); + cl->port_driver = -1; + } +} + +static const struct snd_soc_dai_ops mca_be_ops = { + .prepare = mca_be_prepare, + .hw_free = mca_be_hw_free, + .startup = mca_be_startup, + .shutdown = mca_be_shutdown, +}; + +static int mca_set_runtime_hwparams(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct dma_chan *chan) +{ + struct device *dma_dev = chan->device->dev; + struct snd_dmaengine_dai_dma_data dma_data = {}; + int ret; + + struct snd_pcm_hardware hw; + + memset(&hw, 0, sizeof(hw)); + + hw.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED; + hw.periods_min = 2; + hw.periods_max = UINT_MAX; + hw.period_bytes_min = 256; + hw.period_bytes_max = dma_get_max_seg_size(dma_dev); + hw.buffer_bytes_max = SIZE_MAX; + hw.fifo_size = 16; + + ret = snd_dmaengine_pcm_refine_runtime_hwparams(substream, &dma_data, + &hw, chan); + + if (ret) + return ret; + + return snd_soc_set_runtime_hwparams(substream, &hw); +} + +static int mca_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct mca_cluster *cl = mca_dai_to_cluster(asoc_rtd_to_cpu(rtd, 0)); + struct dma_chan *chan = cl->dma_chans[substream->stream]; + int ret; + + if (rtd->dai_link->no_pcm) + return 0; + + ret = mca_set_runtime_hwparams(component, substream, chan); + if (ret) + return ret; + + return snd_dmaengine_pcm_open(substream, chan); +} + +static int mca_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream); + struct dma_slave_config slave_config; + int ret; + + if (rtd->dai_link->no_pcm) + return 0; + + memset(&slave_config, 0, sizeof(slave_config)); + ret = snd_hwparams_to_dma_slave_config(substream, params, + &slave_config); + if (ret < 0) + return ret; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + slave_config.dst_port_window_size = + min_t(u32, params_channels(params), 4); + else + slave_config.src_port_window_size = + min_t(u32, params_channels(params), 4); + + return dmaengine_slave_config(chan, &slave_config); +} + +static int mca_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + + if (rtd->dai_link->no_pcm) + return 0; + + return snd_dmaengine_pcm_close(substream); +} + +static int mca_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + + if (rtd->dai_link->no_pcm) + return 0; + + /* + * Before we do the PCM trigger proper, insert an opportunity + * to reset the frontend's SERDES. + */ + mca_fe_early_trigger(substream, cmd, asoc_rtd_to_cpu(rtd, 0)); + + return snd_dmaengine_pcm_trigger(substream, cmd); +} + +static snd_pcm_uframes_t mca_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + + if (rtd->dai_link->no_pcm) + return -ENOTSUPP; + + return snd_dmaengine_pcm_pointer(substream); +} + +static int mca_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) +{ + struct mca_cluster *cl = mca_dai_to_cluster(asoc_rtd_to_cpu(rtd, 0)); + unsigned int i; + + if (rtd->dai_link->no_pcm) + return 0; + + for_each_pcm_streams(i) { + struct snd_pcm_substream *substream = + rtd->pcm->streams[i].substream; + struct dma_chan *chan = cl->dma_chans[i]; + + if (!substream) + continue; + + if (!chan) { + dev_err(component->dev, "missing DMA channel for stream %d on SERDES %d\n", + i, cl->no); + return -EINVAL; + } + + snd_pcm_set_managed_buffer(substream, SNDRV_DMA_TYPE_DEV_IRAM, + chan->device->dev, 512 * 1024 * 6, + SIZE_MAX); + } + + return 0; +} + +static const struct snd_soc_component_driver mca_component = { + .name = "apple-mca", + .open = mca_pcm_open, + .close = mca_close, + .hw_params = mca_hw_params, + .trigger = mca_trigger, + .pointer = mca_pointer, + .pcm_construct = mca_pcm_new, +}; + +static void apple_mca_release(struct mca_data *mca) +{ + int i, stream; + + for (i = 0; i < mca->nclusters; i++) { + struct mca_cluster *cl = &mca->clusters[i]; + + for_each_pcm_streams(stream) { + if (IS_ERR_OR_NULL(cl->dma_chans[stream])) + continue; + + dma_release_channel(cl->dma_chans[stream]); + } + + if (!IS_ERR_OR_NULL(cl->clk_parent)) + clk_put(cl->clk_parent); + + if (!IS_ERR_OR_NULL(cl->pd_dev)) + dev_pm_domain_detach(cl->pd_dev, true); + } + + if (mca->pd_link) + device_link_del(mca->pd_link); + + if (!IS_ERR_OR_NULL(mca->pd_dev)) + dev_pm_domain_detach(mca->pd_dev, true); + + reset_control_assert(mca->rstc); +} + +static int apple_mca_probe(struct platform_device *pdev) +{ + struct mca_data *mca; + struct mca_cluster *clusters; + struct snd_soc_dai_driver *dai_drivers; + struct resource *res; + void __iomem *base; + int nclusters; + int ret, i; + + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(base)) + return PTR_ERR(base); + + if (resource_size(res) < CLUSTER_STRIDE) + return -EINVAL; + nclusters = (resource_size(res) - CLUSTER_STRIDE) / CLUSTER_STRIDE + 1; + + mca = devm_kzalloc(&pdev->dev, struct_size(mca, clusters, nclusters), + GFP_KERNEL); + if (!mca) + return -ENOMEM; + mca->dev = &pdev->dev; + mca->nclusters = nclusters; + platform_set_drvdata(pdev, mca); + clusters = mca->clusters; + + mca->switch_base = + devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(mca->switch_base)) + return PTR_ERR(mca->switch_base); + + mca->rstc = devm_reset_control_get_optional_shared(&pdev->dev, NULL); + if (IS_ERR(mca->rstc)) + return PTR_ERR(mca->rstc); + + dai_drivers = devm_kzalloc( + &pdev->dev, sizeof(*dai_drivers) * 2 * nclusters, GFP_KERNEL); + if (!dai_drivers) + return -ENOMEM; + + mca->pd_dev = dev_pm_domain_attach_by_id(&pdev->dev, 0); + if (IS_ERR(mca->pd_dev)) + return -EINVAL; + + mca->pd_link = device_link_add(&pdev->dev, mca->pd_dev, + DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | + DL_FLAG_RPM_ACTIVE); + if (!mca->pd_link) { + ret = -EINVAL; + /* Prevent an unbalanced reset assert */ + mca->rstc = NULL; + goto err_release; + } + + reset_control_deassert(mca->rstc); + + for (i = 0; i < nclusters; i++) { + struct mca_cluster *cl = &clusters[i]; + struct snd_soc_dai_driver *fe = + &dai_drivers[mca->nclusters + i]; + struct snd_soc_dai_driver *be = &dai_drivers[i]; + int stream; + + cl->host = mca; + cl->no = i; + cl->base = base + CLUSTER_STRIDE * i; + cl->port_driver = -1; + cl->clk_parent = of_clk_get(pdev->dev.of_node, i); + if (IS_ERR(cl->clk_parent)) { + dev_err(&pdev->dev, "unable to obtain clock %d: %ld\n", + i, PTR_ERR(cl->clk_parent)); + ret = PTR_ERR(cl->clk_parent); + goto err_release; + } + cl->pd_dev = dev_pm_domain_attach_by_id(&pdev->dev, i + 1); + if (IS_ERR(cl->pd_dev)) { + dev_err(&pdev->dev, + "unable to obtain cluster %d PD: %ld\n", i, + PTR_ERR(cl->pd_dev)); + ret = PTR_ERR(cl->pd_dev); + goto err_release; + } + + for_each_pcm_streams(stream) { + struct dma_chan *chan; + bool is_tx = (stream == SNDRV_PCM_STREAM_PLAYBACK); +#ifndef USE_RXB_FOR_CAPTURE + char *name = devm_kasprintf(&pdev->dev, GFP_KERNEL, + is_tx ? "tx%da" : "rx%da", + i); +#else + char *name = devm_kasprintf(&pdev->dev, GFP_KERNEL, + is_tx ? "tx%da" : "rx%db", + i); +#endif + + chan = of_dma_request_slave_channel(pdev->dev.of_node, + name); + if (IS_ERR(chan)) { + if (PTR_ERR(chan) != -EPROBE_DEFER) + dev_err(&pdev->dev, + "no %s DMA channel: %ld\n", + name, PTR_ERR(chan)); + + ret = PTR_ERR(chan); + goto err_release; + } + + cl->dma_chans[stream] = chan; + } + + fe->id = i; + fe->name = + devm_kasprintf(&pdev->dev, GFP_KERNEL, "mca-pcm-%d", i); + if (!fe->name) { + ret = -ENOMEM; + goto err_release; + } + fe->ops = &mca_fe_ops; + fe->playback.channels_min = 1; + fe->playback.channels_max = 32; + fe->playback.rates = SNDRV_PCM_RATE_8000_192000; + fe->playback.formats = APPLE_MCA_FMTBITS; + fe->capture.channels_min = 1; + fe->capture.channels_max = 32; + fe->capture.rates = SNDRV_PCM_RATE_8000_192000; + fe->capture.formats = APPLE_MCA_FMTBITS; + fe->symmetric_rate = 1; + + fe->playback.stream_name = + devm_kasprintf(&pdev->dev, GFP_KERNEL, "PCM%d TX", i); + fe->capture.stream_name = + devm_kasprintf(&pdev->dev, GFP_KERNEL, "PCM%d RX", i); + + if (!fe->playback.stream_name || !fe->capture.stream_name) { + ret = -ENOMEM; + goto err_release; + } + + be->id = i + nclusters; + be->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "mca-i2s-%d", i); + if (!be->name) { + ret = -ENOMEM; + goto err_release; + } + be->ops = &mca_be_ops; + be->playback.channels_min = 1; + be->playback.channels_max = 32; + be->playback.rates = SNDRV_PCM_RATE_8000_192000; + be->playback.formats = APPLE_MCA_FMTBITS; + be->capture.channels_min = 1; + be->capture.channels_max = 32; + be->capture.rates = SNDRV_PCM_RATE_8000_192000; + be->capture.formats = APPLE_MCA_FMTBITS; + + be->playback.stream_name = + devm_kasprintf(&pdev->dev, GFP_KERNEL, "I2S%d TX", i); + be->capture.stream_name = + devm_kasprintf(&pdev->dev, GFP_KERNEL, "I2S%d RX", i); + if (!be->playback.stream_name || !be->capture.stream_name) { + ret = -ENOMEM; + goto err_release; + } + } + + ret = devm_snd_soc_register_component(&pdev->dev, &mca_component, + dai_drivers, nclusters * 2); + if (ret) { + dev_err(&pdev->dev, "unable to register ASoC component: %d\n", + ret); + goto err_release; + } + + return 0; + +err_release: + apple_mca_release(mca); + return ret; +} + +static int apple_mca_remove(struct platform_device *pdev) +{ + struct mca_data *mca = platform_get_drvdata(pdev); + + apple_mca_release(mca); + return 0; +} + +static const struct of_device_id apple_mca_of_match[] = { + { .compatible = "apple,mca", }, + {} +}; +MODULE_DEVICE_TABLE(of, apple_mca_of_match); + +static struct platform_driver apple_mca_driver = { + .driver = { + .name = "apple-mca", + .of_match_table = apple_mca_of_match, + }, + .probe = apple_mca_probe, + .remove = apple_mca_remove, +}; +module_platform_driver(apple_mca_driver); + +MODULE_AUTHOR("Martin Povišer "); +MODULE_DESCRIPTION("ASoC Apple MCA driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 4065f0b25b7b30ba4dd4665deb5305ead1c0db25 Mon Sep 17 00:00:00 2001 From: Martin Povišer Date: Wed, 24 Aug 2022 18:07:15 +0200 Subject: ASoC: apple: mca: Add locking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In DAI ops, accesses to the native cluster (of the DAI), and to data of clusters related to it by a DPCM frontend-backend link, should have been synchronized by the 'pcm_mutex' lock at ASoC level. What is not covered are the 'port_driver' accesses on foreign clusters to which the current cluster has no a priori relation, so fill in locking for that. (This should only matter in bizarre configurations of sharing one MCA peripheral between ASoC cards.) Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220824160715.95779-5-povik+lin@cutebit.org Signed-off-by: Mark Brown --- sound/soc/apple/mca.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c index 807b85469408..aa67d57c9a9b 100644 --- a/sound/soc/apple/mca.c +++ b/sound/soc/apple/mca.c @@ -158,6 +158,9 @@ struct mca_data { struct reset_control *rstc; struct device_link *pd_link; + /* Mutex for accessing port_driver of foreign clusters */ + struct mutex port_mutex; + int nclusters; struct mca_cluster clusters[]; }; @@ -296,16 +299,21 @@ static bool mca_fe_clocks_in_use(struct mca_cluster *cl) struct mca_cluster *be_cl; int stream, i; + mutex_lock(&mca->port_mutex); for (i = 0; i < mca->nclusters; i++) { be_cl = &mca->clusters[i]; if (be_cl->port_driver != cl->no) continue; - for_each_pcm_streams(stream) - if (be_cl->clocks_in_use[stream]) + for_each_pcm_streams(stream) { + if (be_cl->clocks_in_use[stream]) { + mutex_unlock(&mca->port_mutex); return true; + } + } } + mutex_unlock(&mca->port_mutex); return false; } @@ -349,6 +357,11 @@ static int mca_be_hw_free(struct snd_pcm_substream *substream, if (cl->port_driver < 0) return -EINVAL; + /* + * We are operating on a foreign cluster here, but since we + * belong to the same PCM, accesses should have been + * synchronized at ASoC level. + */ fe_cl = &mca->clusters[cl->port_driver]; if (!mca_fe_clocks_in_use(fe_cl)) return 0; /* Nothing to do */ @@ -721,7 +734,9 @@ static int mca_be_startup(struct snd_pcm_substream *substream, cl->base + REG_PORT_CLOCK_SEL); writel_relaxed(PORT_DATA_SEL_TXA(fe_cl->no), cl->base + REG_PORT_DATA_SEL); + mutex_lock(&mca->port_mutex); cl->port_driver = fe_cl->no; + mutex_unlock(&mca->port_mutex); cl->port_started[substream->stream] = true; return 0; @@ -731,6 +746,7 @@ static void mca_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct mca_cluster *cl = mca_dai_to_cluster(dai); + struct mca_data *mca = cl->host; cl->port_started[substream->stream] = false; @@ -741,7 +757,9 @@ static void mca_be_shutdown(struct snd_pcm_substream *substream, */ writel_relaxed(0, cl->base + REG_PORT_ENABLES); writel_relaxed(0, cl->base + REG_PORT_DATA_SEL); + mutex_lock(&mca->port_mutex); cl->port_driver = -1; + mutex_unlock(&mca->port_mutex); } } @@ -962,6 +980,7 @@ static int apple_mca_probe(struct platform_device *pdev) return -ENOMEM; mca->dev = &pdev->dev; mca->nclusters = nclusters; + mutex_init(&mca->port_mutex); platform_set_drvdata(pdev, mca); clusters = mca->clusters; -- cgit v1.2.3 From 6ed462d1c1167506479089e655355b3c123fee89 Mon Sep 17 00:00:00 2001 From: Martin Povišer Date: Wed, 24 Aug 2022 18:07:12 +0200 Subject: ASoC: Add Apple MCA I2S transceiver bindings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add binding schema for MCA I2S transceiver found on Apple M1 and other chips. Signed-off-by: Martin Povišer Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220824160715.95779-2-povik+lin@cutebit.org Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/apple,mca.yaml | 131 +++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/apple,mca.yaml diff --git a/Documentation/devicetree/bindings/sound/apple,mca.yaml b/Documentation/devicetree/bindings/sound/apple,mca.yaml new file mode 100644 index 000000000000..d5dc92b5b654 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/apple,mca.yaml @@ -0,0 +1,131 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/apple,mca.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Apple MCA I2S transceiver + +description: | + MCA is an I2S transceiver peripheral found on M1 and other Apple chips. It is + composed of a number of identical clusters which can operate independently + or in an interlinked fashion. Up to 6 clusters have been seen on an MCA. + +maintainers: + - Martin Povišer + +properties: + compatible: + items: + - enum: + - apple,t6000-mca + - apple,t8103-mca + - const: apple,mca + + reg: + items: + - description: Register region of the MCA clusters proper + - description: Register region of the DMA glue and its FIFOs + + interrupts: + minItems: 4 + maxItems: 6 + description: + One interrupt per each cluster + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + + dmas: + minItems: 16 + maxItems: 24 + description: + DMA channels corresponding to the SERDES units in the peripheral. They are + listed in groups of four per cluster, and within the group they are given + as associated to the TXA, RXA, TXB, RXB units. + + dma-names: + minItems: 16 + items: + - const: tx0a + - const: rx0a + - const: tx0b + - const: rx0b + - const: tx1a + - const: rx1a + - const: tx1b + - const: rx1b + - const: tx2a + - const: rx2a + - const: tx2b + - const: rx2b + - const: tx3a + - const: rx3a + - const: tx3b + - const: rx3b + - const: tx4a + - const: rx4a + - const: tx4b + - const: rx4b + - const: tx5a + - const: rx5a + - const: tx5b + - const: rx5b + description: | + Names for the DMA channels: 'tx'/'rx', then cluster number, then 'a'/'b' + based on the associated SERDES unit. + + clocks: + minItems: 4 + maxItems: 6 + description: + Clusters' input reference clock. + + resets: + maxItems: 1 + + power-domains: + minItems: 5 + maxItems: 7 + description: + First a general power domain for register access, then the power + domains of individual clusters for their operation. + + '#sound-dai-cells': + const: 1 + +required: + - compatible + - reg + - dmas + - dma-names + - clocks + - power-domains + - '#sound-dai-cells' + +additionalProperties: false + +examples: + - | + mca: i2s@9b600000 { + compatible = "apple,t6000-mca", "apple,mca"; + reg = <0x9b600000 0x10000>, + <0x9b200000 0x20000>; + + clocks = <&nco 0>, <&nco 1>, <&nco 2>, <&nco 3>; + power-domains = <&ps_audio_p>, <&ps_mca0>, <&ps_mca1>, + <&ps_mca2>, <&ps_mca3>; + dmas = <&admac 0>, <&admac 1>, <&admac 2>, <&admac 3>, + <&admac 4>, <&admac 5>, <&admac 6>, <&admac 7>, + <&admac 8>, <&admac 9>, <&admac 10>, <&admac 11>, + <&admac 12>, <&admac 13>, <&admac 14>, <&admac 15>; + dma-names = "tx0a", "rx0a", "tx0b", "rx0b", + "tx1a", "rx1a", "tx1b", "rx1b", + "tx2a", "rx2a", "tx2b", "rx2b", + "tx3a", "rx3a", "tx3b", "rx3b"; + + #sound-dai-cells = <1>; + }; -- cgit v1.2.3 From 4a34613b2017e89fdf4f63cda65da68b5f50f284 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Thu, 25 Aug 2022 20:35:25 +0800 Subject: ASoC: sigmadsp: switch to use kmemdup_nul() helper Use kmemdup_nul() helper instead of open-coding to simplify the code. Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20220825123525.1845695-1-yangyingliang@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/sigmadsp.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c index b992216aee55..3047a6fbb380 100644 --- a/sound/soc/codecs/sigmadsp.c +++ b/sound/soc/codecs/sigmadsp.c @@ -227,13 +227,11 @@ static int sigma_fw_load_control(struct sigmadsp *sigmadsp, if (!ctrl) return -ENOMEM; - name = kzalloc(name_len + 1, GFP_KERNEL); + name = kmemdup_nul(ctrl_chunk->name, name_len, GFP_KERNEL); if (!name) { ret = -ENOMEM; goto err_free_ctrl; } - memcpy(name, ctrl_chunk->name, name_len); - name[name_len] = '\0'; ctrl->name = name; /* -- cgit v1.2.3 From 6bbabd28805f36baf6d0f3eb082db032a638f612 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 22 Aug 2022 02:35:32 +0000 Subject: ASoC: soc-pcm.c: call __soc_pcm_close() in soc_pcm_close() commit b7898396f4bbe16 ("ASoC: soc-pcm: Fix and cleanup DPCM locking") added __soc_pcm_close() for non-lock version of soc_pcm_close(). But soc_pcm_close() is not using it. It is no problem, but confusable. static int __soc_pcm_close(...) { => return soc_pcm_clean(rtd, substream, 0); } static int soc_pcm_close(...) { ... snd_soc_dpcm_mutex_lock(rtd); => soc_pcm_clean(rtd, substream, 0); snd_soc_dpcm_mutex_unlock(rtd); return 0; } This patch use it. Fixes: b7898396f4bbe16 ("ASoC: soc-pcm: Fix and cleanup DPCM locking") Cc: Takashi Iwai Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87czctgg3w.wl-kuninori.morimoto.gx@renesas.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 209dfa437cb4..b5720e272c51 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -723,7 +723,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); snd_soc_dpcm_mutex_lock(rtd); - soc_pcm_clean(rtd, substream, 0); + __soc_pcm_close(rtd, substream); snd_soc_dpcm_mutex_unlock(rtd); return 0; } -- cgit v1.2.3 From 23204d928a27146d13e11c9383632775345ecca8 Mon Sep 17 00:00:00 2001 From: Martin Povišer Date: Thu, 25 Aug 2022 16:02:37 +0200 Subject: ASoC: tas2764: Allow mono streams MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The part is a mono speaker amp, but it can do downmix and switch between left and right channel, so the right channel range is 1 to 2. (This mirrors commit bf54d97a835d ("ASoC: tas2770: Allow mono streams") which was a fix to the tas2770 driver.) Fixes: 827ed8a0fa50 ("ASoC: tas2764: Add the driver for the TAS2764") Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220825140241.53963-2-povik+lin@cutebit.org Signed-off-by: Mark Brown --- sound/soc/codecs/tas2764.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c index 846d9d3ecc9d..0df5d975c3c9 100644 --- a/sound/soc/codecs/tas2764.c +++ b/sound/soc/codecs/tas2764.c @@ -485,7 +485,7 @@ static struct snd_soc_dai_driver tas2764_dai_driver[] = { .id = 0, .playback = { .stream_name = "ASI1 Playback", - .channels_min = 2, + .channels_min = 1, .channels_max = 2, .rates = TAS2764_RATES, .formats = TAS2764_FORMATS, -- cgit v1.2.3 From 09273f38832406db19a8907a934687cc10660a6b Mon Sep 17 00:00:00 2001 From: Martin Povišer Date: Thu, 25 Aug 2022 16:02:38 +0200 Subject: ASoC: tas2764: Drop conflicting set_bias_level power setting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver is setting the PWR_CTRL field in both the set_bias_level callback and on DAPM events of the DAC widget (and also in the mute_stream method). Drop the set_bias_level callback altogether as the power setting it does is in conflict with the other code paths. (This mirrors commit c8a6ae3fe1c8 ("ASoC: tas2770: Drop conflicting set_bias_level power setting") which was a fix to the tas2770 driver.) Fixes: 827ed8a0fa50 ("ASoC: tas2764: Add the driver for the TAS2764") Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220825140241.53963-3-povik+lin@cutebit.org Signed-off-by: Mark Brown --- sound/soc/codecs/tas2764.c | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c index 0df5d975c3c9..f4ac6edefdc0 100644 --- a/sound/soc/codecs/tas2764.c +++ b/sound/soc/codecs/tas2764.c @@ -50,38 +50,6 @@ static void tas2764_reset(struct tas2764_priv *tas2764) usleep_range(1000, 2000); } -static int tas2764_set_bias_level(struct snd_soc_component *component, - enum snd_soc_bias_level level) -{ - struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component); - - switch (level) { - case SND_SOC_BIAS_ON: - snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, - TAS2764_PWR_CTRL_MASK, - TAS2764_PWR_CTRL_ACTIVE); - break; - case SND_SOC_BIAS_STANDBY: - case SND_SOC_BIAS_PREPARE: - snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, - TAS2764_PWR_CTRL_MASK, - TAS2764_PWR_CTRL_MUTE); - break; - case SND_SOC_BIAS_OFF: - snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, - TAS2764_PWR_CTRL_MASK, - TAS2764_PWR_CTRL_SHUTDOWN); - break; - - default: - dev_err(tas2764->dev, - "wrong power level setting %d\n", level); - return -EINVAL; - } - - return 0; -} - #ifdef CONFIG_PM static int tas2764_codec_suspend(struct snd_soc_component *component) { @@ -549,7 +517,6 @@ static const struct snd_soc_component_driver soc_component_driver_tas2764 = { .probe = tas2764_codec_probe, .suspend = tas2764_codec_suspend, .resume = tas2764_codec_resume, - .set_bias_level = tas2764_set_bias_level, .controls = tas2764_snd_controls, .num_controls = ARRAY_SIZE(tas2764_snd_controls), .dapm_widgets = tas2764_dapm_widgets, -- cgit v1.2.3 From f5ad67f13623548e5aff847f89700c178aaf2a98 Mon Sep 17 00:00:00 2001 From: Martin Povišer Date: Thu, 25 Aug 2022 16:02:39 +0200 Subject: ASoC: tas2764: Fix mute/unmute MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because the PWR_CTRL field is modeled as the power state of the DAC widget, and at the same time it is used to implement mute/unmute, we need some additional book-keeping to have the right end result no matter the sequence of calls. Without this fix, one permanently mutes an ongoing stream by toggling the associated speaker pin control. (This mirrors commit 1e5907bcb3a3 ("ASoC: tas2770: Fix handling of mute/unmute") which was a fix to the tas2770 driver.) Fixes: 827ed8a0fa50 ("ASoC: tas2764: Add the driver for the TAS2764") Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220825140241.53963-4-povik+lin@cutebit.org Signed-off-by: Mark Brown --- sound/soc/codecs/tas2764.c | 57 ++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c index f4ac6edefdc0..39902f77a2e0 100644 --- a/sound/soc/codecs/tas2764.c +++ b/sound/soc/codecs/tas2764.c @@ -34,6 +34,9 @@ struct tas2764_priv { int v_sense_slot; int i_sense_slot; + + bool dac_powered; + bool unmuted; }; static void tas2764_reset(struct tas2764_priv *tas2764) @@ -50,6 +53,26 @@ static void tas2764_reset(struct tas2764_priv *tas2764) usleep_range(1000, 2000); } +static int tas2764_update_pwr_ctrl(struct tas2764_priv *tas2764) +{ + struct snd_soc_component *component = tas2764->component; + unsigned int val; + int ret; + + if (tas2764->dac_powered) + val = tas2764->unmuted ? + TAS2764_PWR_CTRL_ACTIVE : TAS2764_PWR_CTRL_MUTE; + else + val = TAS2764_PWR_CTRL_SHUTDOWN; + + ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, + TAS2764_PWR_CTRL_MASK, val); + if (ret < 0) + return ret; + + return 0; +} + #ifdef CONFIG_PM static int tas2764_codec_suspend(struct snd_soc_component *component) { @@ -82,9 +105,7 @@ static int tas2764_codec_resume(struct snd_soc_component *component) usleep_range(1000, 2000); } - ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, - TAS2764_PWR_CTRL_MASK, - TAS2764_PWR_CTRL_ACTIVE); + ret = tas2764_update_pwr_ctrl(tas2764); if (ret < 0) return ret; @@ -118,14 +139,12 @@ static int tas2764_dac_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: - ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, - TAS2764_PWR_CTRL_MASK, - TAS2764_PWR_CTRL_MUTE); + tas2764->dac_powered = true; + ret = tas2764_update_pwr_ctrl(tas2764); break; case SND_SOC_DAPM_PRE_PMD: - ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, - TAS2764_PWR_CTRL_MASK, - TAS2764_PWR_CTRL_SHUTDOWN); + tas2764->dac_powered = false; + ret = tas2764_update_pwr_ctrl(tas2764); break; default: dev_err(tas2764->dev, "Unsupported event\n"); @@ -170,17 +189,11 @@ static const struct snd_soc_dapm_route tas2764_audio_map[] = { static int tas2764_mute(struct snd_soc_dai *dai, int mute, int direction) { - struct snd_soc_component *component = dai->component; - int ret; - - ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, - TAS2764_PWR_CTRL_MASK, - mute ? TAS2764_PWR_CTRL_MUTE : 0); + struct tas2764_priv *tas2764 = + snd_soc_component_get_drvdata(dai->component); - if (ret < 0) - return ret; - - return 0; + tas2764->unmuted = !mute; + return tas2764_update_pwr_ctrl(tas2764); } static int tas2764_set_bitwidth(struct tas2764_priv *tas2764, int bitwidth) @@ -494,12 +507,6 @@ static int tas2764_codec_probe(struct snd_soc_component *component) if (ret < 0) return ret; - ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, - TAS2764_PWR_CTRL_MASK, - TAS2764_PWR_CTRL_MUTE); - if (ret < 0) - return ret; - return 0; } -- cgit v1.2.3 From dae191fb957f82fbf570d13c060110eb278813ec Mon Sep 17 00:00:00 2001 From: Martin Povišer Date: Thu, 25 Aug 2022 16:02:40 +0200 Subject: ASoC: tas2764: Add IRQ handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an IRQ handler which logs detected faults (but doesn't do anything else). Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220825140241.53963-5-povik+lin@cutebit.org Signed-off-by: Mark Brown --- sound/soc/codecs/tas2764.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/tas2764.h | 19 ++++++++++ 2 files changed, 112 insertions(+) diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c index 39902f77a2e0..e99a46fb503f 100644 --- a/sound/soc/codecs/tas2764.c +++ b/sound/soc/codecs/tas2764.c @@ -31,6 +31,7 @@ struct tas2764_priv { struct gpio_desc *sdz_gpio; struct regmap *regmap; struct device *dev; + int irq; int v_sense_slot; int i_sense_slot; @@ -39,6 +40,57 @@ struct tas2764_priv { bool unmuted; }; +static const char *tas2764_int_ltch0_msgs[8] = { + "fault: over temperature", /* INT_LTCH0 & BIT(0) */ + "fault: over current", + "fault: bad TDM clock", + "limiter active", + "fault: PVDD below limiter inflection point", + "fault: limiter max attenuation", + "fault: BOP infinite hold", + "fault: BOP mute", /* INT_LTCH0 & BIT(7) */ +}; + +static const unsigned int tas2764_int_readout_regs[6] = { + TAS2764_INT_LTCH0, + TAS2764_INT_LTCH1, + TAS2764_INT_LTCH1_0, + TAS2764_INT_LTCH2, + TAS2764_INT_LTCH3, + TAS2764_INT_LTCH4, +}; + +static irqreturn_t tas2764_irq(int irq, void *data) +{ + struct tas2764_priv *tas2764 = data; + u8 latched[6] = {0, 0, 0, 0, 0, 0}; + int ret = IRQ_NONE; + int i; + + for (i = 0; i < ARRAY_SIZE(latched); i++) + latched[i] = snd_soc_component_read(tas2764->component, + tas2764_int_readout_regs[i]); + + for (i = 0; i < 8; i++) { + if (latched[0] & BIT(i)) { + dev_crit_ratelimited(tas2764->dev, "%s\n", + tas2764_int_ltch0_msgs[i]); + ret = IRQ_HANDLED; + } + } + + if (latched[0]) { + dev_err_ratelimited(tas2764->dev, "other context to the fault: %02x,%02x,%02x,%02x,%02x", + latched[1], latched[2], latched[3], latched[4], latched[5]); + snd_soc_component_update_bits(tas2764->component, + TAS2764_INT_CLK_CFG, + TAS2764_INT_CLK_CFG_IRQZ_CLR, + TAS2764_INT_CLK_CFG_IRQZ_CLR); + } + + return ret; +} + static void tas2764_reset(struct tas2764_priv *tas2764) { if (tas2764->reset_gpio) { @@ -497,6 +549,34 @@ static int tas2764_codec_probe(struct snd_soc_component *component) tas2764_reset(tas2764); + if (tas2764->irq) { + ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK0, 0xff); + if (ret < 0) + return ret; + + ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK1, 0xff); + if (ret < 0) + return ret; + + ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK2, 0xff); + if (ret < 0) + return ret; + + ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK3, 0xff); + if (ret < 0) + return ret; + + ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK4, 0xff); + if (ret < 0) + return ret; + + ret = devm_request_threaded_irq(tas2764->dev, tas2764->irq, NULL, tas2764_irq, + IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW, + "tas2764", tas2764); + if (ret) + dev_warn(tas2764->dev, "failed to request IRQ: %d\n", ret); + } + ret = snd_soc_component_update_bits(tas2764->component, TAS2764_TDM_CFG5, TAS2764_TDM_CFG5_VSNS_ENABLE, 0); if (ret < 0) @@ -559,9 +639,21 @@ static const struct regmap_range_cfg tas2764_regmap_ranges[] = { }, }; +static bool tas2764_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TAS2764_INT_LTCH0 ... TAS2764_INT_LTCH4: + case TAS2764_INT_CLK_CFG: + return true; + default: + return false; + } +} + static const struct regmap_config tas2764_i2c_regmap = { .reg_bits = 8, .val_bits = 8, + .volatile_reg = tas2764_volatile_register, .reg_defaults = tas2764_reg_defaults, .num_reg_defaults = ARRAY_SIZE(tas2764_reg_defaults), .cache_type = REGCACHE_RBTREE, @@ -615,6 +707,7 @@ static int tas2764_i2c_probe(struct i2c_client *client) return -ENOMEM; tas2764->dev = &client->dev; + tas2764->irq = client->irq; i2c_set_clientdata(client, tas2764); dev_set_drvdata(&client->dev, tas2764); diff --git a/sound/soc/codecs/tas2764.h b/sound/soc/codecs/tas2764.h index f015f22a083b..960b337ed0fc 100644 --- a/sound/soc/codecs/tas2764.h +++ b/sound/soc/codecs/tas2764.h @@ -87,4 +87,23 @@ #define TAS2764_TDM_CFG6_ISNS_ENABLE BIT(6) #define TAS2764_TDM_CFG6_50_MASK GENMASK(5, 0) +/* Interrupt Masks */ +#define TAS2764_INT_MASK0 TAS2764_REG(0x0, 0x3b) +#define TAS2764_INT_MASK1 TAS2764_REG(0x0, 0x3c) +#define TAS2764_INT_MASK2 TAS2764_REG(0x0, 0x40) +#define TAS2764_INT_MASK3 TAS2764_REG(0x0, 0x41) +#define TAS2764_INT_MASK4 TAS2764_REG(0x0, 0x3d) + +/* Latched Fault Registers */ +#define TAS2764_INT_LTCH0 TAS2764_REG(0x0, 0x49) +#define TAS2764_INT_LTCH1 TAS2764_REG(0x0, 0x4a) +#define TAS2764_INT_LTCH1_0 TAS2764_REG(0x0, 0x4b) +#define TAS2764_INT_LTCH2 TAS2764_REG(0x0, 0x4f) +#define TAS2764_INT_LTCH3 TAS2764_REG(0x0, 0x50) +#define TAS2764_INT_LTCH4 TAS2764_REG(0x0, 0x51) + +/* Clock/IRQ Settings */ +#define TAS2764_INT_CLK_CFG TAS2764_REG(0x0, 0x5c) +#define TAS2764_INT_CLK_CFG_IRQZ_CLR BIT(2) + #endif /* __TAS2764__ */ -- cgit v1.2.3 From aca86ec9a02a4d6099dbe23d1078faa005d58422 Mon Sep 17 00:00:00 2001 From: Martin Povišer Date: Thu, 25 Aug 2022 16:02:41 +0200 Subject: ASoC: tas2764: Export highpass filter setting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expose a control for the setting of 'DC blocker' highpass filter in the playback path of TAS2764. Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220825140241.53963-6-povik+lin@cutebit.org Signed-off-by: Mark Brown --- sound/soc/codecs/tas2764.c | 10 ++++++++++ sound/soc/codecs/tas2764.h | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c index e99a46fb503f..51b87a936179 100644 --- a/sound/soc/codecs/tas2764.c +++ b/sound/soc/codecs/tas2764.c @@ -593,11 +593,21 @@ static int tas2764_codec_probe(struct snd_soc_component *component) static DECLARE_TLV_DB_SCALE(tas2764_digital_tlv, 1100, 50, 0); static DECLARE_TLV_DB_SCALE(tas2764_playback_volume, -10050, 50, 1); +static const char * const tas2764_hpf_texts[] = { + "Disabled", "2 Hz", "50 Hz", "100 Hz", "200 Hz", + "400 Hz", "800 Hz" +}; + +static SOC_ENUM_SINGLE_DECL( + tas2764_hpf_enum, TAS2764_DC_BLK0, + TAS2764_DC_BLK0_HPF_FREQ_PB_SHIFT, tas2764_hpf_texts); + static const struct snd_kcontrol_new tas2764_snd_controls[] = { SOC_SINGLE_TLV("Speaker Volume", TAS2764_DVC, 0, TAS2764_DVC_MAX, 1, tas2764_playback_volume), SOC_SINGLE_TLV("Amp Gain Volume", TAS2764_CHNL_0, 1, 0x14, 0, tas2764_digital_tlv), + SOC_ENUM("HPF Corner Frequency", tas2764_hpf_enum), }; static const struct snd_soc_component_driver soc_component_driver_tas2764 = { diff --git a/sound/soc/codecs/tas2764.h b/sound/soc/codecs/tas2764.h index 960b337ed0fc..168af772a898 100644 --- a/sound/soc/codecs/tas2764.h +++ b/sound/soc/codecs/tas2764.h @@ -33,6 +33,10 @@ #define TAS2764_VSENSE_POWER_EN 3 #define TAS2764_ISENSE_POWER_EN 4 +/* DC Blocker Control */ +#define TAS2764_DC_BLK0 TAS2764_REG(0x0, 0x04) +#define TAS2764_DC_BLK0_HPF_FREQ_PB_SHIFT 0 + /* Digital Volume Control */ #define TAS2764_DVC TAS2764_REG(0X0, 0x1a) #define TAS2764_DVC_MAX 0xc9 -- cgit v1.2.3 From 255a03bb1bb3b10d1c1ca785c596db84723f59d7 Mon Sep 17 00:00:00 2001 From: Aidan MacDonald Date: Thu, 21 Jul 2022 11:25:57 +0100 Subject: ASoC: wcd9335: Convert irq chip to config regs Type registers in regmap-irq have been deprecated in favor of config registers, which are more general. Chips using type_base can switch over to a single config base register and a standard ->set_irq_type() callback provided by regmap-irq, which uses the type info associated with each 'struct regmap_irq' to update type registers in the same way as the old code did. Signed-off-by: Aidan MacDonald Link: https://lore.kernel.org/r/20220721102558.25457-2-aidanmacdonald.0x0@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index beeeb35e8032..2c5aa4df1e66 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -5013,16 +5013,22 @@ static const struct regmap_irq wcd9335_codec_irqs[] = { }, }; +static const unsigned int wcd9335_config_regs[] = { + WCD9335_INTR_LEVEL0, +}; + static const struct regmap_irq_chip wcd9335_regmap_irq1_chip = { .name = "wcd9335_pin1_irq", .status_base = WCD9335_INTR_PIN1_STATUS0, .mask_base = WCD9335_INTR_PIN1_MASK0, .ack_base = WCD9335_INTR_PIN1_CLEAR0, - .type_base = WCD9335_INTR_LEVEL0, - .num_type_reg = 4, .num_regs = 4, .irqs = wcd9335_codec_irqs, .num_irqs = ARRAY_SIZE(wcd9335_codec_irqs), + .config_base = wcd9335_config_regs, + .num_config_bases = ARRAY_SIZE(wcd9335_config_regs), + .num_config_regs = 4, + .set_type_config = regmap_irq_set_type_config_simple, }; static int wcd9335_parse_dt(struct wcd9335_codec *wcd) -- cgit v1.2.3 From de3287f177a5666409978a1a0331a33e2842d43b Mon Sep 17 00:00:00 2001 From: Aidan MacDonald Date: Thu, 21 Jul 2022 11:25:58 +0100 Subject: ASoC: wcd938x: Remove spurious type_base from irq chip There is no reason to set type_base here: the chip doesn't set num_type_regs and none of the IRQs have type information so it's not possible for regmap-irq to configure IRQ types. Type registers are also deprecated in regmap-irq, so any IRQ type support in the future should be implemented using config registers instead. Signed-off-by: Aidan MacDonald Link: https://lore.kernel.org/r/20220721102558.25457-3-aidanmacdonald.0x0@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd938x.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index 781ae569be29..aca06a4026f3 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -1298,7 +1298,6 @@ static struct regmap_irq_chip wcd938x_regmap_irq_chip = { .num_regs = 3, .status_base = WCD938X_DIGITAL_INTR_STATUS_0, .mask_base = WCD938X_DIGITAL_INTR_MASK_0, - .type_base = WCD938X_DIGITAL_INTR_LEVEL_0, .ack_base = WCD938X_DIGITAL_INTR_CLEAR_0, .use_ack = 1, .runtime_pm = true, -- cgit v1.2.3 From 99a387c7818fe422fa96458f56bc74f05f263013 Mon Sep 17 00:00:00 2001 From: Venkata Prasad Potturu Date: Fri, 26 Aug 2022 12:12:45 +0530 Subject: ASoC: amd: acp: Modify dai_id macros to be more generic Change dai_id macros to make I2S instances in order. Signed-off-by: Venkata Prasad Potturu Link: https://lore.kernel.org/r/20220826064250.3302260-1-venkataprasad.potturu@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/amd.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h index afa4e25cba19..5f2119f42271 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -21,9 +21,9 @@ #define ACP3X_DEV 3 #define ACP6X_DEV 6 -#define I2S_SP_INSTANCE 0x00 -#define I2S_BT_INSTANCE 0x01 -#define DMIC_INSTANCE 0x02 +#define DMIC_INSTANCE 0x00 +#define I2S_SP_INSTANCE 0x01 +#define I2S_BT_INSTANCE 0x02 #define I2S_HS_INSTANCE 0x03 #define MEM_WINDOW_START 0x4080000 -- cgit v1.2.3 From b9320f545e2c91caf2a15f67537ef538928ca6af Mon Sep 17 00:00:00 2001 From: Xiangsheng Hou Date: Mon, 25 Jul 2022 20:02:05 +0800 Subject: dt-bindings: mediatek: Add axi clock in mt8173 dts example For mt8173, it is needed to add the axi clock for dma mode. Signed-off-by: Xiangsheng Hou Reviewed-by: AngeloGioacchino Del Regno Acked-by: Rob Herring Link: https://lore.kernel.org/r/20220725120204.10834-1-xiangsheng.hou@mediatek.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml b/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml index 970b1119898b..a453996c13f2 100644 --- a/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml +++ b/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml @@ -85,8 +85,9 @@ examples: compatible = "mediatek,mt8173-nor"; reg = <0 0x1100d000 0 0xe0>; interrupts = <1>; - clocks = <&pericfg CLK_PERI_SPI>, <&topckgen CLK_TOP_SPINFI_IFR_SEL>; - clock-names = "spi", "sf"; + clocks = <&pericfg CLK_PERI_SPI>, <&topckgen CLK_TOP_SPINFI_IFR_SEL>, + <&pericfg CLK_PERI_NFI>; + clock-names = "spi", "sf", "axi"; #address-cells = <1>; #size-cells = <0>; -- cgit v1.2.3 From 5b7f4e5de61ba8c44317718936864da29eeba62a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 26 Aug 2022 12:36:59 +0300 Subject: ASoC: codecs: allow compile testing without MFD drivers Motorola CPCAP, Lochnagar Sound, Rockchip RK817 and Qualcomm WCD9340/WCD9341 do not depend on parent MFD driver in build time and can be compile tested without respective MFD part for increased build coverage. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220826093659.1059276-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 5926b33ba09e..94b7bb85d236 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -610,7 +610,7 @@ config SND_SOC_BT_SCO config SND_SOC_CPCAP tristate "Motorola CPCAP codec" - depends on MFD_CPCAP + depends on MFD_CPCAP || COMPILE_TEST config SND_SOC_CQ0093VC tristate @@ -972,7 +972,7 @@ config SND_SOC_LM49453 config SND_SOC_LOCHNAGAR_SC tristate "Lochnagar Sound Card" - depends on MFD_LOCHNAGAR + depends on MFD_LOCHNAGAR || COMPILE_TEST help This driver support the sound card functionality of the Cirrus Logic Lochnagar audio development board. @@ -1197,7 +1197,7 @@ config SND_SOC_RK3328 config SND_SOC_RK817 tristate "Rockchip RK817 audio CODEC" - depends on MFD_RK808 + depends on MFD_RK808 || COMPILE_TEST select REGMAP_I2C config SND_SOC_RL6231 @@ -1745,7 +1745,7 @@ config SND_SOC_WCD934X tristate "WCD9340/WCD9341 Codec" depends on COMMON_CLK select SND_SOC_WCD_MBHC - depends on MFD_WCD934X + depends on MFD_WCD934X || COMPILE_TEST help The WCD9340/9341 is a audio codec IC Integrated in Qualcomm SoCs like SDM845. -- cgit v1.2.3 From e0550fffd5b3d32118a335718d1e3ec93e6bc411 Mon Sep 17 00:00:00 2001 From: Jinpeng Cui Date: Mon, 29 Aug 2022 09:13:19 +0000 Subject: ASoC: codecs: max98088: remove redundant ret variable Return value from devm_snd_soc_register_component() directly instead of taking this in another redundant variable. Reported-by: Zeal Robot Signed-off-by: Jinpeng Cui Link: https://lore.kernel.org/r/20220829091319.266068-1-cui.jinpeng2@zte.com.cn Signed-off-by: Mark Brown --- sound/soc/codecs/max98088.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index b208fb530a8b..405ec16be2b6 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -1749,7 +1749,6 @@ MODULE_DEVICE_TABLE(i2c, max98088_i2c_id); static int max98088_i2c_probe(struct i2c_client *i2c) { struct max98088_priv *max98088; - int ret; const struct i2c_device_id *id; max98088 = devm_kzalloc(&i2c->dev, sizeof(struct max98088_priv), @@ -1772,9 +1771,8 @@ static int max98088_i2c_probe(struct i2c_client *i2c) i2c_set_clientdata(i2c, max98088); max98088->pdata = i2c->dev.platform_data; - ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_max98088, + return devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_max98088, &max98088_dai[0], 2); - return ret; } #if defined(CONFIG_OF) -- cgit v1.2.3 From 161bff51181f919a4b80fe2ab3504d60ac4b4316 Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Sat, 27 Aug 2022 22:26:45 +0530 Subject: ASoC: amd: add Pink Sardine platform ACP IP register header Add ACP IP Register header for Pink Sardine platform. Signed-off-by: Syed Saba Kareem Reviewed-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20220827165657.2343818-2-Syed.SabaKareem@amd.com Signed-off-by: Mark Brown --- include/sound/acp62_chip_offset_byte.h | 444 +++++++++++++++++++++++++++++++++ 1 file changed, 444 insertions(+) create mode 100644 include/sound/acp62_chip_offset_byte.h diff --git a/include/sound/acp62_chip_offset_byte.h b/include/sound/acp62_chip_offset_byte.h new file mode 100644 index 000000000000..f03992f81168 --- /dev/null +++ b/include/sound/acp62_chip_offset_byte.h @@ -0,0 +1,444 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * AMD ACP 6.2 Register Documentation + * + * Copyright 2022 Advanced Micro Devices, Inc. + */ + +#ifndef _acp_ip_OFFSET_HEADER +#define _acp_ip_OFFSET_HEADER + +/* Registers from ACP_DMA block */ +#define ACP_DMA_CNTL_0 0x0000000 +#define ACP_DMA_CNTL_1 0x0000004 +#define ACP_DMA_CNTL_2 0x0000008 +#define ACP_DMA_CNTL_3 0x000000C +#define ACP_DMA_CNTL_4 0x0000010 +#define ACP_DMA_CNTL_5 0x0000014 +#define ACP_DMA_CNTL_6 0x0000018 +#define ACP_DMA_CNTL_7 0x000001C +#define ACP_DMA_DSCR_STRT_IDX_0 0x0000020 +#define ACP_DMA_DSCR_STRT_IDX_1 0x0000024 +#define ACP_DMA_DSCR_STRT_IDX_2 0x0000028 +#define ACP_DMA_DSCR_STRT_IDX_3 0x000002C +#define ACP_DMA_DSCR_STRT_IDX_4 0x0000030 +#define ACP_DMA_DSCR_STRT_IDX_5 0x0000034 +#define ACP_DMA_DSCR_STRT_IDX_6 0x0000038 +#define ACP_DMA_DSCR_STRT_IDX_7 0x000003C +#define ACP_DMA_DSCR_CNT_0 0x0000040 +#define ACP_DMA_DSCR_CNT_1 0x0000044 +#define ACP_DMA_DSCR_CNT_2 0x0000048 +#define ACP_DMA_DSCR_CNT_3 0x000004C +#define ACP_DMA_DSCR_CNT_4 0x0000050 +#define ACP_DMA_DSCR_CNT_5 0x0000054 +#define ACP_DMA_DSCR_CNT_6 0x0000058 +#define ACP_DMA_DSCR_CNT_7 0x000005C +#define ACP_DMA_PRIO_0 0x0000060 +#define ACP_DMA_PRIO_1 0x0000064 +#define ACP_DMA_PRIO_2 0x0000068 +#define ACP_DMA_PRIO_3 0x000006C +#define ACP_DMA_PRIO_4 0x0000070 +#define ACP_DMA_PRIO_5 0x0000074 +#define ACP_DMA_PRIO_6 0x0000078 +#define ACP_DMA_PRIO_7 0x000007C +#define ACP_DMA_CUR_DSCR_0 0x0000080 +#define ACP_DMA_CUR_DSCR_1 0x0000084 +#define ACP_DMA_CUR_DSCR_2 0x0000088 +#define ACP_DMA_CUR_DSCR_3 0x000008C +#define ACP_DMA_CUR_DSCR_4 0x0000090 +#define ACP_DMA_CUR_DSCR_5 0x0000094 +#define ACP_DMA_CUR_DSCR_6 0x0000098 +#define ACP_DMA_CUR_DSCR_7 0x000009C +#define ACP_DMA_CUR_TRANS_CNT_0 0x00000A0 +#define ACP_DMA_CUR_TRANS_CNT_1 0x00000A4 +#define ACP_DMA_CUR_TRANS_CNT_2 0x00000A8 +#define ACP_DMA_CUR_TRANS_CNT_3 0x00000AC +#define ACP_DMA_CUR_TRANS_CNT_4 0x00000B0 +#define ACP_DMA_CUR_TRANS_CNT_5 0x00000B4 +#define ACP_DMA_CUR_TRANS_CNT_6 0x00000B8 +#define ACP_DMA_CUR_TRANS_CNT_7 0x00000BC +#define ACP_DMA_ERR_STS_0 0x00000C0 +#define ACP_DMA_ERR_STS_1 0x00000C4 +#define ACP_DMA_ERR_STS_2 0x00000C8 +#define ACP_DMA_ERR_STS_3 0x00000CC +#define ACP_DMA_ERR_STS_4 0x00000D0 +#define ACP_DMA_ERR_STS_5 0x00000D4 +#define ACP_DMA_ERR_STS_6 0x00000D8 +#define ACP_DMA_ERR_STS_7 0x00000DC +#define ACP_DMA_DESC_BASE_ADDR 0x00000E0 +#define ACP_DMA_DESC_MAX_NUM_DSCR 0x00000E4 +#define ACP_DMA_CH_STS 0x00000E8 +#define ACP_DMA_CH_GROUP 0x00000EC +#define ACP_DMA_CH_RST_STS 0x00000F0 + +/* Registers from ACP_AXI2AXIATU block */ +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1 0x0000C00 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_1 0x0000C04 +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_2 0x0000C08 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_2 0x0000C0C +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_3 0x0000C10 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_3 0x0000C14 +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_4 0x0000C18 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_4 0x0000C1C +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5 0x0000C20 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_5 0x0000C24 +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_6 0x0000C28 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_6 0x0000C2C +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_7 0x0000C30 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_7 0x0000C34 +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_8 0x0000C38 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_8 0x0000C3C +#define ACPAXI2AXI_ATU_CTRL 0x0000C40 +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_9 0x0000C44 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_9 0x0000C48 +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_10 0x0000C4C +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_10 0x0000C50 +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_11 0x0000C54 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_11 0x0000C58 +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_12 0x0000C5C +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_12 0x0000C60 +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_13 0x0000C64 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_13 0x0000C68 +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_14 0x0000C6C +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_14 0x0000C70 +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_15 0x0000C74 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_15 0x0000C78 +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_16 0x0000C7C +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_16 0x0000C80 + +/* Registers from ACP_CLKRST block */ +#define ACP_SOFT_RESET 0x0001000 +#define ACP_CONTROL 0x0001004 +#define ACP_STATUS 0x0001008 +#define ACP_DYNAMIC_CG_MASTER_CONTROL 0x0001010 +#define ACP_ZSC_DSP_CTRL 0x0001014 +#define ACP_ZSC_STS 0x0001018 +#define ACP_PGFSM_CONTROL 0x0001024 +#define ACP_PGFSM_STATUS 0x0001028 +#define ACP_CLKMUX_SEL 0x000102C + +/* Registers from ACP_AON block */ +#define ACP_PME_EN 0x0001400 +#define ACP_DEVICE_STATE 0x0001404 +#define AZ_DEVICE_STATE 0x0001408 +#define ACP_PIN_CONFIG 0x0001440 +#define ACP_PAD_PULLUP_CTRL 0x0001444 +#define ACP_PAD_PULLDOWN_CTRL 0x0001448 +#define ACP_PAD_DRIVE_STRENGTH_CTRL 0x000144C +#define ACP_PAD_SCHMEN_CTRL 0x0001450 +#define ACP_SW_PAD_KEEPER_EN 0x0001454 +#define ACP_SW_WAKE_EN 0x0001458 +#define ACP_I2S_WAKE_EN 0x000145C +#define ACP_SW1_WAKE_EN 0x0001460 + +/* Registers from ACP_P1_MISC block */ +#define ACP_EXTERNAL_INTR_ENB 0x0001A00 +#define ACP_EXTERNAL_INTR_CNTL 0x0001A04 +#define ACP_EXTERNAL_INTR_CNTL1 0x0001A08 +#define ACP_EXTERNAL_INTR_STAT 0x0001A0C +#define ACP_EXTERNAL_INTR_STAT1 0x0001A10 +#define ACP_ERROR_STATUS 0x0001A4C +#define ACP_P1_SW_I2S_ERROR_REASON 0x0001A50 +#define ACP_P1_SW_POS_TRACK_I2S_TX_CTRL 0x0001A6C +#define ACP_P1_SW_I2S_TX_DMA_POS 0x0001A70 +#define ACP_P1_SW_POS_TRACK_I2S_RX_CTRL 0x0001A74 +#define ACP_P1_SW_I2S_RX_DMA_POS 0x0001A78 +#define ACP_P1_DMIC_I2S_GPIO_INTR_CTRL 0x0001A7C +#define ACP_P1_DMIC_I2S_GPIO_INTR_STATUS 0x0001A80 +#define ACP_SCRATCH_REG_BASE_ADDR 0x0001A84 +#define ACP_P1_SW_POS_TRACK_BT_TX_CTRL 0x0001A88 +#define ACP_P1_SW_BT_TX_DMA_POS 0x0001A8C +#define ACP_P1_SW_POS_TRACK_HS_TX_CTRL 0x0001A90 +#define ACP_P1_SW_HS_TX_DMA_POS 0x0001A94 +#define ACP_P1_SW_POS_TRACK_BT_RX_CTRL 0x0001A98 +#define ACP_P1_SW_BT_RX_DMA_POS 0x0001A9C +#define ACP_P1_SW_POS_TRACK_HS_RX_CTRL 0x0001AA0 +#define ACP_P1_SW_HS_RX_DMA_POS 0x0001AA4 + +/* Registers from ACP_AUDIO_BUFFERS block */ +#define ACP_I2S_RX_RINGBUFADDR 0x0002000 +#define ACP_I2S_RX_RINGBUFSIZE 0x0002004 +#define ACP_I2S_RX_LINKPOSITIONCNTR 0x0002008 +#define ACP_I2S_RX_FIFOADDR 0x000200C +#define ACP_I2S_RX_FIFOSIZE 0x0002010 +#define ACP_I2S_RX_DMA_SIZE 0x0002014 +#define ACP_I2S_RX_LINEARPOSITIONCNTR_HIGH 0x0002018 +#define ACP_I2S_RX_LINEARPOSITIONCNTR_LOW 0x000201C +#define ACP_I2S_RX_INTR_WATERMARK_SIZE 0x0002020 +#define ACP_I2S_TX_RINGBUFADDR 0x0002024 +#define ACP_I2S_TX_RINGBUFSIZE 0x0002028 +#define ACP_I2S_TX_LINKPOSITIONCNTR 0x000202C +#define ACP_I2S_TX_FIFOADDR 0x0002030 +#define ACP_I2S_TX_FIFOSIZE 0x0002034 +#define ACP_I2S_TX_DMA_SIZE 0x0002038 +#define ACP_I2S_TX_LINEARPOSITIONCNTR_HIGH 0x000203C +#define ACP_I2S_TX_LINEARPOSITIONCNTR_LOW 0x0002040 +#define ACP_I2S_TX_INTR_WATERMARK_SIZE 0x0002044 +#define ACP_BT_RX_RINGBUFADDR 0x0002048 +#define ACP_BT_RX_RINGBUFSIZE 0x000204C +#define ACP_BT_RX_LINKPOSITIONCNTR 0x0002050 +#define ACP_BT_RX_FIFOADDR 0x0002054 +#define ACP_BT_RX_FIFOSIZE 0x0002058 +#define ACP_BT_RX_DMA_SIZE 0x000205C +#define ACP_BT_RX_LINEARPOSITIONCNTR_HIGH 0x0002060 +#define ACP_BT_RX_LINEARPOSITIONCNTR_LOW 0x0002064 +#define ACP_BT_RX_INTR_WATERMARK_SIZE 0x0002068 +#define ACP_BT_TX_RINGBUFADDR 0x000206C +#define ACP_BT_TX_RINGBUFSIZE 0x0002070 +#define ACP_BT_TX_LINKPOSITIONCNTR 0x0002074 +#define ACP_BT_TX_FIFOADDR 0x0002078 +#define ACP_BT_TX_FIFOSIZE 0x000207C +#define ACP_BT_TX_DMA_SIZE 0x0002080 +#define ACP_BT_TX_LINEARPOSITIONCNTR_HIGH 0x0002084 +#define ACP_BT_TX_LINEARPOSITIONCNTR_LOW 0x0002088 +#define ACP_BT_TX_INTR_WATERMARK_SIZE 0x000208C +#define ACP_HS_RX_RINGBUFADDR 0x0002090 +#define ACP_HS_RX_RINGBUFSIZE 0x0002094 +#define ACP_HS_RX_LINKPOSITIONCNTR 0x0002098 +#define ACP_HS_RX_FIFOADDR 0x000209C +#define ACP_HS_RX_FIFOSIZE 0x00020A0 +#define ACP_HS_RX_DMA_SIZE 0x00020A4 +#define ACP_HS_RX_LINEARPOSITIONCNTR_HIGH 0x00020A8 +#define ACP_HS_RX_LINEARPOSITIONCNTR_LOW 0x00020AC +#define ACP_HS_RX_INTR_WATERMARK_SIZE 0x00020B0 +#define ACP_HS_TX_RINGBUFADDR 0x00020B4 +#define ACP_HS_TX_RINGBUFSIZE 0x00020B8 +#define ACP_HS_TX_LINKPOSITIONCNTR 0x00020BC +#define ACP_HS_TX_FIFOADDR 0x00020C0 +#define ACP_HS_TX_FIFOSIZE 0x00020C4 +#define ACP_HS_TX_DMA_SIZE 0x00020C8 +#define ACP_HS_TX_LINEARPOSITIONCNTR_HIGH 0x00020CC +#define ACP_HS_TX_LINEARPOSITIONCNTR_LOW 0x00020D0 +#define ACP_HS_TX_INTR_WATERMARK_SIZE 0x00020D4 + +/* Registers from ACP_I2S_TDM block */ +#define ACP_I2STDM_IER 0x0002400 +#define ACP_I2STDM_IRER 0x0002404 +#define ACP_I2STDM_RXFRMT 0x0002408 +#define ACP_I2STDM_ITER 0x000240C +#define ACP_I2STDM_TXFRMT 0x0002410 +#define ACP_I2STDM0_MSTRCLKGEN 0x0002414 +#define ACP_I2STDM1_MSTRCLKGEN 0x0002418 +#define ACP_I2STDM2_MSTRCLKGEN 0x000241C +#define ACP_I2STDM_REFCLKGEN 0x0002420 + +/* Registers from ACP_BT_TDM block */ +#define ACP_BTTDM_IER 0x0002800 +#define ACP_BTTDM_IRER 0x0002804 +#define ACP_BTTDM_RXFRMT 0x0002808 +#define ACP_BTTDM_ITER 0x000280C +#define ACP_BTTDM_TXFRMT 0x0002810 +#define ACP_HSTDM_IER 0x0002814 +#define ACP_HSTDM_IRER 0x0002818 +#define ACP_HSTDM_RXFRMT 0x000281C +#define ACP_HSTDM_ITER 0x0002820 +#define ACP_HSTDM_TXFRMT 0x0002824 + +/* Registers from ACP_WOV block */ +#define ACP_WOV_PDM_ENABLE 0x0002C04 +#define ACP_WOV_PDM_DMA_ENABLE 0x0002C08 +#define ACP_WOV_RX_RINGBUFADDR 0x0002C0C +#define ACP_WOV_RX_RINGBUFSIZE 0x0002C10 +#define ACP_WOV_RX_LINKPOSITIONCNTR 0x0002C14 +#define ACP_WOV_RX_LINEARPOSITIONCNTR_HIGH 0x0002C18 +#define ACP_WOV_RX_LINEARPOSITIONCNTR_LOW 0x0002C1C +#define ACP_WOV_RX_INTR_WATERMARK_SIZE 0x0002C20 +#define ACP_WOV_PDM_FIFO_FLUSH 0x0002C24 +#define ACP_WOV_PDM_NO_OF_CHANNELS 0x0002C28 +#define ACP_WOV_PDM_DECIMATION_FACTOR 0x0002C2C +#define ACP_WOV_PDM_VAD_CTRL 0x0002C30 +#define ACP_WOV_WAKE 0x0002C54 +#define ACP_WOV_BUFFER_STATUS 0x0002C58 +#define ACP_WOV_MISC_CTRL 0x0002C5C +#define ACP_WOV_CLK_CTRL 0x0002C60 +#define ACP_PDM_VAD_DYNAMIC_CLK_GATING_EN 0x0002C64 +#define ACP_WOV_ERROR_STATUS_REGISTER 0x0002C68 +#define ACP_PDM_CLKDIV 0x0002C6C + +/* Registers from ACP_P1_AUDIO_BUFFERS block */ +#define ACP_P1_I2S_RX_RINGBUFADDR 0x0003A00 +#define ACP_P1_I2S_RX_RINGBUFSIZE 0x0003A04 +#define ACP_P1_I2S_RX_LINKPOSITIONCNTR 0x0003A08 +#define ACP_P1_I2S_RX_FIFOADDR 0x0003A0C +#define ACP_P1_I2S_RX_FIFOSIZE 0x0003A10 +#define ACP_P1_I2S_RX_DMA_SIZE 0x0003A14 +#define ACP_P1_I2S_RX_LINEARPOSITIONCNTR_HIGH 0x0003A18 +#define ACP_P1_I2S_RX_LINEARPOSITIONCNTR_LOW 0x0003A1C +#define ACP_P1_I2S_RX_INTR_WATERMARK_SIZE 0x0003A20 +#define ACP_P1_I2S_TX_RINGBUFADDR 0x0003A24 +#define ACP_P1_I2S_TX_RINGBUFSIZE 0x0003A28 +#define ACP_P1_I2S_TX_LINKPOSITIONCNTR 0x0003A2C +#define ACP_P1_I2S_TX_FIFOADDR 0x0003A30 +#define ACP_P1_I2S_TX_FIFOSIZE 0x0003A34 +#define ACP_P1_I2S_TX_DMA_SIZE 0x0003A38 +#define ACP_P1_I2S_TX_LINEARPOSITIONCNTR_HIGH 0x0003A3C +#define ACP_P1_I2S_TX_LINEARPOSITIONCNTR_LOW 0x0003A40 +#define ACP_P1_I2S_TX_INTR_WATERMARK_SIZE 0x0003A44 +#define ACP_P1_BT_RX_RINGBUFADDR 0x0003A48 +#define ACP_P1_BT_RX_RINGBUFSIZE 0x0003A4C +#define ACP_P1_BT_RX_LINKPOSITIONCNTR 0x0003A50 +#define ACP_P1_BT_RX_FIFOADDR 0x0003A54 +#define ACP_P1_BT_RX_FIFOSIZE 0x0003A58 +#define ACP_P1_BT_RX_DMA_SIZE 0x0003A5C +#define ACP_P1_BT_RX_LINEARPOSITIONCNTR_HIGH 0x0003A60 +#define ACP_P1_BT_RX_LINEARPOSITIONCNTR_LOW 0x0003A64 +#define ACP_P1_BT_RX_INTR_WATERMARK_SIZE 0x0003A68 +#define ACP_P1_BT_TX_RINGBUFADDR 0x0003A6C +#define ACP_P1_BT_TX_RINGBUFSIZE 0x0003A70 +#define ACP_P1_BT_TX_LINKPOSITIONCNTR 0x0003A74 +#define ACP_P1_BT_TX_FIFOADDR 0x0003A78 +#define ACP_P1_BT_TX_FIFOSIZE 0x0003A7C +#define ACP_P1_BT_TX_DMA_SIZE 0x0003A80 +#define ACP_P1_BT_TX_LINEARPOSITIONCNTR_HIGH 0x0003A84 +#define ACP_P1_BT_TX_LINEARPOSITIONCNTR_LOW 0x0003A88 +#define ACP_P1_BT_TX_INTR_WATERMARK_SIZE 0x0003A8C +#define ACP_P1_HS_RX_RINGBUFADDR 0x0003A90 +#define ACP_P1_HS_RX_RINGBUFSIZE 0x0003A94 +#define ACP_P1_HS_RX_LINKPOSITIONCNTR 0x0003A98 +#define ACP_P1_HS_RX_FIFOADDR 0x0003A9C +#define ACP_P1_HS_RX_FIFOSIZE 0x0003AA0 +#define ACP_P1_HS_RX_DMA_SIZE 0x0003AA4 +#define ACP_P1_HS_RX_LINEARPOSITIONCNTR_HIGH 0x0003AA8 +#define ACP_P1_HS_RX_LINEARPOSITIONCNTR_LOW 0x0003AAC +#define ACP_P1_HS_RX_INTR_WATERMARK_SIZE 0x0003AB0 +#define ACP_P1_HS_TX_RINGBUFADDR 0x0003AB4 +#define ACP_P1_HS_TX_RINGBUFSIZE 0x0003AB8 +#define ACP_P1_HS_TX_LINKPOSITIONCNTR 0x0003ABC +#define ACP_P1_HS_TX_FIFOADDR 0x0003AC0 +#define ACP_P1_HS_TX_FIFOSIZE 0x0003AC4 +#define ACP_P1_HS_TX_DMA_SIZE 0x0003AC8 +#define ACP_P1_HS_TX_LINEARPOSITIONCNTR_HIGH 0x0003ACC +#define ACP_P1_HS_TX_LINEARPOSITIONCNTR_LOW 0x0003AD0 +#define ACP_P1_HS_TX_INTR_WATERMARK_SIZE 0x0003AD4 + +/* Registers from ACP_SCRATCH block */ +#define ACP_SCRATCH_REG_0 0x0010000 +#define ACP_SCRATCH_REG_1 0x0010004 +#define ACP_SCRATCH_REG_2 0x0010008 +#define ACP_SCRATCH_REG_3 0x001000C +#define ACP_SCRATCH_REG_4 0x0010010 +#define ACP_SCRATCH_REG_5 0x0010014 +#define ACP_SCRATCH_REG_6 0x0010018 +#define ACP_SCRATCH_REG_7 0x001001C +#define ACP_SCRATCH_REG_8 0x0010020 +#define ACP_SCRATCH_REG_9 0x0010024 +#define ACP_SCRATCH_REG_10 0x0010028 +#define ACP_SCRATCH_REG_11 0x001002C +#define ACP_SCRATCH_REG_12 0x0010030 +#define ACP_SCRATCH_REG_13 0x0010034 +#define ACP_SCRATCH_REG_14 0x0010038 +#define ACP_SCRATCH_REG_15 0x001003C +#define ACP_SCRATCH_REG_16 0x0010040 +#define ACP_SCRATCH_REG_17 0x0010044 +#define ACP_SCRATCH_REG_18 0x0010048 +#define ACP_SCRATCH_REG_19 0x001004C +#define ACP_SCRATCH_REG_20 0x0010050 +#define ACP_SCRATCH_REG_21 0x0010054 +#define ACP_SCRATCH_REG_22 0x0010058 +#define ACP_SCRATCH_REG_23 0x001005C +#define ACP_SCRATCH_REG_24 0x0010060 +#define ACP_SCRATCH_REG_25 0x0010064 +#define ACP_SCRATCH_REG_26 0x0010068 +#define ACP_SCRATCH_REG_27 0x001006C +#define ACP_SCRATCH_REG_28 0x0010070 +#define ACP_SCRATCH_REG_29 0x0010074 +#define ACP_SCRATCH_REG_30 0x0010078 +#define ACP_SCRATCH_REG_31 0x001007C +#define ACP_SCRATCH_REG_32 0x0010080 +#define ACP_SCRATCH_REG_33 0x0010084 +#define ACP_SCRATCH_REG_34 0x0010088 +#define ACP_SCRATCH_REG_35 0x001008C +#define ACP_SCRATCH_REG_36 0x0010090 +#define ACP_SCRATCH_REG_37 0x0010094 +#define ACP_SCRATCH_REG_38 0x0010098 +#define ACP_SCRATCH_REG_39 0x001009C +#define ACP_SCRATCH_REG_40 0x00100A0 +#define ACP_SCRATCH_REG_41 0x00100A4 +#define ACP_SCRATCH_REG_42 0x00100A8 +#define ACP_SCRATCH_REG_43 0x00100AC +#define ACP_SCRATCH_REG_44 0x00100B0 +#define ACP_SCRATCH_REG_45 0x00100B4 +#define ACP_SCRATCH_REG_46 0x00100B8 +#define ACP_SCRATCH_REG_47 0x00100BC +#define ACP_SCRATCH_REG_48 0x00100C0 +#define ACP_SCRATCH_REG_49 0x00100C4 +#define ACP_SCRATCH_REG_50 0x00100C8 +#define ACP_SCRATCH_REG_51 0x00100CC +#define ACP_SCRATCH_REG_52 0x00100D0 +#define ACP_SCRATCH_REG_53 0x00100D4 +#define ACP_SCRATCH_REG_54 0x00100D8 +#define ACP_SCRATCH_REG_55 0x00100DC +#define ACP_SCRATCH_REG_56 0x00100E0 +#define ACP_SCRATCH_REG_57 0x00100E4 +#define ACP_SCRATCH_REG_58 0x00100E8 +#define ACP_SCRATCH_REG_59 0x00100EC +#define ACP_SCRATCH_REG_60 0x00100F0 +#define ACP_SCRATCH_REG_61 0x00100F4 +#define ACP_SCRATCH_REG_62 0x00100F8 +#define ACP_SCRATCH_REG_63 0x00100FC +#define ACP_SCRATCH_REG_64 0x0010100 +#define ACP_SCRATCH_REG_65 0x0010104 +#define ACP_SCRATCH_REG_66 0x0010108 +#define ACP_SCRATCH_REG_67 0x001010C +#define ACP_SCRATCH_REG_68 0x0010110 +#define ACP_SCRATCH_REG_69 0x0010114 +#define ACP_SCRATCH_REG_70 0x0010118 +#define ACP_SCRATCH_REG_71 0x001011C +#define ACP_SCRATCH_REG_72 0x0010120 +#define ACP_SCRATCH_REG_73 0x0010124 +#define ACP_SCRATCH_REG_74 0x0010128 +#define ACP_SCRATCH_REG_75 0x001012C +#define ACP_SCRATCH_REG_76 0x0010130 +#define ACP_SCRATCH_REG_77 0x0010134 +#define ACP_SCRATCH_REG_78 0x0010138 +#define ACP_SCRATCH_REG_79 0x001013C +#define ACP_SCRATCH_REG_80 0x0010140 +#define ACP_SCRATCH_REG_81 0x0010144 +#define ACP_SCRATCH_REG_82 0x0010148 +#define ACP_SCRATCH_REG_83 0x001014C +#define ACP_SCRATCH_REG_84 0x0010150 +#define ACP_SCRATCH_REG_85 0x0010154 +#define ACP_SCRATCH_REG_86 0x0010158 +#define ACP_SCRATCH_REG_87 0x001015C +#define ACP_SCRATCH_REG_88 0x0010160 +#define ACP_SCRATCH_REG_89 0x0010164 +#define ACP_SCRATCH_REG_90 0x0010168 +#define ACP_SCRATCH_REG_91 0x001016C +#define ACP_SCRATCH_REG_92 0x0010170 +#define ACP_SCRATCH_REG_93 0x0010174 +#define ACP_SCRATCH_REG_94 0x0010178 +#define ACP_SCRATCH_REG_95 0x001017C +#define ACP_SCRATCH_REG_96 0x0010180 +#define ACP_SCRATCH_REG_97 0x0010184 +#define ACP_SCRATCH_REG_98 0x0010188 +#define ACP_SCRATCH_REG_99 0x001018C +#define ACP_SCRATCH_REG_100 0x0010190 +#define ACP_SCRATCH_REG_101 0x0010194 +#define ACP_SCRATCH_REG_102 0x0010198 +#define ACP_SCRATCH_REG_103 0x001019C +#define ACP_SCRATCH_REG_104 0x00101A0 +#define ACP_SCRATCH_REG_105 0x00101A4 +#define ACP_SCRATCH_REG_106 0x00101A8 +#define ACP_SCRATCH_REG_107 0x00101AC +#define ACP_SCRATCH_REG_108 0x00101B0 +#define ACP_SCRATCH_REG_109 0x00101B4 +#define ACP_SCRATCH_REG_110 0x00101B8 +#define ACP_SCRATCH_REG_111 0x00101BC +#define ACP_SCRATCH_REG_112 0x00101C0 +#define ACP_SCRATCH_REG_113 0x00101C4 +#define ACP_SCRATCH_REG_114 0x00101C8 +#define ACP_SCRATCH_REG_115 0x00101CC +#define ACP_SCRATCH_REG_116 0x00101D0 +#define ACP_SCRATCH_REG_117 0x00101D4 +#define ACP_SCRATCH_REG_118 0x00101D8 +#define ACP_SCRATCH_REG_119 0x00101DC +#define ACP_SCRATCH_REG_120 0x00101E0 +#define ACP_SCRATCH_REG_121 0x00101E4 +#define ACP_SCRATCH_REG_122 0x00101E8 +#define ACP_SCRATCH_REG_123 0x00101EC +#define ACP_SCRATCH_REG_124 0x00101F0 +#define ACP_SCRATCH_REG_125 0x00101F4 +#define ACP_SCRATCH_REG_126 0x00101F8 +#define ACP_SCRATCH_REG_127 0x00101FC +#define ACP_SCRATCH_REG_128 0x0010200 +#endif -- cgit v1.2.3 From 95e43a170bb1e91a7972610d33a26ea4841e2cdd Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Sat, 27 Aug 2022 22:26:46 +0530 Subject: ASoC: amd: add Pink Sardine ACP PCI driver ACP is a PCI audio device. This patch adds PCI driver to bind to this device and get PCI resources for Pink Sardine Platform. Signed-off-by: Syed Saba Kareem Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20220827165657.2343818-3-Syed.SabaKareem@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/ps/acp62.h | 20 ++++++++++ sound/soc/amd/ps/pci-ps.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 sound/soc/amd/ps/acp62.h create mode 100644 sound/soc/amd/ps/pci-ps.c diff --git a/sound/soc/amd/ps/acp62.h b/sound/soc/amd/ps/acp62.h new file mode 100644 index 000000000000..5291585f45f9 --- /dev/null +++ b/sound/soc/amd/ps/acp62.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * AMD ALSA SoC PDM Driver + * + * Copyright (C) 2022 Advanced Micro Devices, Inc. All rights reserved. + */ + +#include + +#define ACP_DEVICE_ID 0x15E2 + +static inline u32 acp62_readl(void __iomem *base_addr) +{ + return readl(base_addr); +} + +static inline void acp62_writel(u32 val, void __iomem *base_addr) +{ + writel(val, base_addr); +} diff --git a/sound/soc/amd/ps/pci-ps.c b/sound/soc/amd/ps/pci-ps.c new file mode 100644 index 000000000000..8bb33845622a --- /dev/null +++ b/sound/soc/amd/ps/pci-ps.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * AMD Pink Sardine ACP PCI Driver + * + * Copyright 2022 Advanced Micro Devices, Inc. + */ + +#include +#include +#include + +#include "acp62.h" + +struct acp62_dev_data { + void __iomem *acp62_base; +}; + +static int snd_acp62_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) +{ + struct acp62_dev_data *adata; + u32 addr; + int ret; + + /* Pink Sardine device check */ + switch (pci->revision) { + case 0x63: + break; + default: + dev_dbg(&pci->dev, "acp62 pci device not found\n"); + return -ENODEV; + } + if (pci_enable_device(pci)) { + dev_err(&pci->dev, "pci_enable_device failed\n"); + return -ENODEV; + } + + ret = pci_request_regions(pci, "AMD ACP6.2 audio"); + if (ret < 0) { + dev_err(&pci->dev, "pci_request_regions failed\n"); + goto disable_pci; + } + adata = devm_kzalloc(&pci->dev, sizeof(struct acp62_dev_data), + GFP_KERNEL); + if (!adata) { + ret = -ENOMEM; + goto release_regions; + } + + addr = pci_resource_start(pci, 0); + adata->acp62_base = devm_ioremap(&pci->dev, addr, + pci_resource_len(pci, 0)); + if (!adata->acp62_base) { + ret = -ENOMEM; + goto release_regions; + } + pci_set_master(pci); + pci_set_drvdata(pci, adata); + return 0; +release_regions: + pci_release_regions(pci); +disable_pci: + pci_disable_device(pci); + + return ret; +} + +static void snd_acp62_remove(struct pci_dev *pci) +{ + pci_release_regions(pci); + pci_disable_device(pci); +} + +static const struct pci_device_id snd_acp62_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_DEVICE_ID), + .class = PCI_CLASS_MULTIMEDIA_OTHER << 8, + .class_mask = 0xffffff }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, snd_acp62_ids); + +static struct pci_driver ps_acp62_driver = { + .name = KBUILD_MODNAME, + .id_table = snd_acp62_ids, + .probe = snd_acp62_probe, + .remove = snd_acp62_remove, +}; + +module_pci_driver(ps_acp62_driver); + +MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); +MODULE_AUTHOR("Syed.SabaKareem@amd.com"); +MODULE_DESCRIPTION("AMD ACP Pink Sardine PCI driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 9766bb62cf315ccbfc6203372074dffe69389356 Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Sat, 27 Aug 2022 22:26:47 +0530 Subject: ASoC: amd: add acp6.2 init/de-init functions Add Pink Sardine platform ACP6.2 PCI driver init/deinit functions. Signed-off-by: Syed Saba Kareem Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20220827165657.2343818-4-Syed.SabaKareem@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/ps/acp62.h | 12 ++++++ sound/soc/amd/ps/pci-ps.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) diff --git a/sound/soc/amd/ps/acp62.h b/sound/soc/amd/ps/acp62.h index 5291585f45f9..cb07c0656ff2 100644 --- a/sound/soc/amd/ps/acp62.h +++ b/sound/soc/amd/ps/acp62.h @@ -9,6 +9,18 @@ #define ACP_DEVICE_ID 0x15E2 +#define ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK 0x00010001 +#define ACP_PGFSM_CNTL_POWER_ON_MASK 1 +#define ACP_PGFSM_CNTL_POWER_OFF_MASK 0 +#define ACP_PGFSM_STATUS_MASK 3 +#define ACP_POWERED_ON 0 +#define ACP_POWER_ON_IN_PROGRESS 1 +#define ACP_POWERED_OFF 2 +#define ACP_POWER_OFF_IN_PROGRESS 3 + +#define ACP_ERROR_MASK 0x20000000 +#define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF + static inline u32 acp62_readl(void __iomem *base_addr) { return readl(base_addr); diff --git a/sound/soc/amd/ps/pci-ps.c b/sound/soc/amd/ps/pci-ps.c index 8bb33845622a..a87dbf8847e6 100644 --- a/sound/soc/amd/ps/pci-ps.c +++ b/sound/soc/amd/ps/pci-ps.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "acp62.h" @@ -15,6 +16,100 @@ struct acp62_dev_data { void __iomem *acp62_base; }; +static int acp62_power_on(void __iomem *acp_base) +{ + u32 val; + int timeout; + + val = acp62_readl(acp_base + ACP_PGFSM_STATUS); + + if (!val) + return val; + + if ((val & ACP_PGFSM_STATUS_MASK) != ACP_POWER_ON_IN_PROGRESS) + acp62_writel(ACP_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL); + timeout = 0; + while (++timeout < 500) { + val = acp62_readl(acp_base + ACP_PGFSM_STATUS); + if (!val) + return 0; + udelay(1); + } + return -ETIMEDOUT; +} + +static int acp62_reset(void __iomem *acp_base) +{ + u32 val; + int timeout; + + acp62_writel(1, acp_base + ACP_SOFT_RESET); + timeout = 0; + while (++timeout < 500) { + val = acp62_readl(acp_base + ACP_SOFT_RESET); + if (val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK) + break; + cpu_relax(); + } + acp62_writel(0, acp_base + ACP_SOFT_RESET); + timeout = 0; + while (++timeout < 500) { + val = acp62_readl(acp_base + ACP_SOFT_RESET); + if (!val) + return 0; + cpu_relax(); + } + return -ETIMEDOUT; +} + +static void acp62_enable_interrupts(void __iomem *acp_base) +{ + acp62_writel(1, acp_base + ACP_EXTERNAL_INTR_ENB); +} + +static void acp62_disable_interrupts(void __iomem *acp_base) +{ + acp62_writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp_base + + ACP_EXTERNAL_INTR_STAT); + acp62_writel(0, acp_base + ACP_EXTERNAL_INTR_CNTL); + acp62_writel(0, acp_base + ACP_EXTERNAL_INTR_ENB); +} + +static int acp62_init(void __iomem *acp_base, struct device *dev) +{ + int ret; + + ret = acp62_power_on(acp_base); + if (ret) { + dev_err(dev, "ACP power on failed\n"); + return ret; + } + acp62_writel(0x01, acp_base + ACP_CONTROL); + ret = acp62_reset(acp_base); + if (ret) { + dev_err(dev, "ACP reset failed\n"); + return ret; + } + acp62_writel(0x03, acp_base + ACP_CLKMUX_SEL); + acp62_enable_interrupts(acp_base); + return 0; +} + +static int acp62_deinit(void __iomem *acp_base, struct device *dev) +{ + int ret; + + acp62_disable_interrupts(acp_base); + ret = acp62_reset(acp_base); + if (ret) { + dev_err(dev, "ACP reset failed\n"); + return ret; + } + acp62_writel(0, acp_base + ACP_CLKMUX_SEL); + acp62_writel(0, acp_base + ACP_CONTROL); + return 0; +} + static int snd_acp62_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { @@ -56,6 +151,10 @@ static int snd_acp62_probe(struct pci_dev *pci, } pci_set_master(pci); pci_set_drvdata(pci, adata); + ret = acp62_init(adata->acp62_base, &pci->dev); + if (ret) + goto release_regions; + return 0; release_regions: pci_release_regions(pci); @@ -67,6 +166,13 @@ disable_pci: static void snd_acp62_remove(struct pci_dev *pci) { + struct acp62_dev_data *adata; + int ret; + + adata = pci_get_drvdata(pci); + ret = acp62_deinit(adata->acp62_base, &pci->dev); + if (ret) + dev_err(&pci->dev, "ACP de-init failed\n"); pci_release_regions(pci); pci_disable_device(pci); } -- cgit v1.2.3 From 515ee2574aa4d6bf05dce194e342bd2712ea4bd4 Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Sat, 27 Aug 2022 22:26:48 +0530 Subject: ASoC: amd: add platform devices for acp6.2 pdm driver and dmic driver ACP6.2 IP has PDM decoder block. Create a platform device for it, so that the PDM platform driver can be bound to this device. Pass PCI resources like MMIO to this platform device. Create a platform device for generic dmic codec driver. Signed-off-by: Syed Saba Kareem Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20220827165657.2343818-5-Syed.SabaKareem@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/ps/acp62.h | 23 ++++++++++++++ sound/soc/amd/ps/pci-ps.c | 81 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 102 insertions(+), 2 deletions(-) diff --git a/sound/soc/amd/ps/acp62.h b/sound/soc/amd/ps/acp62.h index cb07c0656ff2..507cdf8f501d 100644 --- a/sound/soc/amd/ps/acp62.h +++ b/sound/soc/amd/ps/acp62.h @@ -8,6 +8,10 @@ #include #define ACP_DEVICE_ID 0x15E2 +#define ACP6x_REG_START 0x1240000 +#define ACP6x_REG_END 0x1250200 +#define ACP6x_DEVS 2 +#define ACP6x_PDM_MODE 1 #define ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK 0x00010001 #define ACP_PGFSM_CNTL_POWER_ON_MASK 1 @@ -21,6 +25,25 @@ #define ACP_ERROR_MASK 0x20000000 #define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF +enum acp_config { + ACP_CONFIG_0 = 0, + ACP_CONFIG_1, + ACP_CONFIG_2, + ACP_CONFIG_3, + ACP_CONFIG_4, + ACP_CONFIG_5, + ACP_CONFIG_6, + ACP_CONFIG_7, + ACP_CONFIG_8, + ACP_CONFIG_9, + ACP_CONFIG_10, + ACP_CONFIG_11, + ACP_CONFIG_12, + ACP_CONFIG_13, + ACP_CONFIG_14, + ACP_CONFIG_15, +}; + static inline u32 acp62_readl(void __iomem *base_addr) { return readl(base_addr); diff --git a/sound/soc/amd/ps/pci-ps.c b/sound/soc/amd/ps/pci-ps.c index a87dbf8847e6..adad29667791 100644 --- a/sound/soc/amd/ps/pci-ps.c +++ b/sound/soc/amd/ps/pci-ps.c @@ -9,11 +9,16 @@ #include #include #include +#include +#include #include "acp62.h" struct acp62_dev_data { void __iomem *acp62_base; + struct resource *res; + bool acp62_audio_mode; + struct platform_device *pdev[ACP6x_DEVS]; }; static int acp62_power_on(void __iomem *acp_base) @@ -114,8 +119,12 @@ static int snd_acp62_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { struct acp62_dev_data *adata; + struct platform_device_info pdevinfo[ACP6x_DEVS]; + int index, ret; + int val = 0x00; + struct acpi_device *adev; + const union acpi_object *obj; u32 addr; - int ret; /* Pink Sardine device check */ switch (pci->revision) { @@ -154,8 +163,72 @@ static int snd_acp62_probe(struct pci_dev *pci, ret = acp62_init(adata->acp62_base, &pci->dev); if (ret) goto release_regions; + val = acp62_readl(adata->acp62_base + ACP_PIN_CONFIG); + switch (val) { + case ACP_CONFIG_0: + case ACP_CONFIG_1: + case ACP_CONFIG_2: + case ACP_CONFIG_3: + case ACP_CONFIG_9: + case ACP_CONFIG_15: + dev_info(&pci->dev, "Audio Mode %d\n", val); + break; + default: + + /* Checking DMIC hardware*/ + adev = acpi_find_child_device(ACPI_COMPANION(&pci->dev), 0x02, 0); + + if (!adev) + break; + + if (!acpi_dev_get_property(adev, "acp-audio-device-type", + ACPI_TYPE_INTEGER, &obj) && + obj->integer.value == 2) { + adata->res = devm_kzalloc(&pci->dev, sizeof(struct resource), GFP_KERNEL); + if (!adata->res) { + ret = -ENOMEM; + goto de_init; + } + + adata->res->name = "acp_iomem"; + adata->res->flags = IORESOURCE_MEM; + adata->res->start = addr; + adata->res->end = addr + (ACP6x_REG_END - ACP6x_REG_START); + adata->acp62_audio_mode = ACP6x_PDM_MODE; + memset(&pdevinfo, 0, sizeof(pdevinfo)); + pdevinfo[0].name = "acp_ps_pdm_dma"; + pdevinfo[0].id = 0; + pdevinfo[0].parent = &pci->dev; + pdevinfo[0].num_res = 1; + pdevinfo[0].res = adata->res; + + pdevinfo[1].name = "dmic-codec"; + pdevinfo[1].id = 0; + pdevinfo[1].parent = &pci->dev; + + for (index = 0; index < ACP6x_DEVS; index++) { + adata->pdev[index] = + platform_device_register_full(&pdevinfo[index]); + + if (IS_ERR(adata->pdev[index])) { + dev_err(&pci->dev, + "cannot register %s device\n", + pdevinfo[index].name); + ret = PTR_ERR(adata->pdev[index]); + goto unregister_devs; + } + } + } + break; + } return 0; +unregister_devs: + for (--index; index >= 0; index--) + platform_device_unregister(adata->pdev[index]); +de_init: + if (acp62_deinit(adata->acp62_base, &pci->dev)) + dev_err(&pci->dev, "ACP de-init failed\n"); release_regions: pci_release_regions(pci); disable_pci: @@ -167,9 +240,13 @@ disable_pci: static void snd_acp62_remove(struct pci_dev *pci) { struct acp62_dev_data *adata; - int ret; + int ret, index; adata = pci_get_drvdata(pci); + if (adata->acp62_audio_mode == ACP6x_PDM_MODE) { + for (index = 0; index < ACP6x_DEVS; index++) + platform_device_unregister(adata->pdev[index]); + } ret = acp62_deinit(adata->acp62_base, &pci->dev); if (ret) dev_err(&pci->dev, "ACP de-init failed\n"); -- cgit v1.2.3 From 33cea6bbe48896bcaa03f030f5b52e05de68bccd Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Sat, 27 Aug 2022 22:26:49 +0530 Subject: ASoC: amd: add acp6.2 pdm platform driver PDM platform driver binds to the platform device created by ACP6.2 PCI device. PDM driver registers ALSA DMA and CPU DAI components with ASoC framework. Signed-off-by: Syed Saba Kareem Reviewed-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20220827165657.2343818-6-Syed.SabaKareem@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/ps/acp62.h | 5 +++ sound/soc/amd/ps/ps-pdm-dma.c | 82 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 sound/soc/amd/ps/ps-pdm-dma.c diff --git a/sound/soc/amd/ps/acp62.h b/sound/soc/amd/ps/acp62.h index 507cdf8f501d..1f117f62465a 100644 --- a/sound/soc/amd/ps/acp62.h +++ b/sound/soc/amd/ps/acp62.h @@ -44,6 +44,11 @@ enum acp_config { ACP_CONFIG_15, }; +struct pdm_dev_data { + void __iomem *acp62_base; + struct snd_pcm_substream *capture_stream; +}; + static inline u32 acp62_readl(void __iomem *base_addr) { return readl(base_addr); diff --git a/sound/soc/amd/ps/ps-pdm-dma.c b/sound/soc/amd/ps/ps-pdm-dma.c new file mode 100644 index 000000000000..964686b46097 --- /dev/null +++ b/sound/soc/amd/ps/ps-pdm-dma.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * AMD ALSA SoC Pink Sardine PDM Driver + * + * Copyright 2022 Advanced Micro Devices, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "acp62.h" + +#define DRV_NAME "acp_ps_pdm_dma" + +static struct snd_soc_dai_driver acp62_pdm_dai_driver = { + .name = "acp_ps_pdm_dma.0", + .capture = { + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 2, + .rate_min = 48000, + .rate_max = 48000, + }, +}; + +static const struct snd_soc_component_driver acp62_pdm_component = { + .name = DRV_NAME, +}; + +static int acp62_pdm_audio_probe(struct platform_device *pdev) +{ + struct resource *res; + struct pdm_dev_data *adata; + int status; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n"); + return -ENODEV; + } + + adata = devm_kzalloc(&pdev->dev, sizeof(*adata), GFP_KERNEL); + if (!adata) + return -ENOMEM; + + adata->acp62_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!adata->acp62_base) + return -ENOMEM; + + adata->capture_stream = NULL; + + dev_set_drvdata(&pdev->dev, adata); + status = devm_snd_soc_register_component(&pdev->dev, + &acp62_pdm_component, + &acp62_pdm_dai_driver, 1); + if (status) { + dev_err(&pdev->dev, "Fail to register acp pdm dai\n"); + + return -ENODEV; + } + return 0; +} + +static struct platform_driver acp62_pdm_dma_driver = { + .probe = acp62_pdm_audio_probe, + .driver = { + .name = "acp_ps_pdm_dma", + }, +}; + +module_platform_driver(acp62_pdm_dma_driver); + +MODULE_AUTHOR("Syed.SabaKareem@amd.com"); +MODULE_DESCRIPTION("AMD PINK SARDINE PDM Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); -- cgit v1.2.3 From 5bbeca60a57bb9a35cc98c064bbb575738d5be0d Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Sat, 27 Aug 2022 22:26:50 +0530 Subject: ASoC: amd: add acp6.2 irq handler Add ACP6.2 irq handler for handling irq events for ACP IP. Add pdm irq events handling. Whenever audio data equal to the PDM watermark level are consumed, interrupt is generated. Acknowledge the interrupt. Signed-off-by: Syed Saba Kareem Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20220827165657.2343818-7-Syed.SabaKareem@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/ps/acp62.h | 2 ++ sound/soc/amd/ps/pci-ps.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/sound/soc/amd/ps/acp62.h b/sound/soc/amd/ps/acp62.h index 1f117f62465a..eed7a05ba112 100644 --- a/sound/soc/amd/ps/acp62.h +++ b/sound/soc/amd/ps/acp62.h @@ -24,6 +24,7 @@ #define ACP_ERROR_MASK 0x20000000 #define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF +#define PDM_DMA_STAT 0x10 enum acp_config { ACP_CONFIG_0 = 0, @@ -45,6 +46,7 @@ enum acp_config { }; struct pdm_dev_data { + u32 pdm_irq; void __iomem *acp62_base; struct snd_pcm_substream *capture_stream; }; diff --git a/sound/soc/amd/ps/pci-ps.c b/sound/soc/amd/ps/pci-ps.c index adad29667791..e4ddd80d0dd4 100644 --- a/sound/soc/amd/ps/pci-ps.c +++ b/sound/soc/amd/ps/pci-ps.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include "acp62.h" @@ -115,6 +117,27 @@ static int acp62_deinit(void __iomem *acp_base, struct device *dev) return 0; } +static irqreturn_t acp62_irq_handler(int irq, void *dev_id) +{ + struct acp62_dev_data *adata; + struct pdm_dev_data *ps_pdm_data; + u32 val; + + adata = dev_id; + if (!adata) + return IRQ_NONE; + + val = acp62_readl(adata->acp62_base + ACP_EXTERNAL_INTR_STAT); + if (val & BIT(PDM_DMA_STAT)) { + ps_pdm_data = dev_get_drvdata(&adata->pdev[0]->dev); + acp62_writel(BIT(PDM_DMA_STAT), adata->acp62_base + ACP_EXTERNAL_INTR_STAT); + if (ps_pdm_data->capture_stream) + snd_pcm_period_elapsed(ps_pdm_data->capture_stream); + return IRQ_HANDLED; + } + return IRQ_NONE; +} + static int snd_acp62_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { @@ -125,7 +148,9 @@ static int snd_acp62_probe(struct pci_dev *pci, struct acpi_device *adev; const union acpi_object *obj; u32 addr; + unsigned int irqflags; + irqflags = IRQF_SHARED; /* Pink Sardine device check */ switch (pci->revision) { case 0x63: @@ -218,6 +243,12 @@ static int snd_acp62_probe(struct pci_dev *pci, ret = PTR_ERR(adata->pdev[index]); goto unregister_devs; } + ret = devm_request_irq(&pci->dev, pci->irq, acp62_irq_handler, + irqflags, "ACP_PCI_IRQ", adata); + if (ret) { + dev_err(&pci->dev, "ACP PCI IRQ request failed\n"); + goto unregister_devs; + } } } break; -- cgit v1.2.3 From 5137305662ef5cad12ff472ca4c8c3b266fd46c5 Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Sat, 27 Aug 2022 22:26:51 +0530 Subject: ASoC: amd: add acp6.2 pdm driver dma ops This patch adds PDM driver DMA operations for Pink Sardine Platform. Signed-off-by: Syed Saba Kareem Reviewed-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20220827165657.2343818-8-Syed.SabaKareem@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/ps/acp62.h | 33 +++++ sound/soc/amd/ps/ps-pdm-dma.c | 313 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 346 insertions(+) diff --git a/sound/soc/amd/ps/acp62.h b/sound/soc/amd/ps/acp62.h index eed7a05ba112..a3b349104cf2 100644 --- a/sound/soc/amd/ps/acp62.h +++ b/sound/soc/amd/ps/acp62.h @@ -26,6 +26,31 @@ #define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF #define PDM_DMA_STAT 0x10 +#define PDM_DMA_INTR_MASK 0x10000 +#define ACP_ERROR_STAT 29 +#define PDM_DECIMATION_FACTOR 2 +#define ACP_PDM_CLK_FREQ_MASK 7 +#define ACP_WOV_MISC_CTRL_MASK 0x10 +#define ACP_PDM_ENABLE 1 +#define ACP_PDM_DISABLE 0 +#define ACP_PDM_DMA_EN_STATUS 2 +#define TWO_CH 2 +#define DELAY_US 5 +#define ACP_COUNTER 20000 + +#define ACP_SRAM_PTE_OFFSET 0x03800000 +#define PAGE_SIZE_4K_ENABLE 2 +#define PDM_PTE_OFFSET 0 +#define PDM_MEM_WINDOW_START 0x4000000 + +#define CAPTURE_MIN_NUM_PERIODS 4 +#define CAPTURE_MAX_NUM_PERIODS 4 +#define CAPTURE_MAX_PERIOD_SIZE 8192 +#define CAPTURE_MIN_PERIOD_SIZE 4096 + +#define MAX_BUFFER (CAPTURE_MAX_PERIOD_SIZE * CAPTURE_MAX_NUM_PERIODS) +#define MIN_BUFFER MAX_BUFFER + enum acp_config { ACP_CONFIG_0 = 0, ACP_CONFIG_1, @@ -45,6 +70,14 @@ enum acp_config { ACP_CONFIG_15, }; +struct pdm_stream_instance { + u16 num_pages; + u16 channels; + dma_addr_t dma_addr; + u64 bytescount; + void __iomem *acp62_base; +}; + struct pdm_dev_data { u32 pdm_irq; void __iomem *acp62_base; diff --git a/sound/soc/amd/ps/ps-pdm-dma.c b/sound/soc/amd/ps/ps-pdm-dma.c index 964686b46097..f0ec1a4f3b9d 100644 --- a/sound/soc/amd/ps/ps-pdm-dma.c +++ b/sound/soc/amd/ps/ps-pdm-dma.c @@ -17,6 +17,313 @@ #define DRV_NAME "acp_ps_pdm_dma" +static const struct snd_pcm_hardware acp62_pdm_hardware_capture = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE, + .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE, + .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE, + .periods_min = CAPTURE_MIN_NUM_PERIODS, + .periods_max = CAPTURE_MAX_NUM_PERIODS, +}; + +static void acp62_init_pdm_ring_buffer(u32 physical_addr, u32 buffer_size, + u32 watermark_size, void __iomem *acp_base) +{ + acp62_writel(physical_addr, acp_base + ACP_WOV_RX_RINGBUFADDR); + acp62_writel(buffer_size, acp_base + ACP_WOV_RX_RINGBUFSIZE); + acp62_writel(watermark_size, acp_base + ACP_WOV_RX_INTR_WATERMARK_SIZE); + acp62_writel(0x01, acp_base + ACPAXI2AXI_ATU_CTRL); +} + +static void acp62_enable_pdm_clock(void __iomem *acp_base) +{ + u32 pdm_clk_enable, pdm_ctrl; + + pdm_clk_enable = ACP_PDM_CLK_FREQ_MASK; + pdm_ctrl = 0x00; + + acp62_writel(pdm_clk_enable, acp_base + ACP_WOV_CLK_CTRL); + pdm_ctrl = acp62_readl(acp_base + ACP_WOV_MISC_CTRL); + pdm_ctrl |= ACP_WOV_MISC_CTRL_MASK; + acp62_writel(pdm_ctrl, acp_base + ACP_WOV_MISC_CTRL); +} + +static void acp62_enable_pdm_interrupts(void __iomem *acp_base) +{ + u32 ext_int_ctrl; + + ext_int_ctrl = acp62_readl(acp_base + ACP_EXTERNAL_INTR_CNTL); + ext_int_ctrl |= PDM_DMA_INTR_MASK; + acp62_writel(ext_int_ctrl, acp_base + ACP_EXTERNAL_INTR_CNTL); +} + +static void acp62_disable_pdm_interrupts(void __iomem *acp_base) +{ + u32 ext_int_ctrl; + + ext_int_ctrl = acp62_readl(acp_base + ACP_EXTERNAL_INTR_CNTL); + ext_int_ctrl &= ~PDM_DMA_INTR_MASK; + acp62_writel(ext_int_ctrl, acp_base + ACP_EXTERNAL_INTR_CNTL); +} + +static bool acp62_check_pdm_dma_status(void __iomem *acp_base) +{ + bool pdm_dma_status; + u32 pdm_enable, pdm_dma_enable; + + pdm_dma_status = false; + pdm_enable = acp62_readl(acp_base + ACP_WOV_PDM_ENABLE); + pdm_dma_enable = acp62_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE); + if ((pdm_enable & ACP_PDM_ENABLE) && (pdm_dma_enable & ACP_PDM_DMA_EN_STATUS)) + pdm_dma_status = true; + + return pdm_dma_status; +} + +static int acp62_start_pdm_dma(void __iomem *acp_base) +{ + u32 pdm_enable; + u32 pdm_dma_enable; + int timeout; + + pdm_enable = 0x01; + pdm_dma_enable = 0x01; + + acp62_enable_pdm_clock(acp_base); + acp62_writel(pdm_enable, acp_base + ACP_WOV_PDM_ENABLE); + acp62_writel(pdm_dma_enable, acp_base + ACP_WOV_PDM_DMA_ENABLE); + timeout = 0; + while (++timeout < ACP_COUNTER) { + pdm_dma_enable = acp62_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE); + if ((pdm_dma_enable & 0x02) == ACP_PDM_DMA_EN_STATUS) + return 0; + udelay(DELAY_US); + } + return -ETIMEDOUT; +} + +static int acp62_stop_pdm_dma(void __iomem *acp_base) +{ + u32 pdm_enable, pdm_dma_enable; + int timeout; + + pdm_enable = 0x00; + pdm_dma_enable = 0x00; + + pdm_enable = acp62_readl(acp_base + ACP_WOV_PDM_ENABLE); + pdm_dma_enable = acp62_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE); + if (pdm_dma_enable & 0x01) { + pdm_dma_enable = 0x02; + acp62_writel(pdm_dma_enable, acp_base + ACP_WOV_PDM_DMA_ENABLE); + timeout = 0; + while (++timeout < ACP_COUNTER) { + pdm_dma_enable = acp62_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE); + if ((pdm_dma_enable & 0x02) == 0x00) + break; + udelay(DELAY_US); + } + if (timeout == ACP_COUNTER) + return -ETIMEDOUT; + } + if (pdm_enable == ACP_PDM_ENABLE) { + pdm_enable = ACP_PDM_DISABLE; + acp62_writel(pdm_enable, acp_base + ACP_WOV_PDM_ENABLE); + } + acp62_writel(0x01, acp_base + ACP_WOV_PDM_FIFO_FLUSH); + return 0; +} + +static void acp62_config_dma(struct pdm_stream_instance *rtd, int direction) +{ + u16 page_idx; + u32 low, high, val; + dma_addr_t addr; + + addr = rtd->dma_addr; + val = PDM_PTE_OFFSET; + + /* Group Enable */ + acp62_writel(ACP_SRAM_PTE_OFFSET | BIT(31), rtd->acp62_base + + ACPAXI2AXI_ATU_BASE_ADDR_GRP_1); + acp62_writel(PAGE_SIZE_4K_ENABLE, rtd->acp62_base + + ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1); + for (page_idx = 0; page_idx < rtd->num_pages; page_idx++) { + /* Load the low address of page int ACP SRAM through SRBM */ + low = lower_32_bits(addr); + high = upper_32_bits(addr); + + acp62_writel(low, rtd->acp62_base + ACP_SCRATCH_REG_0 + val); + high |= BIT(31); + acp62_writel(high, rtd->acp62_base + ACP_SCRATCH_REG_0 + val + 4); + val += 8; + addr += PAGE_SIZE; + } +} + +static int acp62_pdm_dma_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime; + struct pdm_dev_data *adata; + struct pdm_stream_instance *pdm_data; + int ret; + + runtime = substream->runtime; + adata = dev_get_drvdata(component->dev); + pdm_data = kzalloc(sizeof(*pdm_data), GFP_KERNEL); + if (!pdm_data) + return -EINVAL; + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + runtime->hw = acp62_pdm_hardware_capture; + + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) { + dev_err(component->dev, "set integer constraint failed\n"); + kfree(pdm_data); + return ret; + } + + acp62_enable_pdm_interrupts(adata->acp62_base); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + adata->capture_stream = substream; + + pdm_data->acp62_base = adata->acp62_base; + runtime->private_data = pdm_data; + return ret; +} + +static int acp62_pdm_dma_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct pdm_stream_instance *rtd; + size_t size, period_bytes; + + rtd = substream->runtime->private_data; + if (!rtd) + return -EINVAL; + size = params_buffer_bytes(params); + period_bytes = params_period_bytes(params); + rtd->dma_addr = substream->runtime->dma_addr; + rtd->num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT); + acp62_config_dma(rtd, substream->stream); + acp62_init_pdm_ring_buffer(PDM_MEM_WINDOW_START, size, + period_bytes, rtd->acp62_base); + return 0; +} + +static u64 acp62_pdm_get_byte_count(struct pdm_stream_instance *rtd, + int direction) +{ + u32 high, low; + u64 byte_count; + + high = acp62_readl(rtd->acp62_base + ACP_WOV_RX_LINEARPOSITIONCNTR_HIGH); + byte_count = high; + low = acp62_readl(rtd->acp62_base + ACP_WOV_RX_LINEARPOSITIONCNTR_LOW); + byte_count = (byte_count << 32) | low; + return byte_count; +} + +static snd_pcm_uframes_t acp62_pdm_dma_pointer(struct snd_soc_component *comp, + struct snd_pcm_substream *stream) +{ + struct pdm_stream_instance *rtd; + u32 pos, buffersize; + u64 bytescount; + + rtd = stream->runtime->private_data; + buffersize = frames_to_bytes(stream->runtime, + stream->runtime->buffer_size); + bytescount = acp62_pdm_get_byte_count(rtd, stream->stream); + if (bytescount > rtd->bytescount) + bytescount -= rtd->bytescount; + pos = do_div(bytescount, buffersize); + return bytes_to_frames(stream->runtime, pos); +} + +static int acp62_pdm_dma_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) +{ + struct device *parent = component->dev->parent; + + snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, + parent, MIN_BUFFER, MAX_BUFFER); + return 0; +} + +static int acp62_pdm_dma_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct pdm_dev_data *adata = dev_get_drvdata(component->dev); + struct snd_pcm_runtime *runtime = substream->runtime; + + acp62_disable_pdm_interrupts(adata->acp62_base); + adata->capture_stream = NULL; + kfree(runtime->private_data); + return 0; +} + +static int acp62_pdm_dai_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct pdm_stream_instance *rtd; + int ret; + bool pdm_status; + unsigned int ch_mask; + + rtd = substream->runtime->private_data; + ret = 0; + switch (substream->runtime->channels) { + case TWO_CH: + ch_mask = 0x00; + break; + default: + return -EINVAL; + } + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + acp62_writel(ch_mask, rtd->acp62_base + ACP_WOV_PDM_NO_OF_CHANNELS); + acp62_writel(PDM_DECIMATION_FACTOR, rtd->acp62_base + + ACP_WOV_PDM_DECIMATION_FACTOR); + rtd->bytescount = acp62_pdm_get_byte_count(rtd, substream->stream); + pdm_status = acp62_check_pdm_dma_status(rtd->acp62_base); + if (!pdm_status) + ret = acp62_start_pdm_dma(rtd->acp62_base); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + pdm_status = acp62_check_pdm_dma_status(rtd->acp62_base); + if (pdm_status) + ret = acp62_stop_pdm_dma(rtd->acp62_base); + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static const struct snd_soc_dai_ops acp62_pdm_dai_ops = { + .trigger = acp62_pdm_dai_trigger, +}; + static struct snd_soc_dai_driver acp62_pdm_dai_driver = { .name = "acp_ps_pdm_dma.0", .capture = { @@ -27,10 +334,16 @@ static struct snd_soc_dai_driver acp62_pdm_dai_driver = { .rate_min = 48000, .rate_max = 48000, }, + .ops = &acp62_pdm_dai_ops, }; static const struct snd_soc_component_driver acp62_pdm_component = { .name = DRV_NAME, + .open = acp62_pdm_dma_open, + .close = acp62_pdm_dma_close, + .hw_params = acp62_pdm_dma_hw_params, + .pointer = acp62_pdm_dma_pointer, + .pcm_construct = acp62_pdm_dma_new, }; static int acp62_pdm_audio_probe(struct platform_device *pdev) -- cgit v1.2.3 From 3a543d56e3d3c9bb67ffe3ff9ad7ddf77e448019 Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Sat, 27 Aug 2022 22:26:52 +0530 Subject: ASoC: amd: add acp6.2 pci driver pm ops Add acp6.2 pci driver pm ops. Signed-off-by: Syed Saba Kareem Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20220827165657.2343818-9-Syed.SabaKareem@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/ps/acp62.h | 3 +++ sound/soc/amd/ps/pci-ps.c | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/sound/soc/amd/ps/acp62.h b/sound/soc/amd/ps/acp62.h index a3b349104cf2..2ee53fcd33e9 100644 --- a/sound/soc/amd/ps/acp62.h +++ b/sound/soc/amd/ps/acp62.h @@ -51,6 +51,9 @@ #define MAX_BUFFER (CAPTURE_MAX_PERIOD_SIZE * CAPTURE_MAX_NUM_PERIODS) #define MIN_BUFFER MAX_BUFFER +/* time in ms for runtime suspend delay */ +#define ACP_SUSPEND_DELAY_MS 2000 + enum acp_config { ACP_CONFIG_0 = 0, ACP_CONFIG_1, diff --git a/sound/soc/amd/ps/pci-ps.c b/sound/soc/amd/ps/pci-ps.c index e4ddd80d0dd4..075d9a23205d 100644 --- a/sound/soc/amd/ps/pci-ps.c +++ b/sound/soc/amd/ps/pci-ps.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "acp62.h" @@ -253,6 +254,10 @@ static int snd_acp62_probe(struct pci_dev *pci, } break; } + pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(&pci->dev); + pm_runtime_put_noidle(&pci->dev); + pm_runtime_allow(&pci->dev); return 0; unregister_devs: for (--index; index >= 0; index--) @@ -268,6 +273,35 @@ disable_pci: return ret; } +static int __maybe_unused snd_acp62_suspend(struct device *dev) +{ + struct acp62_dev_data *adata; + int ret; + + adata = dev_get_drvdata(dev); + ret = acp62_deinit(adata->acp62_base, dev); + if (ret) + dev_err(dev, "ACP de-init failed\n"); + return ret; +} + +static int __maybe_unused snd_acp62_resume(struct device *dev) +{ + struct acp62_dev_data *adata; + int ret; + + adata = dev_get_drvdata(dev); + ret = acp62_init(adata->acp62_base, dev); + if (ret) + dev_err(dev, "ACP init failed\n"); + return ret; +} + +static const struct dev_pm_ops acp62_pm_ops = { + SET_RUNTIME_PM_OPS(snd_acp62_suspend, snd_acp62_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(snd_acp62_suspend, snd_acp62_resume) +}; + static void snd_acp62_remove(struct pci_dev *pci) { struct acp62_dev_data *adata; @@ -281,6 +315,8 @@ static void snd_acp62_remove(struct pci_dev *pci) ret = acp62_deinit(adata->acp62_base, &pci->dev); if (ret) dev_err(&pci->dev, "ACP de-init failed\n"); + pm_runtime_forbid(&pci->dev); + pm_runtime_get_noresume(&pci->dev); pci_release_regions(pci); pci_disable_device(pci); } @@ -298,6 +334,9 @@ static struct pci_driver ps_acp62_driver = { .id_table = snd_acp62_ids, .probe = snd_acp62_probe, .remove = snd_acp62_remove, + .driver = { + .pm = &acp62_pm_ops, + } }; module_pci_driver(ps_acp62_driver); -- cgit v1.2.3 From 28023a78790c33f5df0147fd00ab3cf333edd24f Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Sat, 27 Aug 2022 22:26:53 +0530 Subject: ASoC: amd: add acp6.2 pdm driver pm ops Add acp6.2 pdm driver pm ops. Signed-off-by: Syed Saba Kareem Reviewed-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20220827165657.2343818-10-Syed.SabaKareem@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/ps/ps-pdm-dma.c | 57 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/sound/soc/amd/ps/ps-pdm-dma.c b/sound/soc/amd/ps/ps-pdm-dma.c index f0ec1a4f3b9d..b207b726cd82 100644 --- a/sound/soc/amd/ps/ps-pdm-dma.c +++ b/sound/soc/amd/ps/ps-pdm-dma.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "acp62.h" @@ -377,13 +378,69 @@ static int acp62_pdm_audio_probe(struct platform_device *pdev) return -ENODEV; } + pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_allow(&pdev->dev); return 0; } +static int acp62_pdm_audio_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + return 0; +} + +static int __maybe_unused acp62_pdm_resume(struct device *dev) +{ + struct pdm_dev_data *adata; + struct snd_pcm_runtime *runtime; + struct pdm_stream_instance *rtd; + u32 period_bytes, buffer_len; + + adata = dev_get_drvdata(dev); + if (adata->capture_stream && adata->capture_stream->runtime) { + runtime = adata->capture_stream->runtime; + rtd = runtime->private_data; + period_bytes = frames_to_bytes(runtime, runtime->period_size); + buffer_len = frames_to_bytes(runtime, runtime->buffer_size); + acp62_config_dma(rtd, SNDRV_PCM_STREAM_CAPTURE); + acp62_init_pdm_ring_buffer(PDM_MEM_WINDOW_START, buffer_len, + period_bytes, adata->acp62_base); + } + acp62_enable_pdm_interrupts(adata->acp62_base); + return 0; +} + +static int __maybe_unused acp62_pdm_suspend(struct device *dev) +{ + struct pdm_dev_data *adata; + + adata = dev_get_drvdata(dev); + acp62_disable_pdm_interrupts(adata->acp62_base); + return 0; +} + +static int __maybe_unused acp62_pdm_runtime_resume(struct device *dev) +{ + struct pdm_dev_data *adata; + + adata = dev_get_drvdata(dev); + acp62_enable_pdm_interrupts(adata->acp62_base); + return 0; +} + +static const struct dev_pm_ops acp62_pdm_pm_ops = { + SET_RUNTIME_PM_OPS(acp62_pdm_suspend, acp62_pdm_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(acp62_pdm_suspend, acp62_pdm_resume) +}; + static struct platform_driver acp62_pdm_dma_driver = { .probe = acp62_pdm_audio_probe, + .remove = acp62_pdm_audio_remove, .driver = { .name = "acp_ps_pdm_dma", + .pm = &acp62_pdm_pm_ops, }, }; -- cgit v1.2.3 From 1e4366489e2c059cb00e453737e802d74fd9b1d1 Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Sat, 27 Aug 2022 22:26:54 +0530 Subject: ASoC: amd: enable Pink Sardine acp6.2 drivers build Pink Sardine ACP6.2 drivers can be built by selecting necessary kernel config option. The patch enables build support of the same. Signed-off-by: Syed Saba Kareem Reviewed-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20220827165657.2343818-11-Syed.SabaKareem@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/Kconfig | 10 ++++++++++ sound/soc/amd/Makefile | 1 + sound/soc/amd/ps/Makefile | 7 +++++++ 3 files changed, 18 insertions(+) create mode 100644 sound/soc/amd/ps/Makefile diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig index 08f5289dac54..bd785a0efb67 100644 --- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -127,3 +127,13 @@ config SND_SOC_AMD_RPL_ACP6x triggered for ACP PCI driver. Say m if you have such a device. If unsure select "N". + +config SND_SOC_AMD_PS + tristate "AMD Audio Coprocessor-v6.2 Pink Sardine support" + depends on X86 && PCI && ACPI + help + This option enables Audio Coprocessor i.e ACP v6.2 support on + AMD Pink sardine platform. By enabling this flag build will be + triggered for ACP PCI driver, ACP PDM DMA driver. + Say m if you have such a device. + If unsure select "N". diff --git a/sound/soc/amd/Makefile b/sound/soc/amd/Makefile index 0592e7c5c407..82e1cf864a40 100644 --- a/sound/soc/amd/Makefile +++ b/sound/soc/amd/Makefile @@ -18,3 +18,4 @@ 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 obj-$(CONFIG_SND_SOC_AMD_RPL_ACP6x) += rpl/ +obj-$(CONFIG_SND_SOC_AMD_PS) += ps/ diff --git a/sound/soc/amd/ps/Makefile b/sound/soc/amd/ps/Makefile new file mode 100644 index 000000000000..23afa5e32ffa --- /dev/null +++ b/sound/soc/amd/ps/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Pink Sardine platform Support +snd-pci-ps-objs := pci-ps.o +snd-ps-pdm-dma-objs := ps-pdm-dma.o + +obj-$(CONFIG_SND_SOC_AMD_PS) += snd-pci-ps.o +obj-$(CONFIG_SND_SOC_AMD_PS) += snd-ps-pdm-dma.o -- cgit v1.2.3 From 76dd567591c89f92dea97b581988538312ae584f Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Sat, 27 Aug 2022 22:26:55 +0530 Subject: ASoC: amd: create platform device for acp6.2 machine driver Create platform device for acp6.2 machine driver. Signed-off-by: Syed Saba Kareem Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20220827165657.2343818-12-Syed.SabaKareem@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/ps/acp62.h | 2 +- sound/soc/amd/ps/pci-ps.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/amd/ps/acp62.h b/sound/soc/amd/ps/acp62.h index 2ee53fcd33e9..8b30aefa4cd0 100644 --- a/sound/soc/amd/ps/acp62.h +++ b/sound/soc/amd/ps/acp62.h @@ -10,7 +10,7 @@ #define ACP_DEVICE_ID 0x15E2 #define ACP6x_REG_START 0x1240000 #define ACP6x_REG_END 0x1250200 -#define ACP6x_DEVS 2 +#define ACP6x_DEVS 3 #define ACP6x_PDM_MODE 1 #define ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK 0x00010001 diff --git a/sound/soc/amd/ps/pci-ps.c b/sound/soc/amd/ps/pci-ps.c index 075d9a23205d..dff2e2376bbf 100644 --- a/sound/soc/amd/ps/pci-ps.c +++ b/sound/soc/amd/ps/pci-ps.c @@ -233,6 +233,10 @@ static int snd_acp62_probe(struct pci_dev *pci, pdevinfo[1].id = 0; pdevinfo[1].parent = &pci->dev; + pdevinfo[2].name = "acp_ps_mach"; + pdevinfo[2].id = 0; + pdevinfo[2].parent = &pci->dev; + for (index = 0; index < ACP6x_DEVS; index++) { adata->pdev[index] = platform_device_register_full(&pdevinfo[index]); -- cgit v1.2.3 From 0c8327c07b2ecc4a4443b1dae407f0d4854b5ae1 Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Sat, 27 Aug 2022 22:26:56 +0530 Subject: ASoC: amd: add Pink Sardine machine driver using dmic Add Pink Sardine platform machine driver using dmic. Signed-off-by: Syed Saba Kareem Reviewed-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20220827165657.2343818-13-Syed.SabaKareem@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/ps/ps-mach.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 sound/soc/amd/ps/ps-mach.c diff --git a/sound/soc/amd/ps/ps-mach.c b/sound/soc/amd/ps/ps-mach.c new file mode 100644 index 000000000000..b3e97093481d --- /dev/null +++ b/sound/soc/amd/ps/ps-mach.c @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Machine driver for AMD Pink Sardine platform using DMIC + * + * Copyright 2022 Advanced Micro Devices, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "acp62.h" + +#define DRV_NAME "acp_ps_mach" + +SND_SOC_DAILINK_DEF(acp62_pdm, + DAILINK_COMP_ARRAY(COMP_CPU("acp_ps_pdm_dma.0"))); + +SND_SOC_DAILINK_DEF(dmic_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec.0", + "dmic-hifi"))); + +SND_SOC_DAILINK_DEF(pdm_platform, + DAILINK_COMP_ARRAY(COMP_PLATFORM("acp_ps_pdm_dma.0"))); + +static struct snd_soc_dai_link acp62_dai_pdm[] = { + { + .name = "acp62-dmic-capture", + .stream_name = "DMIC capture", + .capture_only = 1, + SND_SOC_DAILINK_REG(acp62_pdm, dmic_codec, pdm_platform), + }, +}; + +static struct snd_soc_card acp62_card = { + .name = "acp62", + .owner = THIS_MODULE, + .dai_link = acp62_dai_pdm, + .num_links = 1, +}; + +static int acp62_probe(struct platform_device *pdev) +{ + struct acp62_pdm *machine = NULL; + struct snd_soc_card *card; + int ret; + + platform_set_drvdata(pdev, &acp62_card); + card = platform_get_drvdata(pdev); + acp62_card.dev = &pdev->dev; + + snd_soc_card_set_drvdata(card, machine); + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) { + return dev_err_probe(&pdev->dev, ret, + "snd_soc_register_card(%s) failed\n", + card->name); + } + + return 0; +} + +static struct platform_driver acp62_mach_driver = { + .driver = { + .name = "acp_ps_mach", + .pm = &snd_soc_pm_ops, + }, + .probe = acp62_probe, +}; + +module_platform_driver(acp62_mach_driver); + +MODULE_AUTHOR("Syed.SabaKareem@amd.com"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); -- cgit v1.2.3 From 2a09cef652d9c1e76229a4381e928560bec3d878 Mon Sep 17 00:00:00 2001 From: Syed Saba Kareem Date: Sat, 27 Aug 2022 22:26:57 +0530 Subject: ASoC: amd: enable Pink sardine platform machine driver build. This patch enables Pink Sardine platform machine driver build. Signed-off-by: Syed Saba Kareem Reviewed-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20220827165657.2343818-14-Syed.SabaKareem@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/Kconfig | 11 +++++++++++ sound/soc/amd/ps/Makefile | 2 ++ 2 files changed, 13 insertions(+) diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig index bd785a0efb67..68837d42736d 100644 --- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -137,3 +137,14 @@ config SND_SOC_AMD_PS triggered for ACP PCI driver, ACP PDM DMA driver. Say m if you have such a device. If unsure select "N". + +config SND_SOC_AMD_PS_MACH + tristate "AMD PINK SARDINE support for DMIC" + select SND_SOC_DMIC + depends on SND_SOC_AMD_PS + help + This option enables machine driver for Pink Sardine platform + using dmic. ACP IP has PDM Decoder block with DMA controller. + DMIC can be connected directly to ACP IP. + Say m if you have such a device. + If unsure select "N". diff --git a/sound/soc/amd/ps/Makefile b/sound/soc/amd/ps/Makefile index 23afa5e32ffa..383973a12f6a 100644 --- a/sound/soc/amd/ps/Makefile +++ b/sound/soc/amd/ps/Makefile @@ -2,6 +2,8 @@ # Pink Sardine platform Support snd-pci-ps-objs := pci-ps.o snd-ps-pdm-dma-objs := ps-pdm-dma.o +snd-soc-ps-mach-objs := ps-mach.o obj-$(CONFIG_SND_SOC_AMD_PS) += snd-pci-ps.o obj-$(CONFIG_SND_SOC_AMD_PS) += snd-ps-pdm-dma.o +obj-$(CONFIG_SND_SOC_AMD_PS_MACH) += snd-soc-ps-mach.o -- cgit v1.2.3 From 999b95a72d90ed7a7073eae594fa35462d71854f Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 29 Aug 2022 16:52:03 -0500 Subject: ALSA: hda/hdmi: Replace zero-length array with DECLARE_FLEX_ARRAY() helper Zero-length arrays are deprecated and we are moving towards adopting C99 flexible-array members, instead. So, replace zero-length array declaration in union audio_infoframe with the new DECLARE_FLEX_ARRAY() helper macro. This helper allows for a flexible-array member in a union. Link: https://github.com/KSPP/linux/issues/193 Link: https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html Signed-off-by: Gustavo A. R. Silva Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/Yw01A+TvF1FWQ588@work Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 6c209cd26c0c..2191d445d74e 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -229,7 +229,7 @@ struct dp_audio_infoframe { union audio_infoframe { struct hdmi_audio_infoframe hdmi; struct dp_audio_infoframe dp; - u8 bytes[0]; + DECLARE_FLEX_ARRAY(u8, bytes); }; /* -- cgit v1.2.3 From 5204e836544763cb085e653c82d4da77a427591a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 30 Aug 2022 10:58:55 +0300 Subject: ASoC: codecs: rk817: fix missing I2C dependency in compile test SND_SOC_RK817 uses I2C regmap so compile testing without parent MFD_RK808, requires I2C: WARNING: unmet direct dependencies detected for REGMAP_I2C Depends on [n]: I2C [=n] Selected by [y]: - SND_SOC_RK817 [=y] && SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && (MFD_RK808 [=n] || COMPILE_TEST [=y]) Reported-by: kernel test robot Fixes: 5b7f4e5de61b ("ASoC: codecs: allow compile testing without MFD drivers") Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220830075855.278046-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 94b7bb85d236..968d0701f2e8 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1197,7 +1197,7 @@ config SND_SOC_RK3328 config SND_SOC_RK817 tristate "Rockchip RK817 audio CODEC" - depends on MFD_RK808 || COMPILE_TEST + depends on MFD_RK808 || COMPILE_TEST && I2C select REGMAP_I2C config SND_SOC_RL6231 -- cgit v1.2.3 From ced579dcaaa45fe16ac6c12fe847d650734af7bb Mon Sep 17 00:00:00 2001 From: Syed Saba kareem Date: Tue, 30 Aug 2022 18:52:55 +0530 Subject: ASoC: amd: fix spelling mistake: "i.e" -> "i.e." trivial fix to spelling mistake in Kconfig File. Reported by : Randy Dunlap Signed-off-by: Syed Saba Kareem Link: https://lore.kernel.org/r/20220830132259.7759-1-Syed.SabaKareem@amd.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 68837d42736d..150786279257 100644 --- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -122,7 +122,7 @@ config SND_SOC_AMD_RPL_ACP6x tristate "AMD Audio Coprocessor-v6.2 RPL support" depends on X86 && PCI help - This option enables Audio Coprocessor i.e ACP v6.2 support on + This option enables Audio Coprocessor i.e. ACP v6.2 support on AMD RPL platform. By enabling this flag build will be triggered for ACP PCI driver. Say m if you have such a device. -- cgit v1.2.3 From 272ff8828f35658aace17e3227624fbbd68a6bcf Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Mon, 22 Aug 2022 13:15:01 +0300 Subject: ASoC: SOF: compress: Move sof_compr_copy functionality Since we're preparing to add support for compress capture, we need to move the content of sof_compr_copy into a separate function which handles the playback direction just like the initial sof_compr_copy. Reviewed-by: Paul Olaru Reviewed-by: Daniel Baluta Signed-off-by: Laurentiu Mihalcea Link: https://lore.kernel.org/r/20220822101502.17644-2-laurentiu.mihalcea@nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/compress.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/sound/soc/sof/compress.c b/sound/soc/sof/compress.c index c8ae778a50d1..2ee81096bec5 100644 --- a/sound/soc/sof/compress.c +++ b/sound/soc/sof/compress.c @@ -297,18 +297,13 @@ static int sof_compr_trigger(struct snd_soc_component *component, &reply, sizeof(reply)); } -static int sof_compr_copy(struct snd_soc_component *component, - struct snd_compr_stream *cstream, - char __user *buf, size_t count) +static int sof_compr_copy_playback(struct snd_compr_runtime *rtd, + char __user *buf, size_t count) { - struct snd_compr_runtime *rtd = cstream->runtime; - unsigned int offset, n; void *ptr; + unsigned int offset, n; int ret; - if (count > rtd->buffer_size) - count = rtd->buffer_size; - div_u64_rem(rtd->total_bytes_available, rtd->buffer_size, &offset); ptr = rtd->dma_area + offset; n = rtd->buffer_size - offset; @@ -323,6 +318,18 @@ static int sof_compr_copy(struct snd_soc_component *component, return count - ret; } +static int sof_compr_copy(struct snd_soc_component *component, + struct snd_compr_stream *cstream, + char __user *buf, size_t count) +{ + struct snd_compr_runtime *rtd = cstream->runtime; + + if (count > rtd->buffer_size) + count = rtd->buffer_size; + + return sof_compr_copy_playback(rtd, buf, count); +} + static int sof_compr_pointer(struct snd_soc_component *component, struct snd_compr_stream *cstream, struct snd_compr_tstamp *tstamp) -- cgit v1.2.3 From 1a01e19278022cd2f7daa7a065ed47c5022dbad9 Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Mon, 22 Aug 2022 13:15:02 +0300 Subject: ASoC: SOF: compress: Add copy function for capture case Added a new copy function used to copy data to user buffer in the case of compress capture. Reviewed-by: Paul Olaru Reviewed-by: Daniel Baluta Signed-off-by: Laurentiu Mihalcea Link: https://lore.kernel.org/r/20220822101502.17644-3-laurentiu.mihalcea@nxp.com Signed-off-by: Mark Brown --- sound/soc/sof/compress.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/compress.c b/sound/soc/sof/compress.c index 2ee81096bec5..8e1a9ba111ad 100644 --- a/sound/soc/sof/compress.c +++ b/sound/soc/sof/compress.c @@ -318,6 +318,27 @@ static int sof_compr_copy_playback(struct snd_compr_runtime *rtd, return count - ret; } +static int sof_compr_copy_capture(struct snd_compr_runtime *rtd, + char __user *buf, size_t count) +{ + void *ptr; + unsigned int offset, n; + int ret; + + div_u64_rem(rtd->total_bytes_transferred, rtd->buffer_size, &offset); + ptr = rtd->dma_area + offset; + n = rtd->buffer_size - offset; + + if (count < n) { + ret = copy_to_user(buf, ptr, count); + } else { + ret = copy_to_user(buf, ptr, n); + ret += copy_to_user(buf + n, rtd->dma_area, count - n); + } + + return count - ret; +} + static int sof_compr_copy(struct snd_soc_component *component, struct snd_compr_stream *cstream, char __user *buf, size_t count) @@ -327,7 +348,10 @@ static int sof_compr_copy(struct snd_soc_component *component, if (count > rtd->buffer_size) count = rtd->buffer_size; - return sof_compr_copy_playback(rtd, buf, count); + if (cstream->direction == SND_COMPRESS_PLAYBACK) + return sof_compr_copy_playback(rtd, buf, count); + else + return sof_compr_copy_capture(rtd, buf, count); } static int sof_compr_pointer(struct snd_soc_component *component, -- cgit v1.2.3 From c90d6054ff9d75bc185c48b798b745aa2c05236c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 22 Aug 2022 20:42:35 +0200 Subject: ASoC: hdmi-codec: remove unused definitions cppcheck warning: sound/soc/codecs/hdmi-codec.c:24:16: style: struct member 'hdmi_codec_channel_ma`p_table::map' is never used. [unusedStructMember] unsigned char map; /* ALSA API channel map position */ ^ Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Reviewed-by: Chao Song Link: https://lore.kernel.org/r/20220822184239.169757-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/hdmi-codec.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 5679102de91f..863e679d2ac1 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -20,10 +20,6 @@ #define HDMI_CODEC_CHMAP_IDX_UNKNOWN -1 -struct hdmi_codec_channel_map_table { - unsigned char map; /* ALSA API channel map position */ -}; - /* * CEA speaker placement for HDMI 1.4: * -- cgit v1.2.3 From 43265ceeb0b9cb1f8f5fb182adaa6c2ed4941478 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 22 Aug 2022 20:42:36 +0200 Subject: ASoC: wcd-mbhc-v2: remove always-true condition cppcheck warning: 'cross_conn<0' is always true [knownConditionTrueFalse] } else if (cross_conn < 0) /* Error */ ^ '!cross_conn' is not redundant } else if (!cross_conn) { /* no cross connection */ ^ is always true } else if (cross_conn < 0) /* Error */ ^ sound/soc/codecs/wcd-mbhc-v2.c:1192:26: style: Condition sound/soc/codecs/wcd-mbhc-v2.c:1188:15: note: Assuming that condition sound/soc/codecs/wcd-mbhc-v2.c:1192:26: note: Condition 'cross_conn<0' Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Reviewed-by: Chao Song Link: https://lore.kernel.org/r/20220822184239.169757-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd-mbhc-v2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c index 98baef594bf3..b16a18dbfe7a 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.c +++ b/sound/soc/codecs/wcd-mbhc-v2.c @@ -1189,7 +1189,7 @@ correct_plug_type: pt_gnd_mic_swap_cnt = 0; plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv); continue; - } else if (cross_conn < 0) /* Error */ + } else /* Error if (cross_conn < 0) */ continue; if (pt_gnd_mic_swap_cnt == GND_MIC_SWAP_THRESHOLD) { -- cgit v1.2.3 From c9a9b4dbc18f4dc609d47b9ac19545b31fb21e3f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 22 Aug 2022 20:42:37 +0200 Subject: ASoC: wcd9335: remove always-true condition cppcheck warning: sound/soc/codecs/wcd9335.c:1824:22: style: Condition 'tx_port==13' is always true [knownConditionTrueFalse] } else if (tx_port == 13) { ^ sound/soc/codecs/wcd9335.c:1802:16: note: Assuming that condition 'tx_port==12' is not redundant if ((tx_port == 12) || (tx_port >= 14)) { ^ sound/soc/codecs/wcd9335.c:1802:35: note: Assuming that condition 'tx_port>=14' is not redundant if ((tx_port == 12) || (tx_port >= 14)) { ^ sound/soc/codecs/wcd9335.c:1824:22: note: Condition 'tx_port==13' is always true } else if (tx_port == 13) { ^ sound/soc/codecs/wcd9335.c:1845:22: style: Condition 'tx_port==13' is always true [knownConditionTrueFalse] } else if (tx_port == 13) { ^ sound/soc/codecs/wcd9335.c:1802:16: note: Assuming that condition 'tx_port==12' is not redundant if ((tx_port == 12) || (tx_port >= 14)) { ^ sound/soc/codecs/wcd9335.c:1802:35: note: Assuming that condition 'tx_port>=14' is not redundant if ((tx_port == 12) || (tx_port >= 14)) { ^ sound/soc/codecs/wcd9335.c:1845:22: note: Condition 'tx_port==13' is always true } else if (tx_port == 13) { ^ Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Reviewed-by: Chao Song Link: https://lore.kernel.org/r/20220822184239.169757-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 2c5aa4df1e66..06c6adbe5920 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -1821,12 +1821,10 @@ static int wcd9335_set_decimator_rate(struct snd_soc_dai *dai, tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3; shift = 0; shift_val = 0x0F; - } else if (tx_port == 13) { + } else /* (tx_port == 13) */ { tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3; shift = 4; shift_val = 0x03; - } else { - return -EINVAL; } tx_mux_sel = snd_soc_component_read(comp, tx_port_reg) & -- cgit v1.2.3 From 3653a6a2a7c146f04940d572d2728c939b50cba1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 22 Aug 2022 20:42:38 +0200 Subject: ASoC: fsl: fsl-utils: remove useless assignment cppcheck warning: sound/soc/fsl/fsl_utils.c:127:10: style: Variable 'ret' is assigned a value that is never used. [unreadVariable] int ret = 0; ^ Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Reviewed-by: Chao Song Acked-by: Shengjiu Wang Link: https://lore.kernel.org/r/20220822184239.169757-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_utils.c b/sound/soc/fsl/fsl_utils.c index d0fc430f7033..a5ab27c2f711 100644 --- a/sound/soc/fsl/fsl_utils.c +++ b/sound/soc/fsl/fsl_utils.c @@ -124,7 +124,7 @@ void fsl_asoc_reparent_pll_clocks(struct device *dev, struct clk *clk, { struct clk *p, *pll = NULL, *npll = NULL; bool reparent = false; - int ret = 0; + int ret; if (!clk || !pll8k_clk || !pll11k_clk) return; -- cgit v1.2.3 From 7a0431bbda8ae24de56ea1dadcf1a2e56f939707 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 22 Aug 2022 20:42:39 +0200 Subject: ASoC: ti: omap-mcbsp: remove useless assignment sound/soc/ti/omap-mcbsp.c:617:10: style: Variable 'ret' is assigned a value that is never used. [unreadVariable] int ret = 0; ^ Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Reviewed-by: Chao Song Link: https://lore.kernel.org/r/20220822184239.169757-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/ti/omap-mcbsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/ti/omap-mcbsp.c b/sound/soc/ti/omap-mcbsp.c index 0b377bb7737f..7c539a41a6a3 100644 --- a/sound/soc/ti/omap-mcbsp.c +++ b/sound/soc/ti/omap-mcbsp.c @@ -614,7 +614,7 @@ static int omap_mcbsp_init(struct platform_device *pdev) { struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev); struct resource *res; - int ret = 0; + int ret; spin_lock_init(&mcbsp->lock); mcbsp->free = true; -- cgit v1.2.3 From ec2988da1a4671f31b898351daeee2e65ca508f7 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 26 Aug 2022 10:59:26 +0200 Subject: ASoC: dt-bindings: max98396: Document data monitor properties This device features a data monitor that puts the device in software reset upon a configurable set of events. Signed-off-by: Daniel Mack Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20220826085927.2336224-1-daniel@zonque.org Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/adi,max98396.yaml | 34 ++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/adi,max98396.yaml b/Documentation/devicetree/bindings/sound/adi,max98396.yaml index 8d2ef991db40..7985b1410017 100644 --- a/Documentation/devicetree/bindings/sound/adi,max98396.yaml +++ b/Documentation/devicetree/bindings/sound/adi,max98396.yaml @@ -78,6 +78,40 @@ properties: interleaved on a single output channel. type: boolean + adi,dmon-stuck-enable: + description: + Enables the "data monitor stuck" feature. Once the data monitor is + enabled, it actively monitors the selected input data (from DIN) to the + speaker amplifier. Once a data error is detected, the data monitor + automatically places the device into software shutdown. + type: boolean + + adi,dmon-stuck-threshold-bits: + description: + Sets the threshold for the "data monitor stuck" feature, in bits. + enum: [9, 11, 13, 15] + default: 15 + + adi,dmon-magnitude-enable: + description: + Enables the "data monitor magnitude" feature. Once the data monitor is + enabled, it actively monitors the selected input data (from DIN) to the + speaker amplifier. Once a data error is detected, the data monitor + automatically places the device into software shutdown. + type: boolean + + adi,dmon-magnitude-threshold-bits: + description: + Sets the threshold for the "data monitor magnitude" feature, in bits. + enum: [2, 3, 4, 5] + default: 5 + + adi,dmon-duration-ms: + description: + Sets the duration for the "data monitor" feature, in milliseconds. + enum: [64, 256, 1024, 4096] + default: 64 + reset-gpios: maxItems: 1 -- cgit v1.2.3 From 33b7504ae08a20ad22f3bd867623c72bddefdd12 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 26 Aug 2022 10:59:27 +0200 Subject: ASoC: max98396: Make data monitor features configurable Allow the data monitor features to be enabled explicitly, and enable control over their details. Signed-off-by: Daniel Mack Link: https://lore.kernel.org/r/20220826085927.2336224-2-daniel@zonque.org Signed-off-by: Mark Brown --- sound/soc/codecs/max98396.c | 102 ++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/max98396.h | 14 ++++++ 2 files changed, 116 insertions(+) diff --git a/sound/soc/codecs/max98396.c b/sound/soc/codecs/max98396.c index 364b4b7ee033..a7b6a23f2cd8 100644 --- a/sound/soc/codecs/max98396.c +++ b/sound/soc/codecs/max98396.c @@ -1483,6 +1483,87 @@ static int max98396_probe(struct snd_soc_component *component) MAX98396_CLK_MON_AUTO_RESTART_MASK, MAX98396_CLK_MON_AUTO_RESTART_MASK); + regmap_update_bits(max98396->regmap, + MAX98396_R203F_ENABLE_CTRLS, + MAX98396_CTRL_DMON_STUCK_EN_MASK, + max98396->dmon_stuck_enable ? + MAX98396_CTRL_DMON_STUCK_EN_MASK : 0); + + regmap_update_bits(max98396->regmap, + MAX98396_R203F_ENABLE_CTRLS, + MAX98396_CTRL_DMON_MAG_EN_MASK, + max98396->dmon_mag_enable ? + MAX98396_CTRL_DMON_MAG_EN_MASK : 0); + + switch (max98396->dmon_duration) { + case 64: + regmap_update_bits(max98396->regmap, + MAX98396_R2039_DATA_MON_CTRL, + MAX98396_DMON_DURATION_MASK, 0); + break; + case 256: + regmap_update_bits(max98396->regmap, + MAX98396_R2039_DATA_MON_CTRL, + MAX98396_DMON_DURATION_MASK, 1); + break; + case 1024: + regmap_update_bits(max98396->regmap, + MAX98396_R2039_DATA_MON_CTRL, + MAX98396_DMON_DURATION_MASK, 2); + break; + case 4096: + regmap_update_bits(max98396->regmap, + MAX98396_R2039_DATA_MON_CTRL, + MAX98396_DMON_DURATION_MASK, 3); + break; + default: + dev_err(component->dev, "Invalid DMON duration %d\n", + max98396->dmon_duration); + } + + switch (max98396->dmon_stuck_threshold) { + case 15: + regmap_update_bits(max98396->regmap, + MAX98396_R2039_DATA_MON_CTRL, + MAX98396_DMON_STUCK_THRESH_MASK, + 0 << MAX98396_DMON_STUCK_THRESH_SHIFT); + break; + case 13: + regmap_update_bits(max98396->regmap, + MAX98396_R2039_DATA_MON_CTRL, + MAX98396_DMON_STUCK_THRESH_MASK, + 1 << MAX98396_DMON_STUCK_THRESH_SHIFT); + break; + case 22: + regmap_update_bits(max98396->regmap, + MAX98396_R2039_DATA_MON_CTRL, + MAX98396_DMON_STUCK_THRESH_MASK, + 2 << MAX98396_DMON_STUCK_THRESH_SHIFT); + break; + case 9: + regmap_update_bits(max98396->regmap, + MAX98396_R2039_DATA_MON_CTRL, + MAX98396_DMON_STUCK_THRESH_MASK, + 3 << MAX98396_DMON_STUCK_THRESH_SHIFT); + break; + default: + dev_err(component->dev, "Invalid DMON stuck threshold %d\n", + max98396->dmon_stuck_threshold); + } + + switch (max98396->dmon_mag_threshold) { + case 2 ... 5: + regmap_update_bits(max98396->regmap, + MAX98396_R2039_DATA_MON_CTRL, + MAX98396_DMON_STUCK_THRESH_MASK, + (5 - max98396->dmon_mag_threshold) + << MAX98396_DMON_MAG_THRESH_SHIFT); + break; + default: + dev_err(component->dev, "Invalid DMON magnitude threshold %d\n", + max98396->dmon_mag_threshold); + } + /* Speaker Amplifier PCM RX Enable by default */ regmap_update_bits(max98396->regmap, MAX98396_R205E_PCM_RX_EN, @@ -1614,6 +1695,27 @@ static void max98396_read_device_property(struct device *dev, max98396->bypass_slot = value & 0xF; else max98396->bypass_slot = 0; + + max98396->dmon_stuck_enable = + device_property_read_bool(dev, "adi,dmon-stuck-enable"); + + if (!device_property_read_u32(dev, "adi,dmon-stuck-threshold-bits", &value)) + max98396->dmon_stuck_threshold = value; + else + max98396->dmon_stuck_threshold = 15; + + max98396->dmon_mag_enable = + device_property_read_bool(dev, "adi,dmon-magnitude-enable"); + + if (!device_property_read_u32(dev, "adi,dmon-magnitude-threshold-bits", &value)) + max98396->dmon_mag_threshold = value; + else + max98396->dmon_mag_threshold = 5; + + if (!device_property_read_u32(dev, "adi,dmon-duration-ms", &value)) + max98396->dmon_duration = value; + else + max98396->dmon_duration = 64; } static void max98396_core_supplies_disable(void *priv) diff --git a/sound/soc/codecs/max98396.h b/sound/soc/codecs/max98396.h index 7278c779989a..d396aa3e698b 100644 --- a/sound/soc/codecs/max98396.h +++ b/sound/soc/codecs/max98396.h @@ -212,8 +212,17 @@ #define MAX98396_CLK_MON_AUTO_RESTART_MASK (0x1 << 0) #define MAX98396_CLK_MON_AUTO_RESTART_SHIFT (0) +/* MAX98396_R2039_DATA_MON_CTRL */ +#define MAX98396_DMON_MAG_THRESH_SHIFT (4) +#define MAX98396_DMON_MAG_THRESH_MASK (0x3 << MAX98396_DMON_MAG_THRESH_SHIFT) +#define MAX98396_DMON_STUCK_THRESH_SHIFT (2) +#define MAX98396_DMON_STUCK_THRESH_MASK (0x3 << MAX98396_DMON_STUCK_THRESH_SHIFT) +#define MAX98396_DMON_DURATION_MASK (0x3) + /* MAX98396_R203F_ENABLE_CTRLS */ #define MAX98396_CTRL_CMON_EN_SHIFT (0) +#define MAX98396_CTRL_DMON_STUCK_EN_MASK (0x1 << 1) +#define MAX98396_CTRL_DMON_MAG_EN_MASK (0x1 << 2) /* MAX98396_R2041_PCM_MODE_CFG */ #define MAX98396_PCM_MODE_CFG_FORMAT_MASK (0x7 << 3) @@ -305,6 +314,11 @@ struct max98396_priv { unsigned int i_slot; unsigned int spkfb_slot; unsigned int bypass_slot; + bool dmon_stuck_enable; + unsigned int dmon_stuck_threshold; + bool dmon_mag_enable; + unsigned int dmon_mag_threshold; + unsigned int dmon_duration; bool interleave_mode; bool tdm_mode; int tdm_max_samplerate; -- cgit v1.2.3 From ac5e2fb425e1121ceef2b9d1b3ffccc195d55707 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 31 Aug 2022 15:00:21 +0200 Subject: ALSA: usb-audio: Drop superfluous interface setup at parsing We reset each interface that is being parsed for each stream, but this is superfluous and even can lead to spurious errors. Since the interface is set up properly at opening the endpoint for each actual stream operation, let's drop the superfluous one. Link: https://lore.kernel.org/r/20220831130021.4762-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/stream.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sound/usb/stream.c b/sound/usb/stream.c index ceb93d798182..99578e9a8af0 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -1221,12 +1221,6 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, if (err < 0) return err; } - - /* try to set the interface... */ - usb_set_interface(chip->dev, iface_no, 0); - snd_usb_init_pitch(chip, fp); - snd_usb_init_sample_rate(chip, fp, fp->rate_max); - usb_set_interface(chip->dev, iface_no, altno); } return 0; } -- cgit v1.2.3 From 9815746c48ebbd38d32a7a1dade7fa1e3948c54d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 1 Sep 2022 13:14:57 +0300 Subject: ASoC: codecs: wcd934x: add Slimbus dependency The WCD934X codec is a Slimbus driver, so it must depend on SLIMBUS, also for compile tests: ERROR: modpost: "slim_stream_prepare" [sound/soc/codecs/snd-soc-wcd934x.ko] undefined! Reported-by: kernel test robot Fixes: 5b7f4e5de61b ("ASoC: codecs: allow compile testing without MFD drivers") Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220901101458.365354-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 968d0701f2e8..2fc37f4e061c 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1744,6 +1744,7 @@ config SND_SOC_WCD_MBHC config SND_SOC_WCD934X tristate "WCD9340/WCD9341 Codec" depends on COMMON_CLK + depends on SLIMBUS select SND_SOC_WCD_MBHC depends on MFD_WCD934X || COMPILE_TEST help -- cgit v1.2.3 From 69e3e537ec8a2e345f72f65ff24d3486d4764d83 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 1 Sep 2022 13:14:58 +0300 Subject: ASoC: codecs: rk817: drop I2C dependencies The RK817 codec uses regmap API and not directly regmap I2C. It is the parent MFD who uses and selects regmap I2C. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220901101458.365354-2-krzysztof.kozlowski@linaro.org 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 2fc37f4e061c..c7d83fe999e9 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1197,8 +1197,7 @@ config SND_SOC_RK3328 config SND_SOC_RK817 tristate "Rockchip RK817 audio CODEC" - depends on MFD_RK808 || COMPILE_TEST && I2C - select REGMAP_I2C + depends on MFD_RK808 || COMPILE_TEST config SND_SOC_RL6231 tristate -- cgit v1.2.3 From 7d2497b7fd3bf45706360bfe289f19d61d37f536 Mon Sep 17 00:00:00 2001 From: Martin Povišer Date: Thu, 1 Sep 2022 13:34:14 +0200 Subject: ASoC: apple: mca: Unselect COMMON_CLK in Kconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MCA driver selects COMMON_CLK, which leads to misconfiguration on platforms with HAVE_LEGACY_CLK (under compile test). Kconfig catches the conflict with the following warning: WARNING: unmet direct dependencies detected for COMMON_CLK Depends on [n]: !HAVE_LEGACY_CLK [=y] Selected by [m]: - SND_SOC_APPLE_MCA [=m] && SOUND [=m] && !UML && SND [=m] && SND_SOC [=m] && (ARCH_APPLE || COMPILE_TEST [=y]) Eventually the build fails with errors like: >> drivers/clk/clk.c:867:6: error: redefinition of 'clk_unprepare' 867 | void clk_unprepare(struct clk *clk) | ^~~~~~~~~~~~~ In file included from drivers/clk/clk.c:9: include/linux/clk.h:303:20: note: previous definition of 'clk_unprepare' with type 'void(struct clk *)' 303 | static inline void clk_unprepare(struct clk *clk) | ^~~~~~~~~~~~~ which appears to be because COMMON_CLK is selected but HAVE_CLK_PREPARE is not. In the end it seems we had no business selecting COMMON_CLK from an unrelated driver like that, so remove the selection. The linux/clk.h API is there anyway. Fixes: 3df5d0d97289 ("ASoC: apple: mca: Start new platform driver") Reported-by: kernel test robot Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220901113415.27449-1-povik+lin@cutebit.org Signed-off-by: Mark Brown --- sound/soc/apple/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/apple/Kconfig b/sound/soc/apple/Kconfig index 0ba955657e98..793f7782e0d7 100644 --- a/sound/soc/apple/Kconfig +++ b/sound/soc/apple/Kconfig @@ -2,7 +2,6 @@ config SND_SOC_APPLE_MCA tristate "Apple Silicon MCA driver" depends on ARCH_APPLE || COMPILE_TEST select SND_DMAENGINE_PCM - select COMMON_CLK default ARCH_APPLE help This option enables an ASoC platform driver for MCA peripherals found -- cgit v1.2.3 From 55e2bd9c41e800638676dce3f19dcfd16b309a08 Mon Sep 17 00:00:00 2001 From: Martin Povišer Date: Thu, 1 Sep 2022 13:34:15 +0200 Subject: MAINTAINERS: Fix file pattern for ARM/APPLE MACHINE SOUND DRIVERS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is what was meant of course. Fixes: 3df5d0d97289 ("ASoC: apple: mca: Start new platform driver") Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220901113415.27449-2-povik+lin@cutebit.org Signed-off-by: Mark Brown --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 5f91a6b62f2f..895e8ace80dd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1905,7 +1905,7 @@ L: asahi@lists.linux.dev L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/sound/apple,* -F: drivers/sound/apple/* +F: sound/soc/apple/* ARM/ARTPEC MACHINE SUPPORT M: Jesper Nilsson -- cgit v1.2.3 From f51ba1148a810a16eead9f0b29bfa2a8f8ab3afb Mon Sep 17 00:00:00 2001 From: Valentina Goncharenko Date: Thu, 1 Sep 2022 13:28:14 +0300 Subject: ALSA: asihpi - Remove useless code in hpi_meter_get_peak() The hpi_meter_get_peak() function contains the expression "hm.obj_index = hm.obj_index", which does not carry any semantic load. Found by Linux Verification Center (linuxtesting.org) with SVACE. Fixes: 719f82d3987a ("ALSA: Add support of AudioScience ASI boards") Signed-off-by: Valentina Goncharenko Link: https://lore.kernel.org/r/20220901102814.131855-1-goncharenko.vp@ispras.ru Signed-off-by: Takashi Iwai --- sound/pci/asihpi/hpifunc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/pci/asihpi/hpifunc.c b/sound/pci/asihpi/hpifunc.c index 1de05383126a..24047fafef51 100644 --- a/sound/pci/asihpi/hpifunc.c +++ b/sound/pci/asihpi/hpifunc.c @@ -2020,7 +2020,6 @@ u16 hpi_meter_get_peak(u32 h_control, short an_peakdB[HPI_MAX_CHANNELS] HPI_CONTROL_GET_STATE); if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index)) return HPI_ERROR_INVALID_HANDLE; - hm.obj_index = hm.obj_index; hm.u.c.attribute = HPI_METER_PEAK; hpi_send_recv(&hm, &hr); -- cgit v1.2.3 From 32eeeed963ad4f41b422b3e314d96ded7283b201 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 1 Sep 2022 15:08:31 +0200 Subject: ALSA: usb-audio: Clean up endpoint setups at PCM prepare This patch cleans up the superfluous checks and calls for setting up the endpoints at PCM prepare callback: - Drop stop_endpoints() and sync_pending_stops() calls; the stream is guaranteed to have been already stopped and synced at each PCM prepare call by ALSA PCM core - Call snd_usb_endpoint_prepare() unconditionally; the check for endpoint->need_setup is done in snd_pcm_hw_endpoint_prepare() itself - Apply snd_usb_set_format_quirk() only when the endpoint is actually set up (i.e. the return code from snd_usb_endpoint_prepare() > 0) - Move a few lines back into snd_usb_pcm_prepare(); it's even easier to follow than a small useless function Link: https://lore.kernel.org/r/20220901130831.6136-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/pcm.c | 40 ++++++++++------------------------------ 1 file changed, 10 insertions(+), 30 deletions(-) diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index b604f7e95e82..4ed53a3dc922 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -433,35 +433,6 @@ static void close_endpoints(struct snd_usb_audio *chip, } } -static int configure_endpoints(struct snd_usb_audio *chip, - struct snd_usb_substream *subs) -{ - int err; - - if (subs->data_endpoint->need_setup) { - /* stop any running stream beforehand */ - if (stop_endpoints(subs, false)) - sync_pending_stops(subs); - if (subs->sync_endpoint) { - err = snd_usb_endpoint_prepare(chip, subs->sync_endpoint); - if (err < 0) - return err; - } - err = snd_usb_endpoint_prepare(chip, subs->data_endpoint); - if (err < 0) - return err; - snd_usb_set_format_quirk(subs, subs->cur_audiofmt); - } else { - if (subs->sync_endpoint) { - err = snd_usb_endpoint_prepare(chip, subs->sync_endpoint); - if (err < 0) - return err; - } - } - - return 0; -} - /* * hw_params callback * @@ -640,9 +611,18 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) goto unlock; } - ret = configure_endpoints(chip, subs); + if (subs->sync_endpoint) { + ret = snd_usb_endpoint_prepare(chip, subs->sync_endpoint); + if (ret < 0) + goto unlock; + } + + ret = snd_usb_endpoint_prepare(chip, subs->data_endpoint); if (ret < 0) goto unlock; + else if (ret > 0) + snd_usb_set_format_quirk(subs, subs->cur_audiofmt); + ret = 0; /* reset the pointer */ subs->buffer_bytes = frames_to_bytes(runtime, runtime->buffer_size); -- cgit v1.2.3 From 376be51caf8871419bbcbb755e1e615d30dc3153 Mon Sep 17 00:00:00 2001 From: Jiasheng Jiang Date: Fri, 2 Sep 2022 09:30:30 +0800 Subject: ASoC: rsnd: Add check for rsnd_mod_power_on As rsnd_mod_power_on() can return negative numbers, it should be better to check the return value and deal with the exception. Fixes: e7d850dd10f4 ("ASoC: rsnd: use mod base common method on SSI-parent") Signed-off-by: Jiasheng Jiang Acked-by: Kuninori Morimoto Link: https://lore.kernel.org/r/20220902013030.3691266-1-jiasheng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ctu.c | 6 +++++- sound/soc/sh/rcar/dvc.c | 6 +++++- sound/soc/sh/rcar/mix.c | 6 +++++- sound/soc/sh/rcar/src.c | 5 ++++- sound/soc/sh/rcar/ssi.c | 4 +++- 5 files changed, 22 insertions(+), 5 deletions(-) diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index 6156445bcb69..e39eb2ac7e95 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/rcar/ctu.c @@ -171,7 +171,11 @@ static int rsnd_ctu_init(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { - rsnd_mod_power_on(mod); + int ret; + + ret = rsnd_mod_power_on(mod); + if (ret < 0) + return ret; rsnd_ctu_activation(mod); diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 5137e03a9d7c..16befcbc312c 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -186,7 +186,11 @@ static int rsnd_dvc_init(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { - rsnd_mod_power_on(mod); + int ret; + + ret = rsnd_mod_power_on(mod); + if (ret < 0) + return ret; rsnd_dvc_activation(mod); diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c index 3572c2c5686c..1de0e085804c 100644 --- a/sound/soc/sh/rcar/mix.c +++ b/sound/soc/sh/rcar/mix.c @@ -146,7 +146,11 @@ static int rsnd_mix_init(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { - rsnd_mod_power_on(mod); + int ret; + + ret = rsnd_mod_power_on(mod); + if (ret < 0) + return ret; rsnd_mix_activation(mod); diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 0ea84ae57c6a..f832165e46bc 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -463,11 +463,14 @@ static int rsnd_src_init(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_src *src = rsnd_mod_to_src(mod); + int ret; /* reset sync convert_rate */ src->sync.val = 0; - rsnd_mod_power_on(mod); + ret = rsnd_mod_power_on(mod); + if (ret < 0) + return ret; rsnd_src_activation(mod); diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 43c5e27dc5c8..7ade6c5ed96f 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -480,7 +480,9 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, ssi->usrcnt++; - rsnd_mod_power_on(mod); + ret = rsnd_mod_power_on(mod); + if (ret < 0) + return ret; rsnd_ssi_config_init(mod, io); -- cgit v1.2.3 From 10d5d8cbf6268e612bacac29c0beef489d3c1398 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 30 Aug 2022 03:17:03 +0000 Subject: ASoC: soc-pcm.c: remove unnecessary codec2codec_close_delayed_work() commit 4bf2e385aa59c2fae ("ASoC: core: Init pcm runtime work early to avoid warnings") has added generic close_delayed_work() which checks close_delayed_work_func static void close_delayed_work(...) { ... => if (rtd->close_delayed_work_func) rtd->close_delayed_work_func(rtd); } So, we don't need to have NULL function for Codec2Codec. => static void codec2codec_close_delayed_work() { /* * Currently nothing to do for c2c links * Since c2c links are internal nodes in the DAPM graph and * don't interface with the outside world or application layer * we don't have to do any special handling on close. */ } int soc_new_pcm(...) { ... if (rtd->dai_link->params) => rtd->close_delayed_work_func = codec2codec_close_delayed_work; else rtd->close_delayed_work_func = snd_soc_close_delayed_work; ... } Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87sfle4dzk.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index b5720e272c51..39e8fde36c88 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -852,16 +852,6 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) return ret; } -static void codec2codec_close_delayed_work(struct snd_soc_pcm_runtime *rtd) -{ - /* - * Currently nothing to do for c2c links - * Since c2c links are internal nodes in the DAPM graph and - * don't interface with the outside world or application layer - * we don't have to do any special handling on close. - */ -} - /* * Called by ALSA when the PCM substream is prepared, can set format, sample * rate, etc. This function is non atomic and can be called multiple times, @@ -2899,9 +2889,13 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) return ret; /* DAPM dai link stream work */ - if (rtd->dai_link->params) - rtd->close_delayed_work_func = codec2codec_close_delayed_work; - else + /* + * Currently nothing to do for c2c links + * Since c2c links are internal nodes in the DAPM graph and + * don't interface with the outside world or application layer + * we don't have to do any special handling on close. + */ + if (!rtd->dai_link->params) rtd->close_delayed_work_func = snd_soc_close_delayed_work; rtd->pcm = pcm; -- cgit v1.2.3 From 041107289c5cebb0693a55c432ab50862a450476 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 30 Aug 2022 03:17:12 +0000 Subject: ASoC: soc-pcm.c: add soc_pcm_ret() Current soc-pcm.c has many similar code for error case. This patch adds soc_pcm_ret() and share the code and error message. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87r10y4dzb.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 84 +++++++++++++++++++++++------------------------------ 1 file changed, 36 insertions(+), 48 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 39e8fde36c88..ce09caf8f8c8 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -27,6 +27,28 @@ #include #include +#define soc_pcm_ret(rtd, ret) _soc_pcm_ret(rtd, __func__, ret) +static inline int _soc_pcm_ret(struct snd_soc_pcm_runtime *rtd, + const char *func, int ret) +{ + /* Positive, Zero values are not errors */ + if (ret >= 0) + return ret; + + /* Negative values might be errors */ + switch (ret) { + case -EPROBE_DEFER: + case -ENOTSUPP: + break; + default: + dev_err(rtd->dev, + "ASoC: error at %s on %s: %d\n", + func, rtd->dai_link->name, ret); + } + + return ret; +} + 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); @@ -832,12 +854,10 @@ dynamic: snd_soc_runtime_activate(rtd, substream->stream); ret = 0; err: - if (ret < 0) { + if (ret < 0) soc_pcm_clean(rtd, substream, 1); - dev_err(rtd->dev, "%s() failed (%d)", __func__, ret); - } - return ret; + return soc_pcm_ret(rtd, ret); } /* PCM open ops for non-DPCM streams */ @@ -891,10 +911,7 @@ static int __soc_pcm_prepare(struct snd_soc_pcm_runtime *rtd, snd_soc_dai_digital_mute(dai, 0, substream->stream); out: - if (ret < 0) - dev_err(rtd->dev, "ASoC: %s() failed (%d)\n", __func__, ret); - - return ret; + return soc_pcm_ret(rtd, ret); } /* PCM prepare ops for non-DPCM streams */ @@ -1060,12 +1077,10 @@ static int __soc_pcm_hw_params(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_pcm_component_hw_params(substream, params); out: - if (ret < 0) { + if (ret < 0) soc_pcm_hw_clean(rtd, substream, 1); - dev_err(rtd->dev, "ASoC: %s() failed (%d)\n", __func__, ret); - } - return ret; + return soc_pcm_ret(rtd, ret); } /* hw_params PCM ops for non-DPCM streams */ @@ -1627,10 +1642,7 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) unwind: dpcm_be_dai_startup_rollback(fe, stream, dpcm); - dev_err(fe->dev, "ASoC: %s() failed at %s (%d)\n", - __func__, be->dai_link->name, err); - - return err; + return soc_pcm_ret(fe, err); } static void dpcm_runtime_setup_fe(struct snd_pcm_substream *substream) @@ -1830,10 +1842,7 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream, } } error: - if (err < 0) - dev_err(fe->dev, "ASoC: %s failed (%d)\n", __func__, err); - - return err; + return soc_pcm_ret(fe, err); } static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream) @@ -1870,10 +1879,7 @@ unwind: be_err: dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); - if (ret < 0) - dev_err(fe->dev, "%s() failed (%d)\n", __func__, ret); - - return ret; + return soc_pcm_ret(fe, ret); } static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream) @@ -2072,10 +2078,7 @@ out: dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); snd_soc_dpcm_mutex_unlock(fe); - if (ret < 0) - dev_err(fe->dev, "ASoC: %s failed (%d)\n", __func__, ret); - - return ret; + return soc_pcm_ret(fe, ret); } int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, @@ -2244,10 +2247,7 @@ next: if (ret) break; } - if (ret < 0) - dev_err(fe->dev, "ASoC: %s() failed at %s (%d)\n", - __func__, be->dai_link->name, ret); - return ret; + return soc_pcm_ret(fe, ret); } EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger); @@ -2418,10 +2418,7 @@ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream) be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE; } - if (ret < 0) - dev_err(fe->dev, "ASoC: %s() failed (%d)\n", __func__, ret); - - return ret; + return soc_pcm_ret(fe, ret); } static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream) @@ -2458,10 +2455,7 @@ out: dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); snd_soc_dpcm_mutex_unlock(fe); - if (ret < 0) - dev_err(fe->dev, "ASoC: %s() failed (%d)\n", __func__, ret); - - return ret; + return soc_pcm_ret(fe, ret); } static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream) @@ -2494,10 +2488,7 @@ static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream) /* run the stream event for each BE */ dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP); - if (err < 0) - dev_err(fe->dev, "ASoC: %s() failed (%d)\n", __func__, err); - - return err; + return soc_pcm_ret(fe, err); } static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) @@ -2587,10 +2578,7 @@ disconnect: dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; } - if (ret < 0) - dev_err(fe->dev, "ASoC: %s() failed (%d)\n", __func__, ret); - - return ret; + return soc_pcm_ret(fe, ret); } static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new) -- cgit v1.2.3 From 6932b20d4f41dc01dc58c0afb335e688575c7d54 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 30 Aug 2022 03:17:19 +0000 Subject: ASoC: soc-pcm.c: check fe condition at out of loop Current dpcm_add_paths() is checking fe condition in loop (= A), but fe condition (X) is not related to the loop (B). (X) static int dpcm_add_paths(fe, stream, ...) { ... (B) for_each_dapm_widgets(list, i, widget) { ... (A) if (!fe->dpcm[stream].runtime && !fe->fe_compr) continue; ... } ... } This patch checks fe condition at out of loop Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87pmgi4dz4.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index ce09caf8f8c8..f8b62487babd 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1458,6 +1458,10 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, struct snd_soc_dapm_widget *widget; int i, new = 0, err; + /* don't connect if FE is not running */ + if (!fe->dpcm[stream].runtime && !fe->fe_compr) + return new; + /* Create any new FE <--> BE connections */ for_each_dapm_widgets(list, i, widget) { @@ -1482,10 +1486,6 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, continue; } - /* don't connect if FE is not running */ - if (!fe->dpcm[stream].runtime && !fe->fe_compr) - continue; - /* * Filter for systems with 'component_chaining' enabled. * This helps to avoid unnecessary re-configuration of an -- cgit v1.2.3 From b6b55b232564ade5cd91e9b9e2228b49f230d67f Mon Sep 17 00:00:00 2001 From: Martin Povišer Date: Thu, 25 Aug 2022 16:22:25 +0200 Subject: ASoC: tas2562: Drop conflicting set_bias_level power setting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver is setting the PWR_CTRL field in both the set_bias_level callback and on DAPM events of the DAC widget (and also in the mute_stream method). Drop the set_bias_level callback altogether as the power setting it does is in conflict with the other code paths. (This mirrors commit c8a6ae3fe1c8 ("ASoC: tas2770: Drop conflicting set_bias_level power setting") which was a fix to the tas2770 driver.) Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220825142226.80929-2-povik+lin@cutebit.org Signed-off-by: Mark Brown --- sound/soc/codecs/tas2562.c | 35 ----------------------------------- 1 file changed, 35 deletions(-) diff --git a/sound/soc/codecs/tas2562.c b/sound/soc/codecs/tas2562.c index dc088a1c6721..2b0cdb6d1600 100644 --- a/sound/soc/codecs/tas2562.c +++ b/sound/soc/codecs/tas2562.c @@ -63,39 +63,6 @@ enum tas256x_model { TAS2110, }; -static int tas2562_set_bias_level(struct snd_soc_component *component, - enum snd_soc_bias_level level) -{ - struct tas2562_data *tas2562 = - snd_soc_component_get_drvdata(component); - - switch (level) { - case SND_SOC_BIAS_ON: - snd_soc_component_update_bits(component, - TAS2562_PWR_CTRL, - TAS2562_MODE_MASK, TAS2562_ACTIVE); - break; - case SND_SOC_BIAS_STANDBY: - case SND_SOC_BIAS_PREPARE: - snd_soc_component_update_bits(component, - TAS2562_PWR_CTRL, - TAS2562_MODE_MASK, TAS2562_MUTE); - break; - case SND_SOC_BIAS_OFF: - snd_soc_component_update_bits(component, - TAS2562_PWR_CTRL, - TAS2562_MODE_MASK, TAS2562_SHUTDOWN); - break; - - default: - dev_err(tas2562->dev, - "wrong power level setting %d\n", level); - return -EINVAL; - } - - return 0; -} - static int tas2562_set_samplerate(struct tas2562_data *tas2562, int samplerate) { int samp_rate; @@ -579,7 +546,6 @@ static const struct snd_soc_component_driver soc_component_dev_tas2110 = { .probe = tas2562_codec_probe, .suspend = tas2562_suspend, .resume = tas2562_resume, - .set_bias_level = tas2562_set_bias_level, .controls = tas2562_snd_controls, .num_controls = ARRAY_SIZE(tas2562_snd_controls), .dapm_widgets = tas2110_dapm_widgets, @@ -618,7 +584,6 @@ static const struct snd_soc_component_driver soc_component_dev_tas2562 = { .probe = tas2562_codec_probe, .suspend = tas2562_suspend, .resume = tas2562_resume, - .set_bias_level = tas2562_set_bias_level, .controls = tas2562_snd_controls, .num_controls = ARRAY_SIZE(tas2562_snd_controls), .dapm_widgets = tas2562_dapm_widgets, -- cgit v1.2.3 From 2848d34c3ba1fc6f1ece0736a4faa16c6277f4d3 Mon Sep 17 00:00:00 2001 From: Martin Povišer Date: Thu, 25 Aug 2022 16:22:26 +0200 Subject: ASoC: tas2562: Fix mute/unmute MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because the PWR_CTRL field is modeled as the power state of the DAC widget, and at the same time it is used to implement mute/unmute, we need some additional book-keeping to have the right end result no matter the sequence of calls. Without this fix, one permanently mutes an ongoing stream by toggling the associated speaker pin control. (This mirrors commit 1e5907bcb3a3 ("ASoC: tas2770: Fix handling of mute/unmute") which was a fix to the tas2770 driver.) Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220825142226.80929-3-povik+lin@cutebit.org Signed-off-by: Mark Brown --- sound/soc/codecs/tas2562.c | 55 ++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/sound/soc/codecs/tas2562.c b/sound/soc/codecs/tas2562.c index 2b0cdb6d1600..66149055aba9 100644 --- a/sound/soc/codecs/tas2562.c +++ b/sound/soc/codecs/tas2562.c @@ -54,6 +54,8 @@ struct tas2562_data { int i_sense_slot; int volume_lvl; int model_id; + bool dac_powered; + bool unmuted; }; enum tas256x_model { @@ -351,30 +353,43 @@ static int tas2562_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } +static int tas2562_update_pwr_ctrl(struct tas2562_data *tas2562) +{ + struct snd_soc_component *component = tas2562->component; + unsigned int val; + int ret; + + if (tas2562->dac_powered) + val = tas2562->unmuted ? + TAS2562_ACTIVE : TAS2562_MUTE; + else + val = TAS2562_SHUTDOWN; + + ret = snd_soc_component_update_bits(component, TAS2562_PWR_CTRL, + TAS2562_MODE_MASK, val); + if (ret < 0) + return ret; + + return 0; +} + static int tas2562_mute(struct snd_soc_dai *dai, int mute, int direction) { - struct snd_soc_component *component = dai->component; + struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(dai->component); - return snd_soc_component_update_bits(component, TAS2562_PWR_CTRL, - TAS2562_MODE_MASK, - mute ? TAS2562_MUTE : 0); + tas2562->unmuted = !mute; + return tas2562_update_pwr_ctrl(tas2562); } static int tas2562_codec_probe(struct snd_soc_component *component) { struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); - int ret; tas2562->component = component; if (tas2562->sdz_gpio) gpiod_set_value_cansleep(tas2562->sdz_gpio, 1); - ret = snd_soc_component_update_bits(component, TAS2562_PWR_CTRL, - TAS2562_MODE_MASK, TAS2562_MUTE); - if (ret < 0) - return ret; - return 0; } @@ -428,30 +443,18 @@ static int tas2562_dac_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: - ret = snd_soc_component_update_bits(component, - TAS2562_PWR_CTRL, - TAS2562_MODE_MASK, - TAS2562_MUTE); - if (ret) - goto end; + tas2562->dac_powered = true; + ret = tas2562_update_pwr_ctrl(tas2562); break; case SND_SOC_DAPM_PRE_PMD: - ret = snd_soc_component_update_bits(component, - TAS2562_PWR_CTRL, - TAS2562_MODE_MASK, - TAS2562_SHUTDOWN); - if (ret) - goto end; + tas2562->dac_powered = false; + ret = tas2562_update_pwr_ctrl(tas2562); break; default: dev_err(tas2562->dev, "Not supported evevt\n"); return -EINVAL; } -end: - if (ret < 0) - return ret; - return 0; } -- cgit v1.2.3 From 35c8ae25c4fdeabf490e005692795a3be17ca5f6 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Fri, 26 Aug 2022 01:05:30 +0300 Subject: ASoC: wm_adsp: Handle optional legacy support The tracing capabilities for the speaker protection fw enabled via commit c55b3e46cb99 ("ASoC: wm_adsp: Add trace caps to speaker protection FW") are not be available on all platforms, such as the Valve's Steam Deck which is based on the Halo Core DSP. As a consequence, whenever the firmware is loaded, a rather misleading 'Failed to parse legacy: -19' error message is written to the kernel ring buffer: [ 288.977412] steamdeck kernel: cs35l41 spi-VLV1776:01: DSP1: Firmware version: 3 [ 288.978002] steamdeck kernel: cs35l41 spi-VLV1776:01: DSP1: cs35l41-dsp1-spk-prot.wmfw: Fri 02 Apr 2021 21:03:50 W. Europe Daylight Time [ 289.094065] steamdeck kernel: cs35l41 spi-VLV1776:01: DSP1: Firmware: 400a4 vendor: 0x2 v0.33.0, 2 algorithms [ 289.095073] steamdeck kernel: cs35l41 spi-VLV1776:01: DSP1: 0: ID cd v29.53.0 XM@94 YM@e [ 289.095665] steamdeck kernel: cs35l41 spi-VLV1776:01: DSP1: 1: ID f20b v0.0.1 XM@170 YM@0 [ 289.096275] steamdeck kernel: cs35l41 spi-VLV1776:01: DSP1: Protection: C:\Users\ocanavan\Desktop\cirrusTune_july2021.bin [ 291.172383] steamdeck kernel: cs35l41 spi-VLV1776:01: DSP1: Failed to parse legacy: -19 Update wm_adsp_buffer_init() to print a more descriptive info message when wm_adsp_buffer_parse_legacy() returns -ENODEV. Fixes: c55b3e46cb99 ("ASoC: wm_adsp: Add trace caps to speaker protection FW") Signed-off-by: Cristian Ciocaltea Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20220825220530.1205141-1-cristian.ciocaltea@collabora.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index cfaa45ede916..8a2e9771bb50 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -1602,7 +1602,9 @@ static int wm_adsp_buffer_init(struct wm_adsp *dsp) if (list_empty(&dsp->buffer_list)) { /* Fall back to legacy support */ ret = wm_adsp_buffer_parse_legacy(dsp); - if (ret) + if (ret == -ENODEV) + adsp_info(dsp, "Legacy support not available\n"); + else if (ret) adsp_warn(dsp, "Failed to parse legacy: %d\n", ret); } -- cgit v1.2.3 From 354f6008b730a217a3e6ad982eda42e90e6f7473 Mon Sep 17 00:00:00 2001 From: Chunxu Li Date: Sat, 3 Sep 2022 11:21:51 +0800 Subject: ASoC: SOF: Introduce function sof_of_machine_select From current design in sof_machine_check the SOF can only support ACPI type machine. In sof_machine_check if there is no ACPI machine exist, the function will return -ENODEV directly, that's we don't expected if we do not base on ACPI machine. So we add a new function named sof_of_machine_select that we can pass sof_machine_check and obtain info required by snd_sof_new_platform_drv. Signed-off-by: Chunxu Li Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220903032151.13664-1-chunxu.li@mediatek.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-audio.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index c18e723435bd..ea9663d448eb 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -785,6 +785,28 @@ int sof_dai_get_bclk(struct snd_soc_pcm_runtime *rtd) } EXPORT_SYMBOL(sof_dai_get_bclk); +static struct snd_sof_of_mach *sof_of_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_sof_of_mach *mach = desc->of_machines; + + if (!mach) + return NULL; + + for (; mach->compatible; mach++) { + if (of_machine_is_compatible(mach->compatible)) { + sof_pdata->tplg_filename = mach->sof_tplg_filename; + if (mach->fw_filename) + sof_pdata->fw_filename = mach->fw_filename; + + return mach; + } + } + + return NULL; +} + /* * SOF Driver enumeration. */ @@ -795,6 +817,7 @@ int sof_machine_check(struct snd_sof_dev *sdev) struct snd_soc_acpi_mach *mach; if (!IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)) { + const struct snd_sof_of_mach *of_mach; /* find machine */ mach = snd_sof_machine_select(sdev); @@ -804,6 +827,12 @@ int sof_machine_check(struct snd_sof_dev *sdev) return 0; } + of_mach = sof_of_machine_select(sdev); + if (of_mach) { + sof_pdata->of_machine = of_mach; + return 0; + } + if (!IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)) { dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n"); return -ENODEV; -- cgit v1.2.3 From 4ec8179c212fb1530df4a1df6db75756c06da5f6 Mon Sep 17 00:00:00 2001 From: Martin Povišer Date: Mon, 5 Sep 2022 09:40:30 +0200 Subject: ASoC: apple: mca: Postpone requesting of DMA channels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the requesting of DMA channels further down from 'probe' to 'pcm_new'. This is to spare the allocated DMA channel resources as we typically only ever use one or two of the clusters for PCM streaming. Before we would request DMA channels for all clusters. (This is prompted by a change in the Audio DMA Controller driver, which will now be allocating cache SRAM to channels.) Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220905074030.1293-1-povik+lin@cutebit.org Signed-off-by: Mark Brown --- sound/soc/apple/mca.c | 79 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 33 deletions(-) diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c index aa67d57c9a9b..69643524796e 100644 --- a/sound/soc/apple/mca.c +++ b/sound/soc/apple/mca.c @@ -885,6 +885,43 @@ static snd_pcm_uframes_t mca_pointer(struct snd_soc_component *component, return snd_dmaengine_pcm_pointer(substream); } +static struct dma_chan *mca_request_dma_channel(struct mca_cluster *cl, unsigned int stream) +{ + bool is_tx = (stream == SNDRV_PCM_STREAM_PLAYBACK); +#ifndef USE_RXB_FOR_CAPTURE + char *name = devm_kasprintf(cl->host->dev, GFP_KERNEL, + is_tx ? "tx%da" : "rx%da", cl->no); +#else + char *name = devm_kasprintf(cl->host->dev, GFP_KERNEL, + is_tx ? "tx%da" : "rx%db", cl->no); +#endif + return of_dma_request_slave_channel(cl->host->dev->of_node, name); + +} + +static void mca_pcm_free(struct snd_soc_component *component, + struct snd_pcm *pcm) +{ + struct snd_soc_pcm_runtime *rtd = snd_pcm_chip(pcm); + struct mca_cluster *cl = mca_dai_to_cluster(asoc_rtd_to_cpu(rtd, 0)); + unsigned int i; + + if (rtd->dai_link->no_pcm) + return; + + for_each_pcm_streams(i) { + struct snd_pcm_substream *substream = + rtd->pcm->streams[i].substream; + + if (!substream || !cl->dma_chans[i]) + continue; + + dma_release_channel(cl->dma_chans[i]); + cl->dma_chans[i] = NULL; + } +} + + static int mca_pcm_new(struct snd_soc_component *component, struct snd_soc_pcm_runtime *rtd) { @@ -897,17 +934,21 @@ static int mca_pcm_new(struct snd_soc_component *component, for_each_pcm_streams(i) { struct snd_pcm_substream *substream = rtd->pcm->streams[i].substream; - struct dma_chan *chan = cl->dma_chans[i]; + struct dma_chan *chan; if (!substream) continue; - if (!chan) { - dev_err(component->dev, "missing DMA channel for stream %d on SERDES %d\n", - i, cl->no); + chan = mca_request_dma_channel(cl, i); + + if (IS_ERR_OR_NULL(chan)) { + dev_err(component->dev, "unable to obtain DMA channel (stream %d cluster %d): %pe\n", + i, cl->no, chan); + mca_pcm_free(component, rtd->pcm); return -EINVAL; } + cl->dma_chans[i] = chan; snd_pcm_set_managed_buffer(substream, SNDRV_DMA_TYPE_DEV_IRAM, chan->device->dev, 512 * 1024 * 6, SIZE_MAX); @@ -924,6 +965,7 @@ static const struct snd_soc_component_driver mca_component = { .trigger = mca_trigger, .pointer = mca_pointer, .pcm_construct = mca_pcm_new, + .pcm_destruct = mca_pcm_free, }; static void apple_mca_release(struct mca_data *mca) @@ -1019,7 +1061,6 @@ static int apple_mca_probe(struct platform_device *pdev) struct snd_soc_dai_driver *fe = &dai_drivers[mca->nclusters + i]; struct snd_soc_dai_driver *be = &dai_drivers[i]; - int stream; cl->host = mca; cl->no = i; @@ -1041,34 +1082,6 @@ static int apple_mca_probe(struct platform_device *pdev) goto err_release; } - for_each_pcm_streams(stream) { - struct dma_chan *chan; - bool is_tx = (stream == SNDRV_PCM_STREAM_PLAYBACK); -#ifndef USE_RXB_FOR_CAPTURE - char *name = devm_kasprintf(&pdev->dev, GFP_KERNEL, - is_tx ? "tx%da" : "rx%da", - i); -#else - char *name = devm_kasprintf(&pdev->dev, GFP_KERNEL, - is_tx ? "tx%da" : "rx%db", - i); -#endif - - chan = of_dma_request_slave_channel(pdev->dev.of_node, - name); - if (IS_ERR(chan)) { - if (PTR_ERR(chan) != -EPROBE_DEFER) - dev_err(&pdev->dev, - "no %s DMA channel: %ld\n", - name, PTR_ERR(chan)); - - ret = PTR_ERR(chan); - goto err_release; - } - - cl->dma_chans[stream] = chan; - } - fe->id = i; fe->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "mca-pcm-%d", i); -- cgit v1.2.3 From f0b933236ec97de5ee49c60aae57a9c5c4dadc87 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Sun, 4 Sep 2022 12:28:39 +0200 Subject: lib/string_helpers: Introduce parse_int_array_user() Add new helper function to allow for splitting specified user string into a sequence of integers. Internally it makes use of get_options() so the returned sequence contains the integers extracted plus an additional element that begins the sequence and specifies the integers count. Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20220904102840.862395-2-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- include/linux/string_helpers.h | 2 ++ lib/string_helpers.c | 44 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/include/linux/string_helpers.h b/include/linux/string_helpers.h index 4d72258d42fd..dc2e726fd820 100644 --- a/include/linux/string_helpers.h +++ b/include/linux/string_helpers.h @@ -21,6 +21,8 @@ enum string_size_units { void string_get_size(u64 size, u64 blk_size, enum string_size_units units, char *buf, int len); +int parse_int_array_user(const char __user *from, size_t count, int **array); + #define UNESCAPE_SPACE BIT(0) #define UNESCAPE_OCTAL BIT(1) #define UNESCAPE_HEX BIT(2) diff --git a/lib/string_helpers.c b/lib/string_helpers.c index 5ed3beb066e6..230020a2e076 100644 --- a/lib/string_helpers.c +++ b/lib/string_helpers.c @@ -131,6 +131,50 @@ void string_get_size(u64 size, u64 blk_size, const enum string_size_units units, } EXPORT_SYMBOL(string_get_size); +/** + * parse_int_array_user - Split string into a sequence of integers + * @from: The user space buffer to read from + * @count: The maximum number of bytes to read + * @array: Returned pointer to sequence of integers + * + * On success @array is allocated and initialized with a sequence of + * integers extracted from the @from plus an additional element that + * begins the sequence and specifies the integers count. + * + * Caller takes responsibility for freeing @array when it is no longer + * needed. + */ +int parse_int_array_user(const char __user *from, size_t count, int **array) +{ + int *ints, nints; + char *buf; + int ret = 0; + + buf = memdup_user_nul(from, count); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + get_options(buf, 0, &nints); + if (!nints) { + ret = -ENOENT; + goto free_buf; + } + + ints = kcalloc(nints + 1, sizeof(*ints), GFP_KERNEL); + if (!ints) { + ret = -ENOMEM; + goto free_buf; + } + + get_options(buf, nints + 1, ints); + *array = ints; + +free_buf: + kfree(buf); + return ret; +} +EXPORT_SYMBOL(parse_int_array_user); + static bool unescape_space(char **src, char **dst) { char *p = *dst, *q = *src; -- cgit v1.2.3 From b9163e9b5f14d690752010ee843b2d788c3536f1 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Sun, 4 Sep 2022 12:28:40 +0200 Subject: ASoC: SOF: Remove strsplit_u32() and tokenize_input() Make use of global integer-array parsing helper instead of the internal one as both serve same purpose. With that, both strsplit_u32() and tokenize_input() become unused so remove them. Reviewed-by: Andy Shevchenko Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20220904102840.862395-3-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-client-probes.c | 104 ++++++-------------------------------- 1 file changed, 15 insertions(+), 89 deletions(-) diff --git a/sound/soc/sof/sof-client-probes.c b/sound/soc/sof/sof-client-probes.c index eb246b823461..ddeabbb5580e 100644 --- a/sound/soc/sof/sof-client-probes.c +++ b/sound/soc/sof/sof-client-probes.c @@ -12,6 +12,8 @@ #include #include #include +#include + #include #include #include "sof-client.h" @@ -410,79 +412,6 @@ static const struct snd_compress_ops sof_probes_compressed_ops = { .copy = sof_probes_compr_copy, }; -/** - * strsplit_u32 - Split string into sequence of u32 tokens - * @buf: String to split into tokens. - * @delim: String containing delimiter characters. - * @tkns: Returned u32 sequence pointer. - * @num_tkns: Returned number of tokens obtained. - */ -static int strsplit_u32(char *buf, const char *delim, u32 **tkns, size_t *num_tkns) -{ - char *s; - u32 *data, *tmp; - size_t count = 0; - size_t cap = 32; - int ret = 0; - - *tkns = NULL; - *num_tkns = 0; - data = kcalloc(cap, sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - while ((s = strsep(&buf, delim)) != NULL) { - ret = kstrtouint(s, 0, data + count); - if (ret) - goto exit; - if (++count >= cap) { - cap *= 2; - tmp = krealloc(data, cap * sizeof(*data), GFP_KERNEL); - if (!tmp) { - ret = -ENOMEM; - goto exit; - } - data = tmp; - } - } - - if (!count) - goto exit; - *tkns = kmemdup(data, count * sizeof(*data), GFP_KERNEL); - if (!(*tkns)) { - ret = -ENOMEM; - goto exit; - } - *num_tkns = count; - -exit: - kfree(data); - return ret; -} - -static int tokenize_input(const char __user *from, size_t count, - loff_t *ppos, u32 **tkns, size_t *num_tkns) -{ - char *buf; - int ret; - - buf = kmalloc(count + 1, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - ret = simple_write_to_buffer(buf, count, ppos, from, count); - if (ret != count) { - ret = ret >= 0 ? -EIO : ret; - goto exit; - } - - buf[count] = '\0'; - ret = strsplit_u32(buf, ",", tkns, num_tkns); -exit: - kfree(buf); - return ret; -} - static ssize_t sof_probes_dfs_points_read(struct file *file, char __user *to, size_t count, loff_t *ppos) { @@ -548,8 +477,8 @@ sof_probes_dfs_points_write(struct file *file, const char __user *from, struct sof_probes_priv *priv = cdev->data; struct device *dev = &cdev->auxdev.dev; struct sof_probe_point_desc *desc; - size_t num_tkns, bytes; - u32 *tkns; + u32 num_elems, *array; + size_t bytes; int ret, err; if (priv->extractor_stream_tag == SOF_PROBES_INVALID_NODE_ID) { @@ -557,16 +486,18 @@ sof_probes_dfs_points_write(struct file *file, const char __user *from, return -ENOENT; } - ret = tokenize_input(from, count, ppos, &tkns, &num_tkns); + ret = parse_int_array_user(from, count, (int **)&array); if (ret < 0) return ret; - bytes = sizeof(*tkns) * num_tkns; - if (!num_tkns || (bytes % sizeof(*desc))) { + + num_elems = *array; + bytes = sizeof(*array) * num_elems; + if (bytes % sizeof(*desc)) { ret = -EINVAL; goto exit; } - desc = (struct sof_probe_point_desc *)tkns; + desc = (struct sof_probe_point_desc *)&array[1]; ret = pm_runtime_resume_and_get(dev); if (ret < 0 && ret != -EACCES) { @@ -583,7 +514,7 @@ sof_probes_dfs_points_write(struct file *file, const char __user *from, if (err < 0) dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", err); exit: - kfree(tkns); + kfree(array); return ret; } @@ -603,22 +534,17 @@ sof_probes_dfs_points_remove_write(struct file *file, const char __user *from, struct sof_client_dev *cdev = file->private_data; struct sof_probes_priv *priv = cdev->data; struct device *dev = &cdev->auxdev.dev; - size_t num_tkns; - u32 *tkns; int ret, err; + u32 *array; if (priv->extractor_stream_tag == SOF_PROBES_INVALID_NODE_ID) { dev_warn(dev, "no extractor stream running\n"); return -ENOENT; } - ret = tokenize_input(from, count, ppos, &tkns, &num_tkns); + ret = parse_int_array_user(from, count, (int **)&array); if (ret < 0) return ret; - if (!num_tkns) { - ret = -EINVAL; - goto exit; - } ret = pm_runtime_resume_and_get(dev); if (ret < 0) { @@ -626,7 +552,7 @@ sof_probes_dfs_points_remove_write(struct file *file, const char __user *from, goto exit; } - ret = sof_probes_points_remove(cdev, tkns, num_tkns); + ret = sof_probes_points_remove(cdev, &array[1], array[0]); if (!ret) ret = count; @@ -635,7 +561,7 @@ sof_probes_dfs_points_remove_write(struct file *file, const char __user *from, if (err < 0) dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", err); exit: - kfree(tkns); + kfree(array); return ret; } -- cgit v1.2.3 From 6392dcd1d0c7034ccf630ec55fc9e5810ecadf3b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 4 Sep 2022 18:12:47 +0200 Subject: ALSA: usb-audio: Register card at the last interface The USB-audio driver matches per interface, and as default, it registers the card instance at the very first instance. This can be a problem for the devices that have multiple interfaces to be probed, as the udev rule isn't applied properly for the later appearing interfaces. Although we introduced the delayed_register option and the quirks for covering those shortcomings, it's nothing but a workaround for specific devices. This patch is an another attempt to fix the problem in a more generic way. Now the driver checks the whole USB device descriptor at the very first time when an interface is attached to a sound card. It looks at each matching interface in the descriptor and remembers the last matching one. The snd_card_register() is invoked only when this last interface is probed. After this change, the quirks for the delayed registration become superfluous, hence they are removed along with the patch. OTOH, the delayed_register option is still kept, as it might be useful for some corner cases (e.g. a special driver overtakes the interface probe from the standard driver, and the last interface probe may miss). Link: https://lore.kernel.org/r/20220904161247.16461-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/card.c | 32 +++++++++++++++++++++++++------- sound/usb/quirks.c | 42 ------------------------------------------ sound/usb/quirks.h | 2 -- sound/usb/usbaudio.h | 1 + 4 files changed, 26 insertions(+), 51 deletions(-) diff --git a/sound/usb/card.c b/sound/usb/card.c index 706d249a9ad6..3aea241435fb 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -690,7 +690,7 @@ static bool get_alias_id(struct usb_device *dev, unsigned int *id) return false; } -static bool check_delayed_register_option(struct snd_usb_audio *chip, int iface) +static int check_delayed_register_option(struct snd_usb_audio *chip) { int i; unsigned int id, inum; @@ -699,14 +699,31 @@ static bool check_delayed_register_option(struct snd_usb_audio *chip, int iface) if (delayed_register[i] && sscanf(delayed_register[i], "%x:%x", &id, &inum) == 2 && id == chip->usb_id) - return iface < inum; + return inum; } - return false; + return -1; } static const struct usb_device_id usb_audio_ids[]; /* defined below */ +/* look for the last interface that matches with our ids and remember it */ +static void find_last_interface(struct snd_usb_audio *chip) +{ + struct usb_host_config *config = chip->dev->actconfig; + struct usb_interface *intf; + int i; + + if (!config) + return; + for (i = 0; i < config->desc.bNumInterfaces; i++) { + intf = config->interface[i]; + if (usb_match_id(intf, usb_audio_ids)) + chip->last_iface = intf->altsetting[0].desc.bInterfaceNumber; + } + usb_audio_dbg(chip, "Found last interface = %d\n", chip->last_iface); +} + /* look for the corresponding quirk */ static const struct snd_usb_audio_quirk * get_alias_quirk(struct usb_device *dev, unsigned int id) @@ -813,6 +830,7 @@ static int usb_audio_probe(struct usb_interface *intf, err = -ENODEV; goto __error; } + find_last_interface(chip); } if (chip->num_interfaces >= MAX_CARD_INTERFACES) { @@ -862,11 +880,11 @@ static int usb_audio_probe(struct usb_interface *intf, chip->need_delayed_register = false; /* clear again */ } - /* we are allowed to call snd_card_register() many times, but first - * check to see if a device needs to skip it or do anything special + /* register card if we reach to the last interface or to the specified + * one given via option */ - if (!snd_usb_registration_quirk(chip, ifnum) && - !check_delayed_register_option(chip, ifnum)) { + if (check_delayed_register_option(chip) == ifnum || + chip->last_iface == ifnum) { err = snd_card_register(chip->card); if (err < 0) goto __error; diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 194c75c45628..eadac586bcc8 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -2030,48 +2030,6 @@ void snd_usb_audioformat_attributes_quirk(struct snd_usb_audio *chip, } } -/* - * registration quirk: - * the registration is skipped if a device matches with the given ID, - * unless the interface reaches to the defined one. This is for delaying - * the registration until the last known interface, so that the card and - * devices appear at the same time. - */ - -struct registration_quirk { - unsigned int usb_id; /* composed via USB_ID() */ - unsigned int interface; /* the interface to trigger register */ -}; - -#define REG_QUIRK_ENTRY(vendor, product, iface) \ - { .usb_id = USB_ID(vendor, product), .interface = (iface) } - -static const struct registration_quirk registration_quirks[] = { - REG_QUIRK_ENTRY(0x0951, 0x16d8, 2), /* Kingston HyperX AMP */ - REG_QUIRK_ENTRY(0x0951, 0x16ed, 2), /* Kingston HyperX Cloud Alpha S */ - REG_QUIRK_ENTRY(0x0951, 0x16ea, 2), /* Kingston HyperX Cloud Flight S */ - REG_QUIRK_ENTRY(0x0ecb, 0x1f46, 2), /* JBL Quantum 600 */ - REG_QUIRK_ENTRY(0x0ecb, 0x1f47, 2), /* JBL Quantum 800 */ - REG_QUIRK_ENTRY(0x0ecb, 0x1f4c, 2), /* JBL Quantum 400 */ - REG_QUIRK_ENTRY(0x0ecb, 0x2039, 2), /* JBL Quantum 400 */ - REG_QUIRK_ENTRY(0x0ecb, 0x203c, 2), /* JBL Quantum 600 */ - REG_QUIRK_ENTRY(0x0ecb, 0x203e, 2), /* JBL Quantum 800 */ - { 0 } /* terminator */ -}; - -/* return true if skipping registration */ -bool snd_usb_registration_quirk(struct snd_usb_audio *chip, int iface) -{ - const struct registration_quirk *q; - - for (q = registration_quirks; q->usb_id; q++) - if (chip->usb_id == q->usb_id) - return iface < q->interface; - - /* Register as normal */ - return false; -} - /* * driver behavior quirk flags */ diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h index 31abb7cb01a5..f9bfd5ac7bab 100644 --- a/sound/usb/quirks.h +++ b/sound/usb/quirks.h @@ -48,8 +48,6 @@ void snd_usb_audioformat_attributes_quirk(struct snd_usb_audio *chip, struct audioformat *fp, int stream); -bool snd_usb_registration_quirk(struct snd_usb_audio *chip, int iface); - void snd_usb_init_quirk_flags(struct snd_usb_audio *chip); #endif /* __USBAUDIO_QUIRKS_H */ diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index ffbb4b0d09a0..2c6575029b1c 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -37,6 +37,7 @@ struct snd_usb_audio { unsigned int quirk_flags; unsigned int need_delayed_register:1; /* warn for delayed registration */ int num_interfaces; + int last_iface; int num_suspended_intf; int sample_rate_read_error; -- cgit v1.2.3 From 4c8d695cb9bc5f6fd298a586602947b2fc099a64 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 6 Sep 2022 11:23:06 +0200 Subject: ALSA: hda: beep: Simplify keep-power-at-enable behavior The recent fix for IDT codecs to keep the power up while the beep is enabled can be better integrated into the beep helper code. This patch cleans up the code with refactoring. Fixes: 414d38ba8710 ("ALSA: hda/sigmatel: Keep power up while beep is enabled") Link: https://lore.kernel.org/r/20220906092306.26183-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_beep.c | 15 +++++++++++++-- sound/pci/hda/hda_beep.h | 1 + sound/pci/hda/patch_sigmatel.c | 25 ++----------------------- 3 files changed, 16 insertions(+), 25 deletions(-) diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index 53a2b89f8983..e63621bcb214 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -118,6 +118,12 @@ static int snd_hda_beep_event(struct input_dev *dev, unsigned int type, return 0; } +static void turn_on_beep(struct hda_beep *beep) +{ + if (beep->keep_power_at_enable) + snd_hda_power_up_pm(beep->codec); +} + static void turn_off_beep(struct hda_beep *beep) { cancel_work_sync(&beep->beep_work); @@ -125,6 +131,8 @@ static void turn_off_beep(struct hda_beep *beep) /* turn off beep */ generate_tone(beep, 0); } + if (beep->keep_power_at_enable) + snd_hda_power_down_pm(beep->codec); } /** @@ -140,7 +148,9 @@ int snd_hda_enable_beep_device(struct hda_codec *codec, int enable) enable = !!enable; if (beep->enabled != enable) { beep->enabled = enable; - if (!enable) + if (enable) + turn_on_beep(beep); + else turn_off_beep(beep); return 1; } @@ -167,7 +177,8 @@ static int beep_dev_disconnect(struct snd_device *device) input_unregister_device(beep->dev); else input_free_device(beep->dev); - turn_off_beep(beep); + if (beep->enabled) + turn_off_beep(beep); return 0; } diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h index a25358a4807a..db76e3ddba65 100644 --- a/sound/pci/hda/hda_beep.h +++ b/sound/pci/hda/hda_beep.h @@ -25,6 +25,7 @@ struct hda_beep { unsigned int enabled:1; unsigned int linear_tone:1; /* linear tone for IDT/STAC codec */ unsigned int playing:1; + unsigned int keep_power_at_enable:1; /* set by driver */ struct work_struct beep_work; /* scheduled task for beep event */ struct mutex mutex; void (*power_hook)(struct hda_beep *beep, bool on); diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 7f340f18599c..a794a01a68ca 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4311,6 +4311,8 @@ static int stac_parse_auto_config(struct hda_codec *codec) if (codec->beep) { /* IDT/STAC codecs have linear beep tone parameter */ codec->beep->linear_tone = spec->linear_tone_beep; + /* keep power up while beep is enabled */ + codec->beep->keep_power_at_enable = 1; /* if no beep switch is available, make its own one */ caps = query_amp_caps(codec, nid, HDA_OUTPUT); if (!(caps & AC_AMPCAP_MUTE)) { @@ -4444,28 +4446,6 @@ static int stac_suspend(struct hda_codec *codec) return 0; } - -static int stac_check_power_status(struct hda_codec *codec, hda_nid_t nid) -{ -#ifdef CONFIG_SND_HDA_INPUT_BEEP - struct sigmatel_spec *spec = codec->spec; -#endif - int ret = snd_hda_gen_check_power_status(codec, nid); - -#ifdef CONFIG_SND_HDA_INPUT_BEEP - if (nid == spec->gen.beep_nid && codec->beep) { - if (codec->beep->enabled != spec->beep_power_on) { - spec->beep_power_on = codec->beep->enabled; - if (spec->beep_power_on) - snd_hda_power_up_pm(codec); - else - snd_hda_power_down_pm(codec); - } - ret |= spec->beep_power_on; - } -#endif - return ret; -} #else #define stac_suspend NULL #endif /* CONFIG_PM */ @@ -4478,7 +4458,6 @@ static const struct hda_codec_ops stac_patch_ops = { .unsol_event = snd_hda_jack_unsol_event, #ifdef CONFIG_PM .suspend = stac_suspend, - .check_power_status = stac_check_power_status, #endif }; -- cgit v1.2.3 From aca289f7cd233b3c983b43b59cdaa0d934ea3da7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 5 Sep 2022 19:58:25 +0300 Subject: ALSA: hda: cs35l41: Call put_device() in the scope of get_device() When put_device() is called in another function it's hard to realize that and easy to "fix" the code in a wrong way. Instead, move put_device() to be in the same scope as get_device(), so we prevent appearance of any attempts to "fix" the code. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220905165826.35979-1-andriy.shevchenko@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l41_hda.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c index 15e2a0009080..12e955931044 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -1154,7 +1154,6 @@ static int cs35l41_no_acpi_dsd(struct cs35l41_hda *cs35l41, struct device *physd hw_cfg->gpio2.func = CS35L41_INTERRUPT; hw_cfg->gpio2.valid = true; hw_cfg->valid = true; - put_device(physdev); if (strncmp(hid, "CLSA0100", 8) == 0) { hw_cfg->bst_type = CS35L41_EXT_BOOST_NO_VSPK_SWITCH; @@ -1204,9 +1203,10 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i property = "cirrus,dev-index"; ret = device_property_count_u32(physdev, property); - if (ret <= 0) - return cs35l41_no_acpi_dsd(cs35l41, physdev, id, hid); - + if (ret <= 0) { + ret = cs35l41_no_acpi_dsd(cs35l41, physdev, id, hid); + goto err_put_physdev; + } if (ret > ARRAY_SIZE(values)) { ret = -EINVAL; goto err; @@ -1295,8 +1295,9 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i return 0; err: - put_device(physdev); dev_err(cs35l41->dev, "Failed property %s: %d\n", property, ret); +err_put_physdev: + put_device(physdev); return ret; } -- cgit v1.2.3 From 7269734abbf5960d0be9050ba3991c0af1d9f574 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 5 Sep 2022 19:58:26 +0300 Subject: ALSA: hda: cs35l41: Utilize acpi_get_subsystem_id() Replace open coded variant of recently introduced acpi_get_subsystem_id(). Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220905165826.35979-2-andriy.shevchenko@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l41_hda.c | 46 +++++++++------------------------------------ 1 file changed, 9 insertions(+), 37 deletions(-) diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c index 12e955931044..3952f2853703 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -842,8 +842,8 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas comps->dev = dev; if (!cs35l41->acpi_subsystem_id) - cs35l41->acpi_subsystem_id = devm_kasprintf(dev, GFP_KERNEL, "%.8x", - comps->codec->core.subsystem_id); + cs35l41->acpi_subsystem_id = kasprintf(GFP_KERNEL, "%.8x", + comps->codec->core.subsystem_id); cs35l41->codec = comps->codec; strscpy(comps->name, dev_name(dev), sizeof(comps->name)); @@ -1048,36 +1048,6 @@ static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41) return cs35l41_hda_channel_map(cs35l41->dev, 0, NULL, 1, &hw_cfg->spk_pos); } -static int cs35l41_get_acpi_sub_string(struct device *dev, struct acpi_device *adev, - const char **subsysid) -{ - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *obj; - acpi_status status; - int ret = 0; - - status = acpi_evaluate_object(adev->handle, "_SUB", NULL, &buffer); - if (ACPI_SUCCESS(status)) { - obj = buffer.pointer; - if (obj->type == ACPI_TYPE_STRING) { - *subsysid = devm_kstrdup(dev, obj->string.pointer, GFP_KERNEL); - if (*subsysid == NULL) { - dev_err(dev, "Cannot allocate Subsystem ID"); - ret = -ENOMEM; - } - } else { - dev_warn(dev, "Warning ACPI _SUB did not return a string\n"); - ret = -ENODEV; - } - acpi_os_free(buffer.pointer); - } else { - dev_dbg(dev, "Warning ACPI _SUB failed: %#x\n", status); - ret = -ENODEV; - } - - return ret; -} - static int cs35l41_get_speaker_id(struct device *dev, int amp_index, int num_amps, int fixed_gpio_id) { @@ -1182,6 +1152,7 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i u32 values[HDA_MAX_COMPONENTS]; struct acpi_device *adev; struct device *physdev; + const char *sub; char *property; size_t nval; int i, ret; @@ -1195,11 +1166,10 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i physdev = get_device(acpi_get_first_physical_node(adev)); acpi_dev_put(adev); - ret = cs35l41_get_acpi_sub_string(cs35l41->dev, adev, &cs35l41->acpi_subsystem_id); - if (ret) - dev_info(cs35l41->dev, "No Subsystem ID found in ACPI: %d", ret); - else - dev_dbg(cs35l41->dev, "Subsystem ID %s found", cs35l41->acpi_subsystem_id); + sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev)); + if (IS_ERR(sub)) + sub = NULL; + cs35l41->acpi_subsystem_id = sub; property = "cirrus,dev-index"; ret = device_property_count_u32(physdev, property); @@ -1434,6 +1404,7 @@ err: if (cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type)) gpiod_set_value_cansleep(cs35l41->reset_gpio, 0); gpiod_put(cs35l41->reset_gpio); + kfree(cs35l41->acpi_subsystem_id); return ret; } @@ -1456,6 +1427,7 @@ void cs35l41_hda_remove(struct device *dev) if (cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type)) gpiod_set_value_cansleep(cs35l41->reset_gpio, 0); gpiod_put(cs35l41->reset_gpio); + kfree(cs35l41->acpi_subsystem_id); } EXPORT_SYMBOL_NS_GPL(cs35l41_hda_remove, SND_HDA_SCODEC_CS35L41); -- cgit v1.2.3 From 64ec924c781ee846bd469be8d1d6bbed78c0f439 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Tue, 6 Sep 2022 11:27:23 +0200 Subject: ASoC: mediatek: mt8195-mt6359: Properly register sound card for SOF Adding a probe callback on this snd_soc_card is required when Sound Open Firmware support is desired, as we need to appropriately populate the stream_name for SOF to be able to bind widgets. Failing to do so will produce errors when applying the SOF topology leading to card registration failure (so, no sound). While at it, also make sure to fill the topology_shortname as required. Fixes: 0caf1120c583 ("ASoC: mediatek: mt8195: extract SOF common code") Signed-off-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220906092727.37324-2-angelogioacchino.delregno@collabora.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8195/mt8195-mt6359.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359.c b/sound/soc/mediatek/mt8195/mt8195-mt6359.c index c530e3fc27e4..961e769602d6 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359.c @@ -1383,7 +1383,13 @@ static int mt8195_mt6359_dev_probe(struct platform_device *pdev) sof_priv->num_streams = ARRAY_SIZE(g_sof_conn_streams); sof_priv->sof_dai_link_fixup = mt8195_dai_link_fixup; soc_card_data->sof_priv = sof_priv; + card->probe = mtk_sof_card_probe; card->late_probe = mtk_sof_card_late_probe; + if (!card->topology_shortname_created) { + snprintf(card->topology_shortname, 32, "sof-%s", card->name); + card->topology_shortname_created = true; + } + card->name = card->topology_shortname; sof_on = 1; } -- cgit v1.2.3 From 404bec4c8f6c38ae5fa208344f1086d38026e93d Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Tue, 6 Sep 2022 11:27:24 +0200 Subject: ASoC: SOF: mediatek: mt8195: Import namespace SND_SOC_SOF_MTK_COMMON Here we're using function mtk_adsp_dump() from mtk-adsp-common: explicitly import its namespace. Fixes: 3a054f90e955 ("ASoC: SOF: mediatek: Add mt8195 debug dump") Signed-off-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220906092727.37324-3-angelogioacchino.delregno@collabora.com Signed-off-by: Mark Brown --- sound/soc/sof/mediatek/mt8195/mt8195.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index 9c146015cd1b..ff575de7e46a 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -652,4 +652,5 @@ static struct platform_driver snd_sof_of_mt8195_driver = { module_platform_driver(snd_sof_of_mt8195_driver); MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); +MODULE_IMPORT_NS(SND_SOC_SOF_MTK_COMMON); MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3 From c2186a9b3a98f1ff814996aa52a019158bfad9c9 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Tue, 6 Sep 2022 11:27:25 +0200 Subject: ASoC: SOF: mediatek: mt8195: Add mailbox generic callbacks for IPC Add the .mailbox_{read,write} generic callbacks for SOF IPC and, while at it, also change the ipc_msg_data callback to use the SOF API sof_ipc_msg_data() instead of the custom function mt8195_ipc_msg_data(). Signed-off-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220906092727.37324-4-angelogioacchino.delregno@collabora.com Signed-off-by: Mark Brown --- sound/soc/sof/mediatek/mt8195/mt8195.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index ff575de7e46a..68747ee21c6f 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -496,14 +496,6 @@ static int mt8195_get_bar_index(struct snd_sof_dev *sdev, u32 type) return type; } -static int mt8195_ipc_msg_data(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream, - void *p, size_t sz) -{ - sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); - return 0; -} - static void mt8195_adsp_dump(struct snd_sof_dev *sdev, u32 flags) { u32 dbg_pc, dbg_data, dbg_bus0, dbg_bus1, dbg_inst; @@ -574,6 +566,10 @@ static struct snd_sof_dsp_ops sof_mt8195_ops = { .block_read = sof_block_read, .block_write = sof_block_write, + /* Mailbox IO */ + .mailbox_read = sof_mailbox_read, + .mailbox_write = sof_mailbox_write, + /* Register IO */ .write = sof_io_write, .read = sof_io_read, @@ -584,7 +580,7 @@ static struct snd_sof_dsp_ops sof_mt8195_ops = { .send_msg = mt8195_send_msg, .get_mailbox_offset = mt8195_get_mailbox_offset, .get_window_offset = mt8195_get_window_offset, - .ipc_msg_data = mt8195_ipc_msg_data, + .ipc_msg_data = sof_ipc_msg_data, .set_stream_data_offset = sof_set_stream_data_offset, /* misc */ -- cgit v1.2.3 From cf84edeeb95ee8e76f12bb02a7444876d031bea7 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Tue, 6 Sep 2022 11:27:26 +0200 Subject: ASoC: SOF: mediatek: mt8195: Add generic pcm_{open,close} callbacks Use the generic sof_stream_pcm_{open,close}() functions for the pcm_{open,close} callbacks. Signed-off-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220906092727.37324-5-angelogioacchino.delregno@collabora.com Signed-off-by: Mark Brown --- sound/soc/sof/mediatek/mt8195/mt8195.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index 68747ee21c6f..c1590e78edd4 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -586,6 +586,10 @@ static struct snd_sof_dsp_ops sof_mt8195_ops = { /* misc */ .get_bar_index = mt8195_get_bar_index, + /* stream callbacks */ + .pcm_open = sof_stream_pcm_open, + .pcm_close = sof_stream_pcm_close, + /* firmware loading */ .load_firmware = snd_sof_load_firmware_memcpy, -- cgit v1.2.3 From 8a7d5d85ed2161869452ddb9ec45345dad665f52 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Tue, 6 Sep 2022 11:27:27 +0200 Subject: ASoC: SOF: mediatek: mt8195: Add devicetree support to select topologies Support devicetree by adding a snd_soc_of_mach array, specifying SOF topologies for a generic MT8195 machine and for Google Tomato Chromebooks. Signed-off-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220906092727.37324-6-angelogioacchino.delregno@collabora.com Signed-off-by: Mark Brown --- sound/soc/sof/mediatek/mt8195/mt8195.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index c1590e78edd4..c12192c8a6f8 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -615,7 +615,20 @@ static struct snd_sof_dsp_ops sof_mt8195_ops = { SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, }; +static struct snd_sof_of_mach sof_mt8195_machs[] = { + { + .compatible = "google,tomato", + .sof_tplg_filename = "sof-mt8195-mt6359-rt1019-rt5682-dts.tplg" + }, { + .compatible = "mediatek,mt8195", + .sof_tplg_filename = "sof-mt8195.tplg" + }, { + /* sentinel */ + } +}; + static const struct sof_dev_desc sof_of_mt8195_desc = { + .of_machines = sof_mt8195_machs, .ipc_supported_mask = BIT(SOF_IPC), .ipc_default = SOF_IPC, .default_fw_path = { -- cgit v1.2.3 From 355beeed9319cf3ceea56c7dec874a8a9c443771 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 6 Sep 2022 12:06:09 -0700 Subject: ASoC: simple-card-utils: switch to using gpiod API This patch switches the driver away from legacy gpio/of_gpio API to gpiod API, and removes use of of_get_named_gpio_flags() which I want to make private to gpiolib. Signed-off-by: Dmitry Torokhov Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/YxeaITtlJexygQo9@google.com Signed-off-by: Mark Brown --- sound/soc/generic/simple-card-utils.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 1b201dd09259..bef16833c487 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -729,12 +728,12 @@ int asoc_simple_init_jack(struct snd_soc_card *card, char *pin) { struct device *dev = card->dev; - enum of_gpio_flags flags; + struct gpio_desc *desc; char prop[128]; char *pin_name; char *gpio_name; int mask; - int det; + int error; if (!prefix) prefix = ""; @@ -742,36 +741,39 @@ int asoc_simple_init_jack(struct snd_soc_card *card, sjack->gpio.gpio = -ENOENT; if (is_hp) { - snprintf(prop, sizeof(prop), "%shp-det-gpio", prefix); + snprintf(prop, sizeof(prop), "%shp-det", prefix); pin_name = pin ? pin : "Headphones"; gpio_name = "Headphone detection"; mask = SND_JACK_HEADPHONE; } else { - snprintf(prop, sizeof(prop), "%smic-det-gpio", prefix); + snprintf(prop, sizeof(prop), "%smic-det", prefix); pin_name = pin ? pin : "Mic Jack"; gpio_name = "Mic detection"; mask = SND_JACK_MICROPHONE; } - det = of_get_named_gpio_flags(dev->of_node, prop, 0, &flags); - if (det == -EPROBE_DEFER) - return -EPROBE_DEFER; + desc = gpiod_get_optional(dev, prop, GPIOD_IN); + error = PTR_ERR_OR_ZERO(desc); + if (error) + return error; + + if (desc) { + error = gpiod_set_consumer_name(desc, gpio_name); + if (error) + return error; - if (gpio_is_valid(det)) { sjack->pin.pin = pin_name; sjack->pin.mask = mask; sjack->gpio.name = gpio_name; sjack->gpio.report = mask; - sjack->gpio.gpio = det; - sjack->gpio.invert = !!(flags & OF_GPIO_ACTIVE_LOW); + sjack->gpio.desc = desc; sjack->gpio.debounce_time = 150; snd_soc_card_jack_new_pins(card, pin_name, mask, &sjack->jack, &sjack->pin, 1); - snd_soc_jack_add_gpios(&sjack->jack, 1, - &sjack->gpio); + snd_soc_jack_add_gpios(&sjack->jack, 1, &sjack->gpio); } return 0; -- cgit v1.2.3 From e9d967679e803e7472f06642156f0bb029e26655 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 6 Sep 2022 14:11:10 +0200 Subject: ASoC: dt-bindings: qcom,q6core: remove binding qcom,q6core is already described in soc/qcom/qcom,apr.yaml. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220906121110.301900-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/qcom,q6core.txt | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/qcom,q6core.txt diff --git a/Documentation/devicetree/bindings/sound/qcom,q6core.txt b/Documentation/devicetree/bindings/sound/qcom,q6core.txt deleted file mode 100644 index 5cd4cc9b1fde..000000000000 --- a/Documentation/devicetree/bindings/sound/qcom,q6core.txt +++ /dev/null @@ -1,21 +0,0 @@ -Qualcomm ADSP Core service binding - -Q6CORE is one of the APR audio service on Q6DSP. -Please refer to qcom,apr.txt for details of the common apr service bindings -used by the apr service device. - -- but must contain the following property: - -- compatible: - Usage: required - Value type: - Definition: must be "qcom,q6core-v.". - Or "qcom,q6core" where the version number can be queried - from DSP. - example "qcom,q6core-v2.0" - -= EXAMPLE -apr-service@3 { - compatible = "qcom,q6core"; - reg = ; -}; -- cgit v1.2.3 From 427de091a7112aa8eaf2f689e95c0dbca5ea6543 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 5 Sep 2022 23:17:43 +0000 Subject: ASoC: soc-dapm.c: don't use WARN_ON() at snd_soc_dai_link_event_pre_pmu() Current snd_soc_dai_link_event_pre_pmu() is checking "config". It is using dev_err() (A) if it was NULL, so we don't need to use WARN_ON() (B) to check it, it is over-kill. This patch removes it. (B) if (WARN_ON(!config)) { (A) dev_err(...); ... } Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87zgfd8l7s.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 73b8bd452ca7..02924395ed86 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3885,7 +3885,7 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, * necessary */ config = rtd->dai_link->params + rtd->params_select; - if (WARN_ON(!config)) { + if (!config) { dev_err(w->dapm->dev, "ASoC: link config missing\n"); ret = -EINVAL; goto out; -- cgit v1.2.3 From 3caac759681eeb31ac80e3cc14b972680c8bde54 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 5 Sep 2022 23:17:57 +0000 Subject: ASoC: soc-dapm.c: fixup snd_soc_dapm_new_control_unlocked() error handling Current snd_soc_dapm_new_control_unlocked() error handling is wrong. It is using "goto request_failed" (A), but error message is using "w->name" (B) which is not yet created in such timing. snd_soc_dapm_new_control_unlocked(xxx) { ... switch (w->id) { case xxx: ... if (IS_ERR(...)) { ret = PTR_ERR(...); (A) goto request_failed; } ... } prefix = soc_dapm_prefix(...); if (prefix) (B) w->name = kasprintf(...); else (B) w->name = kstrdup_const(...); ... (A) request_failed: if (ret != -EPROBE_DEFER) (B) dev_err(..., w->name, ...); return ...; } we can create "w->name" at beginning of this function. In such case, we need to call kfree_const(w->name) at error case. This patch do these. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87wnah8l7e.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 02924395ed86..76615d59e2b6 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3630,10 +3630,18 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, enum snd_soc_dapm_direction dir; struct snd_soc_dapm_widget *w; const char *prefix; - int ret; + int ret = -ENOMEM; if ((w = dapm_cnew_widget(widget)) == NULL) - return ERR_PTR(-ENOMEM); + goto cnew_failed; + + prefix = soc_dapm_prefix(dapm); + if (prefix) + w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name); + else + w->name = kstrdup_const(widget->name, GFP_KERNEL); + if (!w->name) + goto name_failed; switch (w->id) { case snd_soc_dapm_regulator_supply: @@ -3672,17 +3680,6 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, break; } - prefix = soc_dapm_prefix(dapm); - if (prefix) - w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name); - else - w->name = kstrdup_const(widget->name, GFP_KERNEL); - if (w->name == NULL) { - kfree_const(w->sname); - kfree(w); - return ERR_PTR(-ENOMEM); - } - switch (w->id) { case snd_soc_dapm_mic: w->is_ep = SND_SOC_DAPM_EP_SOURCE; @@ -3770,9 +3767,11 @@ request_failed: if (ret != -EPROBE_DEFER) dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n", w->name, ret); - + kfree_const(w->name); +name_failed: kfree_const(w->sname); kfree(w); +cnew_failed: return ERR_PTR(ret); } -- cgit v1.2.3 From 6ef8443fb1ced148417d830894240a097ba79a03 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Sep 2022 02:45:12 +0000 Subject: ASoC: soc-dapm.c: add comment for kzalloc()/kfree() on snd_soc_dai_link_event_pre_pmu() snd_soc_dai_link_event_pre_pmu() is using kzalloc()/kfree() for params. It looks we don't need to use these, but are necessary. But, it is difficult to know why it is necessary without any comments. This patch adds the reasons via comment. Link: https://lore.kernel.org/all/Yxc2wzbZsSVZNf8Y@sirena.org.uk/ Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/878rmubn47.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 76615d59e2b6..fc2f75ed190d 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3842,6 +3842,15 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, unsigned int fmt; int ret = 0; + /* + * NOTE + * + * snd_pcm_hw_params is quite large (608 bytes on arm64) and is + * starting to get a bit excessive for allocation on the stack, + * especially when you're building with some of the KASAN type + * stuff that increases stack usage. + * So, we use kzalloc()/kfree() for params in this function. + */ params = kzalloc(sizeof(*params), GFP_KERNEL); if (!params) return -ENOMEM; @@ -3939,7 +3948,9 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, runtime->rate = params_rate(params); out: + /* see above NOTE */ kfree(params); + return ret; } -- cgit v1.2.3 From 59a1063dcaa5c9450dc1d221679418747bf086fc Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Sep 2022 02:45:27 +0000 Subject: ASoC: soc-dapm.c: tidyup snd_soc_dai_link_event_pre_pmu() snd_soc_dai_link_event_pre_pmu() is using if/else for config->formats check, but "else" case is for just error. Unnecessary if/else is not good for readable code. this patch checks if config->formats was zero as error case. Moreover, we don't need to indicate config->formats value in error message, because it is zero. This patch tidyup it, too. => if (config->formats) { ... } else { dev_warn(w->dapm->dev, "ASoC: Invalid format %llx specified\n", => config->formats); ... } Link: https://lore.kernel.org/all/YxiDkDOwRsbXeZ17@sirena.org.uk/ Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/877d2ebn3t.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index fc2f75ed190d..47a7bf99472e 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3900,16 +3900,15 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, } /* Be a little careful as we don't want to overflow the mask array */ - if (config->formats) { - fmt = ffs(config->formats) - 1; - } else { - dev_warn(w->dapm->dev, "ASoC: Invalid format %llx specified\n", - config->formats); + if (!config->formats) { + dev_warn(w->dapm->dev, "ASoC: Invalid format was specified\n"); ret = -EINVAL; goto out; } + fmt = ffs(config->formats) - 1; + snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt); hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min = config->rate_min; -- cgit v1.2.3 From 6ac246105b4fd737ed51b8ac3ef031f837686dee Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Thu, 8 Sep 2022 15:03:59 +0900 Subject: ASoC: max98390: Remove unnecessary amp on/off conrtol The Amp is already control in userspace before trigger calibrate function. Remove unnecessary control in calibrate function and add condition to check calibration is ready. Signed-off-by: Steve Lee Link: https://lore.kernel.org/r/20220908060359.13606-1-steve.lee.analog@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/max98390.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c index 5c08166a8dc6..4ef8cd1053af 100644 --- a/sound/soc/codecs/max98390.c +++ b/sound/soc/codecs/max98390.c @@ -635,10 +635,19 @@ static int max98390_dsm_calib_get(struct snd_kcontrol *kcontrol, static int max98390_dsm_calib_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + unsigned int val; struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct max98390_priv *max98390 = + snd_soc_component_get_drvdata(component); - max98390_dsm_calibrate(component); + regmap_read(max98390->regmap, MAX98390_R23FF_GLOBAL_EN, &val); + if (val == 0x1) + max98390_dsm_calibrate(component); + else { + dev_err(component->dev, "AMP is not ready to run calibration\n"); + return -ECANCELED; + } return 0; } @@ -826,9 +835,6 @@ static int max98390_dsm_calibrate(struct snd_soc_component *component) struct max98390_priv *max98390 = snd_soc_component_get_drvdata(component); - regmap_write(max98390->regmap, MAX98390_R203A_AMP_EN, 0x81); - regmap_write(max98390->regmap, MAX98390_R23FF_GLOBAL_EN, 0x01); - regmap_read(max98390->regmap, THERMAL_RDC_RD_BACK_BYTE1, &rdc); regmap_read(max98390->regmap, @@ -847,9 +853,6 @@ static int max98390_dsm_calibrate(struct snd_soc_component *component) dev_info(component->dev, "rdc resistance about %d.%02d ohm, reg=0x%X temp reg=0x%X\n", rdc_integer, rdc_factor, rdc_cal_result, temp); - regmap_write(max98390->regmap, MAX98390_R23FF_GLOBAL_EN, 0x00); - regmap_write(max98390->regmap, MAX98390_R203A_AMP_EN, 0x80); - return 0; } -- cgit v1.2.3 From b075f21e533aa51c2bda87d86ddfb6a3c0e38a92 Mon Sep 17 00:00:00 2001 From: ye xingchen Date: Thu, 8 Sep 2022 01:03:04 +0000 Subject: ASoC: sti-sas: Remove the unneeded result variable Return the value regmap_write() and sti_sas_init_sas_registers() directly instead of storing it in another redundant variable. Reported-by: Zeal Robot Signed-off-by: ye xingchen Link: https://lore.kernel.org/r/20220908010304.342760-1-ye.xingchen@zte.com.cn Signed-off-by: Mark Brown --- sound/soc/codecs/sti-sas.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c index f076878908ee..99545bcb2ba9 100644 --- a/sound/soc/codecs/sti-sas.c +++ b/sound/soc/codecs/sti-sas.c @@ -96,11 +96,8 @@ static int sti_sas_write_reg(void *context, unsigned int reg, unsigned int value) { struct sti_sas_data *drvdata = context; - int status; - - status = regmap_write(drvdata->dac.regmap, reg, value); - return status; + return regmap_write(drvdata->dac.regmap, reg, value); } static int sti_sas_init_sas_registers(struct snd_soc_component *component, @@ -385,11 +382,8 @@ static int sti_sas_resume(struct snd_soc_component *component) static int sti_sas_component_probe(struct snd_soc_component *component) { struct sti_sas_data *drvdata = dev_get_drvdata(component->dev); - int ret; - ret = sti_sas_init_sas_registers(component, drvdata); - - return ret; + return sti_sas_init_sas_registers(component, drvdata); } static struct snd_soc_component_driver sti_sas_driver = { -- cgit v1.2.3 From e9e7df88996d64544178f48b0299dfe736c6aa22 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Thu, 8 Sep 2022 15:31:56 +0800 Subject: ASoC: ak4458: Remove component probe() and remove() Most function in ak4458_probe() and ak4458_remove() are duplicate with dai ops, so remove them and move dsd_path setting to dai ops. Signed-off-by: Shengjiu Wang Reviewed-by: Daniel Baluta Link: https://lore.kernel.org/r/1662622316-23426-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/codecs/ak4458.c | 53 +++++++---------------------------------------- 1 file changed, 7 insertions(+), 46 deletions(-) diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c index ea33cc83c86c..b534212096ee 100644 --- a/sound/soc/codecs/ak4458.c +++ b/sound/soc/codecs/ak4458.c @@ -447,6 +447,13 @@ static int ak4458_hw_params(struct snd_pcm_substream *substream, snd_soc_component_update_bits(component, AK4458_0B_CONTROL7, AK4458_DCHAIN_MASK, dchn); + if (ak4458->drvdata->type == AK4497) { + ret = snd_soc_component_update_bits(component, AK4458_09_DSD2, + 0x4, (ak4458->dsd_path << 2)); + if (ret < 0) + return ret; + } + ret = ak4458_rstn_control(component, 0); if (ret) return ret; @@ -629,48 +636,6 @@ static void ak4458_reset(struct ak4458_priv *ak4458, bool active) } } -static int ak4458_init(struct snd_soc_component *component) -{ - struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component); - int ret; - - /* External Mute ON */ - if (ak4458->mute_gpiod) - gpiod_set_value_cansleep(ak4458->mute_gpiod, 1); - - ak4458_reset(ak4458, false); - - ret = snd_soc_component_update_bits(component, AK4458_00_CONTROL1, - 0x80, 0x80); /* ACKS bit = 1; 10000000 */ - if (ret < 0) - return ret; - - if (ak4458->drvdata->type == AK4497) { - ret = snd_soc_component_update_bits(component, AK4458_09_DSD2, - 0x4, (ak4458->dsd_path << 2)); - if (ret < 0) - return ret; - } - - return ak4458_rstn_control(component, 1); -} - -static int ak4458_probe(struct snd_soc_component *component) -{ - struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component); - - ak4458->fs = 48000; - - return ak4458_init(component); -} - -static void ak4458_remove(struct snd_soc_component *component) -{ - struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component); - - ak4458_reset(ak4458, true); -} - #ifdef CONFIG_PM static int __maybe_unused ak4458_runtime_suspend(struct device *dev) { @@ -714,8 +679,6 @@ static int __maybe_unused ak4458_runtime_resume(struct device *dev) #endif /* CONFIG_PM */ static const struct snd_soc_component_driver soc_codec_dev_ak4458 = { - .probe = ak4458_probe, - .remove = ak4458_remove, .controls = ak4458_snd_controls, .num_controls = ARRAY_SIZE(ak4458_snd_controls), .dapm_widgets = ak4458_dapm_widgets, @@ -728,8 +691,6 @@ static const struct snd_soc_component_driver soc_codec_dev_ak4458 = { }; static const struct snd_soc_component_driver soc_codec_dev_ak4497 = { - .probe = ak4458_probe, - .remove = ak4458_remove, .controls = ak4497_snd_controls, .num_controls = ARRAY_SIZE(ak4497_snd_controls), .dapm_widgets = ak4497_dapm_widgets, -- cgit v1.2.3 From a0e3a293bc001f5aba8a252b6191030ad5911c82 Mon Sep 17 00:00:00 2001 From: Gaosheng Cui Date: Fri, 9 Sep 2022 11:54:42 +0800 Subject: ALSA: line6: remove line6_set_raw declaration line6_set_raw has been removed since commit 9f673d7a6022 ("staging: line6: drop CONFIG_LINE6_USB_RAW"), so remove it. Signed-off-by: Gaosheng Cui Link: https://lore.kernel.org/r/20220909035443.1065737-2-cuigaosheng1@huawei.com Signed-off-by: Takashi Iwai --- sound/usb/line6/driver.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/usb/line6/driver.h b/sound/usb/line6/driver.h index ecf3a2b39c7e..dbb1d90d3647 100644 --- a/sound/usb/line6/driver.h +++ b/sound/usb/line6/driver.h @@ -193,8 +193,6 @@ extern int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer, int size); extern int line6_send_sysex_message(struct usb_line6 *line6, const char *buffer, int size); -extern ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count); extern int line6_version_request_async(struct usb_line6 *line6); extern int line6_write_data(struct usb_line6 *line6, unsigned address, void *data, unsigned datalen); -- cgit v1.2.3 From 5a55b51a3dea50c8b700cdde0aeb75e0a388486b Mon Sep 17 00:00:00 2001 From: Gaosheng Cui Date: Fri, 9 Sep 2022 11:54:43 +0800 Subject: ALSA: memalloc: remove snd_dma_sg_ops declaration snd_dma_sg_ops has been removed since commit 2c95b92ecd92 ("ALSA: memalloc: Unify x86 SG-buffer handling (take#3)"), so remove it. Signed-off-by: Gaosheng Cui Link: https://lore.kernel.org/r/20220909035443.1065737-3-cuigaosheng1@huawei.com Signed-off-by: Takashi Iwai --- sound/core/memalloc_local.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/core/memalloc_local.h b/sound/core/memalloc_local.h index a6f3a87194da..8b19f3a68a4b 100644 --- a/sound/core/memalloc_local.h +++ b/sound/core/memalloc_local.h @@ -13,8 +13,4 @@ struct snd_malloc_ops { void (*sync)(struct snd_dma_buffer *dmab, enum snd_dma_sync_mode mode); }; -#ifdef CONFIG_SND_DMA_SGBUF -extern const struct snd_malloc_ops snd_dma_sg_ops; -#endif - #endif /* __MEMALLOC_LOCAL_H */ -- cgit v1.2.3 From 5b4fc3956bfda2da22a6f7f25b157ad24ba1cd95 Mon Sep 17 00:00:00 2001 From: Gaosheng Cui Date: Fri, 9 Sep 2022 14:11:26 +0800 Subject: sound: oss: dmasound: remove software_input_volume declaration expand_read_bal has been removed since commit fc37449f7959 ("The next round of scheduled OSS code removal"). software_input_volume has been removed since commit 0a1b42db4bf9 ("sound: sound/oss/dmasound/: cleanups"). so remove the declare for them from header file. Signed-off-by: Gaosheng Cui Link: https://lore.kernel.org/r/20220909061126.1129585-1-cuigaosheng1@huawei.com Signed-off-by: Takashi Iwai --- sound/oss/dmasound/dmasound.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/oss/dmasound/dmasound.h b/sound/oss/dmasound/dmasound.h index ad8ce6a1c25c..f065840c0efb 100644 --- a/sound/oss/dmasound/dmasound.h +++ b/sound/oss/dmasound/dmasound.h @@ -250,7 +250,4 @@ extern int dmasound_catchRadius; #define SW_INPUT_VOLUME_SCALE 4 #define SW_INPUT_VOLUME_DEFAULT (128 / SW_INPUT_VOLUME_SCALE) -extern int expand_read_bal; /* Balance factor for reading */ -extern uint software_input_volume; /* software implemented recording volume! */ - #endif /* _dmasound_h_ */ -- cgit v1.2.3 From 621a3f772be5cfcd472880aa12ccb10d4c7afae3 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 9 Sep 2022 14:43:26 +0300 Subject: ASoC: SOF: ipc4: Only print LOG BUFFER update message info if requested Do not print messages when the SOF_DBG_PRINT_DMA_POSITION_UPDATE_LOGS flag is not set to reduce the amount of prints when the tracing is used. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220909114332.31393-2-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c index 432b812bdf9c..1c51938ce43b 100644 --- a/sound/soc/sof/ipc4.c +++ b/sound/soc/sof/ipc4.c @@ -205,6 +205,11 @@ static void sof_ipc4_log_header(struct device *dev, u8 *text, struct sof_ipc4_ms /* Notification message */ u32 notif = SOF_IPC4_NOTIFICATION_TYPE_GET(msg->primary); + /* Do not print log buffer notification if not desired */ + if (notif == SOF_IPC4_NOTIFY_LOG_BUFFER_STATUS && + !sof_debug_check_flag(SOF_DBG_PRINT_DMA_POSITION_UPDATE_LOGS)) + return; + if (notif < SOF_IPC4_NOTIFY_TYPE_LAST) str2 = ipc4_dbg_notification_type[notif]; if (!str2) @@ -234,6 +239,13 @@ static void sof_ipc4_log_header(struct device *dev, u8 *text, struct sof_ipc4_ms static void sof_ipc4_log_header(struct device *dev, u8 *text, struct sof_ipc4_msg *msg, bool data_size_valid) { + /* Do not print log buffer notification if not desired */ + if (!sof_debug_check_flag(SOF_DBG_PRINT_DMA_POSITION_UPDATE_LOGS) && + !SOF_IPC4_MSG_IS_MODULE_MSG(msg->primary) && + SOF_IPC4_MSG_TYPE_GET(msg->primary) == SOF_IPC4_GLB_NOTIFICATION && + SOF_IPC4_NOTIFICATION_TYPE_GET(msg->primary) == SOF_IPC4_NOTIFY_LOG_BUFFER_STATUS) + return; + if (data_size_valid && msg->data_size) dev_dbg(dev, "%s: %#x|%#x [data size: %zu]\n", text, msg->primary, msg->extension, msg->data_size); -- cgit v1.2.3 From e9bcfea156b4d8563109c17c033fa496f0ec4995 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 9 Sep 2022 14:43:27 +0300 Subject: ASoC: SOF: ipc4: Add macro to get core ID from log buffer status message The LOG_BUFFER_STATUS message includes the ID of the core which updated its log buffer. With IPC4 each core logs to a different slot in the debug window. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220909114332.31393-3-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/ipc4/header.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/sound/sof/ipc4/header.h b/include/sound/sof/ipc4/header.h index a795deacc2ea..99efe0ef1784 100644 --- a/include/sound/sof/ipc4/header.h +++ b/include/sound/sof/ipc4/header.h @@ -427,6 +427,11 @@ struct sof_ipc4_dx_state_info { #define SOF_IPC4_NOTIFICATION_TYPE_GET(x) (((x) & SOF_IPC4_NOTIFICATION_TYPE_MASK) >> \ SOF_IPC4_NOTIFICATION_TYPE_SHIFT) +#define SOF_IPC4_LOG_CORE_SHIFT 12 +#define SOF_IPC4_LOG_CORE_MASK GENMASK(15, 12) +#define SOF_IPC4_LOG_CORE_GET(x) (((x) & SOF_IPC4_LOG_CORE_MASK) >> \ + SOF_IPC4_LOG_CORE_SHIFT) + /* Value of notification type field - must fit into 8 bits */ enum sof_ipc4_notification_type { /* Phrase detected (notification from WoV module) */ -- cgit v1.2.3 From b59f1532e0b17f22965e327f86d04292f496ccaf Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 9 Sep 2022 14:43:28 +0300 Subject: ASoC: SOF: ipc4: Add define for the outbox window index Instead of using the index number directly, add a define for the outbox window index. It is always window 1 with IPC4. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220909114332.31393-4-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-priv.h | 3 +++ sound/soc/sof/ipc4.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h index 9492fe1796c2..f3dbcc2e6331 100644 --- a/sound/soc/sof/ipc4-priv.h +++ b/sound/soc/sof/ipc4-priv.h @@ -13,6 +13,9 @@ #include #include "sof-priv.h" +/* The DSP window indices are fixed */ +#define SOF_IPC4_OUTBOX_WINDOW_IDX 1 + /** * struct sof_ipc4_fw_data - IPC4-specific data * @manifest_fw_hdr_offset: FW header offset in the manifest diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c index 1c51938ce43b..58aa054663bf 100644 --- a/sound/soc/sof/ipc4.c +++ b/sound/soc/sof/ipc4.c @@ -537,7 +537,7 @@ static int ipc4_fw_ready(struct snd_sof_dev *sdev, struct sof_ipc4_msg *ipc4_msg return inbox_offset; } inbox_size = SOF_IPC4_MSG_MAX_SIZE; - outbox_offset = snd_sof_dsp_get_window_offset(sdev, 1); + outbox_offset = snd_sof_dsp_get_window_offset(sdev, SOF_IPC4_OUTBOX_WINDOW_IDX); outbox_size = SOF_IPC4_MSG_MAX_SIZE; sdev->dsp_box.offset = inbox_offset; -- cgit v1.2.3 From a5d0147ac9f8ea6c08d00b28f0468c9cb3fdfde8 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 9 Sep 2022 14:43:29 +0300 Subject: ASoC: SOF: ipc4: Configure the debug box offset The debug window for IPC4 compatible firmware is always window #2, set the debug_box.offset accordingly. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220909114332.31393-5-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-priv.h | 1 + sound/soc/sof/ipc4.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h index f3dbcc2e6331..4599dd95f17d 100644 --- a/sound/soc/sof/ipc4-priv.h +++ b/sound/soc/sof/ipc4-priv.h @@ -15,6 +15,7 @@ /* The DSP window indices are fixed */ #define SOF_IPC4_OUTBOX_WINDOW_IDX 1 +#define SOF_IPC4_DEBUG_WINDOW_IDX 2 /** * struct sof_ipc4_fw_data - IPC4-specific data diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c index 58aa054663bf..4f7ec18ae7fa 100644 --- a/sound/soc/sof/ipc4.c +++ b/sound/soc/sof/ipc4.c @@ -545,10 +545,14 @@ static int ipc4_fw_ready(struct snd_sof_dev *sdev, struct sof_ipc4_msg *ipc4_msg sdev->host_box.offset = outbox_offset; sdev->host_box.size = outbox_size; + sdev->debug_box.offset = snd_sof_dsp_get_window_offset(sdev, + SOF_IPC4_DEBUG_WINDOW_IDX); + dev_dbg(sdev->dev, "mailbox upstream 0x%x - size 0x%x\n", inbox_offset, inbox_size); dev_dbg(sdev->dev, "mailbox downstream 0x%x - size 0x%x\n", outbox_offset, outbox_size); + dev_dbg(sdev->dev, "debug box 0x%x\n", sdev->debug_box.offset); return sof_ipc4_init_msg_memory(sdev); } -- cgit v1.2.3 From f4ea22f7aa7536560097d765be56445933d07e0d Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 9 Sep 2022 14:43:30 +0300 Subject: ASoC: SOF: ipc4: Add support for mtrace log extraction One of the debugging/logging features for an IPC4 based firmware is the use of the debug window to deliver log messages to host via the shared SRAM. The initial implementation of the mtrace supports only TGL/MTL style of logging, but can be extended to support other types, like APL, SKL, CNL, etc. The window is split into 16 'slots' where the first slot contains the descriptors for the remaining 15 slots. Each DSP core logs to a separate slot and the slot allocation is not fixed, we can not assume that the first slot is always used by core0 for example. The firmware sends LOG_BUFFER_STATUS message when new log batch is available from one of the cores (after it updated the write_ptr in the given slot). Host should update the read_ptr in the same slot when it has taken out log data. The patch also updates the sof_ipc4_fw_data struct with parameters needed for the mtrace to be enabled and used safely. Co-developed-by: Rander Wang Signed-off-by: Rander Wang Co-developed-by: Bard Liao Signed-off-by: Bard Liao Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220909114332.31393-6-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/Makefile | 3 +- sound/soc/sof/ipc4-loader.c | 2 + sound/soc/sof/ipc4-mtrace.c | 643 ++++++++++++++++++++++++++++++++++++++++++++ sound/soc/sof/ipc4-priv.h | 14 +- sound/soc/sof/ipc4.c | 4 + 5 files changed, 664 insertions(+), 2 deletions(-) create mode 100644 sound/soc/sof/ipc4-mtrace.c diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 9a74ed116ed9..eab7cc53f71a 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -9,7 +9,8 @@ snd-sof-objs += ipc3.o ipc3-loader.o ipc3-topology.o ipc3-control.o ipc3-pcm.o\ ipc3-dtrace.o endif ifneq ($(CONFIG_SND_SOC_SOF_INTEL_IPC4),) -snd-sof-objs += ipc4.o ipc4-loader.o ipc4-topology.o ipc4-control.o ipc4-pcm.o +snd-sof-objs += ipc4.o ipc4-loader.o ipc4-topology.o ipc4-control.o ipc4-pcm.o\ + ipc4-mtrace.o endif # SOF client support diff --git a/sound/soc/sof/ipc4-loader.c b/sound/soc/sof/ipc4-loader.c index 8bd2132b4f41..c678f05d0ef5 100644 --- a/sound/soc/sof/ipc4-loader.c +++ b/sound/soc/sof/ipc4-loader.c @@ -157,6 +157,7 @@ static int sof_ipc4_validate_firmware(struct snd_sof_dev *sdev) static int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev) { + struct sof_ipc4_fw_data *ipc4_data = sdev->private; const struct sof_ipc_ops *iops = sdev->ipc->ops; struct sof_ipc4_fw_version *fw_ver; struct sof_ipc4_tuple *tuple; @@ -200,6 +201,7 @@ static int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev) break; case SOF_IPC4_FW_CFG_TRACE_LOG_BYTES: dev_vdbg(sdev->dev, "Trace log size: %u\n", *tuple->value); + ipc4_data->mtrace_log_bytes = *tuple->value; break; default: break; diff --git a/sound/soc/sof/ipc4-mtrace.c b/sound/soc/sof/ipc4-mtrace.c new file mode 100644 index 000000000000..9c7080041d08 --- /dev/null +++ b/sound/soc/sof/ipc4-mtrace.c @@ -0,0 +1,643 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2022 Intel Corporation. All rights reserved. + +#include +#include +#include +#include "sof-priv.h" +#include "ipc4-priv.h" + +/* + * debug info window is organized in 16 (equal sized) pages: + * + * ------------------------ + * | Page0 - descriptors | + * ------------------------ + * | Page1 - slot0 | + * ------------------------ + * | Page2 - slot1 | + * ------------------------ + * | ... | + * ------------------------ + * | Page14 - slot13 | + * ------------------------ + * | Page15 - slot14 | + * ------------------------ + * + * The slot size == page size + * + * The first page contains descriptors for the remaining 15 cores + * The slot descriptor is: + * u32 res_id; + * u32 type; + * u32 vma; + * + * Log buffer slots have the following layout: + * u32 host_read_ptr; + * u32 dsp_write_ptr; + * u8 buffer[]; + * + * The two pointers are offsets within the buffer. + */ + +#define SOF_MTRACE_DESCRIPTOR_SIZE 12 /* 3 x u32 */ + +#define FW_EPOCH_DELTA 11644473600LL + +#define INVALID_SLOT_OFFSET 0xffffffff +#define MAX_ALLOWED_LIBRARIES 16 +#define MAX_MTRACE_SLOTS 15 + +#define SOF_MTRACE_PAGE_SIZE 0x1000 +#define SOF_MTRACE_SLOT_SIZE SOF_MTRACE_PAGE_SIZE + +/* debug log slot types */ +#define SOF_MTRACE_SLOT_UNUSED 0x00000000 +#define SOF_MTRACE_SLOT_CRITICAL_LOG 0x54524300 /* byte 0: core ID */ +#define SOF_MTRACE_SLOT_DEBUG_LOG 0x474f4c00 /* byte 0: core ID */ +#define SOF_MTRACE_SLOT_GDB_STUB 0x42444700 +#define SOF_MTRACE_SLOT_TELEMETRY 0x4c455400 +#define SOF_MTRACE_SLOT_BROKEN 0x44414544 + /* for debug and critical types */ +#define SOF_MTRACE_SLOT_CORE_MASK GENMASK(7, 0) +#define SOF_MTRACE_SLOT_TYPE_MASK GENMASK(31, 8) + +#define DEFAULT_AGING_TIMER_PERIOD_MS 0x100 +#define DEFAULT_FIFO_FULL_TIMER_PERIOD_MS 0x1000 + +/* ipc4 log level and source definitions for logs_priorities_mask */ +#define SOF_MTRACE_LOG_LEVEL_CRITICAL BIT(0) +#define SOF_MTRACE_LOG_LEVEL_ERROR BIT(1) +#define SOF_MTRACE_LOG_LEVEL_WARNING BIT(2) +#define SOF_MTRACE_LOG_LEVEL_INFO BIT(3) +#define SOF_MTRACE_LOG_LEVEL_VERBOSE BIT(4) +#define SOF_MTRACE_LOG_SOURCE_INFRA BIT(5) /* log source 0 */ +#define SOF_MTRACE_LOG_SOURCE_HAL BIT(6) +#define SOF_MTRACE_LOG_SOURCE_MODULE BIT(7) +#define SOF_MTRACE_LOG_SOURCE_AUDIO BIT(8) +#define SOF_MTRACE_LOG_SOURCE_SCHEDULER BIT(9) +#define SOF_MTRACE_LOG_SOURCE_ULP_INFRA BIT(10) +#define SOF_MTRACE_LOG_SOURCE_ULP_MODULE BIT(11) +#define SOF_MTRACE_LOG_SOURCE_VISION BIT(12) /* log source 7 */ +#define DEFAULT_LOGS_PRIORITIES_MASK (SOF_MTRACE_LOG_LEVEL_CRITICAL | \ + SOF_MTRACE_LOG_LEVEL_ERROR | \ + SOF_MTRACE_LOG_LEVEL_WARNING | \ + SOF_MTRACE_LOG_LEVEL_INFO | \ + SOF_MTRACE_LOG_SOURCE_INFRA | \ + SOF_MTRACE_LOG_SOURCE_HAL | \ + SOF_MTRACE_LOG_SOURCE_MODULE | \ + SOF_MTRACE_LOG_SOURCE_AUDIO) + +struct sof_log_state_info { + u32 aging_timer_period; + u32 fifo_full_timer_period; + u32 enable; + u32 logs_priorities_mask[MAX_ALLOWED_LIBRARIES]; +} __packed; + +enum sof_mtrace_state { + SOF_MTRACE_DISABLED, + SOF_MTRACE_INITIALIZING, + SOF_MTRACE_ENABLED, +}; + +struct sof_mtrace_core_data { + struct snd_sof_dev *sdev; + + int id; + u32 slot_offset; + void *log_buffer; + u32 host_read_ptr; + u32 dsp_write_ptr; + /* pos update IPC arrived before the slot offset is known, queried */ + bool delayed_pos_update; + wait_queue_head_t trace_sleep; +}; + +struct sof_mtrace_priv { + struct snd_sof_dev *sdev; + enum sof_mtrace_state mtrace_state; + struct sof_log_state_info state_info; + + struct sof_mtrace_core_data cores[]; +}; + +static int sof_ipc4_mtrace_dfs_open(struct inode *inode, struct file *file) +{ + struct sof_mtrace_core_data *core_data = inode->i_private; + int ret; + + ret = debugfs_file_get(file->f_path.dentry); + if (unlikely(ret)) + return ret; + + core_data->log_buffer = kmalloc(SOF_MTRACE_SLOT_SIZE, GFP_KERNEL); + if (!core_data->log_buffer) { + debugfs_file_put(file->f_path.dentry); + return -ENOMEM; + } + + ret = simple_open(inode, file); + if (ret) { + kfree(core_data->log_buffer); + debugfs_file_put(file->f_path.dentry); + } + + return ret; +} + +static bool sof_wait_mtrace_avail(struct sof_mtrace_core_data *core_data) +{ + wait_queue_entry_t wait; + + /* data immediately available */ + if (core_data->host_read_ptr != core_data->dsp_write_ptr) + return true; + + /* wait for available trace data from FW */ + init_waitqueue_entry(&wait, current); + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&core_data->trace_sleep, &wait); + + if (!signal_pending(current)) { + /* set timeout to max value, no error code */ + schedule_timeout(MAX_SCHEDULE_TIMEOUT); + } + remove_wait_queue(&core_data->trace_sleep, &wait); + + if (core_data->host_read_ptr != core_data->dsp_write_ptr) + return true; + + return false; +} + +static ssize_t sof_ipc4_mtrace_dfs_read(struct file *file, char __user *buffer, + size_t count, loff_t *ppos) +{ + struct sof_mtrace_core_data *core_data = file->private_data; + u32 log_buffer_offset, log_buffer_size, read_ptr, write_ptr; + struct snd_sof_dev *sdev = core_data->sdev; + struct sof_mtrace_priv *priv = sdev->fw_trace_data; + void *log_buffer = core_data->log_buffer; + loff_t lpos = *ppos; + u32 avail; + int ret; + + /* check pos and count */ + if (lpos < 0) + return -EINVAL; + if (!count || count < sizeof(avail)) + return 0; + + /* get available count based on current host offset */ + if (!sof_wait_mtrace_avail(core_data)) { + /* No data available */ + avail = 0; + if (copy_to_user(buffer, &avail, sizeof(avail))) + return -EFAULT; + + return 0; + } + + if (core_data->slot_offset == INVALID_SLOT_OFFSET) + return 0; + + /* The log data buffer starts after the two pointer in the slot */ + log_buffer_offset = core_data->slot_offset + (sizeof(u32) * 2); + /* The log data size excludes the pointers */ + log_buffer_size = SOF_MTRACE_SLOT_SIZE - (sizeof(u32) * 2); + + read_ptr = core_data->host_read_ptr; + write_ptr = core_data->dsp_write_ptr; + + if (read_ptr < write_ptr) + avail = write_ptr - read_ptr; + else + avail = log_buffer_size - read_ptr + write_ptr; + + if (!avail) + return 0; + + if (avail > log_buffer_size) + avail = log_buffer_size; + + /* Need space for the initial u32 of the avail */ + if (avail > count - sizeof(avail)) + avail = count - sizeof(avail); + + if (sof_debug_check_flag(SOF_DBG_PRINT_DMA_POSITION_UPDATE_LOGS)) + dev_dbg(sdev->dev, + "core%d, host read: %#x, dsp write: %#x, avail: %#x\n", + core_data->id, read_ptr, write_ptr, avail); + + if (read_ptr < write_ptr) { + /* Read data between read pointer and write pointer */ + sof_mailbox_read(sdev, log_buffer_offset + read_ptr, log_buffer, avail); + } else { + /* read from read pointer to end of the slot */ + sof_mailbox_read(sdev, log_buffer_offset + read_ptr, log_buffer, + avail - write_ptr); + /* read from slot start to write pointer */ + if (write_ptr) + sof_mailbox_read(sdev, log_buffer_offset, + (u8 *)(log_buffer) + avail - write_ptr, + write_ptr); + } + + /* first write the number of bytes we have gathered */ + ret = copy_to_user(buffer, &avail, sizeof(avail)); + if (ret) + return -EFAULT; + + /* Followed by the data itself */ + ret = copy_to_user(buffer + sizeof(avail), log_buffer, avail); + if (ret) + return -EFAULT; + + /* Update the host_read_ptr in the slot for this core */ + read_ptr += avail; + if (read_ptr >= log_buffer_size) + read_ptr -= log_buffer_size; + sof_mailbox_write(sdev, core_data->slot_offset, &read_ptr, sizeof(read_ptr)); + + /* Only update the host_read_ptr if mtrace is enabled */ + if (priv->mtrace_state != SOF_MTRACE_DISABLED) + core_data->host_read_ptr = read_ptr; + + /* + * Ask for a new buffer from user space for the next chunk, not + * streaming due to the heading number of bytes value. + */ + *ppos += count; + + return count; +} + +static int sof_ipc4_mtrace_dfs_release(struct inode *inode, struct file *file) +{ + struct sof_mtrace_core_data *core_data = inode->i_private; + + debugfs_file_put(file->f_path.dentry); + + kfree(core_data->log_buffer); + + return 0; +} + +static const struct file_operations sof_dfs_mtrace_fops = { + .open = sof_ipc4_mtrace_dfs_open, + .read = sof_ipc4_mtrace_dfs_read, + .llseek = default_llseek, + .release = sof_ipc4_mtrace_dfs_release, + + .owner = THIS_MODULE, +}; + +static ssize_t sof_ipc4_priority_mask_dfs_read(struct file *file, char __user *to, + size_t count, loff_t *ppos) +{ + struct sof_mtrace_priv *priv = file->private_data; + int i, ret, offset, remaining; + char *buf; + + /* + * one entry (14 char + new line = 15): + * " 0: 000001ef" + * + * 16 * 15 + 1 = 241 + */ + buf = kzalloc(241, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + for (i = 0; i < MAX_ALLOWED_LIBRARIES; i++) { + offset = strlen(buf); + remaining = 241 - offset; + snprintf(buf + offset, remaining, "%2d: 0x%08x\n", i, + priv->state_info.logs_priorities_mask[i]); + } + + ret = simple_read_from_buffer(to, count, ppos, buf, strlen(buf)); + + kfree(buf); + return ret; +} + +static ssize_t sof_ipc4_priority_mask_dfs_write(struct file *file, + const char __user *from, + size_t count, loff_t *ppos) +{ + struct sof_mtrace_priv *priv = file->private_data; + int id, ret; + char *buf; + u32 mask; + + /* + * To update Nth mask entry, write: + * "N,0x1234" or "N,1234" to the debugfs file + * The mask will be interpreted as hexadecimal number + */ + buf = memdup_user_nul(from, count); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + ret = sscanf(buf, "%d,0x%x", &id, &mask); + if (ret != 2) { + ret = sscanf(buf, "%d,%x", &id, &mask); + if (ret != 2) { + ret = -EINVAL; + goto out; + } + } + + if (id >= MAX_ALLOWED_LIBRARIES) { + ret = -EINVAL; + goto out; + } + + priv->state_info.logs_priorities_mask[id] = mask; + ret = count; + +out: + kfree(buf); + return ret; +} + +static const struct file_operations sof_dfs_priority_mask_fops = { + .open = simple_open, + .read = sof_ipc4_priority_mask_dfs_read, + .write = sof_ipc4_priority_mask_dfs_write, + .llseek = default_llseek, + + .owner = THIS_MODULE, +}; + +static int mtrace_debugfs_create(struct snd_sof_dev *sdev) +{ + struct sof_mtrace_priv *priv = sdev->fw_trace_data; + struct dentry *dfs_root; + char dfs_name[100]; + int i; + + dfs_root = debugfs_create_dir("mtrace", sdev->debugfs_root); + if (IS_ERR_OR_NULL(dfs_root)) + return 0; + + /* Create files for the logging parameters */ + debugfs_create_u32("aging_timer_period", 0644, dfs_root, + &priv->state_info.aging_timer_period); + debugfs_create_u32("fifo_full_timer_period", 0644, dfs_root, + &priv->state_info.fifo_full_timer_period); + debugfs_create_file("logs_priorities_mask", 0644, dfs_root, priv, + &sof_dfs_priority_mask_fops); + + /* Separate log files per core */ + for (i = 0; i < sdev->num_cores; i++) { + snprintf(dfs_name, sizeof(dfs_name), "core%d", i); + debugfs_create_file(dfs_name, 0444, dfs_root, &priv->cores[i], + &sof_dfs_mtrace_fops); + } + + return 0; +} + +static int ipc4_mtrace_enable(struct snd_sof_dev *sdev) +{ + struct sof_mtrace_priv *priv = sdev->fw_trace_data; + const struct sof_ipc_ops *iops = sdev->ipc->ops; + struct sof_ipc4_msg msg; + u64 system_time; + ktime_t kt; + int ret; + + if (priv->mtrace_state != SOF_MTRACE_DISABLED) + return 0; + + msg.primary = SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); + msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); + msg.primary |= SOF_IPC4_MOD_ID(SOF_IPC4_MOD_INIT_BASEFW_MOD_ID); + msg.primary |= SOF_IPC4_MOD_INSTANCE(SOF_IPC4_MOD_INIT_BASEFW_INSTANCE_ID); + msg.extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_FW_PARAM_SYSTEM_TIME); + + /* The system time is in usec, UTC, epoch is 1601-01-01 00:00:00 */ + kt = ktime_add_us(ktime_get_real(), FW_EPOCH_DELTA * USEC_PER_SEC); + system_time = ktime_to_us(kt); + msg.data_size = sizeof(system_time); + msg.data_ptr = &system_time; + ret = iops->set_get_data(sdev, &msg, msg.data_size, true); + if (ret) + return ret; + + msg.extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_FW_PARAM_ENABLE_LOGS); + + priv->state_info.enable = 1; + + msg.data_size = sizeof(priv->state_info); + msg.data_ptr = &priv->state_info; + + priv->mtrace_state = SOF_MTRACE_INITIALIZING; + ret = iops->set_get_data(sdev, &msg, msg.data_size, true); + if (ret) { + priv->mtrace_state = SOF_MTRACE_DISABLED; + return ret; + } + + priv->mtrace_state = SOF_MTRACE_ENABLED; + + return 0; +} + +static void ipc4_mtrace_disable(struct snd_sof_dev *sdev) +{ + struct sof_mtrace_priv *priv = sdev->fw_trace_data; + const struct sof_ipc_ops *iops = sdev->ipc->ops; + struct sof_ipc4_msg msg; + int i; + + if (priv->mtrace_state == SOF_MTRACE_DISABLED) + return; + + msg.primary = SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); + msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); + msg.primary |= SOF_IPC4_MOD_ID(SOF_IPC4_MOD_INIT_BASEFW_MOD_ID); + msg.primary |= SOF_IPC4_MOD_INSTANCE(SOF_IPC4_MOD_INIT_BASEFW_INSTANCE_ID); + msg.extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_FW_PARAM_ENABLE_LOGS); + + priv->state_info.enable = 0; + + msg.data_size = sizeof(priv->state_info); + msg.data_ptr = &priv->state_info; + iops->set_get_data(sdev, &msg, msg.data_size, true); + + priv->mtrace_state = SOF_MTRACE_DISABLED; + + for (i = 0; i < sdev->num_cores; i++) { + struct sof_mtrace_core_data *core_data = &priv->cores[i]; + + core_data->host_read_ptr = 0; + core_data->dsp_write_ptr = 0; + wake_up(&core_data->trace_sleep); + } +} + +/* + * Each DSP core logs to a dedicated slot. + * Parse the slot descriptors at debug_box offset to find the debug log slots + * and map them to cores. + * There are 15 slots and therefore 15 descriptors to check (MAX_MTRACE_SLOTS) + */ +static void sof_mtrace_find_core_slots(struct snd_sof_dev *sdev) +{ + struct sof_mtrace_priv *priv = sdev->fw_trace_data; + struct sof_mtrace_core_data *core_data; + u32 slot_desc_type_offset, type, core; + int i; + + for (i = 0; i < MAX_MTRACE_SLOTS; i++) { + /* The type is the second u32 in the slot descriptor */ + slot_desc_type_offset = sdev->debug_box.offset; + slot_desc_type_offset += SOF_MTRACE_DESCRIPTOR_SIZE * i + sizeof(u32); + sof_mailbox_read(sdev, slot_desc_type_offset, &type, sizeof(type)); + + if ((type & SOF_MTRACE_SLOT_TYPE_MASK) == SOF_MTRACE_SLOT_DEBUG_LOG) { + core = type & SOF_MTRACE_SLOT_CORE_MASK; + + if (core >= sdev->num_cores) { + dev_dbg(sdev->dev, "core%u is invalid for slot%d\n", + core, i); + continue; + } + + core_data = &priv->cores[core]; + /* + * The area reserved for descriptors have the same size + * as a slot. + * In other words: slot0 starts at + * debug_box + SOF_MTRACE_SLOT_SIZE offset + */ + core_data->slot_offset = sdev->debug_box.offset; + core_data->slot_offset += SOF_MTRACE_SLOT_SIZE * (i + 1); + dev_dbg(sdev->dev, "slot%d is used for core%u\n", i, core); + if (core_data->delayed_pos_update) { + sof_ipc4_mtrace_update_pos(sdev, core); + core_data->delayed_pos_update = false; + } + } else if (type) { + dev_dbg(sdev->dev, "slot%d is not a log slot (%#x)\n", i, type); + } + } +} + +static int ipc4_mtrace_init(struct snd_sof_dev *sdev) +{ + struct sof_ipc4_fw_data *ipc4_data = sdev->private; + struct sof_mtrace_priv *priv; + int i, ret; + + if (sdev->fw_trace_data) { + dev_err(sdev->dev, "fw_trace_data has been already allocated\n"); + return -EBUSY; + } + + if (!ipc4_data->mtrace_log_bytes || + ipc4_data->mtrace_type != SOF_IPC4_MTRACE_INTEL_CAVS_2) { + sdev->fw_trace_is_supported = false; + return 0; + } + + priv = devm_kzalloc(sdev->dev, struct_size(priv, cores, sdev->num_cores), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + sdev->fw_trace_data = priv; + + /* Set initial values for mtrace parameters */ + priv->state_info.aging_timer_period = DEFAULT_AGING_TIMER_PERIOD_MS; + priv->state_info.fifo_full_timer_period = DEFAULT_FIFO_FULL_TIMER_PERIOD_MS; + /* Only enable basefw logs initially (index 0 is always basefw) */ + priv->state_info.logs_priorities_mask[0] = DEFAULT_LOGS_PRIORITIES_MASK; + + for (i = 0; i < sdev->num_cores; i++) { + struct sof_mtrace_core_data *core_data = &priv->cores[i]; + + init_waitqueue_head(&core_data->trace_sleep); + core_data->sdev = sdev; + core_data->id = i; + } + + ret = ipc4_mtrace_enable(sdev); + if (ret) { + /* + * Mark firmware tracing as not supported and return 0 to not + * block the whole audio stack + */ + sdev->fw_trace_is_supported = false; + dev_dbg(sdev->dev, "initialization failed, fw tracing is disabled\n"); + return 0; + } + + sof_mtrace_find_core_slots(sdev); + + ret = mtrace_debugfs_create(sdev); + if (ret) + ipc4_mtrace_disable(sdev); + + return ret; +} + +static void ipc4_mtrace_free(struct snd_sof_dev *sdev) +{ + ipc4_mtrace_disable(sdev); +} + +int sof_ipc4_mtrace_update_pos(struct snd_sof_dev *sdev, int core) +{ + struct sof_mtrace_priv *priv = sdev->fw_trace_data; + struct sof_mtrace_core_data *core_data; + + if (!sdev->fw_trace_is_supported || + priv->mtrace_state == SOF_MTRACE_DISABLED) + return 0; + + if (core >= sdev->num_cores) + return -EINVAL; + + core_data = &priv->cores[core]; + + if (core_data->slot_offset == INVALID_SLOT_OFFSET) { + core_data->delayed_pos_update = true; + return 0; + } + + /* Read out the dsp_write_ptr from the slot for this core */ + sof_mailbox_read(sdev, core_data->slot_offset + sizeof(u32), + &core_data->dsp_write_ptr, 4); + core_data->dsp_write_ptr -= core_data->dsp_write_ptr % 4; + + if (sof_debug_check_flag(SOF_DBG_PRINT_DMA_POSITION_UPDATE_LOGS)) + dev_dbg(sdev->dev, "core%d, host read: %#x, dsp write: %#x", + core, core_data->host_read_ptr, core_data->dsp_write_ptr); + + wake_up(&core_data->trace_sleep); + + return 0; +} + +static int ipc4_mtrace_resume(struct snd_sof_dev *sdev) +{ + return ipc4_mtrace_enable(sdev); +} + +static void ipc4_mtrace_suspend(struct snd_sof_dev *sdev, pm_message_t pm_state) +{ + ipc4_mtrace_disable(sdev); +} + +const struct sof_ipc_fw_tracing_ops ipc4_mtrace_ops = { + .init = ipc4_mtrace_init, + .free = ipc4_mtrace_free, + .suspend = ipc4_mtrace_suspend, + .resume = ipc4_mtrace_resume, +}; diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h index 4599dd95f17d..e3b8484a2f1f 100644 --- a/sound/soc/sof/ipc4-priv.h +++ b/sound/soc/sof/ipc4-priv.h @@ -17,18 +17,29 @@ #define SOF_IPC4_OUTBOX_WINDOW_IDX 1 #define SOF_IPC4_DEBUG_WINDOW_IDX 2 +enum sof_ipc4_mtrace_type { + SOF_IPC4_MTRACE_NOT_AVAILABLE = 0, + SOF_IPC4_MTRACE_INTEL_CAVS_1_5, + SOF_IPC4_MTRACE_INTEL_CAVS_1_8, + SOF_IPC4_MTRACE_INTEL_CAVS_2, +}; + /** * struct sof_ipc4_fw_data - IPC4-specific data * @manifest_fw_hdr_offset: FW header offset in the manifest * @num_fw_modules : Number of modules in base FW * @fw_modules: Array of base FW modules * @nhlt: NHLT table either from the BIOS or the topology manifest + * @mtrace_type: mtrace type supported on the booted platform + * @mtrace_log_bytes: log bytes as reported by the firmware via fw_config reply */ struct sof_ipc4_fw_data { u32 manifest_fw_hdr_offset; int num_fw_modules; void *fw_modules; void *nhlt; + enum sof_ipc4_mtrace_type mtrace_type; + u32 mtrace_log_bytes; }; /** @@ -49,7 +60,8 @@ extern const struct sof_ipc_fw_loader_ops ipc4_loader_ops; extern const struct sof_ipc_tplg_ops ipc4_tplg_ops; extern const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops; extern const struct sof_ipc_pcm_ops ipc4_pcm_ops; +extern const struct sof_ipc_fw_tracing_ops ipc4_mtrace_ops; int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state); - +int sof_ipc4_mtrace_update_pos(struct snd_sof_dev *sdev, int core); #endif diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c index 4f7ec18ae7fa..0d830020556d 100644 --- a/sound/soc/sof/ipc4.c +++ b/sound/soc/sof/ipc4.c @@ -589,6 +589,9 @@ static void sof_ipc4_rx_msg(struct snd_sof_dev *sdev) case SOF_IPC4_NOTIFY_RESOURCE_EVENT: data_size = sizeof(struct sof_ipc4_notify_resource_data); break; + case SOF_IPC4_NOTIFY_LOG_BUFFER_STATUS: + sof_ipc4_mtrace_update_pos(sdev, SOF_IPC4_LOG_CORE_GET(ipc4_msg->primary)); + break; default: dev_dbg(sdev->dev, "Unhandled DSP message: %#x|%#x\n", ipc4_msg->primary, ipc4_msg->extension); @@ -662,4 +665,5 @@ const struct sof_ipc_ops ipc4_ops = { .fw_loader = &ipc4_loader_ops, .tplg = &ipc4_tplg_ops, .pcm = &ipc4_pcm_ops, + .fw_tracing = &ipc4_mtrace_ops, }; -- cgit v1.2.3 From 9ee71a31602fe72111b7a2d188ff84f7ead4cf92 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 9 Sep 2022 14:43:31 +0300 Subject: ASoC: SOF: Intel: icl: Set IPC4-specific DSP ops Add implementation of low level, platform dependent IPC4 message handling and set the DSP ops for IPC4 for ICL platform. Suggested-by: Rander Wang Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220909114332.31393-7-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/icl.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c index 4e37b7fe0627..6a8af2d3b580 100644 --- a/sound/soc/sof/intel/icl.c +++ b/sound/soc/sof/intel/icl.c @@ -13,6 +13,7 @@ #include #include #include +#include "../ipc4-priv.h" #include "../ops.h" #include "hda.h" #include "hda-ipc.h" @@ -106,11 +107,30 @@ int sof_icl_ops_init(struct snd_sof_dev *sdev) /* probe/remove/shutdown */ sof_icl_ops.shutdown = hda_dsp_shutdown; - /* doorbell */ - sof_icl_ops.irq_thread = cnl_ipc_irq_thread; + if (sdev->pdata->ipc_type == SOF_IPC) { + /* doorbell */ + sof_icl_ops.irq_thread = cnl_ipc_irq_thread; - /* ipc */ - sof_icl_ops.send_msg = cnl_ipc_send_msg; + /* ipc */ + sof_icl_ops.send_msg = cnl_ipc_send_msg; + } + + if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) { + struct sof_ipc4_fw_data *ipc4_data; + + sdev->private = devm_kzalloc(sdev->dev, sizeof(*ipc4_data), GFP_KERNEL); + if (!sdev->private) + return -ENOMEM; + + ipc4_data = sdev->private; + ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET; + + /* doorbell */ + sof_icl_ops.irq_thread = cnl_ipc4_irq_thread; + + /* ipc */ + sof_icl_ops.send_msg = cnl_ipc4_send_msg; + } /* debug */ sof_icl_ops.debug_map = icl_dsp_debugfs; -- cgit v1.2.3 From cc4a3a19b986aa13a488c8f319e413e85308f403 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 9 Sep 2022 14:43:32 +0300 Subject: ASoC: SOF: Intel: Add mtrace type information for IPC4 Set the mtrace type for platforms supported by IPC4. Note: currently only SOF_IPC4_MTRACE_INTEL_CAVS_2 type is supported by the ipc4-mtrace driver, which is used by CAVS 2.x platforms (ICL, TGL, ADL) and ACE (MTL). Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220909114332.31393-8-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/apl.c | 2 ++ sound/soc/sof/intel/cnl.c | 2 ++ sound/soc/sof/intel/icl.c | 2 ++ sound/soc/sof/intel/mtl.c | 2 ++ sound/soc/sof/intel/tgl.c | 2 ++ 5 files changed, 10 insertions(+) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 084c245a9522..295df44be271 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -57,6 +57,8 @@ int sof_apl_ops_init(struct snd_sof_dev *sdev) ipc4_data = sdev->private; ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET; + ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_1_5; + /* doorbell */ sof_apl_ops.irq_thread = hda_dsp_ipc4_irq_thread; diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index a064453f0bc3..0bb91df27280 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -366,6 +366,8 @@ int sof_cnl_ops_init(struct snd_sof_dev *sdev) ipc4_data = sdev->private; ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET; + ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_1_8; + /* doorbell */ sof_cnl_ops.irq_thread = cnl_ipc4_irq_thread; diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c index 6a8af2d3b580..59ce3132fada 100644 --- a/sound/soc/sof/intel/icl.c +++ b/sound/soc/sof/intel/icl.c @@ -125,6 +125,8 @@ int sof_icl_ops_init(struct snd_sof_dev *sdev) ipc4_data = sdev->private; ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET; + ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2; + /* doorbell */ sof_icl_ops.irq_thread = cnl_ipc4_irq_thread; diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index 96239ebb1eed..1cc1398336e1 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -764,6 +764,8 @@ int sof_mtl_ops_init(struct snd_sof_dev *sdev) ipc4_data = sdev->private; ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET; + ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2; + /* set DAI ops */ hda_set_dai_drv_ops(sdev, &sof_mtl_ops); diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c index 6dfb4786c782..017bf331ed5a 100644 --- a/sound/soc/sof/intel/tgl.c +++ b/sound/soc/sof/intel/tgl.c @@ -80,6 +80,8 @@ int sof_tgl_ops_init(struct snd_sof_dev *sdev) ipc4_data = sdev->private; ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET; + ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2; + /* doorbell */ sof_tgl_ops.irq_thread = cnl_ipc4_irq_thread; -- cgit v1.2.3 From 8ae4fcfd5b11b5c33154732fcad99ad0f5843ce2 Mon Sep 17 00:00:00 2001 From: "Nícolas F. R. A. Prado" Date: Thu, 8 Sep 2022 12:11:45 -0400 Subject: ASoC: mediatek: mt8192: Allow setting shared clocks from machine driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new function to configure the shared clock between two i2s ports, and export it. This will allow the clock sharing to be set from the machine driver instead of the devicetree. Signed-off-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Tested-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220908161154.648557-2-nfraprado@collabora.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8192/mt8192-afe-common.h | 3 +++ sound/soc/mediatek/mt8192/mt8192-dai-i2s.c | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-common.h b/sound/soc/mediatek/mt8192/mt8192-afe-common.h index d55eff46cc7f..ad461dcb6ee1 100644 --- a/sound/soc/mediatek/mt8192/mt8192-afe-common.h +++ b/sound/soc/mediatek/mt8192/mt8192-afe-common.h @@ -159,6 +159,9 @@ int mt8192_dai_src_register(struct mtk_base_afe *afe); int mt8192_dai_pcm_register(struct mtk_base_afe *afe); int mt8192_dai_tdm_register(struct mtk_base_afe *afe); +int mt8192_dai_i2s_set_share(struct mtk_base_afe *afe, const char *main_i2s_name, + const char *secondary_i2s_name); + unsigned int mt8192_general_rate_transform(struct device *dev, unsigned int rate); unsigned int mt8192_rate_transform(struct device *dev, diff --git a/sound/soc/mediatek/mt8192/mt8192-dai-i2s.c b/sound/soc/mediatek/mt8192/mt8192-dai-i2s.c index 5b29340f9516..630ed7261fc3 100644 --- a/sound/soc/mediatek/mt8192/mt8192-dai-i2s.c +++ b/sound/soc/mediatek/mt8192/mt8192-dai-i2s.c @@ -2057,6 +2057,32 @@ static int mt8192_dai_i2s_get_share(struct mtk_base_afe *afe) return 0; } +/** + * mt8192_dai_i2s_set_share() - Set up I2S ports to share a single clock. + * @afe: Pointer to &struct mtk_base_afe + * @main_i2s_name: The name of the I2S port that will provide the clock + * @secondary_i2s_name: The name of the I2S port that will use this clock + */ +int mt8192_dai_i2s_set_share(struct mtk_base_afe *afe, const char *main_i2s_name, + const char *secondary_i2s_name) +{ + struct mtk_afe_i2s_priv *secondary_i2s_priv; + int main_i2s_id; + + secondary_i2s_priv = get_i2s_priv_by_name(afe, secondary_i2s_name); + if (!secondary_i2s_priv) + return -EINVAL; + + main_i2s_id = get_i2s_id_by_name(afe, main_i2s_name); + if (main_i2s_id < 0) + return main_i2s_id; + + secondary_i2s_priv->share_i2s_id = main_i2s_id; + + return 0; +} +EXPORT_SYMBOL_GPL(mt8192_dai_i2s_set_share); + static int mt8192_dai_i2s_set_priv(struct mtk_base_afe *afe) { int i; -- cgit v1.2.3 From 3ffb9fa3963964a730c34f48e502ac0625efc145 Mon Sep 17 00:00:00 2001 From: "Nícolas F. R. A. Prado" Date: Thu, 8 Sep 2022 12:11:46 -0400 Subject: ASoC: mediatek: mt8192-mt6359: Make i2s9 share the clock from i2s8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both i2s8 and i2s9 are connected to the rt5682 codec and should share the same clock to work in a full-duplex manner. Set the clock sharing during the initialization for rt5682. Signed-off-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Tested-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220908161154.648557-3-nfraprado@collabora.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c index d0f9d66627b1..044d6ab71f0a 100644 --- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c +++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c @@ -311,12 +311,21 @@ static int mt8192_mt6359_init(struct snd_soc_pcm_runtime *rtd) static int mt8192_rt5682_init(struct snd_soc_pcm_runtime *rtd) { + 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 snd_soc_component *cmpnt_codec = asoc_rtd_to_codec(rtd, 0)->component; struct mt8192_mt6359_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_jack *jack = &priv->headset_jack; int ret; + ret = mt8192_dai_i2s_set_share(afe, "I2S8", "I2S9"); + if (ret) { + dev_err(rtd->dev, "Failed to set up shared clocks\n"); + return ret; + } + 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 | -- cgit v1.2.3 From 9ccd51ce396a46d9d4d0c87aa6a82dd26a2f281a Mon Sep 17 00:00:00 2001 From: "Nícolas F. R. A. Prado" Date: Thu, 8 Sep 2022 12:11:47 -0400 Subject: ASoC: mediatek: mt8192: Remove clock share parsing from DT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the clock sharing for i2s ports can be configured from the sound machine driver, remove the logic that was used to parse the properties from the devicetree. Signed-off-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Tested-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220908161154.648557-4-nfraprado@collabora.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8192/mt8192-dai-i2s.c | 35 ------------------------------ 1 file changed, 35 deletions(-) diff --git a/sound/soc/mediatek/mt8192/mt8192-dai-i2s.c b/sound/soc/mediatek/mt8192/mt8192-dai-i2s.c index 630ed7261fc3..ea516d63d94d 100644 --- a/sound/soc/mediatek/mt8192/mt8192-dai-i2s.c +++ b/sound/soc/mediatek/mt8192/mt8192-dai-i2s.c @@ -45,7 +45,6 @@ struct mtk_afe_i2s_priv { int rate; /* for determine which apll to use */ int low_jitter_en; - const char *share_property_name; int share_i2s_id; int mclk_id; @@ -1984,79 +1983,50 @@ static const struct mtk_afe_i2s_priv mt8192_i2s_priv[DAI_I2S_NUM] = { [DAI_I2S0] = { .id = MT8192_DAI_I2S_0, .mclk_id = MT8192_I2S0_MCK, - .share_property_name = "i2s0-share", .share_i2s_id = -1, }, [DAI_I2S1] = { .id = MT8192_DAI_I2S_1, .mclk_id = MT8192_I2S1_MCK, - .share_property_name = "i2s1-share", .share_i2s_id = -1, }, [DAI_I2S2] = { .id = MT8192_DAI_I2S_2, .mclk_id = MT8192_I2S2_MCK, - .share_property_name = "i2s2-share", .share_i2s_id = -1, }, [DAI_I2S3] = { .id = MT8192_DAI_I2S_3, .mclk_id = MT8192_I2S3_MCK, - .share_property_name = "i2s3-share", .share_i2s_id = -1, }, [DAI_I2S5] = { .id = MT8192_DAI_I2S_5, .mclk_id = MT8192_I2S5_MCK, - .share_property_name = "i2s5-share", .share_i2s_id = -1, }, [DAI_I2S6] = { .id = MT8192_DAI_I2S_6, .mclk_id = MT8192_I2S6_MCK, - .share_property_name = "i2s6-share", .share_i2s_id = -1, }, [DAI_I2S7] = { .id = MT8192_DAI_I2S_7, .mclk_id = MT8192_I2S7_MCK, - .share_property_name = "i2s7-share", .share_i2s_id = -1, }, [DAI_I2S8] = { .id = MT8192_DAI_I2S_8, .mclk_id = MT8192_I2S8_MCK, - .share_property_name = "i2s8-share", .share_i2s_id = -1, }, [DAI_I2S9] = { .id = MT8192_DAI_I2S_9, .mclk_id = MT8192_I2S9_MCK, - .share_property_name = "i2s9-share", .share_i2s_id = -1, }, }; -static int mt8192_dai_i2s_get_share(struct mtk_base_afe *afe) -{ - struct mt8192_afe_private *afe_priv = afe->platform_priv; - const struct device_node *of_node = afe->dev->of_node; - const char *of_str; - const char *property_name; - struct mtk_afe_i2s_priv *i2s_priv; - int i; - - for (i = 0; i < DAI_I2S_NUM; i++) { - i2s_priv = afe_priv->dai_priv[mt8192_i2s_priv[i].id]; - property_name = mt8192_i2s_priv[i].share_property_name; - if (of_property_read_string(of_node, property_name, &of_str)) - continue; - i2s_priv->share_i2s_id = get_i2s_id_by_name(afe, of_str); - } - - return 0; -} - /** * mt8192_dai_i2s_set_share() - Set up I2S ports to share a single clock. * @afe: Pointer to &struct mtk_base_afe @@ -2127,10 +2097,5 @@ int mt8192_dai_i2s_register(struct mtk_base_afe *afe) if (ret) return ret; - /* parse share i2s */ - ret = mt8192_dai_i2s_get_share(afe); - if (ret) - return ret; - return 0; } -- cgit v1.2.3 From fea84890e5c1fb65ae8e25b2f9b86363af1f45f2 Mon Sep 17 00:00:00 2001 From: "Nícolas F. R. A. Prado" Date: Thu, 8 Sep 2022 12:11:48 -0400 Subject: ASoC: mediatek: mt8183: Allow setting shared clocks from machine driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new function to configure the shared clock between two i2s ports, and export it. This will allow the clock sharing to be set from the machine driver instead of the devicetree. Signed-off-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220908161154.648557-5-nfraprado@collabora.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8183/mt8183-afe-common.h | 3 +++ sound/soc/mediatek/mt8183/mt8183-dai-i2s.c | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-common.h b/sound/soc/mediatek/mt8183/mt8183-afe-common.h index b220e7a7db7e..40ab48c1566c 100644 --- a/sound/soc/mediatek/mt8183/mt8183-afe-common.h +++ b/sound/soc/mediatek/mt8183/mt8183-afe-common.h @@ -99,6 +99,9 @@ unsigned int mt8183_general_rate_transform(struct device *dev, unsigned int mt8183_rate_transform(struct device *dev, unsigned int rate, int aud_blk); +int mt8183_dai_i2s_set_share(struct mtk_base_afe *afe, const char *main_i2s_name, + const char *secondary_i2s_name); + /* dai register */ int mt8183_dai_adda_register(struct mtk_base_afe *afe); int mt8183_dai_pcm_register(struct mtk_base_afe *afe); diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c b/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c index 138591d71ebd..8902ff608d26 100644 --- a/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c +++ b/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c @@ -1026,6 +1026,32 @@ static int mt8183_dai_i2s_get_share(struct mtk_base_afe *afe) return 0; } +/** + * mt8183_dai_i2s_set_share() - Set up I2S ports to share a single clock. + * @afe: Pointer to &struct mtk_base_afe + * @main_i2s_name: The name of the I2S port that will provide the clock + * @secondary_i2s_name: The name of the I2S port that will use this clock + */ +int mt8183_dai_i2s_set_share(struct mtk_base_afe *afe, const char *main_i2s_name, + const char *secondary_i2s_name) +{ + struct mtk_afe_i2s_priv *secondary_i2s_priv; + int main_i2s_id; + + secondary_i2s_priv = get_i2s_priv_by_name(afe, secondary_i2s_name); + if (!secondary_i2s_priv) + return -EINVAL; + + main_i2s_id = get_i2s_id_by_name(afe, main_i2s_name); + if (main_i2s_id < 0) + return main_i2s_id; + + secondary_i2s_priv->share_i2s_id = main_i2s_id; + + return 0; +} +EXPORT_SYMBOL_GPL(mt8183_dai_i2s_set_share); + static int mt8183_dai_i2s_set_priv(struct mtk_base_afe *afe) { struct mt8183_afe_private *afe_priv = afe->platform_priv; -- cgit v1.2.3 From 4583392a135cc30409f5a6ceebb8374e550b03e0 Mon Sep 17 00:00:00 2001 From: "Nícolas F. R. A. Prado" Date: Thu, 8 Sep 2022 12:11:49 -0400 Subject: ASoC: mediatek: mt8183: Configure shared clocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit i2s0 and i2s5 are paired input/output connected to the same codec and should share the same clock. Likewise for i2s2 and i2s3. Set the clock sharing for each pair during the DAI initialization. Signed-off-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220908161154.648557-6-nfraprado@collabora.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c | 33 ++++++++++++++++++++++ .../mt8183/mt8183-mt6358-ts3a227-max98357.c | 33 ++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c index b33cc9a73ed1..9f22d3939818 100644 --- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c @@ -17,6 +17,7 @@ #include "../../codecs/da7219-aad.h" #include "../../codecs/da7219.h" #include "../../codecs/rt1015.h" +#include "../common/mtk-afe-platform-driver.h" #include "mt8183-afe-common.h" #define DA7219_CODEC_DAI "da7219-hifi" @@ -372,6 +373,36 @@ static int mt8183_da7219_max98357_hdmi_init(struct snd_soc_pcm_runtime *rtd) &priv->hdmi_jack, NULL); } +static int mt8183_bt_init(struct snd_soc_pcm_runtime *rtd) +{ + 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); + int ret; + + ret = mt8183_dai_i2s_set_share(afe, "I2S5", "I2S0"); + if (ret) { + dev_err(rtd->dev, "Failed to set up shared clocks\n"); + return ret; + } + return 0; +} + +static int mt8183_da7219_init(struct snd_soc_pcm_runtime *rtd) +{ + 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); + int ret; + + ret = mt8183_dai_i2s_set_share(afe, "I2S2", "I2S3"); + if (ret) { + dev_err(rtd->dev, "Failed to set up shared clocks\n"); + return ret; + } + return 0; +} + static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { /* FE */ { @@ -500,6 +531,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { .ignore_suspend = 1, .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, .ops = &mt8183_da7219_i2s_ops, + .init = &mt8183_da7219_init, SND_SOC_DAILINK_REG(i2s2), }, { @@ -515,6 +547,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { .ignore_suspend = 1, .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, .ops = &mt8183_mt6358_i2s_ops, + .init = &mt8183_bt_init, SND_SOC_DAILINK_REG(i2s5), }, { diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index ab157db78335..a86085223677 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -15,6 +15,7 @@ #include "../../codecs/rt1015.h" #include "../../codecs/ts3a227e.h" +#include "../common/mtk-afe-platform-driver.h" #include "mt8183-afe-common.h" #define RT1015_CODEC_DAI "rt1015-aif" @@ -391,6 +392,36 @@ mt8183_mt6358_ts3a227_max98357_hdmi_init(struct snd_soc_pcm_runtime *rtd) &priv->hdmi_jack, NULL); } +static int mt8183_bt_init(struct snd_soc_pcm_runtime *rtd) +{ + 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); + int ret; + + ret = mt8183_dai_i2s_set_share(afe, "I2S5", "I2S0"); + if (ret) { + dev_err(rtd->dev, "Failed to set up shared clocks\n"); + return ret; + } + return 0; +} + +static int mt8183_i2s2_init(struct snd_soc_pcm_runtime *rtd) +{ + 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); + int ret; + + ret = mt8183_dai_i2s_set_share(afe, "I2S2", "I2S3"); + if (ret) { + dev_err(rtd->dev, "Failed to set up shared clocks\n"); + return ret; + } + return 0; +} + static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { /* FE */ { @@ -527,6 +558,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { .ignore_suspend = 1, .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, .ops = &mt8183_mt6358_i2s_ops, + .init = &mt8183_i2s2_init, SND_SOC_DAILINK_REG(i2s2), }, { @@ -541,6 +573,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { .dpcm_playback = 1, .ignore_suspend = 1, .ops = &mt8183_mt6358_i2s_ops, + .init = &mt8183_bt_init, SND_SOC_DAILINK_REG(i2s5), }, { -- cgit v1.2.3 From cbebe67859a0e8d51e578fdd9f927f8ef2504ba4 Mon Sep 17 00:00:00 2001 From: "Nícolas F. R. A. Prado" Date: Thu, 8 Sep 2022 12:11:50 -0400 Subject: ASoC: mediatek: mt8183: Remove clock share parsing from DT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the clock sharing for i2s ports can be configured from the sound machine driver, remove the logic that was used to parse the properties from the devicetree. Signed-off-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220908161154.648557-7-nfraprado@collabora.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8183/mt8183-dai-i2s.c | 31 ------------------------------ 1 file changed, 31 deletions(-) diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c b/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c index 8902ff608d26..6a9ace4180d3 100644 --- a/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c +++ b/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c @@ -43,7 +43,6 @@ struct mtk_afe_i2s_priv { int rate; /* for determine which apll to use */ int low_jitter_en; - const char *share_property_name; int share_i2s_id; int mclk_id; @@ -977,55 +976,30 @@ static const struct mtk_afe_i2s_priv mt8183_i2s_priv[DAI_I2S_NUM] = { [DAI_I2S0] = { .id = MT8183_DAI_I2S_0, .mclk_id = MT8183_I2S0_MCK, - .share_property_name = "i2s0-share", .share_i2s_id = -1, }, [DAI_I2S1] = { .id = MT8183_DAI_I2S_1, .mclk_id = MT8183_I2S1_MCK, - .share_property_name = "i2s1-share", .share_i2s_id = -1, }, [DAI_I2S2] = { .id = MT8183_DAI_I2S_2, .mclk_id = MT8183_I2S2_MCK, - .share_property_name = "i2s2-share", .share_i2s_id = -1, }, [DAI_I2S3] = { .id = MT8183_DAI_I2S_3, .mclk_id = MT8183_I2S3_MCK, - .share_property_name = "i2s3-share", .share_i2s_id = -1, }, [DAI_I2S5] = { .id = MT8183_DAI_I2S_5, .mclk_id = MT8183_I2S5_MCK, - .share_property_name = "i2s5-share", .share_i2s_id = -1, }, }; -static int mt8183_dai_i2s_get_share(struct mtk_base_afe *afe) -{ - struct mt8183_afe_private *afe_priv = afe->platform_priv; - const struct device_node *of_node = afe->dev->of_node; - const char *of_str; - const char *property_name; - struct mtk_afe_i2s_priv *i2s_priv; - int i; - - for (i = 0; i < DAI_I2S_NUM; i++) { - i2s_priv = afe_priv->dai_priv[mt8183_i2s_priv[i].id]; - property_name = mt8183_i2s_priv[i].share_property_name; - if (of_property_read_string(of_node, property_name, &of_str)) - continue; - i2s_priv->share_i2s_id = get_i2s_id_by_name(afe, of_str); - } - - return 0; -} - /** * mt8183_dai_i2s_set_share() - Set up I2S ports to share a single clock. * @afe: Pointer to &struct mtk_base_afe @@ -1100,10 +1074,5 @@ int mt8183_dai_i2s_register(struct mtk_base_afe *afe) if (ret) return ret; - /* parse share i2s */ - ret = mt8183_dai_i2s_get_share(afe); - if (ret) - return ret; - return 0; } -- cgit v1.2.3 From b3821f7839c2ec322926d16557aff29f4be1f4dc Mon Sep 17 00:00:00 2001 From: "Nícolas F. R. A. Prado" Date: Thu, 8 Sep 2022 12:11:51 -0400 Subject: arm64: dts: mediatek: kukui: Remove i2s-share properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The i2sN-share properties were never documented in the dt-binding and thus shouldn't be used. Now that the ASoC machine drivers are setting the I2S clock sharing internally, these properties are no longer needed, so remove them. Signed-off-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220908161154.648557-8-nfraprado@collabora.com Signed-off-by: Mark Brown --- arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi index b4b86bb1f1a7..42191b3025a9 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi @@ -221,11 +221,6 @@ }; }; -&afe { - i2s3-share = "I2S2"; - i2s0-share = "I2S5"; -}; - &auxadc { status = "okay"; }; -- cgit v1.2.3 From 4132a778e806f77c2bd01a9a34b07edc9dd99d76 Mon Sep 17 00:00:00 2001 From: "Nícolas F. R. A. Prado" Date: Thu, 8 Sep 2022 12:11:52 -0400 Subject: ASoC: mediatek: mt8186: Allow setting shared clocks from machine driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new function to configure the shared clock between two i2s ports, and export it. This will allow the clock sharing to be set from the machine driver instead of the devicetree. Signed-off-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220908161154.648557-9-nfraprado@collabora.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8186/mt8186-afe-common.h | 3 +++ sound/soc/mediatek/mt8186/mt8186-dai-i2s.c | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-common.h b/sound/soc/mediatek/mt8186/mt8186-afe-common.h index b8f03e1b7e49..d59258520995 100644 --- a/sound/soc/mediatek/mt8186/mt8186-afe-common.h +++ b/sound/soc/mediatek/mt8186/mt8186-afe-common.h @@ -189,6 +189,9 @@ unsigned int mt8186_rate_transform(struct device *dev, unsigned int mt8186_tdm_relatch_rate_transform(struct device *dev, unsigned int rate); +int mt8186_dai_i2s_set_share(struct mtk_base_afe *afe, const char *main_i2s_name, + const char *secondary_i2s_name); + int mt8186_dai_set_priv(struct mtk_base_afe *afe, int id, int priv_size, const void *priv_data); diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c b/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c index e553a555d168..7e8cad682c83 100644 --- a/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c +++ b/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c @@ -1184,6 +1184,32 @@ static int mt8186_dai_i2s_get_share(struct mtk_base_afe *afe) return 0; } +/** + * mt8186_dai_i2s_set_share() - Set up I2S ports to share a single clock. + * @afe: Pointer to &struct mtk_base_afe + * @main_i2s_name: The name of the I2S port that will provide the clock + * @secondary_i2s_name: The name of the I2S port that will use this clock + */ +int mt8186_dai_i2s_set_share(struct mtk_base_afe *afe, const char *main_i2s_name, + const char *secondary_i2s_name) +{ + struct mtk_afe_i2s_priv *secondary_i2s_priv; + int main_i2s_id; + + secondary_i2s_priv = get_i2s_priv_by_name(afe, secondary_i2s_name); + if (!secondary_i2s_priv) + return -EINVAL; + + main_i2s_id = get_i2s_id_by_name(afe, main_i2s_name); + if (main_i2s_id < 0) + return main_i2s_id; + + secondary_i2s_priv->share_i2s_id = main_i2s_id; + + return 0; +} +EXPORT_SYMBOL_GPL(mt8186_dai_i2s_set_share); + static int mt8186_dai_i2s_set_priv(struct mtk_base_afe *afe) { int i; -- cgit v1.2.3 From 9986bdaee4776c5d595933cace9d54c6bc084e91 Mon Sep 17 00:00:00 2001 From: "Nícolas F. R. A. Prado" Date: Thu, 8 Sep 2022 12:11:53 -0400 Subject: ASoC: mediatek: mt8186: Configure shared clocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit i2s0 and i2s1 are paired input/output connected to the same codec and should share the same clock. Likewise for i2s2 and i2s3. Set the clock sharing for each pair during the codec's initialization. Signed-off-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220908161154.648557-10-nfraprado@collabora.com Signed-off-by: Mark Brown --- .../mediatek/mt8186/mt8186-mt6366-da7219-max98357.c | 18 ++++++++++++++++++ .../soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c index 17a15bec41da..6f93f9dd4623 100644 --- a/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c +++ b/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c @@ -54,6 +54,9 @@ static struct snd_soc_codec_conf mt8186_mt6366_da7219_max98357_codec_conf[] = { static int mt8186_da7219_init(struct snd_soc_pcm_runtime *rtd) { + 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 mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card); struct mt8186_mt6366_da7219_max98357_priv *priv = soc_card_data->mach_priv; @@ -62,6 +65,12 @@ static int mt8186_da7219_init(struct snd_soc_pcm_runtime *rtd) asoc_rtd_to_codec(rtd, 0)->component; int ret; + ret = mt8186_dai_i2s_set_share(afe, "I2S1", "I2S0"); + if (ret) { + dev_err(rtd->dev, "Failed to set up shared clocks\n"); + return ret; + } + /* Enable Headset and 4 Buttons Jack detection */ ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_BTN_0 | @@ -160,6 +169,9 @@ static const struct snd_soc_ops mt8186_da7219_i2s_ops = { static int mt8186_mt6366_da7219_max98357_hdmi_init(struct snd_soc_pcm_runtime *rtd) { + 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 snd_soc_component *cmpnt_codec = asoc_rtd_to_codec(rtd, 0)->component; struct mtk_soc_card_data *soc_card_data = @@ -167,6 +179,12 @@ static int mt8186_mt6366_da7219_max98357_hdmi_init(struct snd_soc_pcm_runtime *r struct mt8186_mt6366_da7219_max98357_priv *priv = soc_card_data->mach_priv; int ret; + ret = mt8186_dai_i2s_set_share(afe, "I2S3", "I2S2"); + if (ret) { + dev_err(rtd->dev, "Failed to set up shared clocks\n"); + return ret; + } + ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT, &priv->hdmi_jack); if (ret) { dev_err(rtd->dev, "HDMI Jack creation failed: %d\n", ret); diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c index 393d179d61de..247f20f594d9 100644 --- a/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c +++ b/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c @@ -58,6 +58,9 @@ static struct snd_soc_codec_conf mt8186_mt6366_rt1019_rt5682s_codec_conf[] = { static int mt8186_rt5682s_init(struct snd_soc_pcm_runtime *rtd) { + 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 mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card); struct mt8186_mt6366_rt1019_rt5682s_priv *priv = soc_card_data->mach_priv; @@ -66,6 +69,12 @@ static int mt8186_rt5682s_init(struct snd_soc_pcm_runtime *rtd) asoc_rtd_to_codec(rtd, 0)->component; int ret; + ret = mt8186_dai_i2s_set_share(afe, "I2S1", "I2S0"); + if (ret) { + dev_err(rtd->dev, "Failed to set up shared clocks\n"); + return ret; + } + 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 | @@ -136,6 +145,9 @@ static const struct snd_soc_ops mt8186_rt5682s_i2s_ops = { static int mt8186_mt6366_rt1019_rt5682s_hdmi_init(struct snd_soc_pcm_runtime *rtd) { + 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 snd_soc_component *cmpnt_codec = asoc_rtd_to_codec(rtd, 0)->component; struct mtk_soc_card_data *soc_card_data = @@ -143,6 +155,12 @@ static int mt8186_mt6366_rt1019_rt5682s_hdmi_init(struct snd_soc_pcm_runtime *rt struct mt8186_mt6366_rt1019_rt5682s_priv *priv = soc_card_data->mach_priv; int ret; + ret = mt8186_dai_i2s_set_share(afe, "I2S3", "I2S2"); + if (ret) { + dev_err(rtd->dev, "Failed to set up shared clocks\n"); + return ret; + } + ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT, &priv->hdmi_jack); if (ret) { dev_err(rtd->dev, "HDMI Jack creation failed: %d\n", ret); -- cgit v1.2.3 From 62da80c6a124dd68b12c4d2197ecc74b79823571 Mon Sep 17 00:00:00 2001 From: "Nícolas F. R. A. Prado" Date: Thu, 8 Sep 2022 12:11:54 -0400 Subject: ASoC: mediatek: mt8186: Remove clock share parsing from DT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the clock sharing for i2s ports can be configured from the sound machine driver, remove the logic that was used to parse the properties from the devicetree. Signed-off-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220908161154.648557-11-nfraprado@collabora.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8186/mt8186-dai-i2s.c | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c b/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c index 7e8cad682c83..f07181be4370 100644 --- a/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c +++ b/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c @@ -44,7 +44,6 @@ struct mtk_afe_i2s_priv { int low_jitter_en; int master; /* only i2s0 has slave mode*/ - const char *share_property_name; int share_i2s_id; int mclk_id; @@ -1140,50 +1139,26 @@ static const struct mtk_afe_i2s_priv mt8186_i2s_priv[DAI_I2S_NUM] = { [DAI_I2S0] = { .id = MT8186_DAI_I2S_0, .mclk_id = MT8186_I2S0_MCK, - .share_property_name = "i2s0-share", .share_i2s_id = -1, }, [DAI_I2S1] = { .id = MT8186_DAI_I2S_1, .mclk_id = MT8186_I2S1_MCK, - .share_property_name = "i2s1-share", .share_i2s_id = -1, }, [DAI_I2S2] = { .id = MT8186_DAI_I2S_2, .mclk_id = MT8186_I2S2_MCK, - .share_property_name = "i2s2-share", .share_i2s_id = -1, }, [DAI_I2S3] = { .id = MT8186_DAI_I2S_3, /* clock gate naming is hf_faud_i2s4_m_ck*/ .mclk_id = MT8186_I2S4_MCK, - .share_property_name = "i2s3-share", .share_i2s_id = -1, } }; -static int mt8186_dai_i2s_get_share(struct mtk_base_afe *afe) -{ - struct mt8186_afe_private *afe_priv = afe->platform_priv; - const struct device_node *of_node = afe->dev->of_node; - const char *of_str; - const char *property_name; - struct mtk_afe_i2s_priv *i2s_priv; - int i; - - for (i = 0; i < DAI_I2S_NUM; i++) { - i2s_priv = afe_priv->dai_priv[mt8186_i2s_priv[i].id]; - property_name = mt8186_i2s_priv[i].share_property_name; - if (of_property_read_string(of_node, property_name, &of_str)) - continue; - i2s_priv->share_i2s_id = get_i2s_id_by_name(afe, of_str); - } - - return 0; -} - /** * mt8186_dai_i2s_set_share() - Set up I2S ports to share a single clock. * @afe: Pointer to &struct mtk_base_afe @@ -1252,10 +1227,5 @@ int mt8186_dai_i2s_register(struct mtk_base_afe *afe) if (ret) return ret; - /* parse share i2s */ - ret = mt8186_dai_i2s_get_share(afe); - if (ret) - return ret; - return 0; } -- cgit v1.2.3 From 985f03ba6f4bc37bdacd2e78906e6b731e03ab32 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 9 Sep 2022 01:20:48 +0000 Subject: ASoC: hdmi-codec.c: use devm_kzalloc() for DMA data hdmi-codec.c is using kzalloc(), but we can replace it to devm_kzalloc() and then, we can remove .remove callback. Signed-off-by: Kuninori Morimoto Reviewed-by: Charles Keepax Link: https://lore.kernel.org/r/874jxhmjgw.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/hdmi-codec.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 863e679d2ac1..0b1cdb2d6049 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -823,7 +823,7 @@ static int hdmi_dai_probe(struct snd_soc_dai *dai) if (ret) return ret; - daifmt = kzalloc(sizeof(*daifmt), GFP_KERNEL); + daifmt = devm_kzalloc(dai->dev, sizeof(*daifmt), GFP_KERNEL); if (!daifmt) return -ENOMEM; @@ -890,17 +890,10 @@ static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai) return 0; } -static int hdmi_codec_dai_remove(struct snd_soc_dai *dai) -{ - kfree(dai->playback_dma_data); - return 0; -} - static const struct snd_soc_dai_driver hdmi_i2s_dai = { .name = "i2s-hifi", .id = DAI_ID_I2S, .probe = hdmi_dai_probe, - .remove = hdmi_codec_dai_remove, .playback = { .stream_name = "I2S Playback", .channels_min = 2, @@ -925,7 +918,6 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = { .name = "spdif-hifi", .id = DAI_ID_SPDIF, .probe = hdmi_dai_spdif_probe, - .remove = hdmi_codec_dai_remove, .playback = { .stream_name = "SPDIF Playback", .channels_min = 2, -- cgit v1.2.3 From d2de3f5ead84e230f4651cddf7658ab74ce1a70c Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 9 Sep 2022 11:44:58 +0800 Subject: ASoC: fsl_asrc: Add initialization finishing check in runtime resume If the initialization is not finished, then filling input data to the FIFO may fail. So it is better to add initialization finishing check in the runtime resume for suspend & resume case. And consider the case of three instances working in parallel, increase the retry times to 50 for more initialization time. Signed-off-by: Shengjiu Wang Reviewed-by: Nicolin Chen Link: https://lore.kernel.org/r/1662695098-24602-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_asrc.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index aa5edf32d988..936aef5d2767 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -20,6 +20,7 @@ #define IDEAL_RATIO_DECIMAL_DEPTH 26 #define DIVIDER_NUM 64 +#define INIT_RETRY_NUM 50 #define pair_err(fmt, ...) \ dev_err(&asrc->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) @@ -27,6 +28,9 @@ #define pair_dbg(fmt, ...) \ dev_dbg(&asrc->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) +#define pair_warn(fmt, ...) \ + dev_warn(&asrc->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) + /* Corresponding to process_option */ static unsigned int supported_asrc_rate[] = { 5512, 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, @@ -579,7 +583,7 @@ static void fsl_asrc_start_pair(struct fsl_asrc_pair *pair) { struct fsl_asrc *asrc = pair->asrc; enum asrc_pair_index index = pair->index; - int reg, retry = 10, i; + int reg, retry = INIT_RETRY_NUM, i; /* Enable the current pair */ regmap_update_bits(asrc->regmap, REG_ASRCTR, @@ -592,6 +596,10 @@ static void fsl_asrc_start_pair(struct fsl_asrc_pair *pair) reg &= ASRCFG_INIRQi_MASK(index); } while (!reg && --retry); + /* NOTE: Doesn't treat initialization timeout as an error */ + if (!retry) + pair_warn("initialization isn't finished\n"); + /* Make the input fifo to ASRC STALL level */ regmap_read(asrc->regmap, REG_ASRCNCR, ®); for (i = 0; i < pair->channels * 4; i++) @@ -1257,6 +1265,7 @@ static int fsl_asrc_runtime_resume(struct device *dev) { struct fsl_asrc *asrc = dev_get_drvdata(dev); struct fsl_asrc_priv *asrc_priv = asrc->private; + int reg, retry = INIT_RETRY_NUM; int i, ret; u32 asrctr; @@ -1295,6 +1304,24 @@ static int fsl_asrc_runtime_resume(struct device *dev) regmap_update_bits(asrc->regmap, REG_ASRCTR, ASRCTR_ASRCEi_ALL_MASK, asrctr); + /* Wait for status of initialization for all enabled pairs */ + do { + udelay(5); + regmap_read(asrc->regmap, REG_ASRCFG, ®); + reg = (reg >> ASRCFG_INIRQi_SHIFT(0)) & 0x7; + } while ((reg != ((asrctr >> ASRCTR_ASRCEi_SHIFT(0)) & 0x7)) && --retry); + + /* + * NOTE: Doesn't treat initialization timeout as an error + * Some of the pairs may success, then still can continue. + */ + if (!retry) { + for (i = ASRC_PAIR_A; i < ASRC_PAIR_MAX_NUM; i++) { + if ((asrctr & ASRCTR_ASRCEi_MASK(i)) && !(reg & (1 << i))) + dev_warn(dev, "Pair %c initialization isn't finished\n", 'A' + i); + } + } + return 0; disable_asrck_clk: -- cgit v1.2.3 From 7ae22bdf49d513b0555d25df4d361379fc8ad166 Mon Sep 17 00:00:00 2001 From: YJ Lee Date: Mon, 12 Sep 2022 15:28:54 +0800 Subject: ALSA: dummy: Fix trailing whitespaces. Fix checkpatch.pl ERROR: trailing whitespaces. Signed-off-by: YJ Lee Link: https://lore.kernel.org/r/20220912072854.760824-1-yunjunlee@chromium.org Signed-off-by: Takashi Iwai --- sound/drivers/dummy.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 2a7fc49c1a7c..fcf1ee00bd21 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -296,7 +296,7 @@ static void dummy_systimer_callback(struct timer_list *t) struct dummy_systimer_pcm *dpcm = from_timer(dpcm, t, timer); unsigned long flags; int elapsed = 0; - + spin_lock_irqsave(&dpcm->lock, flags); dummy_systimer_update(dpcm); dummy_systimer_rearm(dpcm); @@ -717,7 +717,7 @@ static int snd_dummy_volume_info(struct snd_kcontrol *kcontrol, uinfo->value.integer.max = 100; return 0; } - + static int snd_dummy_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -766,7 +766,7 @@ static const DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0); .private_value = addr } #define snd_dummy_capsrc_info snd_ctl_boolean_stereo_info - + static int snd_dummy_capsrc_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1100,7 +1100,7 @@ static int snd_dummy_suspend(struct device *pdev) snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); return 0; } - + static int snd_dummy_resume(struct device *pdev) { struct snd_card *card = dev_get_drvdata(pdev); -- cgit v1.2.3 From 446bc11f8614449782feac1d5ff270b3f98bcdf3 Mon Sep 17 00:00:00 2001 From: YJ Lee Date: Mon, 12 Sep 2022 15:29:45 +0800 Subject: ALSA: dummy: Add customizable volume min/max. Add module parameters to support customized min/max volume leveling, which will be useful to test devices with different volume granularity. Signed-off-by: YJ Lee Link: https://lore.kernel.org/r/20220912072945.760949-1-yunjunlee@chromium.org Signed-off-by: Takashi Iwai --- sound/drivers/dummy.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index fcf1ee00bd21..9c17b49a2ae1 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -42,6 +42,8 @@ MODULE_LICENSE("GPL"); #define USE_CHANNELS_MAX 2 #define USE_PERIODS_MIN 1 #define USE_PERIODS_MAX 1024 +#define USE_MIXER_VOLUME_LEVEL_MIN -50 +#define USE_MIXER_VOLUME_LEVEL_MAX 100 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ @@ -50,6 +52,8 @@ static char *model[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = NULL}; static int pcm_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8}; //static int midi_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; +static int mixer_volume_level_min = USE_MIXER_VOLUME_LEVEL_MIN; +static int mixer_volume_level_max = USE_MIXER_VOLUME_LEVEL_MAX; #ifdef CONFIG_HIGH_RES_TIMERS static bool hrtimer = 1; #endif @@ -69,6 +73,10 @@ module_param_array(pcm_substreams, int, NULL, 0444); MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-128) for dummy driver."); //module_param_array(midi_devs, int, NULL, 0444); //MODULE_PARM_DESC(midi_devs, "MIDI devices # (0-2) for dummy driver."); +module_param(mixer_volume_level_min, int, 0444); +MODULE_PARM_DESC(mixer_volume_level_min, "Minimum mixer volume level for dummy driver. Default: -50"); +module_param(mixer_volume_level_max, int, 0444); +MODULE_PARM_DESC(mixer_volume_level_max, "Maximum mixer volume level for dummy driver. Default: 100"); module_param(fake_buffer, bool, 0444); MODULE_PARM_DESC(fake_buffer, "Fake buffer allocations."); #ifdef CONFIG_HIGH_RES_TIMERS @@ -713,8 +721,8 @@ static int snd_dummy_volume_info(struct snd_kcontrol *kcontrol, { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 2; - uinfo->value.integer.min = -50; - uinfo->value.integer.max = 100; + uinfo->value.integer.min = mixer_volume_level_min; + uinfo->value.integer.max = mixer_volume_level_max; return 0; } @@ -739,15 +747,15 @@ static int snd_dummy_volume_put(struct snd_kcontrol *kcontrol, int left, right; left = ucontrol->value.integer.value[0]; - if (left < -50) - left = -50; - if (left > 100) - left = 100; + if (left < mixer_volume_level_min) + left = mixer_volume_level_min; + if (left > mixer_volume_level_max) + left = mixer_volume_level_max; right = ucontrol->value.integer.value[1]; - if (right < -50) - right = -50; - if (right > 100) - right = 100; + if (right < mixer_volume_level_min) + right = mixer_volume_level_min; + if (right > mixer_volume_level_max) + right = mixer_volume_level_max; spin_lock_irq(&dummy->mixer_lock); change = dummy->mixer_volume[addr][0] != left || dummy->mixer_volume[addr][1] != right; @@ -1076,6 +1084,12 @@ static int snd_dummy_probe(struct platform_device *devptr) dummy->pcm_hw.channels_max = m->channels_max; } + if (mixer_volume_level_min > mixer_volume_level_max) { + pr_warn("snd-dummy: Invalid mixer volume level: min=%d, max=%d. Fall back to default value.\n", + mixer_volume_level_min, mixer_volume_level_max); + mixer_volume_level_min = USE_MIXER_VOLUME_LEVEL_MIN; + mixer_volume_level_max = USE_MIXER_VOLUME_LEVEL_MAX; + } err = snd_card_dummy_new_mixer(dummy); if (err < 0) return err; -- cgit v1.2.3 From 4053a41282f8aae290d3fe7b8daef4c8c53a4ab8 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 13 Sep 2022 09:03:07 +0200 Subject: ALSA: hda/hdmi: change type for the 'assigned' variable This change converts the assigned value from int type to the bool type to retain consistency with other structure members like 'setup', 'non_pcm' etc. Signed-off-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20220913070307.3234038-1-perex@perex.cz Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 429cb4b23a1c..1ab7541a63db 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -53,7 +53,7 @@ MODULE_PARM_DESC(enable_all_pins, "Forcibly enable all pins"); struct hdmi_spec_per_cvt { hda_nid_t cvt_nid; - int assigned; + bool assigned; /* the stream has been assigned */ unsigned int channels_min; unsigned int channels_max; u32 rates; @@ -1193,7 +1193,7 @@ static int hdmi_pcm_open_no_pin(struct hda_pcm_stream *hinfo, return err; per_cvt = get_cvt(spec, cvt_idx); - per_cvt->assigned = 1; + per_cvt->assigned = true; hinfo->nid = per_cvt->cvt_nid; pin_cvt_fixup(codec, NULL, per_cvt->cvt_nid); @@ -1262,7 +1262,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, per_cvt = get_cvt(spec, cvt_idx); /* Claim converter */ - per_cvt->assigned = 1; + per_cvt->assigned = true; set_bit(pcm_idx, &spec->pcm_in_use); per_pin = get_pin(spec, pin_idx); @@ -1296,7 +1296,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, snd_hdmi_eld_update_pcm_info(&eld->info, hinfo); if (hinfo->channels_min > hinfo->channels_max || !hinfo->rates || !hinfo->formats) { - per_cvt->assigned = 0; + per_cvt->assigned = false; hinfo->nid = 0; snd_hda_spdif_ctls_unassign(codec, pcm_idx); err = -ENODEV; @@ -1755,7 +1755,7 @@ static void silent_stream_enable(struct hda_codec *codec, } per_cvt = get_cvt(spec, cvt_idx); - per_cvt->assigned = 1; + per_cvt->assigned = true; per_pin->cvt_nid = per_cvt->cvt_nid; per_pin->silent_stream = true; @@ -1815,7 +1815,7 @@ static void silent_stream_disable(struct hda_codec *codec, cvt_idx = cvt_nid_to_cvt_index(codec, per_pin->cvt_nid); if (cvt_idx >= 0 && cvt_idx < spec->num_cvts) { per_cvt = get_cvt(spec, cvt_idx); - per_cvt->assigned = 0; + per_cvt->assigned = false; } if (spec->silent_stream_type == SILENT_STREAM_I915) { @@ -2211,7 +2211,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, goto unlock; } per_cvt = get_cvt(spec, cvt_idx); - per_cvt->assigned = 0; + per_cvt->assigned = false; hinfo->nid = 0; azx_stream(get_azx_dev(substream))->stripe = 0; -- cgit v1.2.3 From da995e22fa7193b067f2545e63d726ffe36ba174 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Tue, 13 Sep 2022 16:26:34 +0800 Subject: ASoC: ak4458: Add ak4458_reset in device probe and remove This patch fixup this warning when CONFIG_PM not defined linux/sound/soc/codecs/ak4458.c:631:13: error: 'ak4458_reset' defined but\ not used [-Werror=unused-function] 631 | static void ak4458_reset(struct ak4458_priv *ak4458, bool active) | ^~~~~~~~~~~~ cc1: all warnings being treated as errors Fixes: e9e7df88996d64 ("ASoC: ak4458: Remove component probe() and remove()") Reported-by: Kuninori Morimoto Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1663057594-29141-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/codecs/ak4458.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c index b534212096ee..626310859814 100644 --- a/sound/soc/codecs/ak4458.c +++ b/sound/soc/codecs/ak4458.c @@ -781,12 +781,16 @@ static int ak4458_i2c_probe(struct i2c_client *i2c) pm_runtime_enable(&i2c->dev); regcache_cache_only(ak4458->regmap, true); + ak4458_reset(ak4458, false); return 0; } static int ak4458_i2c_remove(struct i2c_client *i2c) { + struct ak4458_priv *ak4458 = i2c_get_clientdata(i2c); + + ak4458_reset(ak4458, true); pm_runtime_disable(&i2c->dev); return 0; -- cgit v1.2.3 From a74bfc9eaa497951effddefbcb18f1c7ab56fb35 Mon Sep 17 00:00:00 2001 From: Gaosheng Cui Date: Mon, 22 Aug 2022 11:51:33 +0800 Subject: ASoC: Intel: fix unused-variable warning in probe_codec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In configurations with CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC=n, gcc warns about an unused variable: sound/soc/intel/skylake/skl.c: In function ‘probe_codec’: sound/soc/intel/skylake/skl.c:729:18: error: unused variable ‘skl’ [-Werror=unused-variable] struct skl_dev *skl = bus_to_skl(bus); ^~~ cc1: all warnings being treated as errors Fixes: 3fd63658caed9 ("ASoC: Intel: Drop hdac_ext usage for codec device creation") Signed-off-by: Gaosheng Cui Acked-by: Cezary Rojewski Link: https://lore.kernel.org/r/20220822035133.2147381-1-cuigaosheng1@huawei.com Signed-off-by: Takashi Iwai --- sound/soc/intel/skylake/skl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index c7c1cad2a753..52a041d6144c 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -726,8 +726,8 @@ static int probe_codec(struct hdac_bus *bus, int addr) unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) | (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; unsigned int res = -1; - struct skl_dev *skl = bus_to_skl(bus); #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) + struct skl_dev *skl = bus_to_skl(bus); struct hdac_hda_priv *hda_codec; #endif struct hda_codec *codec; -- cgit v1.2.3 From 596247a42125267163d147b290e2ec4d4e2c2491 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 13 Sep 2022 17:10:58 +0100 Subject: ASoC: Drop mistakenly applied DTS patch This reverts commit b3821f7839c2ec3229 ("arm64: dts: mediatek: kukui: Remove i2s-share properties") which was mistakenly applied to the ASoC tree. Signed-off-by: Mark Brown --- arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi index 42191b3025a9..b4b86bb1f1a7 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi @@ -221,6 +221,11 @@ }; }; +&afe { + i2s3-share = "I2S2"; + i2s0-share = "I2S5"; +}; + &auxadc { status = "okay"; }; -- cgit v1.2.3 From 1c2d23fc6134fa72b040a36ae953e1a6614844f4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 10 Sep 2022 11:08:56 +0200 Subject: ASoC: dt-bindings: qcom,q6afe: remove binding qcom,q6afe is already documented in soc/qcom/qcom,apr.yaml. The version-based compatibles ("qcom,q6afe-v.") are not used (neither in upstream nor in downstream DTS). Signed-off-by: Krzysztof Kozlowski Acked-by: Rob Herring Link: https://lore.kernel.org/r/20220910090856.49271-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/qcom,q6afe.txt | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/qcom,q6afe.txt diff --git a/Documentation/devicetree/bindings/sound/qcom,q6afe.txt b/Documentation/devicetree/bindings/sound/qcom,q6afe.txt deleted file mode 100644 index bc6b5f1fe4f1..000000000000 --- a/Documentation/devicetree/bindings/sound/qcom,q6afe.txt +++ /dev/null @@ -1,20 +0,0 @@ -Qualcomm Audio Front End (Q6AFE) binding - -AFE is one of the APR audio service on Q6DSP -Please refer to qcom,apr.txt for details of the common apr service bindings -used by all apr services. Must contain the following properties. - -- compatible: - Usage: required - Value type: - Definition: must be "qcom,q6afe-v." - Or "qcom,q6afe" where the version number can be queried - from DSP. - example "qcom,q6afe" - -= EXAMPLE - -apr-service@4 { - compatible = "qcom,q6afe"; - reg = ; -}; -- cgit v1.2.3 From 30248f618d30cf1ad9d5a72126799f2f0239860c Mon Sep 17 00:00:00 2001 From: Mikhail Rudenko Date: Sun, 11 Sep 2022 17:57:11 +0300 Subject: ASoC: sunxi: sun4i-codec: silence misleading error in probe In the case when a codec device is probed before codec analog controls, snd_soc_register_card() returns -EPROBE_DEFER, resulting in a misleading error message sun4i-codec 1c22c00.codec: Failed to register our card even if the device is probed successfully later. Use dev_err_probe() to demote the above error to a debug message. Signed-off-by: Mikhail Rudenko Acked-by: Jernej Skrabec Link: https://lore.kernel.org/r/20220911145713.55199-1-mike.rudenko@gmail.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 830beb38bf15..3a7075d03c23 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -1804,7 +1804,7 @@ static int sun4i_codec_probe(struct platform_device *pdev) ret = snd_soc_register_card(card); if (ret) { - dev_err(&pdev->dev, "Failed to register our card\n"); + dev_err_probe(&pdev->dev, ret, "Failed to register our card\n"); goto err_assert_reset; } -- cgit v1.2.3 From 515626a33a194c4caaf2879dbf9e00e882582af0 Mon Sep 17 00:00:00 2001 From: Gaosheng Cui Date: Mon, 22 Aug 2022 11:51:33 +0800 Subject: ASoC: Intel: fix unused-variable warning in probe_codec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In configurations with CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC=n, gcc warns about an unused variable: sound/soc/intel/skylake/skl.c: In function ‘probe_codec’: sound/soc/intel/skylake/skl.c:729:18: error: unused variable ‘skl’ [-Werror=unused-variable] struct skl_dev *skl = bus_to_skl(bus); ^~~ cc1: all warnings being treated as errors Fixes: 3fd63658caed9 ("ASoC: Intel: Drop hdac_ext usage for codec device creation") Signed-off-by: Gaosheng Cui Acked-by: Cezary Rojewski Link: https://lore.kernel.org/r/20220822035133.2147381-1-cuigaosheng1@huawei.com Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index aeca58246fc7..3997af4eaa89 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -697,8 +697,8 @@ static int probe_codec(struct hdac_bus *bus, int addr) unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) | (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; unsigned int res = -1; - struct skl_dev *skl = bus_to_skl(bus); #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) + struct skl_dev *skl = bus_to_skl(bus); struct hdac_hda_priv *hda_codec; int err; #endif -- cgit v1.2.3 From ed8570726ab005da0aa62cc24046ef83fa342e89 Mon Sep 17 00:00:00 2001 From: David Lin Date: Tue, 13 Sep 2022 20:06:41 +0800 Subject: ASoC: nau8825: Add ADCOUT IO drive strength control Add a property to control the driving of ADCOUT. Signed-off-by: David Lin Link: https://lore.kernel.org/r/20220913120641.792502-1-CTLIN0@nuvoton.com Signed-off-by: Mark Brown --- sound/soc/codecs/nau8825.c | 6 ++++++ sound/soc/codecs/nau8825.h | 3 +++ 2 files changed, 9 insertions(+) diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 54ef7b0fa878..80a0864a2f8b 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -1976,6 +1976,10 @@ static void nau8825_init_regs(struct nau8825 *nau8825) /* Disable short Frame Sync detection logic */ regmap_update_bits(regmap, NAU8825_REG_LEFT_TIME_SLOT, NAU8825_DIS_FS_SHORT_DET, NAU8825_DIS_FS_SHORT_DET); + /* ADCDAT IO drive strength control */ + regmap_update_bits(regmap, NAU8825_REG_CHARGE_PUMP, + NAU8825_ADCOUT_DS_MASK, + nau8825->adcout_ds << NAU8825_ADCOUT_DS_SFT); } static const struct regmap_config nau8825_regmap_config = { @@ -2514,6 +2518,7 @@ static void nau8825_print_device_properties(struct nau8825 *nau8825) nau8825->jack_eject_debounce); dev_dbg(dev, "crosstalk-enable: %d\n", nau8825->xtalk_enable); + dev_dbg(dev, "adcout-drive-strong: %d\n", nau8825->adcout_ds); } static int nau8825_read_device_properties(struct device *dev, @@ -2580,6 +2585,7 @@ static int nau8825_read_device_properties(struct device *dev, nau8825->jack_eject_debounce = 0; nau8825->xtalk_enable = device_property_read_bool(dev, "nuvoton,crosstalk-enable"); + nau8825->adcout_ds = device_property_read_bool(dev, "nuvoton,adcout-drive-strong"); nau8825->mclk = devm_clk_get(dev, "mclk"); if (PTR_ERR(nau8825->mclk) == -EPROBE_DEFER) { diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h index 887bbff03ec6..6d112b6145df 100644 --- a/sound/soc/codecs/nau8825.h +++ b/sound/soc/codecs/nau8825.h @@ -418,6 +418,8 @@ #define NAU8825_POWERUP_HP_DRV_L (1 << 0) /* CHARGE_PUMP (0x80) */ +#define NAU8825_ADCOUT_DS_SFT 12 +#define NAU8825_ADCOUT_DS_MASK (1 << NAU8825_ADCOUT_DS_SFT) #define NAU8825_JAMNODCLOW (1 << 10) #define NAU8825_POWER_DOWN_DACR (1 << 9) #define NAU8825_POWER_DOWN_DACL (1 << 8) @@ -477,6 +479,7 @@ struct nau8825 { int imp_rms[NAU8825_XTALK_IMM]; int xtalk_enable; bool xtalk_baktab_initialized; /* True if initialized. */ + bool adcout_ds; }; int nau8825_enable_jack_detect(struct snd_soc_component *component, -- cgit v1.2.3 From 40a57d4b2d82fe4a10bc41aa79532ee33ffdb051 Mon Sep 17 00:00:00 2001 From: David Lin Date: Tue, 13 Sep 2022 20:06:43 +0800 Subject: ASoC: dt-bindings: nau8825: Add ADCOUT IO drive strength control Add a property to control the driving of ADCOUT. Signed-off-by: David Lin Link: https://lore.kernel.org/r/20220913120641.792502-2-CTLIN0@nuvoton.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/nau8825.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/nau8825.txt b/Documentation/devicetree/bindings/sound/nau8825.txt index 388a7bc60b1f..cb861aca8d40 100644 --- a/Documentation/devicetree/bindings/sound/nau8825.txt +++ b/Documentation/devicetree/bindings/sound/nau8825.txt @@ -71,6 +71,9 @@ Optional properties: - nuvoton,crosstalk-enable: make crosstalk function enable if set. + - nuvoton,adcout-drive-strong: make the drive strength of ADCOUT IO PIN strong if set. + Otherwise, the drive keeps normal strength. + - clocks: list of phandle and clock specifier pairs according to common clock bindings for the clocks described in clock-names - clock-names: should include "mclk" for the MCLK master clock -- cgit v1.2.3 From 3e9a838634b181b5775d3459f05c2055d24d080a Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 13 Sep 2022 20:17:06 -0300 Subject: ASoC: tas2562: Propagate the error in tas2562_dac_event() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 2848d34c3ba1 ("ASoC: tas2562: Fix mute/unmute") the following build warning is seen: sound/soc/codecs/tas2562.c:442:13: warning: variable 'ret' set but not used [-Wunused-but-set-variable] Fix the warning by returning the 'ret' variable. Fixes: 2848d34c3ba1 ("ASoC: tas2562: Fix mute/unmute") Signed-off-by: Fabio Estevam Reviewed-by: Martin Povišer Link: https://lore.kernel.org/r/20220913231706.516849-1-festevam@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/tas2562.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/tas2562.c b/sound/soc/codecs/tas2562.c index 66149055aba9..b486d0bd86c9 100644 --- a/sound/soc/codecs/tas2562.c +++ b/sound/soc/codecs/tas2562.c @@ -439,7 +439,7 @@ static int tas2562_dac_event(struct snd_soc_dapm_widget *w, struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); - int ret; + int ret = 0; switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -455,7 +455,7 @@ static int tas2562_dac_event(struct snd_soc_dapm_widget *w, return -EINVAL; } - return 0; + return ret; } static int tas2562_volume_control_get(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From fbb0ec656ee5ee43b4b3022fd8290707265c52df Mon Sep 17 00:00:00 2001 From: Judy Hsiao Date: Wed, 14 Sep 2022 03:12:34 +0000 Subject: ASoC: rockchip: i2s: use regmap_read_poll_timeout to poll I2S_CLR Use regmap_read_poll_timeout to poll I2S_CLR. It also fixes the 'rockchip-i2s ff070000.i2s; fail to clear' when the read of I2S_CLR exceeds the retry limit. Fixes: 0ff9f8b9f592 ("ASoC: rockchip: i2s: Fix error code when fail to read I2S_CLR") Signed-off-by: Judy Hsiao Reviewed-by: Brian Norris Link: https://lore.kernel.org/r/20220914031234.2250298-1-judyhsiao@chromium.org Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_i2s.c | 41 +++++++++++++++------------------------ 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index f5f3540a9e18..28c86f5e435e 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -126,7 +126,6 @@ static inline struct rk_i2s_dev *to_info(struct snd_soc_dai *dai) static int rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on) { unsigned int val = 0; - int retry = 10; int ret = 0; spin_lock(&i2s->lock); @@ -163,18 +162,14 @@ static int rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on) I2S_CLR_TXC | I2S_CLR_RXC); if (ret < 0) goto end; - regmap_read(i2s->regmap, I2S_CLR, &val); - - /* Should wait for clear operation to finish */ - while (val) { - regmap_read(i2s->regmap, I2S_CLR, &val); - retry--; - if (!retry) { - dev_warn(i2s->dev, "fail to clear\n"); - ret = -EBUSY; - break; - } - } + ret = regmap_read_poll_timeout(i2s->regmap, + I2S_CLR, + val, + val != 0, + 20, + 200); + if (ret < 0) + dev_warn(i2s->dev, "fail to clear: %d\n", ret); } } end: @@ -188,7 +183,6 @@ end: static int rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on) { unsigned int val = 0; - int retry = 10; int ret = 0; spin_lock(&i2s->lock); @@ -226,17 +220,14 @@ static int rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on) I2S_CLR_TXC | I2S_CLR_RXC); if (ret < 0) goto end; - regmap_read(i2s->regmap, I2S_CLR, &val); - /* Should wait for clear operation to finish */ - while (val) { - regmap_read(i2s->regmap, I2S_CLR, &val); - retry--; - if (!retry) { - dev_warn(i2s->dev, "fail to clear\n"); - ret = -EBUSY; - break; - } - } + ret = regmap_read_poll_timeout(i2s->regmap, + I2S_CLR, + val, + val != 0, + 20, + 200); + if (ret < 0) + dev_warn(i2s->dev, "fail to clear: %d\n", ret); } } end: -- cgit v1.2.3 From bfb735a3ceff0bab6473bac275da96f9b2a06dec Mon Sep 17 00:00:00 2001 From: Liang He Date: Wed, 14 Sep 2022 21:43:54 +0800 Subject: ASoC: eureka-tlv320: Hold reference returned from of_find_xxx API In eukrea_tlv320_probe(), we need to hold the reference returned from of_find_compatible_node() which has increased the refcount and then call of_node_put() with it when done. Fixes: 66f232908de2 ("ASoC: eukrea-tlv320: Add DT support.") Co-authored-by: Kelin Wang Signed-off-by: Liang He Link: https://lore.kernel.org/r/20220914134354.3995587-1-windhl@126.com Signed-off-by: Mark Brown --- sound/soc/fsl/eukrea-tlv320.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c index 8b61582753c8..9af4c4a35eb1 100644 --- a/sound/soc/fsl/eukrea-tlv320.c +++ b/sound/soc/fsl/eukrea-tlv320.c @@ -86,7 +86,7 @@ static int eukrea_tlv320_probe(struct platform_device *pdev) int ret; int int_port = 0, ext_port; struct device_node *np = pdev->dev.of_node; - struct device_node *ssi_np = NULL, *codec_np = NULL; + struct device_node *ssi_np = NULL, *codec_np = NULL, *tmp_np = NULL; eukrea_tlv320.dev = &pdev->dev; if (np) { @@ -143,7 +143,7 @@ static int eukrea_tlv320_probe(struct platform_device *pdev) } if (machine_is_eukrea_cpuimx27() || - of_find_compatible_node(NULL, NULL, "fsl,imx21-audmux")) { + (tmp_np = of_find_compatible_node(NULL, NULL, "fsl,imx21-audmux"))) { imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0, IMX_AUDMUX_V1_PCR_SYN | IMX_AUDMUX_V1_PCR_TFSDIR | @@ -158,10 +158,11 @@ static int eukrea_tlv320_probe(struct platform_device *pdev) IMX_AUDMUX_V1_PCR_SYN | IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0) ); + of_node_put(tmp_np); } else if (machine_is_eukrea_cpuimx25sd() || machine_is_eukrea_cpuimx35sd() || machine_is_eukrea_cpuimx51sd() || - of_find_compatible_node(NULL, NULL, "fsl,imx31-audmux")) { + (tmp_np = of_find_compatible_node(NULL, NULL, "fsl,imx31-audmux"))) { if (!np) ext_port = machine_is_eukrea_cpuimx25sd() ? 4 : 3; @@ -178,6 +179,7 @@ static int eukrea_tlv320_probe(struct platform_device *pdev) IMX_AUDMUX_V2_PTCR_SYN, IMX_AUDMUX_V2_PDCR_RXDSEL(int_port) ); + of_node_put(tmp_np); } else { if (np) { /* The eukrea,asoc-tlv320 driver was explicitly -- cgit v1.2.3 From b407589583da08405a19f4b0139d128e1ae41658 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 14 Sep 2022 21:33:53 +0800 Subject: ASoC: bcm2835-i2s: Switch to use dev_err_probe() helper dev_err/dev_dbg() can be replace with dev_err_probe() which will check if error code is -EPROBE_DEFER. Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20220914133355.3779364-1-yangyingliang@huawei.com Signed-off-by: Mark Brown --- sound/soc/bcm/bcm2835-i2s.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c index f4d84774dac7..85f705afcdbb 100644 --- a/sound/soc/bcm/bcm2835-i2s.c +++ b/sound/soc/bcm/bcm2835-i2s.c @@ -841,14 +841,9 @@ static int bcm2835_i2s_probe(struct platform_device *pdev) /* get the clock */ dev->clk_prepared = false; dev->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(dev->clk)) { - ret = PTR_ERR(dev->clk); - if (ret == -EPROBE_DEFER) - dev_dbg(&pdev->dev, "could not get clk: %d\n", ret); - else - dev_err(&pdev->dev, "could not get clk: %d\n", ret); - return ret; - } + if (IS_ERR(dev->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(dev->clk), + "could not get clk\n"); /* Request ioarea */ base = devm_platform_ioremap_resource(pdev, 0); -- cgit v1.2.3 From 28a3fb26e83e013c929a2e1185743ece7e8173ff Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 14 Sep 2022 21:33:54 +0800 Subject: ASoC: cs42l42: Switch to use dev_err_probe() helper dev_err() can be replace with dev_err_probe() which will check if error code is -EPROBE_DEFER. Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20220914133355.3779364-2-yangyingliang@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index de1e276bdf7d..162540c153f9 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -2262,11 +2262,9 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client) NULL, cs42l42_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW, "cs42l42", cs42l42); - if (ret == -EPROBE_DEFER) { - goto err_disable_noirq; - } else if (ret != 0) { - dev_err(&i2c_client->dev, - "Failed to request IRQ: %d\n", ret); + if (ret) { + dev_err_probe(&i2c_client->dev, ret, + "Failed to request IRQ\n"); goto err_disable_noirq; } } -- cgit v1.2.3 From a6b0be65123e1dfbcce6653a82394f989d3372ff Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 14 Sep 2022 21:33:55 +0800 Subject: ASoC: soc-dapm: Switch to use dev_err_probe() helper dev_err() can be replace with dev_err_probe() which will check if error code is -EPROBE_DEFER. Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20220914133355.3779364-3-yangyingliang@huawei.com Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 47a7bf99472e..2d105bfee387 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3764,9 +3764,8 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, return w; request_failed: - if (ret != -EPROBE_DEFER) - dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n", - w->name, ret); + dev_err_probe(dapm->dev, ret, "ASoC: Failed to request %s\n", + w->name); kfree_const(w->name); name_failed: kfree_const(w->sname); -- cgit v1.2.3 From b2496de1dfdddfceb87e7a7b791c3a249c860682 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 10 Sep 2022 11:14:22 +0200 Subject: dt-bindings: soc: qcom: apr: correct service children The APR bindings were not describing properly children nodes for DAIs. None of the DTSes use unit addresses for the children, so correct the nodes and reference their schema: clock-controller, dais and routing. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Srinivas Kandagatla Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20220910091428.50418-10-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- .../devicetree/bindings/soc/qcom/qcom,apr.yaml | 64 ++++++++++++++++++---- .../devicetree/bindings/sound/qcom,q6apm-dai.yaml | 10 +--- .../bindings/sound/qcom,q6dsp-lpass-clocks.yaml | 16 ++---- .../bindings/sound/qcom,q6dsp-lpass-ports.yaml | 16 ++---- 4 files changed, 62 insertions(+), 44 deletions(-) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml index 028c5d105adb..ac508622dc04 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml @@ -97,6 +97,21 @@ patternProperties: 3 = AMDB Service. 4 = Voice processing manager. + clock-controller: + $ref: /schemas/sound/qcom,q6dsp-lpass-clocks.yaml# + description: Qualcomm DSP LPASS clock controller + unevaluatedProperties: false + + dais: + # TODO: Waiting for Documentation/devicetree/bindings/sound/qcom,q6asm.txt + type: object + description: Qualcomm DSP audio ports + + routing: + # TODO: Waiting for Documentation/devicetree/bindings/sound/qcom,q6adm.txt + type: object + description: Qualcomm DSP LPASS audio routing + qcom,protection-domain: $ref: /schemas/types.yaml#/definitions/string-array description: protection domain service name and path for apr service @@ -107,17 +122,44 @@ patternProperties: "tms/servreg", "msm/modem/wlan_pd". "tms/servreg", "msm/slpi/sensor_pd". - '#address-cells': - const: 1 - - '#size-cells': - const: 0 - - patternProperties: - "^.*@[0-9a-f]+$": - type: object - description: - Service based devices like clock controllers or digital audio interfaces. + allOf: + - if: + properties: + compatible: + enum: + - qcom,q6afe + then: + properties: + dais: + properties: + compatible: + const: qcom,q6afe-dais + + - if: + properties: + compatible: + enum: + - qcom,q6apm + then: + properties: + dais: + properties: + compatible: + enum: + - qcom,q6apm-dais + - qcom,q6apm-lpass-dais + + - if: + properties: + compatible: + enum: + - qcom,q6asm + then: + properties: + dais: + properties: + compatible: + const: qcom,q6asm-dais additionalProperties: false diff --git a/Documentation/devicetree/bindings/sound/qcom,q6apm-dai.yaml b/Documentation/devicetree/bindings/sound/qcom,q6apm-dai.yaml index 5d972784321d..844d72b30969 100644 --- a/Documentation/devicetree/bindings/sound/qcom,q6apm-dai.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,q6apm-dai.yaml @@ -16,16 +16,12 @@ properties: compatible: const: qcom,q6apm-dais - reg: - maxItems: 1 - iommus: maxItems: 1 required: - compatible - iommus - - reg additionalProperties: false @@ -41,13 +37,9 @@ examples: compatible = "qcom,q6apm"; reg = <1>; - #address-cells = <1>; - #size-cells = <0>; - - apm-dai@1 { + dais { compatible = "qcom,q6apm-dais"; iommus = <&apps_smmu 0x1801 0x0>; - reg = <1>; }; }; }; diff --git a/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-clocks.yaml b/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-clocks.yaml index f83f00737a2f..604861d84ffa 100644 --- a/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-clocks.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-clocks.yaml @@ -18,9 +18,6 @@ properties: - qcom,q6afe-clocks - qcom,q6prm-lpass-clocks - reg: - maxItems: 1 - '#clock-cells': const: 2 description: @@ -32,7 +29,6 @@ properties: required: - compatible - - reg - "#clock-cells" additionalProperties: false @@ -46,11 +42,9 @@ examples: #size-cells = <0>; apr-service@4 { reg = ; - #address-cells = <1>; - #size-cells = <0>; - clock-controller@2 { + + clock-controller { compatible = "qcom,q6afe-clocks"; - reg = <2>; #clock-cells = <2>; }; }; @@ -66,11 +60,9 @@ examples: service@2 { reg = ; compatible = "qcom,q6prm"; - #address-cells = <1>; - #size-cells = <0>; - clock-controller@2 { + + clock-controller { compatible = "qcom,q6prm-lpass-clocks"; - reg = <2>; #clock-cells = <2>; }; }; diff --git a/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml b/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml index dc7fba7b92d5..5e666d9fb388 100644 --- a/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml @@ -18,9 +18,6 @@ properties: - qcom,q6afe-dais - qcom,q6apm-lpass-dais - reg: - maxItems: 1 - '#sound-dai-cells': const: 1 @@ -145,7 +142,6 @@ patternProperties: required: - compatible - - reg - "#sound-dai-cells" - "#address-cells" - "#size-cells" @@ -161,11 +157,9 @@ examples: #size-cells = <0>; apr-service@4 { reg = ; - #address-cells = <1>; - #size-cells = <0>; - q6afedai@1 { + + dais { compatible = "qcom,q6afe-dais"; - reg = <1>; #address-cells = <1>; #size-cells = <0>; #sound-dai-cells = <1>; @@ -187,11 +181,9 @@ examples: service@1 { compatible = "qcom,q6apm"; reg = ; - #address-cells = <1>; - #size-cells = <0>; - q6apmdai@1 { + + dais { compatible = "qcom,q6apm-lpass-dais"; - reg = <1>; #address-cells = <1>; #size-cells = <0>; #sound-dai-cells = <1>; -- cgit v1.2.3 From 7b0ad4629d1fb719ae71a8f2968e8c6268ab1709 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 10 Sep 2022 11:14:23 +0200 Subject: ASoC: dt-bindings: qcom,q6asm: convert to dtschema Convert Qualcomm Audio Stream Manager (Q6ASM) bindings to DT schema. The original bindings documented: 1. APR service node with compatibles: "qcom,q6asm" and "qcom,q6asm-v.", 2. actual DAIs child node with compatible "qcom,q6asm-dais". The conversion entirely drops (1) because the compatible is already documented in bindings/soc/qcom/qcom,apr.yaml. The "qcom,q6asm-v." on the other hand is not used at all - neither in existing DTS, nor in downstream sources - so versions seems to be fully auto-detectable. Another change done in conversion is adding "iommus" property, which is already used in DTS and Linux driver. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220910091428.50418-11-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- .../devicetree/bindings/soc/qcom/qcom,apr.yaml | 6 +- .../devicetree/bindings/sound/qcom,q6asm-dais.yaml | 112 +++++++++++++++++++++ .../devicetree/bindings/sound/qcom,q6asm.txt | 70 ------------- 3 files changed, 117 insertions(+), 71 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/qcom,q6asm-dais.yaml delete mode 100644 Documentation/devicetree/bindings/sound/qcom,q6asm.txt diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml index ac508622dc04..a1a8f77beef7 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml @@ -103,8 +103,12 @@ patternProperties: unevaluatedProperties: false dais: - # TODO: Waiting for Documentation/devicetree/bindings/sound/qcom,q6asm.txt type: object + oneOf: + - $ref: /schemas/sound/qcom,q6apm-dai.yaml# + - $ref: /schemas/sound/qcom,q6dsp-lpass-ports.yaml# + - $ref: /schemas/sound/qcom,q6asm-dais.yaml# + unevaluatedProperties: false description: Qualcomm DSP audio ports routing: diff --git a/Documentation/devicetree/bindings/sound/qcom,q6asm-dais.yaml b/Documentation/devicetree/bindings/sound/qcom,q6asm-dais.yaml new file mode 100644 index 000000000000..8deb8ffb143b --- /dev/null +++ b/Documentation/devicetree/bindings/sound/qcom,q6asm-dais.yaml @@ -0,0 +1,112 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/qcom,q6asm-dais.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Audio Stream Manager (Q6ASM) + +maintainers: + - Krzysztof Kozlowski + - Srinivas Kandagatla + +description: + Q6ASM is one of the APR audio services on Q6DSP. Each of its subnodes + represent a dai with board specific configuration. + +properties: + compatible: + enum: + - qcom,q6asm-dais + + iommus: + maxItems: 1 + + "#sound-dai-cells": + const: 1 + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +patternProperties: + "^dai@[0-9]+$": + type: object + description: + Q6ASM Digital Audio Interface + + properties: + reg: + maxItems: 1 + + direction: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2] + description: | + The direction of the dai stream:: + - Q6ASM_DAI_TX_RX (0) for both tx and rx + - Q6ASM_DAI_TX (1) for only tx (Capture/Encode) + - Q6ASM_DAI_RX (2) for only rx (Playback/Decode) + + is-compress-dai: + type: boolean + description: + Compress offload dai. + + dependencies: + is-compress-dai: ["direction"] + + required: + - reg + + additionalProperties: false + +required: + - compatible + - "#sound-dai-cells" + - "#address-cells" + - "#size-cells" + +additionalProperties: false + +examples: + - | + #include + #include + + apr { + compatible = "qcom,apr-v2"; + qcom,domain = ; + #address-cells = <1>; + #size-cells = <0>; + + service@7 { + compatible = "qcom,q6asm"; + reg = ; + qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd"; + + dais { + compatible = "qcom,q6asm-dais"; + iommus = <&apps_smmu 0x1821 0x0>; + #address-cells = <1>; + #size-cells = <0>; + #sound-dai-cells = <1>; + + dai@0 { + reg = <0>; + }; + + dai@1 { + reg = <1>; + }; + + dai@2 { + reg = <2>; + is-compress-dai; + direction = <1>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/qcom,q6asm.txt b/Documentation/devicetree/bindings/sound/qcom,q6asm.txt deleted file mode 100644 index 0d0075125243..000000000000 --- a/Documentation/devicetree/bindings/sound/qcom,q6asm.txt +++ /dev/null @@ -1,70 +0,0 @@ -Qualcomm Audio Stream Manager (Q6ASM) binding - -Q6ASM is one of the APR audio service on Q6DSP. -Please refer to qcom,apr.txt for details of the common apr service bindings -used by the apr service device. - -- but must contain the following property: - -- compatible: - Usage: required - Value type: - Definition: must be "qcom,q6asm-v.". - Or "qcom,q6asm" where the version number can be queried - from DSP. - example "qcom,q6asm-v2.0" - -= ASM DAIs (Digital Audio Interface) -"dais" subnode of the ASM node represents dai specific configuration - -- compatible: - Usage: required - Value type: - Definition: must be "qcom,q6asm-dais". - -- #sound-dai-cells - Usage: required - Value type: - Definition: Must be 1 - -== ASM DAI is subnode of "dais" and represent a dai, it includes board specific -configuration of each dai. Must contain the following properties. - -- reg - Usage: required - Value type: - Definition: Must be dai id - -- direction: - Usage: Required for Compress offload dais - Value type: - Definition: Specifies the direction of the dai stream - Q6ASM_DAI_TX_RX (0) for both tx and rx - Q6ASM_DAI_TX (1) for only tx (Capture/Encode) - Q6ASM_DAI_RX (2) for only rx (Playback/Decode) - -- is-compress-dai: - Usage: Required for Compress offload dais - Value type: - Definition: present for Compress offload dais - - -= EXAMPLE -#include - -apr-service@7 { - compatible = "qcom,q6asm"; - reg = ; - q6asmdai: dais { - compatible = "qcom,q6asm-dais"; - #address-cells = <1>; - #size-cells = <0>; - #sound-dai-cells = <1>; - - dai@0 { - reg = <0>; - direction = ; - is-compress-dai; - }; - }; -}; -- cgit v1.2.3 From 301628d805019999f1ae9764aadfcface9c4e309 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 10 Sep 2022 11:14:24 +0200 Subject: ASoC: dt-bindings: qcom,q6adm: convert to dtschema Convert Qualcomm Audio Device Manager (Q6ADM) bindings to DT schema. The original bindings documented: 1. APR service node with compatibles: "qcom,q6adm" and "qcom,q6adm-v.", 2. Routing child node with compatible "qcom,q6adm-routing". The conversion entirely drops (1) because the compatible is already documented in bindings/soc/qcom/qcom,apr.yaml. The "qcom,q6adm-v." on the other hand is not used at all - neither in existing DTS, nor in downstream sources - so versions seems to be fully auto-detectable. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20220910091428.50418-12-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- .../devicetree/bindings/soc/qcom/qcom,apr.yaml | 3 +- .../bindings/sound/qcom,q6adm-routing.yaml | 52 ++++++++++++++++++++++ .../devicetree/bindings/sound/qcom,q6adm.txt | 39 ---------------- 3 files changed, 54 insertions(+), 40 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/qcom,q6adm-routing.yaml delete mode 100644 Documentation/devicetree/bindings/sound/qcom,q6adm.txt diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml index a1a8f77beef7..54328d74af85 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml @@ -112,8 +112,9 @@ patternProperties: description: Qualcomm DSP audio ports routing: - # TODO: Waiting for Documentation/devicetree/bindings/sound/qcom,q6adm.txt type: object + $ref: /schemas/sound/qcom,q6adm-routing.yaml# + unevaluatedProperties: false description: Qualcomm DSP LPASS audio routing qcom,protection-domain: diff --git a/Documentation/devicetree/bindings/sound/qcom,q6adm-routing.yaml b/Documentation/devicetree/bindings/sound/qcom,q6adm-routing.yaml new file mode 100644 index 000000000000..d0f7a79e240a --- /dev/null +++ b/Documentation/devicetree/bindings/sound/qcom,q6adm-routing.yaml @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/qcom,q6adm-routing.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Audio Device Manager (Q6ADM) routing + +maintainers: + - Krzysztof Kozlowski + - Srinivas Kandagatla + +description: + Qualcomm Audio Device Manager (Q6ADM) routing node represents routing + specific configuration. + +properties: + compatible: + enum: + - qcom,q6adm-routing + + "#sound-dai-cells": + const: 0 + +required: + - compatible + - "#sound-dai-cells" + +additionalProperties: false + +examples: + - | + #include + #include + + apr { + compatible = "qcom,apr-v2"; + qcom,domain = ; + #address-cells = <1>; + #size-cells = <0>; + + service@8 { + compatible = "qcom,q6adm"; + reg = ; + qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd"; + + routing { + compatible = "qcom,q6adm-routing"; + #sound-dai-cells = <0>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/qcom,q6adm.txt b/Documentation/devicetree/bindings/sound/qcom,q6adm.txt deleted file mode 100644 index 15c353a20de8..000000000000 --- a/Documentation/devicetree/bindings/sound/qcom,q6adm.txt +++ /dev/null @@ -1,39 +0,0 @@ -Qualcomm Audio Device Manager (Q6ADM) binding - -Q6ADM is one of the APR audio service on Q6DSP. -Please refer to qcom,apr.txt for details of the coommon apr service bindings -used by the apr service device. - -- but must contain the following property: - -- compatible: - Usage: required - Value type: - Definition: must be "qcom,q6adm-v.". - Or "qcom,q6adm" where the version number can be queried - from DSP. - example "qcom,q6adm-v2.0" - - -= ADM routing -"routing" subnode of the ADM node represents adm routing specific configuration - -- compatible: - Usage: required - Value type: - Definition: must be "qcom,q6adm-routing". - -- #sound-dai-cells - Usage: required - Value type: - Definition: Must be 0 - -= EXAMPLE -apr-service@8 { - compatible = "qcom,q6adm"; - reg = ; - q6routing: routing { - compatible = "qcom,q6adm-routing"; - #sound-dai-cells = <0>; - }; -}; -- cgit v1.2.3 From 0630efc3b849f65ef3bad803b84bc0819591dac9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 10 Sep 2022 11:14:25 +0200 Subject: ASoC: dt-bindings: qcom,q6dsp-lpass-ports: cleanup example Cleanup the example DTS by adding APR and service compatibles, adding typical properties, using proper device node names for services and fixing indentation to 4-spaces. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Srinivas Kandagatla Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20220910091428.50418-13-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- .../bindings/sound/qcom,q6dsp-lpass-ports.yaml | 48 ++++++++++++---------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml b/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml index 5e666d9fb388..e53fc0960a14 100644 --- a/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml @@ -153,24 +153,29 @@ examples: #include #include apr { + compatible = "qcom,apr-v2"; #address-cells = <1>; #size-cells = <0>; - apr-service@4 { + qcom,domain = ; + + service@4 { + compatible = "qcom,q6afe"; reg = ; + qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd"; dais { - compatible = "qcom,q6afe-dais"; - #address-cells = <1>; - #size-cells = <0>; - #sound-dai-cells = <1>; - - dai@22 { - reg = ; - qcom,sd-lines = <0 1 2 3>; - }; + compatible = "qcom,q6afe-dais"; + #address-cells = <1>; + #size-cells = <0>; + #sound-dai-cells = <1>; + + dai@22 { + reg = ; + qcom,sd-lines = <0 1 2 3>; + }; }; }; - }; + }; - | #include gpr { @@ -178,20 +183,21 @@ examples: #address-cells = <1>; #size-cells = <0>; qcom,domain = ; + service@1 { compatible = "qcom,q6apm"; reg = ; dais { - compatible = "qcom,q6apm-lpass-dais"; - #address-cells = <1>; - #size-cells = <0>; - #sound-dai-cells = <1>; - - dai@22 { - reg = ; - qcom,sd-lines = <0 1 2 3>; - }; + compatible = "qcom,q6apm-lpass-dais"; + #address-cells = <1>; + #size-cells = <0>; + #sound-dai-cells = <1>; + + dai@22 { + reg = ; + qcom,sd-lines = <0 1 2 3>; + }; }; }; - }; + }; -- cgit v1.2.3 From 7af18f4efd85c2e85458e3f504e129a97f6baaf2 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 10 Sep 2022 11:14:26 +0200 Subject: ASoC: dt-bindings: qcom,q6dsp-lpass-clocks: cleanup example Cleanup the example DTS by adding APR and service compatibles, adding typical properties, using proper device node names for services and fixing indentation to 4-spaces. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Srinivas Kandagatla Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20220910091428.50418-14-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- .../bindings/sound/qcom,q6dsp-lpass-clocks.yaml | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-clocks.yaml b/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-clocks.yaml index 604861d84ffa..fd567d20417d 100644 --- a/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-clocks.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-clocks.yaml @@ -38,17 +38,22 @@ examples: #include #include apr { + compatible = "qcom,apr-v2"; + qcom,domain = ; #address-cells = <1>; #size-cells = <0>; - apr-service@4 { + + service@4 { + compatible = "qcom,q6afe"; reg = ; + qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd"; clock-controller { - compatible = "qcom,q6afe-clocks"; - #clock-cells = <2>; + compatible = "qcom,q6afe-clocks"; + #clock-cells = <2>; }; }; - }; + }; - | #include @@ -57,13 +62,14 @@ examples: qcom,domain = ; #address-cells = <1>; #size-cells = <0>; + service@2 { reg = ; compatible = "qcom,q6prm"; clock-controller { - compatible = "qcom,q6prm-lpass-clocks"; - #clock-cells = <2>; + compatible = "qcom,q6prm-lpass-clocks"; + #clock-cells = <2>; }; }; - }; + }; -- cgit v1.2.3 From 5f170e21fe96fbd1f81ace9ec6e6b695e1098733 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 10 Sep 2022 11:14:27 +0200 Subject: ASoC: dt-bindings: qcom,q6apm-dai: adjust indentation in example Cleanup the example DTS by fixing indentation to 4-spaces and adding blank lines for readability. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20220910091428.50418-15-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/qcom,q6apm-dai.yaml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/qcom,q6apm-dai.yaml b/Documentation/devicetree/bindings/sound/qcom,q6apm-dai.yaml index 844d72b30969..24f7bf2bfd95 100644 --- a/Documentation/devicetree/bindings/sound/qcom,q6apm-dai.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,q6apm-dai.yaml @@ -33,13 +33,14 @@ examples: #address-cells = <1>; #size-cells = <0>; qcom,domain = ; + service@1 { - compatible = "qcom,q6apm"; - reg = <1>; + compatible = "qcom,q6apm"; + reg = <1>; - dais { - compatible = "qcom,q6apm-dais"; - iommus = <&apps_smmu 0x1801 0x0>; - }; + dais { + compatible = "qcom,q6apm-dais"; + iommus = <&apps_smmu 0x1801 0x0>; + }; }; }; -- cgit v1.2.3 From b2d7616e13c4eb766f5e2f6568c2e746e76b7b53 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 10 Sep 2022 11:14:28 +0200 Subject: dt-bindings: soc: qcom: apr: add missing properties The APR bindings were not describing all properties already used in DTS: 1. Add qcom,glink-channels, qcom,smd-channels and qcom,intents (widely used). 2. Add power-domains for MSM8996. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Srinivas Kandagatla Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20220910091428.50418-16-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- .../devicetree/bindings/soc/qcom/qcom,apr.yaml | 47 ++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml index 54328d74af85..f47491aab3b1 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml @@ -20,6 +20,9 @@ properties: - qcom,apr-v2 - qcom,gpr + power-domains: + maxItems: 1 + qcom,apr-domain: $ref: /schemas/types.yaml#/definitions/uint32 enum: [1, 2, 3, 4, 5, 6, 7] @@ -52,6 +55,26 @@ properties: 2 = Audio DSP Domain 3 = Application Processor Domain + qcom,glink-channels: + $ref: /schemas/types.yaml#/definitions/string-array + description: Channel name used for the communication + items: + - const: apr_audio_svc + + qcom,intents: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: + List of (size, amount) pairs describing what intents should be + preallocated for this virtual channel. This can be used to tweak the + default intents available for the channel to meet expectations of the + remote. + + qcom,smd-channels: + $ref: /schemas/types.yaml#/definitions/string-array + description: Channel name used for the communication + items: + - const: apr_audio_svc + '#address-cells': const: 1 @@ -172,6 +195,30 @@ required: - compatible - qcom,domain +allOf: + - if: + properties: + compatible: + enum: + - qcom,gpr + then: + properties: + power-domains: false + + - if: + required: + - qcom,glink-channels + then: + properties: + qcom,smd-channels: false + + - if: + required: + - qcom,smd-channels + then: + properties: + qcom,glink-channels: false + additionalProperties: false examples: -- cgit v1.2.3 From 39efc9c8a973ddff5918191525d1679d0fb368ea Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 15 Sep 2022 10:59:47 +0200 Subject: ALSA: usb-audio: Fix last interface check for registration The recent fix in commit 6392dcd1d0c7 ("ALSA: usb-audio: Register card at the last interface") tried to delay the card registration until the last found interface is probed. It assumed that the probe callback gets called for those later interfaces, but it's not always true; as the driver loops over the descriptor and probes the matching ones, it's not separately called via multiple probe calls. This results in the missing card registration, i.e. no sound device. For addressing this problem, replace the check whether the last interface is processed with usb_interface_claimed() instead of the comparison with the probe interface number. Fixes: 6392dcd1d0c7 ("ALSA: usb-audio: Register card at the last interface") Link: https://lore.kernel.org/r/20220915085947.7922-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/card.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/usb/card.c b/sound/usb/card.c index 3aea241435fb..a5ed11ea1145 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -884,7 +884,7 @@ static int usb_audio_probe(struct usb_interface *intf, * one given via option */ if (check_delayed_register_option(chip) == ifnum || - chip->last_iface == ifnum) { + usb_interface_claimed(usb_ifnum_to_if(dev, chip->last_iface))) { err = snd_card_register(chip->card); if (err < 0) goto __error; -- cgit v1.2.3 From 7883017bbcc55fcb1888add3dc825e112d7ae336 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Fri, 16 Sep 2022 22:11:08 +0800 Subject: ALSA: ppc: Switch to use for_each_child_of_node() macro Use for_each_child_of_node() macro instead of open coding it. No functional change. Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20220916141108.683080-1-yangyingliang@huawei.com Signed-off-by: Takashi Iwai --- sound/ppc/tumbler.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index c65e74d7cd0a..f3f8ad7c3df8 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c @@ -1060,8 +1060,7 @@ static struct device_node *find_audio_device(const char *name) if (! gpiop) return NULL; - for (np = of_get_next_child(gpiop, NULL); np; - np = of_get_next_child(gpiop, np)) { + for_each_child_of_node(gpiop, np) { const char *property = of_get_property(np, "audio-gpio", NULL); if (property && strcmp(property, name) == 0) break; @@ -1080,8 +1079,7 @@ static struct device_node *find_compatible_audio_device(const char *name) if (!gpiop) return NULL; - for (np = of_get_next_child(gpiop, NULL); np; - np = of_get_next_child(gpiop, np)) { + for_each_child_of_node(gpiop, np) { if (of_device_is_compatible(np, name)) break; } -- cgit v1.2.3 From 9dd28b467c35eef320a2974f6b1f209343ad8704 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 16 Sep 2022 14:13:49 +0300 Subject: ASoC: max98390: Fix dsm calibration reading With the change introduced by 6ac246105b4f, the calibration can only be done after the codec probe (but questionable if it is working since 203A_AMP_EN is 0) or when the codec is powered up for audio use, in other cases "AMP is not ready to run calibration" is printed. This changes how this worked before the patch: the codec was force powered on for the duration of the calibration readout, then shut down. So, if a calibration was asked when the codec was active, it would have powered it down? To correct the calibration logic: check if the codec is powered on and if it is not then enable it, do the readout and put it back to disabled. Do this while keeping the dapm locked to avoid interfering with normal operation via DAPM. Fixes: 6ac246105b4f ("ASoC: max98390: Remove unnecessary amp on/off conrtol") Reported-by: Fred Oh Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20220916111349.4433-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/max98390.c | 79 ++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c index 4ef8cd1053af..7a5260ff8d6b 100644 --- a/sound/soc/codecs/max98390.c +++ b/sound/soc/codecs/max98390.c @@ -161,8 +161,6 @@ static struct reg_default max98390_reg_defaults[] = { {MAX98390_R23FF_GLOBAL_EN, 0x00}, }; -static int max98390_dsm_calibrate(struct snd_soc_component *component); - static int max98390_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct snd_soc_component *component = codec_dai->component; @@ -635,20 +633,49 @@ static int max98390_dsm_calib_get(struct snd_kcontrol *kcontrol, static int max98390_dsm_calib_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - unsigned int val; - struct snd_soc_component *component = - snd_soc_kcontrol_component(kcontrol); - struct max98390_priv *max98390 = - snd_soc_component_get_drvdata(component); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct max98390_priv *max98390 = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + unsigned int rdc, rdc_cal_result, rdc_integer, rdc_factor, temp, val; + + snd_soc_dapm_mutex_lock(dapm); regmap_read(max98390->regmap, MAX98390_R23FF_GLOBAL_EN, &val); - if (val == 0x1) - max98390_dsm_calibrate(component); - else { - dev_err(component->dev, "AMP is not ready to run calibration\n"); - return -ECANCELED; + if (!val) { + /* Enable the codec for the duration of calibration readout */ + regmap_update_bits(max98390->regmap, MAX98390_R203A_AMP_EN, + MAX98390_AMP_EN_MASK, 1); + regmap_update_bits(max98390->regmap, MAX98390_R23FF_GLOBAL_EN, + MAX98390_GLOBAL_EN_MASK, 1); + } + + regmap_read(max98390->regmap, THERMAL_RDC_RD_BACK_BYTE1, &rdc); + regmap_read(max98390->regmap, THERMAL_RDC_RD_BACK_BYTE0, &rdc_cal_result); + regmap_read(max98390->regmap, MAX98390_MEAS_ADC_CH2_READ, &temp); + + if (!val) { + /* Disable the codec if it was disabled */ + regmap_update_bits(max98390->regmap, MAX98390_R23FF_GLOBAL_EN, + MAX98390_GLOBAL_EN_MASK, 0); + regmap_update_bits(max98390->regmap, MAX98390_R203A_AMP_EN, + MAX98390_AMP_EN_MASK, 0); } + snd_soc_dapm_mutex_unlock(dapm); + + rdc_cal_result |= (rdc << 8) & 0x0000FFFF; + if (rdc_cal_result) + max98390->ref_rdc_value = 268435456U / rdc_cal_result; + + max98390->ambient_temp_value = temp * 52 - 1188; + + rdc_integer = rdc_cal_result * 937 / 65536; + rdc_factor = ((rdc_cal_result * 937 * 100) / 65536) - (rdc_integer * 100); + + dev_info(component->dev, + "rdc resistance about %d.%02d ohm, reg=0x%X temp reg=0x%X\n", + rdc_integer, rdc_factor, rdc_cal_result, temp); + return 0; } @@ -828,34 +855,6 @@ err: return ret; } -static int max98390_dsm_calibrate(struct snd_soc_component *component) -{ - unsigned int rdc, rdc_cal_result, temp; - unsigned int rdc_integer, rdc_factor; - struct max98390_priv *max98390 = - snd_soc_component_get_drvdata(component); - - regmap_read(max98390->regmap, - THERMAL_RDC_RD_BACK_BYTE1, &rdc); - regmap_read(max98390->regmap, - THERMAL_RDC_RD_BACK_BYTE0, &rdc_cal_result); - rdc_cal_result |= (rdc << 8) & 0x0000FFFF; - if (rdc_cal_result) - max98390->ref_rdc_value = 268435456U / rdc_cal_result; - - regmap_read(max98390->regmap, MAX98390_MEAS_ADC_CH2_READ, &temp); - max98390->ambient_temp_value = temp * 52 - 1188; - - rdc_integer = rdc_cal_result * 937 / 65536; - rdc_factor = ((rdc_cal_result * 937 * 100) / 65536) - - (rdc_integer * 100); - - dev_info(component->dev, "rdc resistance about %d.%02d ohm, reg=0x%X temp reg=0x%X\n", - rdc_integer, rdc_factor, rdc_cal_result, temp); - - return 0; -} - static void max98390_init_regs(struct snd_soc_component *component) { struct max98390_priv *max98390 = -- cgit v1.2.3 From fa6e73d69193d0ba3b794f7c303beae498732f40 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 19 Sep 2022 14:21:02 +0200 Subject: ASoC: SOF: add widget setup/free tracing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enables tracking of use_count during widget setup and free routines. Useful for debugging unbalanced use_counts during suspend/resume. Reviewed-by: Péter Ujfalusi Signed-off-by: Noah Klayman Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220919122108.43764-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/trace/events/sof.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ sound/soc/sof/core.c | 3 +++ sound/soc/sof/sof-audio.c | 5 +++++ 3 files changed, 52 insertions(+) create mode 100644 include/trace/events/sof.h diff --git a/include/trace/events/sof.h b/include/trace/events/sof.h new file mode 100644 index 000000000000..f25eef6c95c0 --- /dev/null +++ b/include/trace/events/sof.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright(c) 2022 Intel Corporation. All rights reserved. + * + * Author: Noah Klayman + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM sof + +#if !defined(_TRACE_SOF_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_SOF_H +#include +#include +#include "../../../sound/soc/sof/sof-audio.h" + +DECLARE_EVENT_CLASS(sof_widget_template, + TP_PROTO(struct snd_sof_widget *swidget), + TP_ARGS(swidget), + TP_STRUCT__entry( + __string(name, swidget->widget->name) + __field(int, use_count) + ), + TP_fast_assign( + __assign_str(name, swidget->widget->name); + __entry->use_count = swidget->use_count; + ), + TP_printk("name=%s use_count=%d", __get_str(name), __entry->use_count) +); + +DEFINE_EVENT(sof_widget_template, sof_widget_setup, + TP_PROTO(struct snd_sof_widget *swidget), + TP_ARGS(swidget) +); + +DEFINE_EVENT(sof_widget_template, sof_widget_free, + TP_PROTO(struct snd_sof_widget *swidget), + TP_ARGS(swidget) +); + +#endif /* _TRACE_SOF_H */ + +/* This part must be outside protection */ +#include diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index c99b5e6c026c..3e6141d03770 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -15,6 +15,9 @@ #include "sof-priv.h" #include "ops.h" +#define CREATE_TRACE_POINTS +#include + /* see SOF_DBG_ flags */ 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); diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index ea9663d448eb..a3d3dd7a0037 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -9,6 +9,7 @@ // #include +#include #include "sof-audio.h" #include "sof-of-dev.h" #include "ops.h" @@ -36,6 +37,8 @@ int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) if (!swidget->private) return 0; + trace_sof_widget_free(swidget); + /* only free when use_count is 0 */ if (--swidget->use_count) return 0; @@ -86,6 +89,8 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) if (!swidget->private) return 0; + trace_sof_widget_setup(swidget); + /* widget already set up */ if (++swidget->use_count > 1) return 0; -- cgit v1.2.3 From baedc6300b3d52c71a06f4bddd426488ec243c2b Mon Sep 17 00:00:00 2001 From: Noah Klayman Date: Mon, 19 Sep 2022 14:21:03 +0200 Subject: ASoC: SOF: Intel: add HDA interrupt source tracing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Intel HDaudio controller relies on a single interrupt line which wire-ORs multiple interrupt sources, such as stream, IPC, SoundWire and wakes. This patch adds the ability to trace each event occurrence. Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Signed-off-by: Noah Klayman Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220919122108.43764-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/trace/events/sof_intel.h | 34 ++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/hda.c | 19 +++++++++++++++---- 2 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 include/trace/events/sof_intel.h diff --git a/include/trace/events/sof_intel.h b/include/trace/events/sof_intel.h new file mode 100644 index 000000000000..37a9b92d494e --- /dev/null +++ b/include/trace/events/sof_intel.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright(c) 2022 Intel Corporation. All rights reserved. + * + * Author: Noah Klayman + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM sof_intel + +#if !defined(_TRACE_SOF_INTEL_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_SOF_INTEL_H +#include +#include "../../../sound/soc/sof/sof-audio.h" + +TRACE_EVENT(sof_intel_hda_irq, + TP_PROTO(struct snd_sof_dev *sdev, char *source), + TP_ARGS(sdev, source), + TP_STRUCT__entry( + __string(device_name, dev_name(sdev->dev)) + __string(source, source) + ), + TP_fast_assign( + __assign_str(device_name, dev_name(sdev->dev)); + __assign_str(source, source); + ), + TP_printk("device_name=%s source=%s", + __get_str(device_name), __get_str(source)) +); + +#endif /* _TRACE_SOF_INTEL_H */ + +/* This part must be outside protection */ +#include diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 6d4ecbe14adf..79df990da1ea 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -31,6 +31,9 @@ #include "../ops.h" #include "hda.h" +#define CREATE_TRACE_POINTS +#include + #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) #include #endif @@ -938,17 +941,25 @@ static irqreturn_t hda_dsp_interrupt_thread(int irq, void *context) struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; /* deal with streams and controller first */ - if (hda_dsp_check_stream_irq(sdev)) + if (hda_dsp_check_stream_irq(sdev)) { + trace_sof_intel_hda_irq(sdev, "stream"); hda_dsp_stream_threaded_handler(irq, sdev); + } - if (hda_check_ipc_irq(sdev)) + if (hda_check_ipc_irq(sdev)) { + trace_sof_intel_hda_irq(sdev, "ipc"); sof_ops(sdev)->irq_thread(irq, sdev); + } - if (hda_dsp_check_sdw_irq(sdev)) + if (hda_dsp_check_sdw_irq(sdev)) { + trace_sof_intel_hda_irq(sdev, "sdw"); hda_dsp_sdw_thread(irq, hdev->sdw); + } - if (hda_sdw_check_wakeen_irq(sdev)) + if (hda_sdw_check_wakeen_irq(sdev)) { + trace_sof_intel_hda_irq(sdev, "wakeen"); hda_sdw_process_wakeen(sdev); + } hda_check_for_state_change(sdev); -- cgit v1.2.3 From 032e7c68bb4f4d977d2dd7f7629771973131f15e Mon Sep 17 00:00:00 2001 From: Noah Klayman Date: Mon, 19 Sep 2022 14:21:04 +0200 Subject: ASoC: SOF: Intel: remove unneeded dev_vdbg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch removes an unneeded dev_vdbg call in hda-stream. Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Signed-off-by: Noah Klayman Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220919122108.43764-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-stream.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index b58662faa4aa..8344363beec0 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -93,9 +93,6 @@ static int hda_setup_bdle(struct snd_sof_dev *sdev, bdl++; hstream->frags++; offset += chunk; - - dev_vdbg(sdev->dev, "bdl, frags:%d, chunk size:0x%x;\n", - hstream->frags, chunk); } *bdlp = bdl; -- cgit v1.2.3 From 4a232cc910b943947a52da363bce1265911555f7 Mon Sep 17 00:00:00 2001 From: Noah Klayman Date: Mon, 19 Sep 2022 14:21:05 +0200 Subject: ASoC: SOF: remove unneeded dev_vdbg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch removes some unneeded dev_vdbg calls. Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Signed-off-by: Noah Klayman Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220919122108.43764-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-utils.c | 2 -- sound/soc/sof/topology.c | 9 --------- 2 files changed, 11 deletions(-) diff --git a/sound/soc/sof/sof-utils.c b/sound/soc/sof/sof-utils.c index a3300ecee062..b6345a7345af 100644 --- a/sound/soc/sof/sof-utils.c +++ b/sound/soc/sof/sof-utils.c @@ -45,8 +45,6 @@ int snd_sof_create_page_table(struct device *dev, u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT; u8 *pg_table; - dev_vdbg(dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn); - pg_table = (u8 *)(page_table + idx); /* diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 9273a70fec25..6087483deb48 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1011,9 +1011,6 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp, } list_for_each_entry(rtd, &card->rtd_list, list) { - dev_vdbg(scomp->dev, "tplg: check widget: %s stream: %s dai stream: %s\n", - w->name, w->sname, rtd->dai_link->stream_name); - /* does stream match DAI link ? */ if (!rtd->dai_link->stream_name || strcmp(w->sname, rtd->dai_link->stream_name)) @@ -1537,9 +1534,6 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, stream = SNDRV_PCM_STREAM_PLAYBACK; - dev_vdbg(scomp->dev, "tplg: pcm %s stream tokens: playback d0i3:%d\n", - spcm->pcm.pcm_name, spcm->stream[stream].d0i3_compatible); - caps = &spcm->pcm.caps[stream]; /* allocate playback page table buffer */ @@ -1567,9 +1561,6 @@ capture: if (!spcm->pcm.capture) return ret; - dev_vdbg(scomp->dev, "tplg: pcm %s stream tokens: capture d0i3:%d\n", - spcm->pcm.pcm_name, spcm->stream[stream].d0i3_compatible); - caps = &spcm->pcm.caps[stream]; /* allocate capture page table buffer */ -- cgit v1.2.3 From d272b65704bbbb9c054093c8c7dffb7b1793539f Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 19 Sep 2022 14:21:06 +0200 Subject: ASoC: SOF: Intel: replace dev_vdbg with tracepoints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch replaces all dev_vdbg calls with tracepoints to reduce overhead and enable use of trace collection and analysis tools. Reviewed-by: Péter Ujfalusi Signed-off-by: Noah Klayman Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220919122108.43764-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/trace/events/sof_intel.h | 114 +++++++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/cnl.c | 9 ++-- sound/soc/sof/intel/hda-dsp.c | 4 +- sound/soc/sof/intel/hda-ipc.c | 11 ++-- sound/soc/sof/intel/hda-pcm.c | 4 +- sound/soc/sof/intel/hda-stream.c | 6 +-- sound/soc/sof/intel/mtl.c | 3 +- 7 files changed, 130 insertions(+), 21 deletions(-) diff --git a/include/trace/events/sof_intel.h b/include/trace/events/sof_intel.h index 37a9b92d494e..2a77f9d26c0b 100644 --- a/include/trace/events/sof_intel.h +++ b/include/trace/events/sof_intel.h @@ -11,6 +11,7 @@ #if !defined(_TRACE_SOF_INTEL_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_SOF_INTEL_H #include +#include #include "../../../sound/soc/sof/sof-audio.h" TRACE_EVENT(sof_intel_hda_irq, @@ -28,6 +29,119 @@ TRACE_EVENT(sof_intel_hda_irq, __get_str(device_name), __get_str(source)) ); +DECLARE_EVENT_CLASS(sof_intel_ipc_firmware_template, + TP_ARGS(struct snd_sof_dev *sdev, u32 msg, u32 msg_ext), + TP_PROTO(sdev, msg, msg_ext), + TP_STRUCT__entry( + __string(device_name, dev_name(sdev->dev)) + __field(u32, msg) + __field(u32, msg_ext) + ), + TP_fast_assign( + __assign_str(device_name, dev_name(sdev->dev)); + __entry->msg = msg; + __entry->msg_ext = msg_ext; + ), + TP_printk("device_name=%s msg=%#x msg_ext=%#x", + __get_str(device_name), __entry->msg, __entry->msg_ext) +); + +DEFINE_EVENT(sof_intel_ipc_firmware_template, sof_intel_ipc_firmware_response, + TP_PROTO(struct snd_sof_dev *sdev, u32 msg, u32 msg_ext), + TP_ARGS(sdev, msg, msg_ext) +); + +DEFINE_EVENT(sof_intel_ipc_firmware_template, sof_intel_ipc_firmware_initiated, + TP_PROTO(struct snd_sof_dev *sdev, u32 msg, u32 msg_ext), + TP_ARGS(sdev, msg, msg_ext) +); + +TRACE_EVENT(sof_intel_D0I3C_updated, + TP_PROTO(struct snd_sof_dev *sdev, u8 reg), + TP_ARGS(sdev, reg), + TP_STRUCT__entry( + __string(device_name, dev_name(sdev->dev)) + __field(u8, reg) + ), + TP_fast_assign( + __assign_str(device_name, dev_name(sdev->dev)); + __entry->reg = reg; + ), + TP_printk("device_name=%s register=%#x", + __get_str(device_name), __entry->reg) +); + +TRACE_EVENT(sof_intel_hda_irq_ipc_check, + TP_PROTO(struct snd_sof_dev *sdev, u32 irq_status), + TP_ARGS(sdev, irq_status), + TP_STRUCT__entry( + __string(device_name, dev_name(sdev->dev)) + __field(u32, irq_status) + ), + TP_fast_assign( + __assign_str(device_name, dev_name(sdev->dev)); + __entry->irq_status = irq_status; + ), + TP_printk("device_name=%s irq_status=%#x", + __get_str(device_name), __entry->irq_status) +); + +TRACE_EVENT(sof_intel_hda_dsp_pcm, + TP_PROTO(struct snd_sof_dev *sdev, + struct hdac_stream *hstream, + struct snd_pcm_substream *substream, + snd_pcm_uframes_t pos + ), + TP_ARGS(sdev, hstream, substream, pos), + TP_STRUCT__entry( + __string(device_name, dev_name(sdev->dev)) + __field(u32, hstream_index) + __field(u32, substream) + __field(unsigned long, pos) + ), + TP_fast_assign( + __assign_str(device_name, dev_name(sdev->dev)); + __entry->hstream_index = hstream->index; + __entry->substream = substream->stream; + __entry->pos = pos; + ), + TP_printk("device_name=%s hstream_index=%d substream=%d pos=%lu", + __get_str(device_name), __entry->hstream_index, + __entry->substream, __entry->pos) +); + +TRACE_EVENT(sof_intel_hda_dsp_stream_status, + TP_PROTO(struct device *dev, struct hdac_stream *s, u32 status), + TP_ARGS(dev, s, status), + TP_STRUCT__entry( + __string(device_name, dev_name(dev)) + __field(u32, stream) + __field(u32, status) + ), + TP_fast_assign( + __assign_str(device_name, dev_name(dev)); + __entry->stream = s->index; + __entry->status = status; + ), + TP_printk("device_name=%s stream=%d status=%#x", + __get_str(device_name), __entry->stream, __entry->status) +); + +TRACE_EVENT(sof_intel_hda_dsp_check_stream_irq, + TP_PROTO(struct snd_sof_dev *sdev, u32 status), + TP_ARGS(sdev, status), + TP_STRUCT__entry( + __string(device_name, dev_name(sdev->dev)) + __field(u32, status) + ), + TP_fast_assign( + __assign_str(device_name, dev_name(sdev->dev)); + __entry->status = status; + ), + TP_printk("device_name=%s status=%#x", + __get_str(device_name), __entry->status) +); + #endif /* _TRACE_SOF_INTEL_H */ /* This part must be outside protection */ diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 0bb91df27280..180001d0a38a 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -17,6 +17,7 @@ #include #include +#include #include "../ipc4-priv.h" #include "../ops.h" #include "hda.h" @@ -121,9 +122,7 @@ irqreturn_t cnl_ipc_irq_thread(int irq, void *context) msg_ext = hipci & CNL_DSP_REG_HIPCIDR_MSG_MASK; msg = hipcida & CNL_DSP_REG_HIPCIDA_MSG_MASK; - dev_vdbg(sdev->dev, - "ipc: firmware response, msg:0x%x, msg_ext:0x%x\n", - msg, msg_ext); + trace_sof_intel_ipc_firmware_response(sdev, msg, msg_ext); /* mask Done interrupt */ snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, @@ -153,9 +152,7 @@ irqreturn_t cnl_ipc_irq_thread(int irq, void *context) msg = hipctdr & CNL_DSP_REG_HIPCTDR_MSG_MASK; msg_ext = hipctdd & CNL_DSP_REG_HIPCTDD_MSG_MASK; - dev_vdbg(sdev->dev, - "ipc: firmware initiated, msg:0x%x, msg_ext:0x%x\n", - msg, msg_ext); + trace_sof_intel_ipc_firmware_initiated(sdev, msg, msg_ext); /* handle messages from DSP */ if ((hipctdr & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 671c3e02d7df..1319c8e34021 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "../sof-audio.h" #include "../ops.h" #include "hda.h" @@ -397,8 +398,7 @@ static int hda_dsp_update_d0i3c_register(struct snd_sof_dev *sdev, u8 value) return ret; } - dev_vdbg(bus->dev, "D0I3C updated, register = 0x%x\n", - snd_hdac_chip_readb(bus, VS_D0I3C)); + trace_sof_intel_D0I3C_updated(sdev, snd_hdac_chip_readb(bus, VS_D0I3C)); return 0; } diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 65e688f749ea..c597ef491d38 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -16,6 +16,7 @@ */ #include +#include #include "../ops.h" #include "hda.h" @@ -212,9 +213,7 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) msg = hipci & HDA_DSP_REG_HIPCI_MSG_MASK; msg_ext = hipcie & HDA_DSP_REG_HIPCIE_MSG_MASK; - dev_vdbg(sdev->dev, - "ipc: firmware response, msg:0x%x, msg_ext:0x%x\n", - msg, msg_ext); + trace_sof_intel_ipc_firmware_response(sdev, msg, msg_ext); /* mask Done interrupt */ snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, @@ -255,9 +254,7 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) msg = hipct & HDA_DSP_REG_HIPCT_MSG_MASK; msg_ext = hipcte & HDA_DSP_REG_HIPCTE_MSG_MASK; - dev_vdbg(sdev->dev, - "ipc: firmware initiated, msg:0x%x, msg_ext:0x%x\n", - msg, msg_ext); + trace_sof_intel_ipc_firmware_initiated(sdev, msg, msg_ext); /* mask BUSY interrupt */ snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, @@ -312,7 +309,7 @@ bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev) /* store status */ irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIS); - dev_vdbg(sdev->dev, "irq handler: irq_status:0x%x\n", irq_status); + trace_sof_intel_hda_irq_ipc_check(sdev, irq_status); /* invalid message ? */ if (irq_status == 0xffffffff) diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index 6888e0a4665d..0a9c80216a8c 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "../sof-audio.h" #include "../ops.h" #include "hda.h" @@ -196,8 +197,7 @@ snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev, found: pos = bytes_to_frames(substream->runtime, pos); - dev_vdbg(sdev->dev, "PCM: stream %d dir %d position %lu\n", - hstream->index, substream->stream, pos); + trace_sof_intel_hda_dsp_pcm(sdev, hstream, substream, pos); return pos; } diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 8344363beec0..be60e7785da9 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "../ops.h" #include "../sof-audio.h" #include "hda.h" @@ -697,7 +698,7 @@ bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev) spin_lock_irq(&bus->reg_lock); status = snd_hdac_chip_readl(bus, INTSTS); - dev_vdbg(bus->dev, "stream irq, INTSTS status: 0x%x\n", status); + trace_sof_intel_hda_dsp_check_stream_irq(sdev, status); /* if Register inaccessible, ignore it.*/ if (status != 0xffffffff) @@ -736,8 +737,7 @@ static bool hda_dsp_stream_check(struct hdac_bus *bus, u32 status) if (status & BIT(s->index) && s->opened) { sd_status = snd_hdac_stream_readb(s, SD_STS); - dev_vdbg(bus->dev, "stream %d status 0x%x\n", - s->index, sd_status); + trace_sof_intel_hda_dsp_stream_status(bus->dev, s, sd_status); snd_hdac_stream_writeb(s, SD_STS, sd_status); diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index 1cc1398336e1..406d58804b50 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -11,6 +11,7 @@ #include #include +#include #include "../ipc4-priv.h" #include "../ops.h" #include "hda.h" @@ -63,7 +64,7 @@ static bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev) hfintipptr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFINTIPPTR) & MTL_HFINTIPPTR_PTR_MASK; irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, hfintipptr + MTL_DSP_IRQSTS); - dev_vdbg(sdev->dev, "irq handler: irq_status:0x%x\n", irq_status); + trace_sof_intel_hda_irq_ipc_check(sdev, irq_status); if (irq_status != U32_MAX && (irq_status & MTL_DSP_IRQSTS_IPC)) return true; -- cgit v1.2.3 From bcd2cc350ded769963970c4b0074b38bc9240a64 Mon Sep 17 00:00:00 2001 From: Noah Klayman Date: Mon, 19 Sep 2022 14:21:07 +0200 Subject: ASoC: SOF: replace dev_vdbg with tracepoints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch removes unneeded dev_vdbg calls and replaces remaining ones with tracepoints to reduce overhead and enable use of trace collection and analysis tools. Signed-off-by: Noah Klayman Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Link: https://lore.kernel.org/r/20220919122108.43764-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/trace/events/sof.h | 60 ++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/sof/ipc3.c | 12 +++++----- sound/soc/sof/pcm.c | 5 ++-- 3 files changed, 68 insertions(+), 9 deletions(-) diff --git a/include/trace/events/sof.h b/include/trace/events/sof.h index f25eef6c95c0..03751323aaa8 100644 --- a/include/trace/events/sof.h +++ b/include/trace/events/sof.h @@ -11,6 +11,7 @@ #if !defined(_TRACE_SOF_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_SOF_H #include +#include #include #include "../../../sound/soc/sof/sof-audio.h" @@ -38,6 +39,65 @@ DEFINE_EVENT(sof_widget_template, sof_widget_free, TP_ARGS(swidget) ); +TRACE_EVENT(sof_ipc3_period_elapsed_position, + TP_PROTO(struct snd_sof_dev *sdev, struct sof_ipc_stream_posn *posn), + TP_ARGS(sdev, posn), + TP_STRUCT__entry( + __string(device_name, dev_name(sdev->dev)) + __field(u64, host_posn) + __field(u64, dai_posn) + __field(u64, wallclock) + ), + TP_fast_assign( + __assign_str(device_name, dev_name(sdev->dev)); + __entry->host_posn = posn->host_posn; + __entry->dai_posn = posn->dai_posn; + __entry->wallclock = posn->wallclock; + ), + TP_printk("device_name=%s host_posn=%#llx dai_posn=%#llx wallclock=%#llx", + __get_str(device_name), __entry->host_posn, __entry->dai_posn, + __entry->wallclock) +); + +TRACE_EVENT(sof_pcm_pointer_position, + TP_PROTO(struct snd_sof_dev *sdev, + struct snd_sof_pcm *spcm, + struct snd_pcm_substream *substream, + snd_pcm_uframes_t dma_posn, + snd_pcm_uframes_t dai_posn + ), + TP_ARGS(sdev, spcm, substream, dma_posn, dai_posn), + TP_STRUCT__entry( + __string(device_name, dev_name(sdev->dev)) + __field(u32, pcm_id) + __field(int, stream) + __field(unsigned long, dma_posn) + __field(unsigned long, dai_posn) + ), + TP_fast_assign( + __assign_str(device_name, dev_name(sdev->dev)); + __entry->pcm_id = le32_to_cpu(spcm->pcm.pcm_id); + __entry->stream = substream->stream; + __entry->dma_posn = dma_posn; + __entry->dai_posn = dai_posn; + ), + TP_printk("device_name=%s pcm_id=%d stream=%d dma_posn=%lu dai_posn=%lu", + __get_str(device_name), __entry->pcm_id, __entry->stream, + __entry->dma_posn, __entry->dai_posn) +); + +TRACE_EVENT(sof_stream_position_ipc_rx, + TP_PROTO(struct device *dev), + TP_ARGS(dev), + TP_STRUCT__entry( + __string(device_name, dev_name(dev)) + ), + TP_fast_assign( + __assign_str(device_name, dev_name(dev)); + ), + TP_printk("device_name=%s", __get_str(device_name)) +); + #endif /* _TRACE_SOF_H */ /* This part must be outside protection */ diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c index 82fa320253be..b28af3a48b70 100644 --- a/sound/soc/sof/ipc3.c +++ b/sound/soc/sof/ipc3.c @@ -9,6 +9,7 @@ #include #include +#include #include "sof-priv.h" #include "sof-audio.h" #include "ipc3-priv.h" @@ -23,7 +24,7 @@ static void ipc3_log_header(struct device *dev, u8 *text, u32 cmd) u8 *str2 = NULL; u32 glb; u32 type; - bool vdbg = false; + bool is_sof_ipc_stream_position = false; glb = cmd & SOF_GLB_TYPE_MASK; type = cmd & SOF_CMD_TYPE_MASK; @@ -118,7 +119,7 @@ static void ipc3_log_header(struct device *dev, u8 *text, u32 cmd) case SOF_IPC_STREAM_TRIG_XRUN: str2 = "TRIG_XRUN"; break; case SOF_IPC_STREAM_POSITION: - vdbg = true; + is_sof_ipc_stream_position = true; str2 = "POSITION"; break; case SOF_IPC_STREAM_VORBIS_PARAMS: str2 = "VORBIS_PARAMS"; break; @@ -206,8 +207,8 @@ static void ipc3_log_header(struct device *dev, u8 *text, u32 cmd) } if (str2) { - if (vdbg) - dev_vdbg(dev, "%s: 0x%x: %s: %s\n", text, cmd, str, str2); + if (is_sof_ipc_stream_position) + trace_sof_stream_position_ipc_rx(dev); else dev_dbg(dev, "%s: 0x%x: %s: %s\n", text, cmd, str, str2); } else { @@ -852,8 +853,7 @@ static void ipc3_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id) return; } - dev_vdbg(sdev->dev, "posn : host 0x%llx dai 0x%llx wall 0x%llx\n", - posn.host_posn, posn.dai_posn, posn.wallclock); + trace_sof_ipc3_period_elapsed_position(sdev, &posn); memcpy(&stream->posn, &posn, sizeof(posn)); diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 49f7cb049f62..14571b821eca 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "sof-of-dev.h" #include "sof-priv.h" #include "sof-audio.h" @@ -384,9 +385,7 @@ static snd_pcm_uframes_t sof_pcm_pointer(struct snd_soc_component *component, dai = bytes_to_frames(substream->runtime, spcm->stream[substream->stream].posn.dai_posn); - dev_vdbg(component->dev, - "PCM: stream %d dir %d DMA position %lu DAI position %lu\n", - spcm->pcm.pcm_id, substream->stream, host, dai); + trace_sof_pcm_pointer_position(sdev, spcm, substream, host, dai); return host; } -- cgit v1.2.3 From 794cd3bd69315f724532e35fbc1c45dfad9a79e6 Mon Sep 17 00:00:00 2001 From: Noah Klayman Date: Mon, 19 Sep 2022 14:21:08 +0200 Subject: ASoC: SOF: replace ipc4-loader dev_vdbg with tracepoints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch replaces dev_vdbg with tracepoints in new ipc4-loader code. Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Signed-off-by: Noah Klayman Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220919122108.43764-8-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/trace/events/sof.h | 17 +++++++++++++++++ sound/soc/sof/ipc4-loader.c | 7 ++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/include/trace/events/sof.h b/include/trace/events/sof.h index 03751323aaa8..21c2a1efb9f6 100644 --- a/include/trace/events/sof.h +++ b/include/trace/events/sof.h @@ -98,6 +98,23 @@ TRACE_EVENT(sof_stream_position_ipc_rx, TP_printk("device_name=%s", __get_str(device_name)) ); +TRACE_EVENT(sof_ipc4_fw_config, + TP_PROTO(struct snd_sof_dev *sdev, char *key, u32 value), + TP_ARGS(sdev, key, value), + TP_STRUCT__entry( + __string(device_name, dev_name(sdev->dev)) + __string(key, key) + __field(u32, value) + ), + TP_fast_assign( + __assign_str(device_name, dev_name(sdev->dev)); + __assign_str(key, key); + __entry->value = value; + ), + TP_printk("device_name=%s key=%s value=%d", + __get_str(device_name), __get_str(key), __entry->value) +); + #endif /* _TRACE_SOF_H */ /* This part must be outside protection */ diff --git a/sound/soc/sof/ipc4-loader.c b/sound/soc/sof/ipc4-loader.c index c678f05d0ef5..e635ae515fa9 100644 --- a/sound/soc/sof/ipc4-loader.c +++ b/sound/soc/sof/ipc4-loader.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "ipc4-priv.h" #include "sof-audio.h" #include "sof-priv.h" @@ -194,13 +195,13 @@ static int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev) fw_ver->build); break; case SOF_IPC4_FW_CFG_DL_MAILBOX_BYTES: - dev_vdbg(sdev->dev, "DL mailbox size: %u\n", *tuple->value); + trace_sof_ipc4_fw_config(sdev, "DL mailbox size", *tuple->value); break; case SOF_IPC4_FW_CFG_UL_MAILBOX_BYTES: - dev_vdbg(sdev->dev, "UL mailbox size: %u\n", *tuple->value); + trace_sof_ipc4_fw_config(sdev, "UL mailbox size", *tuple->value); break; case SOF_IPC4_FW_CFG_TRACE_LOG_BYTES: - dev_vdbg(sdev->dev, "Trace log size: %u\n", *tuple->value); + trace_sof_ipc4_fw_config(sdev, "Trace log size", *tuple->value); ipc4_data->mtrace_log_bytes = *tuple->value; break; default: -- cgit v1.2.3 From a25f4e2cdd5d64408b0fa56115ebebd8cc5cb6c0 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Fri, 16 Sep 2022 14:24:23 +0100 Subject: ASoC: qcom: common: use EXPORT_SYMBOL_GPL instead of EXPORT_SYMBOL qcom_snd_parse_of depends on ASoC EXPORT_SYMBOL_GPL functions, so make qcom_snd_parse_of and EXPORT_SYMBOL_GPL. Signed-off-by: Srinivas Kandagatla Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220916132427.1845-2-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c index c407684ce1a2..e53ad84f8ff5 100644 --- a/sound/soc/qcom/common.c +++ b/sound/soc/qcom/common.c @@ -175,6 +175,6 @@ err_put_np: of_node_put(np); return ret; } -EXPORT_SYMBOL(qcom_snd_parse_of); +EXPORT_SYMBOL_GPL(qcom_snd_parse_of); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From e4f10cc23cefe16ed69987cb2648f5111e6eacb4 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Fri, 16 Sep 2022 14:24:24 +0100 Subject: ASoC: dt-bindings: qcom: sort compatible strings Sort compatible strings for consistency reasons. Signed-off-by: Srinivas Kandagatla Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220916132427.1845-3-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/qcom,sm8250.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index a3a4289f713e..bab1a6f1890f 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -20,9 +20,9 @@ properties: - qcom,apq8016-sbc-sndcard - qcom,db845c-sndcard - qcom,msm8916-qdsp6-sndcard + - qcom,qrb5165-rb5-sndcard - qcom,sdm845-sndcard - qcom,sm8250-sndcard - - qcom,qrb5165-rb5-sndcard audio-routing: $ref: /schemas/types.yaml#/definitions/non-unique-string-array -- cgit v1.2.3 From f19097cc5adfd29bf2aecd8e0137331fab36946b Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Fri, 16 Sep 2022 14:24:25 +0100 Subject: ASoC: dt-bindings: qcom,sm8250: add compatibles for sm8450 and sm8250 Add compatibles for sm8450 and sm8250xp based soundcards. Signed-off-by: Srinivas Kandagatla Acked-by: Rob Herring Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220916132427.1845-4-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/qcom,sm8250.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index bab1a6f1890f..70080d04ddc9 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -21,8 +21,10 @@ properties: - qcom,db845c-sndcard - qcom,msm8916-qdsp6-sndcard - qcom,qrb5165-rb5-sndcard + - qcom,sc8280xp-sndcard - qcom,sdm845-sndcard - qcom,sm8250-sndcard + - qcom,sm8450-sndcard audio-routing: $ref: /schemas/types.yaml#/definitions/non-unique-string-array -- cgit v1.2.3 From 3bd975f3ae0a245e4b851c2b0c97b0a71e5359d6 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Fri, 16 Sep 2022 14:24:26 +0100 Subject: ASoC: qcom: sm8250: move some code to common SM8450 machine driver code can be reused across multiple Qualcomm SoCs, At least another 2 of them for now (SM8450 and SC8250XP). Move some of the common SoundWire stream specific code to common file so that other drivers can use it instead of duplication. This patch is to prepare the common driver to be able to add new SoCs support with less dupication. Signed-off-by: Srinivas Kandagatla Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220916132427.1845-5-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/common.c | 171 ++++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/qcom/common.h | 35 ++++++++++ sound/soc/qcom/sm8250.c | 152 ++---------------------------------------- 3 files changed, 213 insertions(+), 145 deletions(-) diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c index e53ad84f8ff5..69dd3b504e20 100644 --- a/sound/soc/qcom/common.c +++ b/sound/soc/qcom/common.c @@ -3,6 +3,9 @@ // Copyright (c) 2018, The Linux Foundation. All rights reserved. #include +#include +#include +#include "qdsp6/q6afe.h" #include "common.h" int qcom_snd_parse_of(struct snd_soc_card *card) @@ -177,4 +180,172 @@ err_put_np: } EXPORT_SYMBOL_GPL(qcom_snd_parse_of); +#if IS_ENABLED(CONFIG_SOUNDWIRE) +int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream, + struct sdw_stream_runtime *sruntime, + bool *stream_prepared) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + int ret; + + if (!sruntime) + return 0; + + switch (cpu_dai->id) { + case WSA_CODEC_DMA_RX_0: + case WSA_CODEC_DMA_RX_1: + case RX_CODEC_DMA_RX_0: + case RX_CODEC_DMA_RX_1: + case TX_CODEC_DMA_TX_0: + case TX_CODEC_DMA_TX_1: + case TX_CODEC_DMA_TX_2: + case TX_CODEC_DMA_TX_3: + break; + default: + return 0; + } + + if (*stream_prepared) { + sdw_disable_stream(sruntime); + sdw_deprepare_stream(sruntime); + *stream_prepared = false; + } + + ret = sdw_prepare_stream(sruntime); + if (ret) + return ret; + + /** + * NOTE: there is a strict hw requirement about the ordering of port + * enables and actual WSA881x PA enable. PA enable should only happen + * after soundwire ports are enabled if not DC on the line is + * accumulated resulting in Click/Pop Noise + * PA enable/mute are handled as part of codec DAPM and digital mute. + */ + + ret = sdw_enable_stream(sruntime); + if (ret) { + sdw_deprepare_stream(sruntime); + return ret; + } + *stream_prepared = true; + + return ret; +} +EXPORT_SYMBOL_GPL(qcom_snd_sdw_prepare); + +int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct sdw_stream_runtime **psruntime) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai; + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct sdw_stream_runtime *sruntime; + int i; + + switch (cpu_dai->id) { + case WSA_CODEC_DMA_RX_0: + case RX_CODEC_DMA_RX_0: + case RX_CODEC_DMA_RX_1: + case TX_CODEC_DMA_TX_0: + case TX_CODEC_DMA_TX_1: + 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_stream(codec_dai, substream->stream); + if (sruntime != ERR_PTR(-ENOTSUPP)) + *psruntime = sruntime; + } + break; + } + + return 0; + +} +EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_params); + +int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream, + struct sdw_stream_runtime *sruntime, bool *stream_prepared) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + + switch (cpu_dai->id) { + case WSA_CODEC_DMA_RX_0: + case WSA_CODEC_DMA_RX_1: + case RX_CODEC_DMA_RX_0: + case RX_CODEC_DMA_RX_1: + case TX_CODEC_DMA_TX_0: + case TX_CODEC_DMA_TX_1: + case TX_CODEC_DMA_TX_2: + case TX_CODEC_DMA_TX_3: + if (sruntime && *stream_prepared) { + sdw_disable_stream(sruntime); + sdw_deprepare_stream(sruntime); + *stream_prepared = false; + } + break; + default: + break; + } + + return 0; +} +EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_free); +#endif + +int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_jack *jack, bool *jack_setup) +{ + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_card *card = rtd->card; + int rval, i; + + if (!*jack_setup) { + rval = snd_soc_card_jack_new(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_MECHANICAL | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | + SND_JACK_BTN_4 | SND_JACK_BTN_5, + jack); + + if (rval < 0) { + dev_err(card->dev, "Unable to add Headphone Jack\n"); + return rval; + } + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA); + 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); + *jack_setup = true; + } + + switch (cpu_dai->id) { + case TX_CODEC_DMA_TX_0: + case TX_CODEC_DMA_TX_1: + case TX_CODEC_DMA_TX_2: + case TX_CODEC_DMA_TX_3: + for_each_rtd_codec_dais(rtd, i, codec_dai) { + rval = snd_soc_component_set_jack(codec_dai->component, + jack, NULL); + if (rval != 0 && rval != -ENOTSUPP) { + dev_warn(card->dev, "Failed to set jack: %d\n", rval); + return rval; + } + } + + break; + default: + break; + } + + + return 0; +} +EXPORT_SYMBOL_GPL(qcom_snd_wcd_jack_setup); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/qcom/common.h b/sound/soc/qcom/common.h index f05c05b12bd7..c5472a642de0 100644 --- a/sound/soc/qcom/common.h +++ b/sound/soc/qcom/common.h @@ -5,7 +5,42 @@ #define __QCOM_SND_COMMON_H__ #include +#include int qcom_snd_parse_of(struct snd_soc_card *card); +int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_jack *jack, bool *jack_setup); +#if IS_ENABLED(CONFIG_SOUNDWIRE) +int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream, + struct sdw_stream_runtime *runtime, + bool *stream_prepared); +int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct sdw_stream_runtime **psruntime); +int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream, + struct sdw_stream_runtime *sruntime, + bool *stream_prepared); +#else +static inline int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream, + struct sdw_stream_runtime *runtime, + bool *stream_prepared) +{ + return -ENOTSUPP; +} + +static inline int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct sdw_stream_runtime **psruntime) +{ + return -ENOTSUPP; +} + +static inline int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream, + struct sdw_stream_runtime *sruntime, + bool *stream_prepared) +{ + return -ENOTSUPP; +} +#endif #endif diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index 98a2fde9e004..8dbe9ef41b1c 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -27,57 +27,8 @@ struct sm8250_snd_data { static int sm8250_snd_init(struct snd_soc_pcm_runtime *rtd) { struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->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); - struct snd_soc_card *card = rtd->card; - int rval, i; - - if (!data->jack_setup) { - struct snd_jack *jack; - - rval = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_LINEOUT | - SND_JACK_MECHANICAL | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | - SND_JACK_BTN_4 | SND_JACK_BTN_5, - &data->jack); - - if (rval < 0) { - dev_err(card->dev, "Unable to add Headphone Jack\n"); - return rval; - } - - jack = data->jack.jack; - - snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_MEDIA); - snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - data->jack_setup = true; - } - - switch (cpu_dai->id) { - case TX_CODEC_DMA_TX_0: - case TX_CODEC_DMA_TX_1: - case TX_CODEC_DMA_TX_2: - case TX_CODEC_DMA_TX_3: - for_each_rtd_codec_dais(rtd, i, codec_dai) { - rval = snd_soc_component_set_jack(codec_dai->component, - &data->jack, NULL); - if (rval != 0 && rval != -ENOTSUPP) { - dev_warn(card->dev, "Failed to set jack: %d\n", rval); - return rval; - } - } - - break; - default: - break; - } - - return 0; + return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup); } static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, @@ -121,92 +72,21 @@ static int sm8250_snd_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai; struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); struct sm8250_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card); - struct sdw_stream_runtime *sruntime; - int i; - - switch (cpu_dai->id) { - case WSA_CODEC_DMA_RX_0: - case RX_CODEC_DMA_RX_0: - case RX_CODEC_DMA_RX_1: - case TX_CODEC_DMA_TX_0: - case TX_CODEC_DMA_TX_1: - 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_stream(codec_dai, - substream->stream); - if (sruntime != ERR_PTR(-ENOTSUPP)) - pdata->sruntime[cpu_dai->id] = sruntime; - } - break; - } - - return 0; + return qcom_snd_sdw_hw_params(substream, params, &pdata->sruntime[cpu_dai->id]); } -static int sm8250_snd_wsa_dma_prepare(struct snd_pcm_substream *substream) +static int sm8250_snd_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card); struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; - int ret; - - if (!sruntime) - return 0; - if (data->stream_prepared[cpu_dai->id]) { - sdw_disable_stream(sruntime); - sdw_deprepare_stream(sruntime); - data->stream_prepared[cpu_dai->id] = false; - } - - ret = sdw_prepare_stream(sruntime); - if (ret) - return ret; - - /** - * NOTE: there is a strict hw requirement about the ordering of port - * enables and actual WSA881x PA enable. PA enable should only happen - * after soundwire ports are enabled if not DC on the line is - * accumulated resulting in Click/Pop Noise - * PA enable/mute are handled as part of codec DAPM and digital mute. - */ - - ret = sdw_enable_stream(sruntime); - if (ret) { - sdw_deprepare_stream(sruntime); - return ret; - } - data->stream_prepared[cpu_dai->id] = true; - - return ret; -} - -static int sm8250_snd_prepare(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); - - switch (cpu_dai->id) { - case WSA_CODEC_DMA_RX_0: - case WSA_CODEC_DMA_RX_1: - case RX_CODEC_DMA_RX_0: - case RX_CODEC_DMA_RX_1: - case TX_CODEC_DMA_TX_0: - case TX_CODEC_DMA_TX_1: - case TX_CODEC_DMA_TX_2: - case TX_CODEC_DMA_TX_3: - return sm8250_snd_wsa_dma_prepare(substream); - default: - break; - } - - return 0; + return qcom_snd_sdw_prepare(substream, sruntime, + &data->stream_prepared[cpu_dai->id]); } static int sm8250_snd_hw_free(struct snd_pcm_substream *substream) @@ -216,26 +96,8 @@ static int sm8250_snd_hw_free(struct snd_pcm_substream *substream) struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; - switch (cpu_dai->id) { - case WSA_CODEC_DMA_RX_0: - case WSA_CODEC_DMA_RX_1: - case RX_CODEC_DMA_RX_0: - case RX_CODEC_DMA_RX_1: - case TX_CODEC_DMA_TX_0: - case TX_CODEC_DMA_TX_1: - case TX_CODEC_DMA_TX_2: - case TX_CODEC_DMA_TX_3: - if (sruntime && data->stream_prepared[cpu_dai->id]) { - sdw_disable_stream(sruntime); - sdw_deprepare_stream(sruntime); - data->stream_prepared[cpu_dai->id] = false; - } - break; - default: - break; - } - - return 0; + return qcom_snd_sdw_hw_free(substream, sruntime, + &data->stream_prepared[cpu_dai->id]); } static const struct snd_soc_ops sm8250_be_ops = { -- cgit v1.2.3 From 295aeea6646ad6cf26c24f5c493ddb60b8f5a0f4 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Fri, 16 Sep 2022 14:24:27 +0100 Subject: ASoC: qcom: add machine driver for sc8280xp Add machine driver for sc8280xp SoC. This intial supports only includes WSA883x Speakers and WCD938x based headset. Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220916132427.1845-6-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/Kconfig | 12 ++++ sound/soc/qcom/Makefile | 2 + sound/soc/qcom/sc8280xp.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+) create mode 100644 sound/soc/qcom/sc8280xp.c diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 750653404ba3..1b0252ec4665 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -173,6 +173,18 @@ config SND_SOC_SM8250 SM8250 SoC-based systems. Say Y if you want to use audio device on this SoCs. +config SND_SOC_SC8280XP + tristate "SoC Machine driver for SC8280XP boards" + depends on QCOM_APR || COMPILE_TEST + depends on SOUNDWIRE + depends on COMMON_CLK + select SND_SOC_QDSP6 + select SND_SOC_QCOM_COMMON + help + To add support for audio on Qualcomm Technologies Inc. + SC8280XP SoC-based systems. + Say Y if you want to use audio device on this SoCs. + config SND_SOC_SC7180 tristate "SoC Machine driver for SC7180 boards" depends on I2C && GPIOLIB diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile index 8b7b876899a8..8b97172cf990 100644 --- a/sound/soc/qcom/Makefile +++ b/sound/soc/qcom/Makefile @@ -26,6 +26,7 @@ snd-soc-sc7180-objs := sc7180.o snd-soc-sc7280-objs := sc7280.o snd-soc-sdm845-objs := sdm845.o snd-soc-sm8250-objs := sm8250.o +snd-soc-sc8280xp-objs := sc8280xp.o snd-soc-qcom-common-objs := common.o obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o @@ -33,6 +34,7 @@ obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o obj-$(CONFIG_SND_SOC_MSM8996) += snd-soc-apq8096.o obj-$(CONFIG_SND_SOC_SC7180) += snd-soc-sc7180.o obj-$(CONFIG_SND_SOC_SC7280) += snd-soc-sc7280.o +obj-$(CONFIG_SND_SOC_SC8280XP) += snd-soc-sc8280xp.o obj-$(CONFIG_SND_SOC_SDM845) += snd-soc-sdm845.o obj-$(CONFIG_SND_SOC_SM8250) += snd-soc-sm8250.o obj-$(CONFIG_SND_SOC_QCOM_COMMON) += snd-soc-qcom-common.o diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c new file mode 100644 index 000000000000..ade44ad7c585 --- /dev/null +++ b/sound/soc/qcom/sc8280xp.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2022, Linaro Limited + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "qdsp6/q6afe.h" +#include "common.h" + +#define DRIVER_NAME "sc8280xp" + +struct sc8280xp_snd_data { + bool stream_prepared[AFE_PORT_MAX]; + struct snd_soc_card *card; + struct sdw_stream_runtime *sruntime[AFE_PORT_MAX]; + struct snd_soc_jack jack; + bool jack_setup; +}; + +static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd) +{ + struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card); + + return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup); +} + +static int sc8280xp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + 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); + + rate->min = rate->max = 48000; + channels->min = 2; + channels->max = 2; + switch (cpu_dai->id) { + case TX_CODEC_DMA_TX_0: + case TX_CODEC_DMA_TX_1: + case TX_CODEC_DMA_TX_2: + case TX_CODEC_DMA_TX_3: + channels->min = 1; + break; + default: + break; + } + + + return 0; +} + +static int sc8280xp_snd_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct sc8280xp_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card); + + return qcom_snd_sdw_hw_params(substream, params, &pdata->sruntime[cpu_dai->id]); +} + +static int sc8280xp_snd_prepare(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card); + struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; + + return qcom_snd_sdw_prepare(substream, sruntime, + &data->stream_prepared[cpu_dai->id]); +} + +static int sc8280xp_snd_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; + + return qcom_snd_sdw_hw_free(substream, sruntime, + &data->stream_prepared[cpu_dai->id]); +} + +static const struct snd_soc_ops sc8280xp_be_ops = { + .hw_params = sc8280xp_snd_hw_params, + .hw_free = sc8280xp_snd_hw_free, + .prepare = sc8280xp_snd_prepare, +}; + +static void sc8280xp_add_be_ops(struct snd_soc_card *card) +{ + struct snd_soc_dai_link *link; + int i; + + for_each_card_prelinks(card, i, link) { + if (link->no_pcm == 1) { + link->init = sc8280xp_snd_init; + link->be_hw_params_fixup = sc8280xp_be_hw_params_fixup; + link->ops = &sc8280xp_be_ops; + } + } +} + +static int sc8280xp_platform_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card; + struct sc8280xp_snd_data *data; + struct device *dev = &pdev->dev; + int ret; + + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) + return -ENOMEM; + card->owner = THIS_MODULE; + /* Allocate the private data */ + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + card->dev = dev; + dev_set_drvdata(dev, card); + snd_soc_card_set_drvdata(card, data); + ret = qcom_snd_parse_of(card); + if (ret) + return ret; + + card->driver_name = DRIVER_NAME; + sc8280xp_add_be_ops(card); + return devm_snd_soc_register_card(dev, card); +} + +static const struct of_device_id snd_sc8280xp_dt_match[] = { + {.compatible = "qcom,sc8280xp-sndcard",}, + {} +}; + +MODULE_DEVICE_TABLE(of, snd_sc8280xp_dt_match); + +static struct platform_driver snd_sc8280xp_driver = { + .probe = sc8280xp_platform_probe, + .driver = { + .name = "snd-sc8280xp", + .of_match_table = snd_sc8280xp_dt_match, + }, +}; +module_platform_driver(snd_sc8280xp_driver); +MODULE_AUTHOR("Srinivas Kandagatla Date: Fri, 16 Sep 2022 06:23:20 +0000 Subject: ASoC: Intel: sof_nau8825: use function devm_kcalloc() instead of devm_kzalloc() Use 2-factor multiplication argument form devm_kcalloc() instead of devm_kzalloc(). Reported-by: Zeal Robot Signed-off-by: ye xingchen Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220916062320.153456-1-ye.xingchen@zte.com.cn Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_nau8825.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c index 8d7e5ba9e516..5585c217f78d 100644 --- a/sound/soc/intel/boards/sof_nau8825.c +++ b/sound/soc/intel/boards/sof_nau8825.c @@ -355,10 +355,10 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, 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); + links = devm_kcalloc(dev, sof_audio_card_nau8825.num_links, + sizeof(struct snd_soc_dai_link), GFP_KERNEL); + cpus = devm_kcalloc(dev, sof_audio_card_nau8825.num_links, + sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); if (!links || !cpus) goto devm_err; @@ -421,9 +421,10 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, /* HDMI */ if (hdmi_num > 0) { - idisp_components = devm_kzalloc(dev, - sizeof(struct snd_soc_dai_link_component) * - hdmi_num, GFP_KERNEL); + idisp_components = devm_kcalloc(dev, + hdmi_num, + sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); if (!idisp_components) goto devm_err; } -- cgit v1.2.3 From 7b88552c26971ccbc6ff35e9d544f7fac94ffef1 Mon Sep 17 00:00:00 2001 From: ye xingchen Date: Fri, 16 Sep 2022 06:25:11 +0000 Subject: ASOC: SOF: use devm_kcalloc() instead of devm_kzalloc() Use 2-factor multiplication argument form devm_kcalloc() instead of devm_kzalloc(). Reported-by: Zeal Robot Signed-off-by: ye xingchen Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220916062511.153962-1-ye.xingchen@zte.com.cn Signed-off-by: Mark Brown --- sound/soc/sof/nocodec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c index 356497fe4f4c..3537805070ad 100644 --- a/sound/soc/sof/nocodec.c +++ b/sound/soc/sof/nocodec.c @@ -32,7 +32,7 @@ static int sof_nocodec_bes_setup(struct device *dev, /* set up BE dai_links */ for (i = 0; i < link_num; i++) { - dlc = devm_kzalloc(dev, 3 * sizeof(*dlc), GFP_KERNEL); + dlc = devm_kcalloc(dev, 3, sizeof(*dlc), GFP_KERNEL); if (!dlc) return -ENOMEM; @@ -78,7 +78,7 @@ static int sof_nocodec_setup(struct device *dev, struct snd_soc_dai_link *links; /* create dummy BE dai_links */ - links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * num_dai_drivers, GFP_KERNEL); + links = devm_kcalloc(dev, num_dai_drivers, sizeof(struct snd_soc_dai_link), GFP_KERNEL); if (!links) return -ENOMEM; -- cgit v1.2.3 From 8e34d743f97f151824a2dc0803695752de80bf7d Mon Sep 17 00:00:00 2001 From: ye xingchen Date: Fri, 16 Sep 2022 06:19:06 +0000 Subject: ASoC: amd: acp: use devm_kcalloc() instead of devm_kzalloc() Use 2-factor multiplication argument form devm_kcalloc() instead of devm_kzalloc(). Reported-by: Zeal Robot Signed-off-by: ye xingchen Link: https://lore.kernel.org/r/20220916061906.152434-1-ye.xingchen@zte.com.cn Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c index ef2ce083521e..a0c84cd07fde 100644 --- a/sound/soc/amd/acp/acp-pci.c +++ b/sound/soc/amd/acp/acp-pci.c @@ -107,7 +107,7 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id goto unregister_dmic_dev; } - res = devm_kzalloc(&pci->dev, sizeof(struct resource) * num_res, GFP_KERNEL); + res = devm_kcalloc(&pci->dev, num_res, sizeof(struct resource), GFP_KERNEL); if (!res) { ret = -ENOMEM; goto unregister_dmic_dev; -- cgit v1.2.3 From ce6be534a615a361bf4877bd321639993dd74dfe Mon Sep 17 00:00:00 2001 From: ye xingchen Date: Fri, 16 Sep 2022 06:22:34 +0000 Subject: ASoC: Intel: sof_cs42l42: use function devm_kcalloc() instead of devm_kzalloc() Use 2-factor multiplication argument form devm_kcalloc() instead of devm_kzalloc(). Reported-by: Zeal Robot Signed-off-by: ye xingchen Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220916062234.153275-1-ye.xingchen@zte.com.cn Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_cs42l42.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/intel/boards/sof_cs42l42.c b/sound/soc/intel/boards/sof_cs42l42.c index 85ffd065895d..e38bd2831e6a 100644 --- a/sound/soc/intel/boards/sof_cs42l42.c +++ b/sound/soc/intel/boards/sof_cs42l42.c @@ -445,9 +445,9 @@ static int create_hdmi_dai_links(struct device *dev, if (hdmi_num <= 0) return 0; - idisp_components = devm_kzalloc(dev, - sizeof(struct snd_soc_dai_link_component) * - hdmi_num, GFP_KERNEL); + idisp_components = devm_kcalloc(dev, + hdmi_num, + sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); if (!idisp_components) goto devm_err; @@ -543,10 +543,10 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, struct snd_soc_dai_link *links; int ret, id = 0, link_seq; - links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * - sof_audio_card_cs42l42.num_links, GFP_KERNEL); - cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) * - sof_audio_card_cs42l42.num_links, GFP_KERNEL); + links = devm_kcalloc(dev, sof_audio_card_cs42l42.num_links, + sizeof(struct snd_soc_dai_link), GFP_KERNEL); + cpus = devm_kcalloc(dev, sof_audio_card_cs42l42.num_links, + sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); if (!links || !cpus) goto devm_err; -- cgit v1.2.3 From 09dea5acbe352481beed7d7114295171f5073dff Mon Sep 17 00:00:00 2001 From: ye xingchen Date: Fri, 16 Sep 2022 06:25:49 +0000 Subject: ASoC: Intel: sof_ssp_amp: use devm_kcalloc() instead of devm_kzalloc() Use 2-factor multiplication argument form devm_kcalloc() instead of devm_kzalloc(). Reported-by: Zeal Robot Signed-off-by: ye xingchen Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220916062549.154114-1-ye.xingchen@zte.com.cn Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_ssp_amp.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/sound/soc/intel/boards/sof_ssp_amp.c b/sound/soc/intel/boards/sof_ssp_amp.c index 4a762e002ac7..94d25aeb6e7c 100644 --- a/sound/soc/intel/boards/sof_ssp_amp.c +++ b/sound/soc/intel/boards/sof_ssp_amp.c @@ -210,10 +210,10 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, struct snd_soc_dai_link *links; int i, id = 0; - links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * - sof_ssp_amp_card.num_links, GFP_KERNEL); - cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) * - sof_ssp_amp_card.num_links, GFP_KERNEL); + links = devm_kcalloc(dev, sof_ssp_amp_card.num_links, + sizeof(struct snd_soc_dai_link), GFP_KERNEL); + cpus = devm_kcalloc(dev, sof_ssp_amp_card.num_links, + sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); if (!links || !cpus) return NULL; @@ -306,9 +306,10 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) { /* HDMI */ if (hdmi_num > 0) { - idisp_components = devm_kzalloc(dev, - sizeof(struct snd_soc_dai_link_component) * - hdmi_num, GFP_KERNEL); + idisp_components = devm_kcalloc(dev, + hdmi_num, + sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); if (!idisp_components) goto devm_err; } -- cgit v1.2.3 From f047199e6f3115896fee25ac8809e1a9a8c948fc Mon Sep 17 00:00:00 2001 From: ye xingchen Date: Fri, 16 Sep 2022 06:20:27 +0000 Subject: ASoC: amd: acp: use function devm_kcalloc() instead of devm_kzalloc() Use 2-factor multiplication argument form devm_kcalloc() instead of devm_kzalloc(). Reported-by: Zeal Robot Signed-off-by: ye xingchen Link: https://lore.kernel.org/r/20220916062027.152815-1-ye.xingchen@zte.com.cn Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-mach-common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c index f0c49127aad1..4c69cb6e3400 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -584,7 +584,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) if (drv_data->dmic_cpu_id) num_links++; - links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * num_links, GFP_KERNEL); + links = devm_kcalloc(dev, num_links, sizeof(struct snd_soc_dai_link), GFP_KERNEL); if (!links) return -ENOMEM; @@ -749,7 +749,7 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) if (drv_data->dmic_cpu_id) num_links++; - links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * num_links, GFP_KERNEL); + links = devm_kcalloc(dev, num_links, sizeof(struct snd_soc_dai_link), GFP_KERNEL); if (!links) return -ENOMEM; -- cgit v1.2.3 From e31a4a9320f1ccf75a690fe7f759896f285bb62e Mon Sep 17 00:00:00 2001 From: Robert Rosengren Date: Mon, 12 Sep 2022 12:54:07 +0200 Subject: ASoC: fsl_spdif: add ALSA event on dpll locked Add an ALSA event on the RX Sample Rate controller upon the dpll locked interrupt, making it possible for audio applications to monitor changes in the hardware. Signed-off-by: Robert Rosengren Acked-by: Shengjiu Wang Link: https://lore.kernel.org/r/20220912105407.3157868-1-robert.rosengren@axis.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_spdif.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 7fc1c96929bb..275aba8e0c46 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -44,6 +44,8 @@ static u8 srpc_dpll_locked[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0xa, 0xb }; #define DEFAULT_RXCLK_SRC 1 +#define RX_SAMPLE_RATE_KCONTROL "RX Sample Rate" + /** * struct fsl_spdif_soc_data: soc specific data * @@ -98,6 +100,8 @@ struct spdif_mixer_control { * @soc: SPDIF soc data * @fsl_spdif_control: SPDIF control data * @cpu_dai_drv: cpu dai driver + * @snd_card: sound card pointer + * @rxrate_kcontrol: kcontrol for RX Sample Rate * @pdev: platform device pointer * @regmap: regmap handler * @dpll_locked: dpll lock flag @@ -122,6 +126,8 @@ struct fsl_spdif_priv { const struct fsl_spdif_soc_data *soc; struct spdif_mixer_control fsl_spdif_control; struct snd_soc_dai_driver cpu_dai_drv; + struct snd_card *snd_card; + struct snd_kcontrol *rxrate_kcontrol; struct platform_device *pdev; struct regmap *regmap; bool dpll_locked; @@ -226,6 +232,12 @@ static void spdif_irq_dpll_lock(struct fsl_spdif_priv *spdif_priv) locked ? "locked" : "loss lock"); spdif_priv->dpll_locked = locked ? true : false; + + if (spdif_priv->snd_card && spdif_priv->rxrate_kcontrol) { + snd_ctl_notify(spdif_priv->snd_card, + SNDRV_CTL_EVENT_MASK_VALUE, + &spdif_priv->rxrate_kcontrol->id); + } } /* Receiver found illegal symbol interrupt handler */ @@ -1197,7 +1209,7 @@ static struct snd_kcontrol_new fsl_spdif_ctrls[] = { /* DPLL lock info get controller */ { .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = "RX Sample Rate", + .name = RX_SAMPLE_RATE_KCONTROL, .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, .info = fsl_spdif_rxrate_info, @@ -1251,6 +1263,13 @@ static int fsl_spdif_dai_probe(struct snd_soc_dai *dai) snd_soc_add_dai_controls(dai, fsl_spdif_ctrls_rcm, ARRAY_SIZE(fsl_spdif_ctrls_rcm)); + spdif_private->snd_card = dai->component->card->snd_card; + spdif_private->rxrate_kcontrol = snd_soc_card_get_kcontrol(dai->component->card, + RX_SAMPLE_RATE_KCONTROL); + if (!spdif_private->rxrate_kcontrol) + dev_err(&spdif_private->pdev->dev, "failed to get %s kcontrol\n", + RX_SAMPLE_RATE_KCONTROL); + /*Clear the val bit for Tx*/ regmap_update_bits(spdif_private->regmap, REG_SPDIF_SCR, SCR_VAL_MASK, SCR_VAL_CLEAR); -- cgit v1.2.3 From c403dcd8b0c4dc01974329e38dc3f82859fd6f99 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 9 Sep 2022 01:19:18 +0000 Subject: ASoC: soc-core.c: setup rtd->pmdown_time at soc_new_pcm_runtime() Almost all default rtd->xxx are setup at soc_new_pcm_runtime() which is sub-function of snd_soc_add_pcm_runtime() (A). But "rtd->pmdown_time" is setup at soc_init_pcm_runtime() (B). It is very random timing setup. This patch setup it at (A), same as other rtd->xxx. static int snd_soc_bind_card(...) { ... for_each_card_prelinks(...) { (A) ret = snd_soc_add_pcm_runtime(...); ... } ... for_each_card_rtds(...) { (B) ret = soc_init_pcm_runtime(...); ... } ... } One note is that current topology/intel are directly calling snd_soc_add_pcm_runtime() (A) without calling soc_init_pcm_runtime() (B). This means, its "rtd->pmdown_time settings" was 0, but will have default value by this patch. "rtd->pmdown_time settings" will be used at snd_soc_runtime_ignore_pmdown_time(). This patch adds "ignore_pmdown_time" to these driver to keep compatibility. bool snd_soc_runtime_ignore_pmdown_time(...) { ... => if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time) return true; ... } Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/875yhxmjjd.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/hdaudio.c | 1 + sound/soc/soc-core.c | 4 +--- sound/soc/soc-topology.c | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/avs/boards/hdaudio.c b/sound/soc/intel/avs/boards/hdaudio.c index d2fc41d39448..073663ba140d 100644 --- a/sound/soc/intel/avs/boards/hdaudio.c +++ b/sound/soc/intel/avs/boards/hdaudio.c @@ -42,6 +42,7 @@ static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int dl[i].dpcm_capture = 1; dl[i].platforms = platform; dl[i].num_platforms = 1; + dl[i].ignore_pmdown_time = 1; dl[i].codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL); dl[i].cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e020ab49cfb1..df2bd8098c63 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -487,6 +487,7 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( rtd->card = card; rtd->dai_link = dai_link; rtd->num = card->num_rtd++; + rtd->pmdown_time = pmdown_time; /* default power off timeout */ /* see for_each_card_rtds */ list_add_tail(&rtd->list, &card->rtd_list); @@ -1247,9 +1248,6 @@ static int soc_init_pcm_runtime(struct snd_soc_card *card, struct snd_soc_component *component; int ret, num, i; - /* set default power off timeout */ - rtd->pmdown_time = pmdown_time; - /* do machine specific initialization */ ret = snd_soc_link_init(rtd); if (ret < 0) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index b101db85446f..c3be24b2fac5 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1755,6 +1755,7 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg, /* enable DPCM */ link->dynamic = 1; + link->ignore_pmdown_time = 1; link->dpcm_playback = le32_to_cpu(pcm->playback); link->dpcm_capture = le32_to_cpu(pcm->capture); if (pcm->flag_mask) -- cgit v1.2.3 From 5cf934e84659ca2f03db6254978d56f053745366 Mon Sep 17 00:00:00 2001 From: Ban Tao Date: Mon, 12 Sep 2022 00:05:33 -0700 Subject: ASoC: sun50i-dmic: dt-bindings: add DT bindings for DMIC controller DT binding documentation for this new ASoC driver. Signed-off-by: Ban Tao Reviewed-by: Rob Herring Reviewed-by: Maxime Ripard Link: https://lore.kernel.org/r/1662966333-18000-1-git-send-email-fengzheng923@gmail.com Signed-off-by: Mark Brown --- .../bindings/sound/allwinner,sun50i-h6-dmic.yaml | 79 ++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/allwinner,sun50i-h6-dmic.yaml diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun50i-h6-dmic.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun50i-h6-dmic.yaml new file mode 100644 index 000000000000..2f12cabe4c71 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/allwinner,sun50i-h6-dmic.yaml @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: (GPL-2.0+ OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/allwinner,sun50i-h6-dmic.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Allwinner H6 DMIC + +maintainers: + - Ban Tao + +properties: + compatible: + const: allwinner,sun50i-h6-dmic + + "#sound-dai-cells": + const: 0 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: Bus Clock + - description: Module Clock + + clock-names: + items: + - const: bus + - const: mod + + dmas: + items: + - description: RX DMA Channel + + dma-names: + items: + - const: rx + + resets: + maxItems: 1 + +required: + - "#sound-dai-cells" + - compatible + - reg + - interrupts + - clocks + - clock-names + - dmas + - dma-names + - resets + +additionalProperties: false + +examples: + - | + #include + #include + + #include + #include + + dmic: dmic@5095000 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun50i-h6-dmic"; + reg = <0x05095000 0x400>; + interrupts = ; + clocks = <&ccu CLK_BUS_DMIC>, <&ccu CLK_DMIC>; + clock-names = "bus", "mod"; + dmas = <&dma 7>; + dma-names = "rx"; + resets = <&ccu RST_BUS_DMIC>; + }; + +... -- cgit v1.2.3 From 9db1c9fa214ef41d098633ff40a87284ca6e1870 Mon Sep 17 00:00:00 2001 From: Muralidhar Reddy Date: Mon, 19 Sep 2022 13:45:48 +0200 Subject: ALSA: intel-dspconfig: add ES8336 support for AlderLake-PS added quirks for ESS8336 for AlderLake-PS Reviewed-by: Ranjani Sridharan Signed-off-by: Muralidhar Reddy Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220919114548.42769-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/hda/intel-dsp-config.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c index d84ffdf47210..1997ffc16663 100644 --- a/sound/hda/intel-dsp-config.c +++ b/sound/hda/intel-dsp-config.c @@ -427,6 +427,11 @@ static const struct config_entry config_table[] = { .device = 0x51cd, }, /* Alderlake-PS */ + { + .flags = FLAG_SOF, + .device = 0x51c9, + .codec_hid = &essx_83x6, + }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, .device = 0x51c9, -- cgit v1.2.3 From c1c1fc8103f794a10c5c15e3c17879caf4f42c8f Mon Sep 17 00:00:00 2001 From: Jairaj Arava Date: Mon, 19 Sep 2022 13:44:29 +0200 Subject: ASoC: SOF: pci: Change DMI match info to support all Chrome platforms In some Chrome platforms if OEM's use their own string as SYS_VENDOR than "Google", it leads to firmware load failure from intel/sof/community path. Hence, changing SYS_VENDOR to PRODUCT_FAMILY in which "Google" is used as common prefix and is supported in all Chrome platforms. Reviewed-by: Ranjani Sridharan Reviewed-by: Chao Song Reviewed-by: Curtis Malainey Signed-off-by: Jairaj Arava Signed-off-by: Curtis Malainey Signed-off-by: Sathyanarayana Nujella Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220919114429.42700-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-pci-dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index d627092b399d..643fd1036d60 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -138,7 +138,7 @@ static const struct dmi_system_id community_key_platforms[] = { .ident = "Google Chromebooks", .callback = chromebook_use_community_key, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_PRODUCT_FAMILY, "Google"), } }, {}, -- cgit v1.2.3 From 59f84d2dd76ad6e681b5135db6e6cc8c8238cd89 Mon Sep 17 00:00:00 2001 From: ye xingchen Date: Fri, 16 Sep 2022 06:24:15 +0000 Subject: ASoC: Intel: sof_es8336: use function devm_kcalloc() instead of devm_kzalloc() Use 2-factor multiplication argument form devm_kcalloc() instead of devm_kzalloc(). Reported-by: Zeal Robot Signed-off-by: ye xingchen Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220916062415.153659-1-ye.xingchen@zte.com.cn Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_es8336.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c index 606cc3242a60..fbb42e54947a 100644 --- a/sound/soc/intel/boards/sof_es8336.c +++ b/sound/soc/intel/boards/sof_es8336.c @@ -481,9 +481,10 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, /* HDMI */ if (hdmi_num > 0) { - idisp_components = devm_kzalloc(dev, - sizeof(struct snd_soc_dai_link_component) * - hdmi_num, GFP_KERNEL); + idisp_components = devm_kcalloc(dev, + hdmi_num, + sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); if (!idisp_components) goto devm_err; } -- cgit v1.2.3 From 9fc2c8ed923d8ec8a49cf5b5076c84867126ca69 Mon Sep 17 00:00:00 2001 From: Ban Tao Date: Sun, 11 Sep 2022 23:45:33 -0700 Subject: ASoC: sunxi: Add Allwinner H6 Digital MIC driver The Allwinner H6 and later SoCs have an DMIC block which is capable of capture. Signed-off-by: Ban Tao Tested-by: Samuel Holland Link: https://lore.kernel.org/r/1662965133-9232-1-git-send-email-fengzheng923@gmail.com Signed-off-by: Mark Brown --- MAINTAINERS | 7 + sound/soc/sunxi/Kconfig | 7 + sound/soc/sunxi/Makefile | 1 + sound/soc/sunxi/sun50i-dmic.c | 406 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 421 insertions(+) create mode 100644 sound/soc/sunxi/sun50i-dmic.c diff --git a/MAINTAINERS b/MAINTAINERS index 5e3f515f0c1f..bda993e76dd4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -820,6 +820,13 @@ L: linux-media@vger.kernel.org S: Maintained F: drivers/staging/media/sunxi/cedrus/ +ALLWINNER DMIC DRIVERS +M: Ban Tao +L: alsa-devel@alsa-project.org (moderated for non-subscribers) +S: Maintained +F: Documentation/devicetree/bindings/sound/allwinner,sun50i-h6-dmic.yaml +F: sound/soc/sunxi/sun50i-dmic.c + ALPHA PORT M: Richard Henderson M: Ivan Kokshaysky diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig index ddcaaa98d3cb..1f18f016acbb 100644 --- a/sound/soc/sunxi/Kconfig +++ b/sound/soc/sunxi/Kconfig @@ -56,6 +56,13 @@ config SND_SUN4I_SPDIF Say Y or M to add support for the S/PDIF audio block in the Allwinner A10 and affiliated SoCs. +config SND_SUN50I_DMIC + tristate "Allwinner H6 DMIC Support" + select SND_SOC_GENERIC_DMAENGINE_PCM + help + Say Y or M to add support for the DMIC audio block in the Allwinner + H6 and affiliated SoCs. + config SND_SUN8I_ADDA_PR_REGMAP tristate select REGMAP diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile index a86be340a076..4483fe9c94ef 100644 --- a/sound/soc/sunxi/Makefile +++ b/sound/soc/sunxi/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o obj-$(CONFIG_SND_SUN50I_CODEC_ANALOG) += sun50i-codec-analog.o obj-$(CONFIG_SND_SUN8I_CODEC) += sun8i-codec.o obj-$(CONFIG_SND_SUN8I_ADDA_PR_REGMAP) += sun8i-adda-pr-regmap.o +obj-$(CONFIG_SND_SUN50I_DMIC) += sun50i-dmic.o diff --git a/sound/soc/sunxi/sun50i-dmic.c b/sound/soc/sunxi/sun50i-dmic.c new file mode 100644 index 000000000000..cd3c07f2070f --- /dev/null +++ b/sound/soc/sunxi/sun50i-dmic.c @@ -0,0 +1,406 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// This driver supports the DMIC in Allwinner's H6 SoCs. +// +// Copyright 2021 Ban Tao + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SUN50I_DMIC_EN_CTL (0x00) + #define SUN50I_DMIC_EN_CTL_GLOBE BIT(8) + #define SUN50I_DMIC_EN_CTL_CHAN(v) ((v) << 0) + #define SUN50I_DMIC_EN_CTL_CHAN_MASK GENMASK(7, 0) +#define SUN50I_DMIC_SR (0x04) + #define SUN50I_DMIC_SR_SAMPLE_RATE(v) ((v) << 0) + #define SUN50I_DMIC_SR_SAMPLE_RATE_MASK GENMASK(2, 0) +#define SUN50I_DMIC_CTL (0x08) + #define SUN50I_DMIC_CTL_OVERSAMPLE_RATE BIT(0) +#define SUN50I_DMIC_DATA (0x10) +#define SUN50I_DMIC_INTC (0x14) + #define SUN50I_DMIC_FIFO_DRQ_EN BIT(2) +#define SUN50I_DMIC_INT_STA (0x18) + #define SUN50I_DMIC_INT_STA_OVERRUN_IRQ_PENDING BIT(1) + #define SUN50I_DMIC_INT_STA_DATA_IRQ_PENDING BIT(0) +#define SUN50I_DMIC_RXFIFO_CTL (0x1c) + #define SUN50I_DMIC_RXFIFO_CTL_FLUSH BIT(31) + #define SUN50I_DMIC_RXFIFO_CTL_MODE_MASK BIT(9) + #define SUN50I_DMIC_RXFIFO_CTL_MODE_LSB (0 << 9) + #define SUN50I_DMIC_RXFIFO_CTL_MODE_MSB (1 << 9) + #define SUN50I_DMIC_RXFIFO_CTL_SAMPLE_MASK BIT(8) + #define SUN50I_DMIC_RXFIFO_CTL_SAMPLE_16 (0 << 8) + #define SUN50I_DMIC_RXFIFO_CTL_SAMPLE_24 (1 << 8) +#define SUN50I_DMIC_CH_NUM (0x24) + #define SUN50I_DMIC_CH_NUM_N(v) ((v) << 0) + #define SUN50I_DMIC_CH_NUM_N_MASK GENMASK(2, 0) +#define SUN50I_DMIC_CNT (0x2c) + #define SUN50I_DMIC_CNT_N (1 << 0) +#define SUN50I_DMIC_HPF_CTRL (0x38) +#define SUN50I_DMIC_VERSION (0x50) + +struct sun50i_dmic_dev { + struct clk *dmic_clk; + struct clk *bus_clk; + struct reset_control *rst; + struct regmap *regmap; + struct snd_dmaengine_dai_dma_data dma_params_rx; +}; + +struct dmic_rate { + unsigned int samplerate; + unsigned int rate_bit; +}; + +const static struct dmic_rate dmic_rate_s[] = { + {48000, 0x0}, + {44100, 0x0}, + {32000, 0x1}, + {24000, 0x2}, + {22050, 0x2}, + {16000, 0x3}, + {12000, 0x4}, + {11025, 0x4}, + {8000, 0x5}, +}; + +static int sun50i_dmic_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct sun50i_dmic_dev *host = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); + + /* only support capture */ + if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) + return -EINVAL; + + regmap_update_bits(host->regmap, SUN50I_DMIC_RXFIFO_CTL, + SUN50I_DMIC_RXFIFO_CTL_FLUSH, + SUN50I_DMIC_RXFIFO_CTL_FLUSH); + regmap_write(host->regmap, SUN50I_DMIC_CNT, SUN50I_DMIC_CNT_N); + + return 0; +} + +static int sun50i_dmic_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *cpu_dai) +{ + int i = 0; + unsigned long rate = params_rate(params); + unsigned int mclk = 0; + unsigned int channels = params_channels(params); + unsigned int chan_en = (1 << channels) - 1; + struct sun50i_dmic_dev *host = snd_soc_dai_get_drvdata(cpu_dai); + + /* DMIC num is N+1 */ + regmap_update_bits(host->regmap, SUN50I_DMIC_CH_NUM, + SUN50I_DMIC_CH_NUM_N_MASK, + SUN50I_DMIC_CH_NUM_N(channels - 1)); + regmap_write(host->regmap, SUN50I_DMIC_HPF_CTRL, chan_en); + regmap_update_bits(host->regmap, SUN50I_DMIC_EN_CTL, + SUN50I_DMIC_EN_CTL_CHAN_MASK, + SUN50I_DMIC_EN_CTL_CHAN(chan_en)); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + regmap_update_bits(host->regmap, SUN50I_DMIC_RXFIFO_CTL, + SUN50I_DMIC_RXFIFO_CTL_SAMPLE_MASK, + SUN50I_DMIC_RXFIFO_CTL_SAMPLE_16); + break; + case SNDRV_PCM_FORMAT_S24_LE: + regmap_update_bits(host->regmap, SUN50I_DMIC_RXFIFO_CTL, + SUN50I_DMIC_RXFIFO_CTL_SAMPLE_MASK, + SUN50I_DMIC_RXFIFO_CTL_SAMPLE_24); + break; + default: + dev_err(cpu_dai->dev, "Invalid format!\n"); + return -EINVAL; + } + /* The hardware supports FIFO mode 1 for 24-bit samples */ + regmap_update_bits(host->regmap, SUN50I_DMIC_RXFIFO_CTL, + SUN50I_DMIC_RXFIFO_CTL_MODE_MASK, + SUN50I_DMIC_RXFIFO_CTL_MODE_MSB); + + switch (rate) { + case 11025: + case 22050: + case 44100: + mclk = 22579200; + break; + case 8000: + case 12000: + case 16000: + case 24000: + case 32000: + case 48000: + mclk = 24576000; + break; + default: + dev_err(cpu_dai->dev, "Invalid rate!\n"); + return -EINVAL; + } + + if (clk_set_rate(host->dmic_clk, mclk)) { + dev_err(cpu_dai->dev, "mclk : %u not support\n", mclk); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(dmic_rate_s); i++) { + if (dmic_rate_s[i].samplerate == rate) { + regmap_update_bits(host->regmap, SUN50I_DMIC_SR, + SUN50I_DMIC_SR_SAMPLE_RATE_MASK, + SUN50I_DMIC_SR_SAMPLE_RATE(dmic_rate_s[i].rate_bit)); + break; + } + } + + switch (params_physical_width(params)) { + case 16: + host->dma_params_rx.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + break; + case 32: + host->dma_params_rx.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + break; + default: + dev_err(cpu_dai->dev, "Unsupported physical sample width: %d\n", + params_physical_width(params)); + return -EINVAL; + } + + /* oversamplerate adjust */ + if (params_rate(params) >= 24000) + regmap_update_bits(host->regmap, SUN50I_DMIC_CTL, + SUN50I_DMIC_CTL_OVERSAMPLE_RATE, + SUN50I_DMIC_CTL_OVERSAMPLE_RATE); + else + regmap_update_bits(host->regmap, SUN50I_DMIC_CTL, + SUN50I_DMIC_CTL_OVERSAMPLE_RATE, 0); + + return 0; +} + +static int sun50i_dmic_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + int ret = 0; + struct sun50i_dmic_dev *host = snd_soc_dai_get_drvdata(dai); + + if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) + return -EINVAL; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + /* DRQ ENABLE */ + regmap_update_bits(host->regmap, SUN50I_DMIC_INTC, + SUN50I_DMIC_FIFO_DRQ_EN, + SUN50I_DMIC_FIFO_DRQ_EN); + /* Global enable */ + regmap_update_bits(host->regmap, SUN50I_DMIC_EN_CTL, + SUN50I_DMIC_EN_CTL_GLOBE, + SUN50I_DMIC_EN_CTL_GLOBE); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + /* DRQ DISABLE */ + regmap_update_bits(host->regmap, SUN50I_DMIC_INTC, + SUN50I_DMIC_FIFO_DRQ_EN, 0); + /* Global disable */ + regmap_update_bits(host->regmap, SUN50I_DMIC_EN_CTL, + SUN50I_DMIC_EN_CTL_GLOBE, 0); + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static int sun50i_dmic_soc_dai_probe(struct snd_soc_dai *dai) +{ + struct sun50i_dmic_dev *host = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, NULL, &host->dma_params_rx); + + return 0; +} + +static const struct snd_soc_dai_ops sun50i_dmic_dai_ops = { + .startup = sun50i_dmic_startup, + .trigger = sun50i_dmic_trigger, + .hw_params = sun50i_dmic_hw_params, +}; + +static const struct regmap_config sun50i_dmic_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = SUN50I_DMIC_VERSION, + .cache_type = REGCACHE_NONE, +}; + +#define SUN50I_DMIC_RATES (SNDRV_PCM_RATE_8000_48000) +#define SUN50I_DMIC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_driver sun50i_dmic_dai = { + .capture = { + .channels_min = 1, + .channels_max = 8, + .rates = SUN50I_DMIC_RATES, + .formats = SUN50I_DMIC_FORMATS, + .sig_bits = 21, + }, + .probe = sun50i_dmic_soc_dai_probe, + .ops = &sun50i_dmic_dai_ops, + .name = "dmic", +}; + +static const struct of_device_id sun50i_dmic_of_match[] = { + { + .compatible = "allwinner,sun50i-h6-dmic", + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, sun50i_dmic_of_match); + +static const struct snd_soc_component_driver sun50i_dmic_component = { + .name = "sun50i-dmic", +}; + +static int sun50i_dmic_runtime_suspend(struct device *dev) +{ + struct sun50i_dmic_dev *host = dev_get_drvdata(dev); + + clk_disable_unprepare(host->dmic_clk); + clk_disable_unprepare(host->bus_clk); + + return 0; +} + +static int sun50i_dmic_runtime_resume(struct device *dev) +{ + struct sun50i_dmic_dev *host = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(host->dmic_clk); + if (ret) + return ret; + + ret = clk_prepare_enable(host->bus_clk); + if (ret) { + clk_disable_unprepare(host->dmic_clk); + return ret; + } + + return 0; +} + +static int sun50i_dmic_probe(struct platform_device *pdev) +{ + struct sun50i_dmic_dev *host; + struct resource *res; + int ret; + void __iomem *base; + + host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); + if (!host) + return -ENOMEM; + + /* Get the addresses */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return dev_err_probe(&pdev->dev, PTR_ERR(base), + "get resource failed.\n"); + + host->regmap = devm_regmap_init_mmio(&pdev->dev, base, + &sun50i_dmic_regmap_config); + + /* Clocks */ + host->bus_clk = devm_clk_get(&pdev->dev, "bus"); + if (IS_ERR(host->bus_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(host->bus_clk), + "failed to get bus clock.\n"); + + host->dmic_clk = devm_clk_get(&pdev->dev, "mod"); + if (IS_ERR(host->dmic_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(host->dmic_clk), + "failed to get dmic clock.\n"); + + host->dma_params_rx.addr = res->start + SUN50I_DMIC_DATA; + host->dma_params_rx.maxburst = 8; + + platform_set_drvdata(pdev, host); + + host->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); + if (IS_ERR(host->rst)) + return dev_err_probe(&pdev->dev, PTR_ERR(host->rst), + "Failed to get reset.\n"); + reset_control_deassert(host->rst); + + ret = devm_snd_soc_register_component(&pdev->dev, &sun50i_dmic_component, + &sun50i_dmic_dai, 1); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "failed to register component.\n"); + + pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + ret = sun50i_dmic_runtime_resume(&pdev->dev); + if (ret) + goto err_disable_runtime_pm; + } + + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + if (ret) + goto err_suspend; + + return 0; +err_suspend: + if (!pm_runtime_status_suspended(&pdev->dev)) + sun50i_dmic_runtime_suspend(&pdev->dev); +err_disable_runtime_pm: + pm_runtime_disable(&pdev->dev); + return ret; +} + +static int sun50i_dmic_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + sun50i_dmic_runtime_suspend(&pdev->dev); + + return 0; +} + +static const struct dev_pm_ops sun50i_dmic_pm = { + SET_RUNTIME_PM_OPS(sun50i_dmic_runtime_suspend, + sun50i_dmic_runtime_resume, NULL) +}; + +static struct platform_driver sun50i_dmic_driver = { + .driver = { + .name = "sun50i-dmic", + .of_match_table = of_match_ptr(sun50i_dmic_of_match), + .pm = &sun50i_dmic_pm, + }, + .probe = sun50i_dmic_probe, + .remove = sun50i_dmic_remove, +}; + +module_platform_driver(sun50i_dmic_driver); + +MODULE_DESCRIPTION("Allwinner sun50i DMIC SoC Interface"); +MODULE_AUTHOR("Ban Tao "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:sun50i-dmic"); -- cgit v1.2.3 From bfc5e8b860ad2a87269975a6043aa6bb245d44bb Mon Sep 17 00:00:00 2001 From: Derek Fang Date: Tue, 13 Sep 2022 10:56:56 +0800 Subject: ASoC: rt5682s: Reduce coupling of Micbias and Vref2 settings Some parts of rt5682s CCF function are implemented by 'MICBIAS' and 'Vref2' dapm widgets. There is a risk of causing not expected behavior if we mix using dapm and CCF operations in machine specific code. This patch reduces the coupling. Signed-off-by: Derek Fang Link: https://lore.kernel.org/r/20220913025658.5005-1-derek.fang@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682s.c | 54 ++++++++++++++++++++++------------------------ sound/soc/codecs/rt5682s.h | 2 ++ 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c index eb47e7cd485a..c5c55d146ddf 100644 --- a/sound/soc/codecs/rt5682s.c +++ b/sound/soc/codecs/rt5682s.c @@ -739,6 +739,7 @@ static void rt5682s_disable_push_button_irq(struct snd_soc_component *component) */ static int rt5682s_headset_detect(struct snd_soc_component *component, int jack_insert) { + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); unsigned int val, count; int jack_type = 0; @@ -805,12 +806,10 @@ static int rt5682s_headset_detect(struct snd_soc_component *component, int jack_ snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_1, RT5682S_TRIG_JD_MASK, RT5682S_TRIG_JD_LOW); - if (!snd_soc_dapm_get_pin_status(&component->dapm, "MICBIAS")) - snd_soc_component_update_bits(component, - RT5682S_PWR_ANLG_1, RT5682S_PWR_MB, 0); - if (!snd_soc_dapm_get_pin_status(&component->dapm, "Vref2")) + if (!rt5682s->wclk_enabled) { snd_soc_component_update_bits(component, - RT5682S_PWR_ANLG_1, RT5682S_PWR_VREF2, 0); + RT5682S_PWR_ANLG_1, RT5682S_PWR_VREF2 | RT5682S_PWR_MB, 0); + } snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_3, RT5682S_PWR_CBJ, 0); @@ -845,6 +844,7 @@ static void rt5682s_jack_detect_handler(struct work_struct *work) snd_soc_dapm_mutex_lock(dapm); mutex_lock(&rt5682s->calibrate_mutex); + mutex_lock(&rt5682s->wclk_mutex); val = snd_soc_component_read(rt5682s->component, RT5682S_AJD1_CTRL) & RT5682S_JDH_RS_MASK; @@ -900,6 +900,7 @@ static void rt5682s_jack_detect_handler(struct work_struct *work) rt5682s->irq_work_delay_time = 50; } + mutex_unlock(&rt5682s->wclk_mutex); mutex_unlock(&rt5682s->calibrate_mutex); snd_soc_dapm_mutex_unlock(dapm); @@ -1218,13 +1219,9 @@ static int set_dmic_power(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_POST_PMD: - if (!rt5682s->jack_type) { - if (!snd_soc_dapm_get_pin_status(w->dapm, "MICBIAS")) - snd_soc_component_update_bits(component, - RT5682S_PWR_ANLG_1, RT5682S_PWR_MB, 0); - if (!snd_soc_dapm_get_pin_status(w->dapm, "Vref2")) - snd_soc_component_update_bits(component, - RT5682S_PWR_ANLG_1, RT5682S_PWR_VREF2, 0); + if (!rt5682s->jack_type && !rt5682s->wclk_enabled) { + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, + RT5682S_PWR_VREF2 | RT5682S_PWR_MB, 0); } break; } @@ -1615,8 +1612,6 @@ static const struct snd_soc_dapm_widget rt5682s_dapm_widgets[] = { RT5682S_PWR_LDO_MB2_BIT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("LDO", RT5682S_PWR_ANLG_3, RT5682S_PWR_LDO_BIT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("Vref2", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("MICBIAS", SND_SOC_NOPM, 0, 0, NULL, 0), /* PLL Powers */ SND_SOC_DAPM_SUPPLY_S("PLLA_LDO", 0, RT5682S_PWR_ANLG_3, @@ -2469,19 +2464,21 @@ static int rt5682s_wclk_prepare(struct clk_hw *hw) if (!rt5682s_clk_check(rt5682s)) return -EINVAL; - snd_soc_dapm_mutex_lock(dapm); - - snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS"); - snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, - RT5682S_PWR_MB, RT5682S_PWR_MB); + mutex_lock(&rt5682s->wclk_mutex); - snd_soc_dapm_force_enable_pin_unlocked(dapm, "Vref2"); snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, - RT5682S_PWR_VREF2 | RT5682S_PWR_FV2, RT5682S_PWR_VREF2); + RT5682S_PWR_VREF2 | RT5682S_PWR_FV2 | RT5682S_PWR_MB, + RT5682S_PWR_VREF2 | RT5682S_PWR_MB); usleep_range(15000, 20000); snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, RT5682S_PWR_FV2, RT5682S_PWR_FV2); + rt5682s->wclk_enabled = 1; + + mutex_unlock(&rt5682s->wclk_mutex); + + snd_soc_dapm_mutex_lock(dapm); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "I2S1"); /* Only need to power PLLB due to the rate set restriction */ snd_soc_dapm_force_enable_pin_unlocked(dapm, "PLLB"); @@ -2502,14 +2499,18 @@ static void rt5682s_wclk_unprepare(struct clk_hw *hw) if (!rt5682s_clk_check(rt5682s)) return; - snd_soc_dapm_mutex_lock(dapm); + mutex_lock(&rt5682s->wclk_mutex); - snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS"); - snd_soc_dapm_disable_pin_unlocked(dapm, "Vref2"); if (!rt5682s->jack_type) snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, RT5682S_PWR_VREF2 | RT5682S_PWR_FV2 | RT5682S_PWR_MB, 0); + rt5682s->wclk_enabled = 0; + + mutex_unlock(&rt5682s->wclk_mutex); + + snd_soc_dapm_mutex_lock(dapm); + snd_soc_dapm_disable_pin_unlocked(dapm, "I2S1"); snd_soc_dapm_disable_pin_unlocked(dapm, "PLLB"); snd_soc_dapm_sync_unlocked(dapm); @@ -2805,7 +2806,6 @@ static inline int rt5682s_dai_probe_clks(struct snd_soc_component *component) static int rt5682s_probe(struct snd_soc_component *component) { struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); - struct snd_soc_dapm_context *dapm = &component->dapm; int ret; rt5682s->component = component; @@ -2814,9 +2814,6 @@ static int rt5682s_probe(struct snd_soc_component *component) if (ret) return ret; - snd_soc_dapm_disable_pin(dapm, "MICBIAS"); - snd_soc_dapm_disable_pin(dapm, "Vref2"); - snd_soc_dapm_sync(dapm); return 0; } @@ -3113,6 +3110,7 @@ static int rt5682s_i2c_probe(struct i2c_client *i2c) mutex_init(&rt5682s->calibrate_mutex); mutex_init(&rt5682s->sar_mutex); + mutex_init(&rt5682s->wclk_mutex); rt5682s_calibrate(rt5682s); regmap_update_bits(rt5682s->regmap, RT5682S_MICBIAS_2, diff --git a/sound/soc/codecs/rt5682s.h b/sound/soc/codecs/rt5682s.h index 7353831c73dd..824dc6543c18 100644 --- a/sound/soc/codecs/rt5682s.h +++ b/sound/soc/codecs/rt5682s.h @@ -1450,6 +1450,7 @@ struct rt5682s_priv { struct delayed_work jd_check_work; struct mutex calibrate_mutex; struct mutex sar_mutex; + struct mutex wclk_mutex; #ifdef CONFIG_COMMON_CLK struct clk_hw dai_clks_hw[RT5682S_DAI_NUM_CLKS]; @@ -1469,6 +1470,7 @@ struct rt5682s_priv { int jack_type; int irq_work_delay_time; + int wclk_enabled; }; int rt5682s_sel_asrc_clk_src(struct snd_soc_component *component, -- cgit v1.2.3 From 6ea304a402322ed4449156805b0a79fa1e326ca7 Mon Sep 17 00:00:00 2001 From: Derek Fang Date: Tue, 13 Sep 2022 10:56:57 +0800 Subject: ASoC: rt5682s: Reduce coupling of I2S1 setting Some parts of rt5682s CCF function are implemented by 'I2S1' dapm widget. The coupling risk exists, so this patch fixes it. Signed-off-by: Derek Fang Link: https://lore.kernel.org/r/20220913025658.5005-2-derek.fang@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682s.c | 104 ++++++++++++++++++++++++++++----------------- 1 file changed, 66 insertions(+), 38 deletions(-) diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c index c5c55d146ddf..325d227a2b37 100644 --- a/sound/soc/codecs/rt5682s.c +++ b/sound/soc/codecs/rt5682s.c @@ -1229,41 +1229,58 @@ static int set_dmic_power(struct snd_soc_dapm_widget *w, return 0; } -static int set_i2s_clk(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) +static void rt5682s_set_i2s(struct rt5682s_priv *rt5682s, int id, int on) { - struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); - int pre_div, id; - unsigned int reg, mask, sft; - - if (event != SND_SOC_DAPM_PRE_PMU) - return 0; - - if (w->shift == RT5682S_PWR_I2S2_BIT) { - id = RT5682S_AIF2; - reg = RT5682S_I2S2_M_CLK_CTRL_1; - mask = RT5682S_I2S2_M_D_MASK; - sft = RT5682S_I2S2_M_D_SFT; + struct snd_soc_component *component = rt5682s->component; + int pre_div; + unsigned int p_reg, p_mask, p_sft; + unsigned int c_reg, c_mask, c_sft; + + if (id == RT5682S_AIF1) { + c_reg = RT5682S_ADDA_CLK_1; + c_mask = RT5682S_I2S_M_D_MASK; + c_sft = RT5682S_I2S_M_D_SFT; + p_reg = RT5682S_PWR_DIG_1; + p_mask = RT5682S_PWR_I2S1; + p_sft = RT5682S_PWR_I2S1_BIT; } else { - id = RT5682S_AIF1; - reg = RT5682S_ADDA_CLK_1; - mask = RT5682S_I2S_M_D_MASK; - sft = RT5682S_I2S_M_D_SFT; + c_reg = RT5682S_I2S2_M_CLK_CTRL_1; + c_mask = RT5682S_I2S2_M_D_MASK; + c_sft = RT5682S_I2S2_M_D_SFT; + p_reg = RT5682S_PWR_DIG_1; + p_mask = RT5682S_PWR_I2S2; + p_sft = RT5682S_PWR_I2S2_BIT; } - if (!rt5682s->master[id]) - return 0; + if (on && rt5682s->master[id]) { + pre_div = get_clk_info(rt5682s->sysclk, rt5682s->lrck[id]); + if (pre_div < 0) { + dev_err(component->dev, "get pre_div failed\n"); + return; + } - pre_div = get_clk_info(rt5682s->sysclk, rt5682s->lrck[id]); - if (pre_div < 0) { - dev_err(component->dev, "get pre_div failed\n"); - return -EINVAL; + dev_dbg(component->dev, "lrck is %dHz and pre_div is %d for iis %d master\n", + rt5682s->lrck[id], pre_div, id); + snd_soc_component_update_bits(component, c_reg, c_mask, pre_div << c_sft); } - dev_dbg(component->dev, "lrck is %dHz and pre_div is %d for iis %d master\n", - rt5682s->lrck[id], pre_div, id); - snd_soc_component_update_bits(component, reg, mask, pre_div << sft); + snd_soc_component_update_bits(component, p_reg, p_mask, on << p_sft); +} + +static int set_i2s_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); + int on = 0; + + if (SND_SOC_DAPM_EVENT_ON(event)) + on = 1; + + if (!strcmp(w->name, "I2S1") && !rt5682s->wclk_enabled) + rt5682s_set_i2s(rt5682s, RT5682S_AIF1, on); + else if (!strcmp(w->name, "I2S2")) + rt5682s_set_i2s(rt5682s, RT5682S_AIF2, on); return 0; } @@ -1715,10 +1732,10 @@ static const struct snd_soc_dapm_widget rt5682s_dapm_widgets[] = { SND_SOC_DAPM_PGA("Stereo1 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), /* Digital Interface */ - SND_SOC_DAPM_SUPPLY("I2S1", RT5682S_PWR_DIG_1, RT5682S_PWR_I2S1_BIT, - 0, set_i2s_clk, SND_SOC_DAPM_PRE_PMU), - SND_SOC_DAPM_SUPPLY("I2S2", RT5682S_PWR_DIG_1, RT5682S_PWR_I2S2_BIT, - 0, set_i2s_clk, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY("I2S1", SND_SOC_NOPM, 0, 0, + set_i2s_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("I2S2", SND_SOC_NOPM, 0, 0, + set_i2s_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0), @@ -2426,12 +2443,15 @@ static int rt5682s_set_bias_level(struct snd_soc_component *component, RT5682S_PWR_LDO, RT5682S_PWR_LDO); break; case SND_SOC_BIAS_STANDBY: - regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_1, - RT5682S_DIG_GATE_CTRL, RT5682S_DIG_GATE_CTRL); + if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) + regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_1, + RT5682S_DIG_GATE_CTRL, RT5682S_DIG_GATE_CTRL); break; case SND_SOC_BIAS_OFF: - regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_1, - RT5682S_DIG_GATE_CTRL | RT5682S_PWR_LDO, 0); + regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_1, RT5682S_PWR_LDO, 0); + if (!rt5682s->wclk_enabled) + regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_1, + RT5682S_DIG_GATE_CTRL, 0); break; case SND_SOC_BIAS_ON: break; @@ -2473,13 +2493,17 @@ static int rt5682s_wclk_prepare(struct clk_hw *hw) snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, RT5682S_PWR_FV2, RT5682S_PWR_FV2); + /* Set and power on I2S1 */ + snd_soc_component_update_bits(component, RT5682S_PWR_DIG_1, + RT5682S_DIG_GATE_CTRL, RT5682S_DIG_GATE_CTRL); + rt5682s_set_i2s(rt5682s, RT5682S_AIF1, 1); + rt5682s->wclk_enabled = 1; mutex_unlock(&rt5682s->wclk_mutex); snd_soc_dapm_mutex_lock(dapm); - snd_soc_dapm_force_enable_pin_unlocked(dapm, "I2S1"); /* Only need to power PLLB due to the rate set restriction */ snd_soc_dapm_force_enable_pin_unlocked(dapm, "PLLB"); snd_soc_dapm_sync_unlocked(dapm); @@ -2505,13 +2529,17 @@ static void rt5682s_wclk_unprepare(struct clk_hw *hw) snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, RT5682S_PWR_VREF2 | RT5682S_PWR_FV2 | RT5682S_PWR_MB, 0); + /* Power down I2S1 */ + rt5682s_set_i2s(rt5682s, RT5682S_AIF1, 0); + snd_soc_component_update_bits(component, RT5682S_PWR_DIG_1, + RT5682S_DIG_GATE_CTRL, 0); + rt5682s->wclk_enabled = 0; mutex_unlock(&rt5682s->wclk_mutex); snd_soc_dapm_mutex_lock(dapm); - snd_soc_dapm_disable_pin_unlocked(dapm, "I2S1"); snd_soc_dapm_disable_pin_unlocked(dapm, "PLLB"); snd_soc_dapm_sync_unlocked(dapm); -- cgit v1.2.3 From 3d47637719c312cfb49d3ba063dc3976535c0e9f Mon Sep 17 00:00:00 2001 From: Derek Fang Date: Tue, 13 Sep 2022 10:56:58 +0800 Subject: ASoC: rt5682s: Reduce coupling of PLLB setting Some parts of rt5682s CCF function are implemented by 'PLLB' dapm widget. The coupling risk exists, so this patch fixes it. Signed-off-by: Derek Fang Link: https://lore.kernel.org/r/20220913025658.5005-3-derek.fang@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682s.c | 116 ++++++++++++++++++++++++++++----------------- 1 file changed, 73 insertions(+), 43 deletions(-) diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c index 325d227a2b37..2831f2f61aba 100644 --- a/sound/soc/codecs/rt5682s.c +++ b/sound/soc/codecs/rt5682s.c @@ -1155,29 +1155,52 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w, return 0; } -static int set_filter_clk(struct snd_soc_dapm_widget *w, + +static int rt5682s_set_pllb_power(struct rt5682s_priv *rt5682s, int on) +{ + struct snd_soc_component *component = rt5682s->component; + + if (on) { + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_3, + RT5682S_PWR_LDO_PLLB | RT5682S_PWR_BIAS_PLLB | RT5682S_PWR_PLLB, + RT5682S_PWR_LDO_PLLB | RT5682S_PWR_BIAS_PLLB | RT5682S_PWR_PLLB); + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_3, + RT5682S_RSTB_PLLB, RT5682S_RSTB_PLLB); + } else { + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_3, + RT5682S_PWR_LDO_PLLB | RT5682S_PWR_BIAS_PLLB | + RT5682S_RSTB_PLLB | RT5682S_PWR_PLLB, 0); + } + + return 0; +} + +static int set_pllb_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); - int ref, val, reg, idx; - static const int div_f[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48}; - static const int div_o[] = {1, 2, 4, 6, 8, 12, 16, 24, 32, 48}; + int on = 0; - val = snd_soc_component_read(component, RT5682S_GPIO_CTRL_1) - & RT5682S_GP4_PIN_MASK; + if (rt5682s->wclk_enabled) + return 0; - if (w->shift == RT5682S_PWR_ADC_S1F_BIT && val == RT5682S_GP4_PIN_ADCDAT2) - ref = 256 * rt5682s->lrck[RT5682S_AIF2]; - else - ref = 256 * rt5682s->lrck[RT5682S_AIF1]; + if (SND_SOC_DAPM_EVENT_ON(event)) + on = 1; - idx = rt5682s_div_sel(rt5682s, ref, div_f, ARRAY_SIZE(div_f)); + rt5682s_set_pllb_power(rt5682s, on); - if (w->shift == RT5682S_PWR_ADC_S1F_BIT) - reg = RT5682S_PLL_TRACK_3; - else - reg = RT5682S_PLL_TRACK_2; + return 0; +} + +static void rt5682s_set_filter_clk(struct rt5682s_priv *rt5682s, int reg, int ref) +{ + struct snd_soc_component *component = rt5682s->component; + int idx; + static const int div_f[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48}; + static const int div_o[] = {1, 2, 4, 6, 8, 12, 16, 24, 32, 48}; + + idx = rt5682s_div_sel(rt5682s, ref, div_f, ARRAY_SIZE(div_f)); snd_soc_component_update_bits(component, reg, RT5682S_FILTER_CLK_DIV_MASK, idx << RT5682S_FILTER_CLK_DIV_SFT); @@ -1191,6 +1214,29 @@ static int set_filter_clk(struct snd_soc_dapm_widget *w, snd_soc_component_update_bits(component, RT5682S_ADDA_CLK_1, RT5682S_ADC_OSR_MASK | RT5682S_DAC_OSR_MASK, (idx << RT5682S_ADC_OSR_SFT) | (idx << RT5682S_DAC_OSR_SFT)); +} + +static int set_filter_clk(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); + int ref, reg, val; + + val = snd_soc_component_read(component, RT5682S_GPIO_CTRL_1) + & RT5682S_GP4_PIN_MASK; + + if (w->shift == RT5682S_PWR_ADC_S1F_BIT && val == RT5682S_GP4_PIN_ADCDAT2) + ref = 256 * rt5682s->lrck[RT5682S_AIF2]; + else + ref = 256 * rt5682s->lrck[RT5682S_AIF1]; + + if (w->shift == RT5682S_PWR_ADC_S1F_BIT) + reg = RT5682S_PLL_TRACK_3; + else + reg = RT5682S_PLL_TRACK_2; + + rt5682s_set_filter_clk(rt5682s, reg, ref); return 0; } @@ -1633,20 +1679,14 @@ static const struct snd_soc_dapm_widget rt5682s_dapm_widgets[] = { /* PLL Powers */ SND_SOC_DAPM_SUPPLY_S("PLLA_LDO", 0, RT5682S_PWR_ANLG_3, RT5682S_PWR_LDO_PLLA_BIT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY_S("PLLB_LDO", 0, RT5682S_PWR_ANLG_3, - RT5682S_PWR_LDO_PLLB_BIT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("PLLA_BIAS", 0, RT5682S_PWR_ANLG_3, RT5682S_PWR_BIAS_PLLA_BIT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY_S("PLLB_BIAS", 0, RT5682S_PWR_ANLG_3, - RT5682S_PWR_BIAS_PLLB_BIT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("PLLA", 0, RT5682S_PWR_ANLG_3, RT5682S_PWR_PLLA_BIT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY_S("PLLB", 0, RT5682S_PWR_ANLG_3, - RT5682S_PWR_PLLB_BIT, 0, set_filter_clk, SND_SOC_DAPM_PRE_PMU), SND_SOC_DAPM_SUPPLY_S("PLLA_RST", 1, RT5682S_PWR_ANLG_3, RT5682S_RSTB_PLLA_BIT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY_S("PLLB_RST", 1, RT5682S_PWR_ANLG_3, - RT5682S_RSTB_PLLB_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("PLLB", SND_SOC_NOPM, 0, 0, + set_pllb_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), /* ASRC */ SND_SOC_DAPM_SUPPLY_S("DAC STO1 ASRC", 1, RT5682S_PLL_TRACK_1, @@ -1813,9 +1853,6 @@ static const struct snd_soc_dapm_route rt5682s_dapm_routes[] = { {"PLLA", NULL, "PLLA_LDO"}, {"PLLA", NULL, "PLLA_BIAS"}, {"PLLA", NULL, "PLLA_RST"}, - {"PLLB", NULL, "PLLB_LDO"}, - {"PLLB", NULL, "PLLB_BIAS"}, - {"PLLB", NULL, "PLLB_RST"}, /*ASRC*/ {"ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc}, @@ -2479,7 +2516,7 @@ static int rt5682s_wclk_prepare(struct clk_hw *hw) struct rt5682s_priv *rt5682s = container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_WCLK_IDX]); struct snd_soc_component *component = rt5682s->component; - struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + int ref, reg; if (!rt5682s_clk_check(rt5682s)) return -EINVAL; @@ -2498,18 +2535,16 @@ static int rt5682s_wclk_prepare(struct clk_hw *hw) RT5682S_DIG_GATE_CTRL, RT5682S_DIG_GATE_CTRL); rt5682s_set_i2s(rt5682s, RT5682S_AIF1, 1); + /* Only need to power on PLLB due to the rate set restriction */ + reg = RT5682S_PLL_TRACK_2; + ref = 256 * rt5682s->lrck[RT5682S_AIF1]; + rt5682s_set_filter_clk(rt5682s, reg, ref); + rt5682s_set_pllb_power(rt5682s, 1); + rt5682s->wclk_enabled = 1; mutex_unlock(&rt5682s->wclk_mutex); - snd_soc_dapm_mutex_lock(dapm); - - /* Only need to power PLLB due to the rate set restriction */ - snd_soc_dapm_force_enable_pin_unlocked(dapm, "PLLB"); - snd_soc_dapm_sync_unlocked(dapm); - - snd_soc_dapm_mutex_unlock(dapm); - return 0; } @@ -2518,7 +2553,6 @@ static void rt5682s_wclk_unprepare(struct clk_hw *hw) struct rt5682s_priv *rt5682s = container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_WCLK_IDX]); struct snd_soc_component *component = rt5682s->component; - struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); if (!rt5682s_clk_check(rt5682s)) return; @@ -2534,16 +2568,12 @@ static void rt5682s_wclk_unprepare(struct clk_hw *hw) snd_soc_component_update_bits(component, RT5682S_PWR_DIG_1, RT5682S_DIG_GATE_CTRL, 0); + /* Power down PLLB */ + rt5682s_set_pllb_power(rt5682s, 0); + rt5682s->wclk_enabled = 0; mutex_unlock(&rt5682s->wclk_mutex); - - snd_soc_dapm_mutex_lock(dapm); - - snd_soc_dapm_disable_pin_unlocked(dapm, "PLLB"); - snd_soc_dapm_sync_unlocked(dapm); - - snd_soc_dapm_mutex_unlock(dapm); } static unsigned long rt5682s_wclk_recalc_rate(struct clk_hw *hw, -- cgit v1.2.3 From 54a0511067217e7039045623942e4e021ef1db84 Mon Sep 17 00:00:00 2001 From: ye xingchen Date: Fri, 16 Sep 2022 06:26:30 +0000 Subject: ASoC: Intel: sof_rt5682: use devm_kcalloc() instead of devm_kzalloc() Use 2-factor multiplication argument form devm_kcalloc() instead of devm_kzalloc(). Reported-by: Zeal Robot Signed-off-by: ye xingchen Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220916062630.154277-1-ye.xingchen@zte.com.cn Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_rt5682.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 045965312245..1bf9455eaf93 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -600,10 +600,10 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, struct snd_soc_dai_link *links; int i, id = 0; - links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * - sof_audio_card_rt5682.num_links, GFP_KERNEL); - cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) * - sof_audio_card_rt5682.num_links, GFP_KERNEL); + links = devm_kcalloc(dev, sof_audio_card_rt5682.num_links, + sizeof(struct snd_soc_dai_link), GFP_KERNEL); + cpus = devm_kcalloc(dev, sof_audio_card_rt5682.num_links, + sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); if (!links || !cpus) goto devm_err; @@ -687,9 +687,10 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, /* HDMI */ if (hdmi_num > 0) { - idisp_components = devm_kzalloc(dev, - sizeof(struct snd_soc_dai_link_component) * - hdmi_num, GFP_KERNEL); + idisp_components = devm_kcalloc(dev, + hdmi_num, + sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); if (!idisp_components) goto devm_err; } -- cgit v1.2.3 From 717a8ff20f32792d6a94f2883e771482c37d844b Mon Sep 17 00:00:00 2001 From: Mikhail Rudenko Date: Wed, 14 Sep 2022 00:22:55 +0300 Subject: ASoC: sunxi: sun4i-codec: set debugfs_prefix for CPU DAI component At present, succesfull probing of H3 Codec results in an error debugfs: Directory '1c22c00.codec' with parent 'H3 Audio Codec' already present! This is caused by a directory name conflict between codec components. Fix it by setting debugfs_prefix for the CPU DAI component. Signed-off-by: Mikhail Rudenko Link: https://lore.kernel.org/r/20220913212256.151799-2-mike.rudenko@gmail.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 3a7075d03c23..835dc3404367 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -1232,6 +1232,9 @@ static const struct snd_soc_component_driver sun8i_a23_codec_codec = { static const struct snd_soc_component_driver sun4i_codec_component = { .name = "sun4i-codec", .legacy_dai_naming = 1, +#ifdef CONFIG_DEBUG_FS + .debugfs_prefix = "cpu", +#endif }; #define SUN4I_CODEC_RATES SNDRV_PCM_RATE_CONTINUOUS -- cgit v1.2.3 From 23162672ff85c24afc19293309500d3a63134ef8 Mon Sep 17 00:00:00 2001 From: Martin Povišer Date: Thu, 15 Sep 2022 11:44:34 +0200 Subject: ASoC: dt-bindings: cs42l42: Add 'cs42l83' compatible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CS42L83 is a publicly undocumented part found in Apple machines, similar (almost identical) to CS42L42. Share the binding schema of CS42L42 for it. Acked-by: Krzysztof Kozlowski Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220915094444.11434-2-povik+lin@cutebit.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/cirrus,cs42l42.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs42l42.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs42l42.yaml index 31800f70e9d9..7356084a2ca2 100644 --- a/Documentation/devicetree/bindings/sound/cirrus,cs42l42.yaml +++ b/Documentation/devicetree/bindings/sound/cirrus,cs42l42.yaml @@ -19,6 +19,7 @@ properties: compatible: enum: - cirrus,cs42l42 + - cirrus,cs42l83 reg: description: -- cgit v1.2.3 From 7e178946c3e4e64cebda4e60d0b7e5c02a502d13 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Thu, 15 Sep 2022 11:44:35 +0200 Subject: ASoC: cs42l42: Add bitclock frequency argument to cs42l42_pll_config() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clean up the handling of bitclock frequency by keeping all the logic in cs42l42_pcm_hw_params(), which then simply passes the frequency as an argument to cs42l42_pll_config(). The previous code had become clunky as a legacy of earlier versions of the clock handling. The logic was split across cs42l42_pcm_hw_params() and cs42l42_pll_config(), with the params-derived bclk stashed in struct cs42l42_private only to pass it to cs42l42_pll_config(). Signed-off-by: Richard Fitzgerald Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220915094444.11434-3-povik+lin@cutebit.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 32 ++++++++++++++++---------------- sound/soc/codecs/cs42l42.h | 1 - 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 21368ed77c6d..037a68488a08 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -647,18 +647,12 @@ static const struct cs42l42_pll_params pll_ratio_table[] = { { 24576000, 1, 0x03, 0x40, 0x000000, 0x03, 0x10, 12288000, 128, 1} }; -static int cs42l42_pll_config(struct snd_soc_component *component) +static int cs42l42_pll_config(struct snd_soc_component *component, unsigned int clk) { struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component); int i; - u32 clk; u32 fsync; - if (!cs42l42->sclk) - clk = cs42l42->bclk; - else - clk = cs42l42->sclk; - /* Don't reconfigure if there is an audio stream running */ if (cs42l42->stream_use) { if (pll_ratio_table[cs42l42->pll_config].sclk == clk) @@ -895,19 +889,25 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream, unsigned int width = (params_width(params) / 8) - 1; unsigned int slot_width = 0; unsigned int val = 0; + unsigned int bclk; int ret; cs42l42->srate = params_rate(params); - /* - * Assume 24-bit samples are in 32-bit slots, to prevent SCLK being - * more than assumed (which would result in overclocking). - */ - if (params_width(params) == 24) - slot_width = 32; + if (cs42l42->sclk) { + /* machine driver has set the SCLK */ + bclk = cs42l42->sclk; + } else { + /* + * Assume 24-bit samples are in 32-bit slots, to prevent SCLK being + * more than assumed (which would result in overclocking). + */ + if (params_width(params) == 24) + slot_width = 32; - /* I2S frame always has multiple of 2 channels */ - cs42l42->bclk = snd_soc_tdm_params_to_bclk(params, slot_width, 0, 2); + /* I2S frame always has multiple of 2 channels */ + bclk = snd_soc_tdm_params_to_bclk(params, slot_width, 0, 2); + } switch (substream->stream) { case SNDRV_PCM_STREAM_CAPTURE: @@ -947,7 +947,7 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream, break; } - ret = cs42l42_pll_config(component); + ret = cs42l42_pll_config(component, bclk); if (ret) return ret; diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index 50299c9f283a..b4ba1467c558 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -30,7 +30,6 @@ struct cs42l42_private { struct snd_soc_jack *jack; struct mutex irq_lock; int pll_config; - int bclk; u32 sclk; u32 srate; u8 plug_state; -- cgit v1.2.3 From 2feab7e7d8c01b67d9ffbfb902d1591c08e9d564 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Thu, 15 Sep 2022 11:44:36 +0200 Subject: ASoC: cs42l42: Use cs42l42->dev instead of &i2c_client->dev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation for splitting cs42l42_i2c_probe() into multiple functions replace use of &i2c_client->dev with cs42l42->dev. This reduces diff clutter in the patch that splits the function. Signed-off-by: Richard Fitzgerald Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220915094444.11434-4-povik+lin@cutebit.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 037a68488a08..9967743a23dd 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -2218,7 +2218,7 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client) cs42l42->regmap = devm_regmap_init_i2c(i2c_client, &cs42l42_regmap); if (IS_ERR(cs42l42->regmap)) { ret = PTR_ERR(cs42l42->regmap); - dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); + dev_err(cs42l42->dev, "regmap_init() failed: %d\n", ret); return ret; } @@ -2226,11 +2226,11 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client) for (i = 0; i < ARRAY_SIZE(cs42l42->supplies); i++) cs42l42->supplies[i].supply = cs42l42_supply_names[i]; - ret = devm_regulator_bulk_get(&i2c_client->dev, + ret = devm_regulator_bulk_get(cs42l42->dev, ARRAY_SIZE(cs42l42->supplies), cs42l42->supplies); if (ret != 0) { - dev_err(&i2c_client->dev, + dev_err(cs42l42->dev, "Failed to request supplies: %d\n", ret); return ret; } @@ -2238,13 +2238,13 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client) ret = regulator_bulk_enable(ARRAY_SIZE(cs42l42->supplies), cs42l42->supplies); if (ret != 0) { - dev_err(&i2c_client->dev, + dev_err(cs42l42->dev, "Failed to enable supplies: %d\n", ret); return ret; } /* Reset the Device */ - cs42l42->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, + cs42l42->reset_gpio = devm_gpiod_get_optional(cs42l42->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(cs42l42->reset_gpio)) { ret = PTR_ERR(cs42l42->reset_gpio); @@ -2252,7 +2252,7 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client) } if (cs42l42->reset_gpio) { - dev_dbg(&i2c_client->dev, "Found reset GPIO\n"); + dev_dbg(cs42l42->dev, "Found reset GPIO\n"); gpiod_set_value_cansleep(cs42l42->reset_gpio, 1); } usleep_range(CS42L42_BOOT_TIME_US, CS42L42_BOOT_TIME_US * 2); @@ -2263,9 +2263,11 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client) NULL, cs42l42_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW, "cs42l42", cs42l42); - if (ret) { - dev_err_probe(&i2c_client->dev, ret, - "Failed to request IRQ\n"); + if (ret == -EPROBE_DEFER) { + goto err_disable_noirq; + } else if (ret != 0) { + dev_err_probe(cs42l42->dev, ret, + "Failed to request IRQ\n"); goto err_disable_noirq; } } @@ -2274,13 +2276,13 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client) devid = cirrus_read_device_id(cs42l42->regmap, CS42L42_DEVID_AB); if (devid < 0) { ret = devid; - dev_err(&i2c_client->dev, "Failed to read device ID: %d\n", ret); + dev_err(cs42l42->dev, "Failed to read device ID: %d\n", ret); goto err_disable; } if (devid != CS42L42_CHIP_ID) { ret = -ENODEV; - dev_err(&i2c_client->dev, + dev_err(cs42l42->dev, "CS42L42 Device ID (%X). Expected %X\n", devid, CS42L42_CHIP_ID); goto err_disable; @@ -2288,11 +2290,11 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client) ret = regmap_read(cs42l42->regmap, CS42L42_REVID, ®); if (ret < 0) { - dev_err(&i2c_client->dev, "Get Revision ID failed\n"); + dev_err(cs42l42->dev, "Get Revision ID failed\n"); goto err_shutdown; } - dev_info(&i2c_client->dev, + dev_info(cs42l42->dev, "Cirrus Logic CS42L42, Revision: %02X\n", reg & 0xFF); /* Power up the codec */ @@ -2312,7 +2314,7 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client) (1 << CS42L42_ADC_PDN_SHIFT) | (0 << CS42L42_PDN_ALL_SHIFT)); - ret = cs42l42_handle_device_data(&i2c_client->dev, cs42l42); + ret = cs42l42_handle_device_data(cs42l42->dev, cs42l42); if (ret != 0) goto err_shutdown; @@ -2323,7 +2325,7 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client) cs42l42_set_interrupt_masks(cs42l42); /* Register codec for machine driver */ - ret = devm_snd_soc_register_component(&i2c_client->dev, + ret = devm_snd_soc_register_component(cs42l42->dev, &soc_component_dev_cs42l42, &cs42l42_dai, 1); if (ret < 0) goto err_shutdown; -- cgit v1.2.3 From 0285042feda799edca63b35cea0cda32ed0c47c2 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Thu, 15 Sep 2022 11:44:37 +0200 Subject: ASoC: cs42l42: Split probe() and remove() into stages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To prepare for adding SoundWire the probe must be split into three parts: 1) The bus-specific probe 2) Common bus-agnostic probe steps 3) Initialization of the peripheral registers Step (3) must be separate because on SoundWire devices the probe must enable power supplies and release reset so that the peripheral can be enumerated by the bus, but it isn't possible to access registers until enumeration has completed. The call to devm_snd_soc_register_component() must be done at stage (2) so that it can EPROBE_DEFER if necessary. In SoundWire systems stage (3) is not a probe event so a deferral at this stage would not result in re-probing dependencies. A new init_done flag indicates that the chip has been identified and initialized. This is used to prevent cs42l42_remove(), cs42l42_suspend(), cs42l42_restore() and cs42l42_irq_thread() from attempting register accesses if the chip was not successfully initialized. Although this cannot happen on I2C, because the entire probe would fail, it is possible on SoundWire if probe succeeds but the cs42l42 is never enumerated. Signed-off-by: Richard Fitzgerald Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220915094444.11434-5-povik+lin@cutebit.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 127 ++++++++++++++++++++++++++++++--------------- sound/soc/codecs/cs42l42.h | 2 + 2 files changed, 87 insertions(+), 42 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 9967743a23dd..b21ea60ef3a8 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -1626,7 +1626,7 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data) unsigned int i; mutex_lock(&cs42l42->irq_lock); - if (cs42l42->suspended) { + if (cs42l42->suspended || !cs42l42->init_done) { mutex_unlock(&cs42l42->irq_lock); return IRQ_NONE; } @@ -2200,28 +2200,13 @@ static int __maybe_unused cs42l42_resume(struct device *dev) return 0; } -static int cs42l42_i2c_probe(struct i2c_client *i2c_client) +static int cs42l42_common_probe(struct cs42l42_private *cs42l42) { - struct cs42l42_private *cs42l42; - int ret, i, devid; - unsigned int reg; - - cs42l42 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l42_private), - GFP_KERNEL); - if (!cs42l42) - return -ENOMEM; + int ret, i; - cs42l42->dev = &i2c_client->dev; - i2c_set_clientdata(i2c_client, cs42l42); + dev_set_drvdata(cs42l42->dev, cs42l42); mutex_init(&cs42l42->irq_lock); - cs42l42->regmap = devm_regmap_init_i2c(i2c_client, &cs42l42_regmap); - if (IS_ERR(cs42l42->regmap)) { - ret = PTR_ERR(cs42l42->regmap); - dev_err(cs42l42->dev, "regmap_init() failed: %d\n", ret); - return ret; - } - BUILD_BUG_ON(ARRAY_SIZE(cs42l42_supply_names) != ARRAY_SIZE(cs42l42->supplies)); for (i = 0; i < ARRAY_SIZE(cs42l42->supplies); i++) cs42l42->supplies[i].supply = cs42l42_supply_names[i]; @@ -2258,20 +2243,44 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client) usleep_range(CS42L42_BOOT_TIME_US, CS42L42_BOOT_TIME_US * 2); /* Request IRQ if one was specified */ - if (i2c_client->irq) { - ret = request_threaded_irq(i2c_client->irq, + if (cs42l42->irq) { + ret = request_threaded_irq(cs42l42->irq, NULL, cs42l42_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW, "cs42l42", cs42l42); - if (ret == -EPROBE_DEFER) { - goto err_disable_noirq; - } else if (ret != 0) { + if (ret) { dev_err_probe(cs42l42->dev, ret, "Failed to request IRQ\n"); goto err_disable_noirq; } } + /* Register codec now so it can EPROBE_DEFER */ + ret = devm_snd_soc_register_component(cs42l42->dev, + &soc_component_dev_cs42l42, + &cs42l42_dai, 1); + if (ret < 0) + goto err; + + return 0; + +err: + if (cs42l42->irq) + free_irq(cs42l42->irq, cs42l42); + +err_disable_noirq: + gpiod_set_value_cansleep(cs42l42->reset_gpio, 0); +err_disable_noreset: + regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), cs42l42->supplies); + + return ret; +} + +static int cs42l42_init(struct cs42l42_private *cs42l42) +{ + unsigned int reg; + int devid, ret; + /* initialize codec */ devid = cirrus_read_device_id(cs42l42->regmap, CS42L42_DEVID_AB); if (devid < 0) { @@ -2321,15 +2330,15 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client) /* Setup headset detection */ cs42l42_setup_hs_type_detect(cs42l42); + /* + * Set init_done before unmasking interrupts so any triggered + * immediately will be handled. + */ + cs42l42->init_done = true; + /* Mask/Unmask Interrupts */ cs42l42_set_interrupt_masks(cs42l42); - /* Register codec for machine driver */ - ret = devm_snd_soc_register_component(cs42l42->dev, - &soc_component_dev_cs42l42, &cs42l42_dai, 1); - if (ret < 0) - goto err_shutdown; - return 0; err_shutdown: @@ -2338,34 +2347,68 @@ err_shutdown: regmap_write(cs42l42->regmap, CS42L42_PWR_CTL1, 0xff); err_disable: - if (i2c_client->irq) - free_irq(i2c_client->irq, cs42l42); + if (cs42l42->irq) + free_irq(cs42l42->irq, cs42l42); -err_disable_noirq: gpiod_set_value_cansleep(cs42l42->reset_gpio, 0); -err_disable_noreset: regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), cs42l42->supplies); return ret; } -static int cs42l42_i2c_remove(struct i2c_client *i2c_client) +static void cs42l42_common_remove(struct cs42l42_private *cs42l42) { - struct cs42l42_private *cs42l42 = i2c_get_clientdata(i2c_client); - - if (i2c_client->irq) - free_irq(i2c_client->irq, cs42l42); + if (cs42l42->irq) + free_irq(cs42l42->irq, cs42l42); /* * The driver might not have control of reset and power supplies, * so ensure that the chip internals are powered down. */ - regmap_write(cs42l42->regmap, CS42L42_CODEC_INT_MASK, 0xff); - regmap_write(cs42l42->regmap, CS42L42_TSRS_PLUG_INT_MASK, 0xff); - regmap_write(cs42l42->regmap, CS42L42_PWR_CTL1, 0xff); + if (cs42l42->init_done) { + regmap_write(cs42l42->regmap, CS42L42_CODEC_INT_MASK, 0xff); + regmap_write(cs42l42->regmap, CS42L42_TSRS_PLUG_INT_MASK, 0xff); + regmap_write(cs42l42->regmap, CS42L42_PWR_CTL1, 0xff); + } gpiod_set_value_cansleep(cs42l42->reset_gpio, 0); regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), cs42l42->supplies); +} + +static int cs42l42_i2c_probe(struct i2c_client *i2c_client) +{ + struct device *dev = &i2c_client->dev; + struct cs42l42_private *cs42l42; + struct regmap *regmap; + int ret; + + cs42l42 = devm_kzalloc(dev, sizeof(struct cs42l42_private), GFP_KERNEL); + if (!cs42l42) + return -ENOMEM; + + regmap = devm_regmap_init_i2c(i2c_client, &cs42l42_regmap); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); + return ret; + } + + cs42l42->dev = dev; + cs42l42->regmap = regmap; + cs42l42->irq = i2c_client->irq; + + ret = cs42l42_common_probe(cs42l42); + if (ret) + return ret; + + return cs42l42_init(cs42l42); +} + +static int cs42l42_i2c_remove(struct i2c_client *i2c_client) +{ + struct cs42l42_private *cs42l42 = dev_get_drvdata(&i2c_client->dev); + + cs42l42_common_remove(cs42l42); return 0; } diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index b4ba1467c558..a8e0d5b414a5 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -29,6 +29,7 @@ struct cs42l42_private { struct completion pdn_done; struct snd_soc_jack *jack; struct mutex irq_lock; + int irq; int pll_config; u32 sclk; u32 srate; @@ -46,6 +47,7 @@ struct cs42l42_private { u8 stream_use; bool hp_adc_up_pending; bool suspended; + bool init_done; }; #endif /* __CS42L42_H__ */ -- cgit v1.2.3 From 56746683c2560ba5604bb212f73eb01f5edfd312 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Thu, 15 Sep 2022 11:44:38 +0200 Subject: ASoC: cs42l42: Split cs42l42_resume into two functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On SoundWire the system resume cannot restore registers until the host controller has re-enumerated the peripheral. This patch splits cs42l42_resume() into two functions, one to power up and the other to restore registers, ready for adding SoundWire support. Signed-off-by: Richard Fitzgerald Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220915094444.11434-6-povik+lin@cutebit.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index b21ea60ef3a8..b629557a386f 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -2184,6 +2184,15 @@ static int __maybe_unused cs42l42_resume(struct device *dev) gpiod_set_value_cansleep(cs42l42->reset_gpio, 1); usleep_range(CS42L42_BOOT_TIME_US, CS42L42_BOOT_TIME_US * 2); + dev_dbg(dev, "System resume powered up\n"); + + return 0; +} + +static void __maybe_unused cs42l42_resume_restore(struct device *dev) +{ + struct cs42l42_private *cs42l42 = dev_get_drvdata(dev); + regcache_cache_only(cs42l42->regmap, false); regcache_mark_dirty(cs42l42->regmap); @@ -2196,6 +2205,17 @@ static int __maybe_unused cs42l42_resume(struct device *dev) mutex_unlock(&cs42l42->irq_lock); dev_dbg(dev, "System resumed\n"); +} + +static int __maybe_unused cs42l42_i2c_resume(struct device *dev) +{ + int ret; + + ret = cs42l42_resume(dev); + if (ret) + return ret; + + cs42l42_resume_restore(dev); return 0; } @@ -2414,7 +2434,7 @@ static int cs42l42_i2c_remove(struct i2c_client *i2c_client) } static const struct dev_pm_ops cs42l42_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(cs42l42_suspend, cs42l42_resume) + SET_SYSTEM_SLEEP_PM_OPS(cs42l42_suspend, cs42l42_i2c_resume) }; #ifdef CONFIG_OF -- cgit v1.2.3 From 52c2e370df07092437d1515e773d28a5f53fc810 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Thu, 15 Sep 2022 11:44:39 +0200 Subject: ASoC: cs42l42: Pass component and dai defs into common probe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pass pointers to snd_soc_component_driver and snd_soc_dai_driver objects into cs42l42_common_probe(). This is in preparation for adding SoundWire support. Signed-off-by: Richard Fitzgerald Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220915094444.11434-7-povik+lin@cutebit.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index b629557a386f..20d84db1a98f 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -579,7 +579,7 @@ static int cs42l42_set_jack(struct snd_soc_component *component, struct snd_soc_ return 0; } -static const struct snd_soc_component_driver soc_component_dev_cs42l42 = { +static const struct snd_soc_component_driver cs42l42_soc_component = { .set_jack = cs42l42_set_jack, .dapm_widgets = cs42l42_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(cs42l42_dapm_widgets), @@ -2220,7 +2220,9 @@ static int __maybe_unused cs42l42_i2c_resume(struct device *dev) return 0; } -static int cs42l42_common_probe(struct cs42l42_private *cs42l42) +static int cs42l42_common_probe(struct cs42l42_private *cs42l42, + const struct snd_soc_component_driver *component_drv, + struct snd_soc_dai_driver *dai) { int ret, i; @@ -2276,9 +2278,7 @@ static int cs42l42_common_probe(struct cs42l42_private *cs42l42) } /* Register codec now so it can EPROBE_DEFER */ - ret = devm_snd_soc_register_component(cs42l42->dev, - &soc_component_dev_cs42l42, - &cs42l42_dai, 1); + ret = devm_snd_soc_register_component(cs42l42->dev, component_drv, dai, 1); if (ret < 0) goto err; @@ -2417,7 +2417,7 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client) cs42l42->regmap = regmap; cs42l42->irq = i2c_client->irq; - ret = cs42l42_common_probe(cs42l42); + ret = cs42l42_common_probe(cs42l42, &cs42l42_soc_component, &cs42l42_dai); if (ret) return ret; -- cgit v1.2.3 From ae9f5e607da47104bc3d02e5c0ed237749f5db51 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Thu, 15 Sep 2022 11:44:40 +0200 Subject: ASoC: cs42l42: Split I2C identity into separate module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split the I2C bus driver definition and probe()/remove() into a separate module so that a SoundWire build of CS42L42 support does not have a spurious dependency on I2C. Signed-off-by: Richard Fitzgerald Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220915094444.11434-8-povik+lin@cutebit.org Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 8 ++- sound/soc/codecs/Makefile | 4 +- sound/soc/codecs/cs42l42-i2c.c | 107 +++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/cs42l42.c | 111 ++++++++--------------------------------- sound/soc/codecs/cs42l42.h | 15 ++++++ 5 files changed, 152 insertions(+), 93 deletions(-) create mode 100644 sound/soc/codecs/cs42l42-i2c.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c7d83fe999e9..01725d0a9500 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -692,9 +692,15 @@ config SND_SOC_CS35L45_I2C Enable support for Cirrus Logic CS35L45 smart speaker amplifier with I2C control. +config SND_SOC_CS42L42_CORE + tristate + config SND_SOC_CS42L42 - tristate "Cirrus Logic CS42L42 CODEC" + tristate "Cirrus Logic CS42L42 CODEC (I2C)" depends on I2C + select REGMAP + select REGMAP_I2C + select SND_SOC_CS42L42_CORE config SND_SOC_CS42L51 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 16a01635dd04..5b7020a0b234 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -65,6 +65,7 @@ snd-soc-cs35l45-objs := cs35l45.o snd-soc-cs35l45-spi-objs := cs35l45-spi.o snd-soc-cs35l45-i2c-objs := cs35l45-i2c.o snd-soc-cs42l42-objs := cs42l42.o +snd-soc-cs42l42-i2c-objs := cs42l42-i2c.o snd-soc-cs42l51-objs := cs42l51.o snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o snd-soc-cs42l52-objs := cs42l52.o @@ -422,7 +423,8 @@ obj-$(CONFIG_SND_SOC_CS35L45_TABLES) += snd-soc-cs35l45-tables.o obj-$(CONFIG_SND_SOC_CS35L45) += snd-soc-cs35l45.o obj-$(CONFIG_SND_SOC_CS35L45_SPI) += snd-soc-cs35l45-spi.o obj-$(CONFIG_SND_SOC_CS35L45_I2C) += snd-soc-cs35l45-i2c.o -obj-$(CONFIG_SND_SOC_CS42L42) += snd-soc-cs42l42.o +obj-$(CONFIG_SND_SOC_CS42L42_CORE) += snd-soc-cs42l42.o +obj-$(CONFIG_SND_SOC_CS42L42) += snd-soc-cs42l42-i2c.o obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o diff --git a/sound/soc/codecs/cs42l42-i2c.c b/sound/soc/codecs/cs42l42-i2c.c new file mode 100644 index 000000000000..5f01b6adc17e --- /dev/null +++ b/sound/soc/codecs/cs42l42-i2c.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * cs42l42-i2c.c -- CS42L42 ALSA SoC audio driver for I2C + * + * Copyright 2016, 2022 Cirrus Logic, Inc. + */ + +#include +#include +#include +#include +#include + +#include "cs42l42.h" + +static int cs42l42_i2c_probe(struct i2c_client *i2c_client) +{ + struct device *dev = &i2c_client->dev; + struct cs42l42_private *cs42l42; + struct regmap *regmap; + int ret; + + cs42l42 = devm_kzalloc(dev, sizeof(*cs42l42), GFP_KERNEL); + if (!cs42l42) + return -ENOMEM; + + regmap = devm_regmap_init_i2c(i2c_client, &cs42l42_regmap); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); + return ret; + } + + cs42l42->dev = dev; + cs42l42->regmap = regmap; + cs42l42->irq = i2c_client->irq; + + ret = cs42l42_common_probe(cs42l42, &cs42l42_soc_component, &cs42l42_dai); + if (ret) + return ret; + + return cs42l42_init(cs42l42); +} + +static int cs42l42_i2c_remove(struct i2c_client *i2c_client) +{ + struct cs42l42_private *cs42l42 = dev_get_drvdata(&i2c_client->dev); + + cs42l42_common_remove(cs42l42); + + return 0; +} + +static int __maybe_unused cs42l42_i2c_resume(struct device *dev) +{ + int ret; + + ret = cs42l42_resume(dev); + if (ret) + return ret; + + cs42l42_resume_restore(dev); + + return 0; +} + +static const struct dev_pm_ops cs42l42_i2c_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(cs42l42_suspend, cs42l42_i2c_resume) +}; + +static const struct of_device_id __maybe_unused cs42l42_of_match[] = { + { .compatible = "cirrus,cs42l42", }, + {} +}; +MODULE_DEVICE_TABLE(of, cs42l42_of_match); + +static const struct acpi_device_id __maybe_unused cs42l42_acpi_match[] = { + {"10134242", 0,}, + {} +}; +MODULE_DEVICE_TABLE(acpi, cs42l42_acpi_match); + +static const struct i2c_device_id cs42l42_id[] = { + {"cs42l42", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, cs42l42_id); + +static struct i2c_driver cs42l42_i2c_driver = { + .driver = { + .name = "cs42l42", + .pm = &cs42l42_i2c_pm_ops, + .of_match_table = of_match_ptr(cs42l42_of_match), + .acpi_match_table = ACPI_PTR(cs42l42_acpi_match), + }, + .id_table = cs42l42_id, + .probe_new = cs42l42_i2c_probe, + .remove = cs42l42_i2c_remove, +}; + +module_i2c_driver(cs42l42_i2c_driver); + +MODULE_DESCRIPTION("ASoC CS42L42 I2C driver"); +MODULE_AUTHOR("Richard Fitzgerald "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(SND_SOC_CS42L42_CORE); diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 20d84db1a98f..59321be1aaa9 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -375,7 +374,7 @@ static const struct regmap_range_cfg cs42l42_page_range = { .window_len = 256, }; -static const struct regmap_config cs42l42_regmap = { +const struct regmap_config cs42l42_regmap = { .reg_bits = 8, .val_bits = 8, @@ -393,6 +392,7 @@ static const struct regmap_config cs42l42_regmap = { .use_single_read = true, .use_single_write = true, }; +EXPORT_SYMBOL_NS_GPL(cs42l42_regmap, SND_SOC_CS42L42_CORE); static DECLARE_TLV_DB_SCALE(adc_tlv, -9700, 100, true); static DECLARE_TLV_DB_SCALE(mixer_tlv, -6300, 100, true); @@ -579,7 +579,7 @@ static int cs42l42_set_jack(struct snd_soc_component *component, struct snd_soc_ return 0; } -static const struct snd_soc_component_driver cs42l42_soc_component = { +const struct snd_soc_component_driver cs42l42_soc_component = { .set_jack = cs42l42_set_jack, .dapm_widgets = cs42l42_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(cs42l42_dapm_widgets), @@ -590,6 +590,7 @@ static const struct snd_soc_component_driver cs42l42_soc_component = { .idle_bias_on = 1, .endianness = 1, }; +EXPORT_SYMBOL_NS_GPL(cs42l42_soc_component, SND_SOC_CS42L42_CORE); /* Switch to SCLK. Atomic delay after the write to allow the switch to complete. */ static const struct reg_sequence cs42l42_to_sclk_seq[] = { @@ -1086,7 +1087,7 @@ static const struct snd_soc_dai_ops cs42l42_ops = { .mute_stream = cs42l42_mute_stream, }; -static struct snd_soc_dai_driver cs42l42_dai = { +struct snd_soc_dai_driver cs42l42_dai = { .name = "cs42l42", .playback = { .stream_name = "Playback", @@ -1106,6 +1107,7 @@ static struct snd_soc_dai_driver cs42l42_dai = { .symmetric_sample_bits = 1, .ops = &cs42l42_ops, }; +EXPORT_SYMBOL_NS_GPL(cs42l42_dai, SND_SOC_CS42L42_CORE); static void cs42l42_manual_hs_type_detect(struct cs42l42_private *cs42l42) { @@ -2101,7 +2103,7 @@ static const struct reg_sequence __maybe_unused cs42l42_shutdown_seq[] = { REG_SEQ0(CS42L42_PWR_CTL1, 0xFF) }; -static int __maybe_unused cs42l42_suspend(struct device *dev) +int cs42l42_suspend(struct device *dev) { struct cs42l42_private *cs42l42 = dev_get_drvdata(dev); unsigned int reg; @@ -2161,8 +2163,9 @@ static int __maybe_unused cs42l42_suspend(struct device *dev) return 0; } +EXPORT_SYMBOL_NS_GPL(cs42l42_suspend, SND_SOC_CS42L42_CORE); -static int __maybe_unused cs42l42_resume(struct device *dev) +int cs42l42_resume(struct device *dev) { struct cs42l42_private *cs42l42 = dev_get_drvdata(dev); int ret; @@ -2188,8 +2191,9 @@ static int __maybe_unused cs42l42_resume(struct device *dev) return 0; } +EXPORT_SYMBOL_NS_GPL(cs42l42_resume, SND_SOC_CS42L42_CORE); -static void __maybe_unused cs42l42_resume_restore(struct device *dev) +void cs42l42_resume_restore(struct device *dev) { struct cs42l42_private *cs42l42 = dev_get_drvdata(dev); @@ -2206,6 +2210,7 @@ static void __maybe_unused cs42l42_resume_restore(struct device *dev) dev_dbg(dev, "System resumed\n"); } +EXPORT_SYMBOL_NS_GPL(cs42l42_resume_restore, SND_SOC_CS42L42_CORE); static int __maybe_unused cs42l42_i2c_resume(struct device *dev) { @@ -2220,9 +2225,9 @@ static int __maybe_unused cs42l42_i2c_resume(struct device *dev) return 0; } -static int cs42l42_common_probe(struct cs42l42_private *cs42l42, - const struct snd_soc_component_driver *component_drv, - struct snd_soc_dai_driver *dai) +int cs42l42_common_probe(struct cs42l42_private *cs42l42, + const struct snd_soc_component_driver *component_drv, + struct snd_soc_dai_driver *dai) { int ret, i; @@ -2295,8 +2300,9 @@ err_disable_noreset: return ret; } +EXPORT_SYMBOL_NS_GPL(cs42l42_common_probe, SND_SOC_CS42L42_CORE); -static int cs42l42_init(struct cs42l42_private *cs42l42) +int cs42l42_init(struct cs42l42_private *cs42l42) { unsigned int reg; int devid, ret; @@ -2375,8 +2381,9 @@ err_disable: cs42l42->supplies); return ret; } +EXPORT_SYMBOL_NS_GPL(cs42l42_init, SND_SOC_CS42L42_CORE); -static void cs42l42_common_remove(struct cs42l42_private *cs42l42) +void cs42l42_common_remove(struct cs42l42_private *cs42l42) { if (cs42l42->irq) free_irq(cs42l42->irq, cs42l42); @@ -2394,85 +2401,7 @@ static void cs42l42_common_remove(struct cs42l42_private *cs42l42) gpiod_set_value_cansleep(cs42l42->reset_gpio, 0); regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), cs42l42->supplies); } - -static int cs42l42_i2c_probe(struct i2c_client *i2c_client) -{ - struct device *dev = &i2c_client->dev; - struct cs42l42_private *cs42l42; - struct regmap *regmap; - int ret; - - cs42l42 = devm_kzalloc(dev, sizeof(struct cs42l42_private), GFP_KERNEL); - if (!cs42l42) - return -ENOMEM; - - regmap = devm_regmap_init_i2c(i2c_client, &cs42l42_regmap); - if (IS_ERR(regmap)) { - ret = PTR_ERR(regmap); - dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); - return ret; - } - - cs42l42->dev = dev; - cs42l42->regmap = regmap; - cs42l42->irq = i2c_client->irq; - - ret = cs42l42_common_probe(cs42l42, &cs42l42_soc_component, &cs42l42_dai); - if (ret) - return ret; - - return cs42l42_init(cs42l42); -} - -static int cs42l42_i2c_remove(struct i2c_client *i2c_client) -{ - struct cs42l42_private *cs42l42 = dev_get_drvdata(&i2c_client->dev); - - cs42l42_common_remove(cs42l42); - - return 0; -} - -static const struct dev_pm_ops cs42l42_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(cs42l42_suspend, cs42l42_i2c_resume) -}; - -#ifdef CONFIG_OF -static const struct of_device_id cs42l42_of_match[] = { - { .compatible = "cirrus,cs42l42", }, - {} -}; -MODULE_DEVICE_TABLE(of, cs42l42_of_match); -#endif - -#ifdef CONFIG_ACPI -static const struct acpi_device_id cs42l42_acpi_match[] = { - {"10134242", 0,}, - {} -}; -MODULE_DEVICE_TABLE(acpi, cs42l42_acpi_match); -#endif - -static const struct i2c_device_id cs42l42_id[] = { - {"cs42l42", 0}, - {} -}; - -MODULE_DEVICE_TABLE(i2c, cs42l42_id); - -static struct i2c_driver cs42l42_i2c_driver = { - .driver = { - .name = "cs42l42", - .pm = &cs42l42_pm_ops, - .of_match_table = of_match_ptr(cs42l42_of_match), - .acpi_match_table = ACPI_PTR(cs42l42_acpi_match), - }, - .id_table = cs42l42_id, - .probe_new = cs42l42_i2c_probe, - .remove = cs42l42_i2c_remove, -}; - -module_i2c_driver(cs42l42_i2c_driver); +EXPORT_SYMBOL_NS_GPL(cs42l42_common_remove, SND_SOC_CS42L42_CORE); MODULE_DESCRIPTION("ASoC CS42L42 driver"); MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, "); diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index a8e0d5b414a5..2a9f178f6190 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -20,6 +20,8 @@ #include #include #include +#include +#include struct cs42l42_private { struct regmap *regmap; @@ -50,4 +52,17 @@ struct cs42l42_private { bool init_done; }; +extern const struct regmap_config cs42l42_regmap; +extern const struct snd_soc_component_driver cs42l42_soc_component; +extern struct snd_soc_dai_driver cs42l42_dai; + +int cs42l42_suspend(struct device *dev); +int cs42l42_resume(struct device *dev); +void cs42l42_resume_restore(struct device *dev); +int cs42l42_common_probe(struct cs42l42_private *cs42l42, + const struct snd_soc_component_driver *component_drv, + struct snd_soc_dai_driver *dai); +int cs42l42_init(struct cs42l42_private *cs42l42); +void cs42l42_common_remove(struct cs42l42_private *cs42l42); + #endif /* __CS42L42_H__ */ -- cgit v1.2.3 From 30b679e2cb058c3dcf6d3ebdf10999f0a7a1644d Mon Sep 17 00:00:00 2001 From: Martin Povišer Date: Thu, 15 Sep 2022 11:44:41 +0200 Subject: ASoC: cs42l42: Export regmap elements to core namespace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Export the regmap callbacks for indicating readable/volatile registers, also the range structure, to the CS42L42 core namespace. This is in advance of reusing these bits in a CS42L83 driver frontend. Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220915094444.11434-9-povik+lin@cutebit.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 9 ++++++--- sound/soc/codecs/cs42l42.h | 4 ++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 59321be1aaa9..5d80994de167 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -171,7 +171,7 @@ static const struct reg_default cs42l42_reg_defaults[] = { { CS42L42_ASP_RX_DAI1_CH2_BIT_LSB, 0x00 }, }; -static bool cs42l42_readable_register(struct device *dev, unsigned int reg) +bool cs42l42_readable_register(struct device *dev, unsigned int reg) { switch (reg) { case CS42L42_PAGE_REGISTER: @@ -330,8 +330,9 @@ static bool cs42l42_readable_register(struct device *dev, unsigned int reg) return false; } } +EXPORT_SYMBOL_NS_GPL(cs42l42_readable_register, SND_SOC_CS42L42_CORE); -static bool cs42l42_volatile_register(struct device *dev, unsigned int reg) +bool cs42l42_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { case CS42L42_DEVID_AB: @@ -362,8 +363,9 @@ static bool cs42l42_volatile_register(struct device *dev, unsigned int reg) return false; } } +EXPORT_SYMBOL_NS_GPL(cs42l42_volatile_register, SND_SOC_CS42L42_CORE); -static const struct regmap_range_cfg cs42l42_page_range = { +const struct regmap_range_cfg cs42l42_page_range = { .name = "Pages", .range_min = 0, .range_max = CS42L42_MAX_REGISTER, @@ -373,6 +375,7 @@ static const struct regmap_range_cfg cs42l42_page_range = { .window_start = 0, .window_len = 256, }; +EXPORT_SYMBOL_NS_GPL(cs42l42_page_range, SND_SOC_CS42L42_CORE); const struct regmap_config cs42l42_regmap = { .reg_bits = 8, diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index 2a9f178f6190..be6f979c82ec 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -52,10 +52,14 @@ struct cs42l42_private { bool init_done; }; +extern const struct regmap_range_cfg cs42l42_page_range; extern const struct regmap_config cs42l42_regmap; extern const struct snd_soc_component_driver cs42l42_soc_component; extern struct snd_soc_dai_driver cs42l42_dai; +bool cs42l42_readable_register(struct device *dev, unsigned int reg); +bool cs42l42_volatile_register(struct device *dev, unsigned int reg); + int cs42l42_suspend(struct device *dev); int cs42l42_resume(struct device *dev); void cs42l42_resume_restore(struct device *dev); -- cgit v1.2.3 From 94d5f62a91aab6ac9c3f4abfd048cbe5f77153ac Mon Sep 17 00:00:00 2001 From: Martin Povišer Date: Thu, 15 Sep 2022 11:44:42 +0200 Subject: ASoC: cs42l83: Extend CS42L42 support to new part MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CS42L83 part is a headphone jack codec found in recent Apple machines. It is a publicly undocumented part but as far as can be told it is identical to CS42L42 except for two points: * The chip ID is different. * Of those registers for which we have a default value in the existing CS42L42 kernel driver, one register (MCLK_CTL) differs in its reset value on CS42L83. To address those two points (and only those), add to the CS42L42 driver a separate CS42L83 front. Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220915094444.11434-10-povik+lin@cutebit.org Signed-off-by: Mark Brown --- MAINTAINERS | 1 + include/sound/cs42l42.h | 1 + sound/soc/codecs/Kconfig | 7 ++ sound/soc/codecs/Makefile | 2 + sound/soc/codecs/cs42l42-i2c.c | 1 + sound/soc/codecs/cs42l42.c | 9 +- sound/soc/codecs/cs42l42.h | 1 + sound/soc/codecs/cs42l83-i2c.c | 242 +++++++++++++++++++++++++++++++++++++++++ 8 files changed, 260 insertions(+), 4 deletions(-) create mode 100644 sound/soc/codecs/cs42l83-i2c.c diff --git a/MAINTAINERS b/MAINTAINERS index 5e3f515f0c1f..18a33e61cbd8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1906,6 +1906,7 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/sound/apple,* F: sound/soc/apple/* +F: sound/soc/codecs/cs42l83-i2c.c ARM/ARTPEC MACHINE SUPPORT M: Jesper Nilsson diff --git a/include/sound/cs42l42.h b/include/sound/cs42l42.h index a55d522f1772..1d1c24fdd0ca 100644 --- a/include/sound/cs42l42.h +++ b/include/sound/cs42l42.h @@ -40,6 +40,7 @@ #define CS42L42_PAGE_30 0x3000 #define CS42L42_CHIP_ID 0x42A42 +#define CS42L83_CHIP_ID 0x42A83 /* Page 0x10 Global Registers */ #define CS42L42_DEVID_AB (CS42L42_PAGE_10 + 0x01) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 01725d0a9500..444cee829a26 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -722,6 +722,13 @@ config SND_SOC_CS42L73 tristate "Cirrus Logic CS42L73 CODEC" depends on I2C +config SND_SOC_CS42L83 + tristate "Cirrus Logic CS42L83 CODEC" + depends on I2C + select REGMAP + select REGMAP_I2C + select SND_SOC_CS42L42_CORE + config SND_SOC_CS4234 tristate "Cirrus Logic CS4234 CODEC" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 5b7020a0b234..9170ee1447dd 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -71,6 +71,7 @@ snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o snd-soc-cs42l52-objs := cs42l52.o snd-soc-cs42l56-objs := cs42l56.o snd-soc-cs42l73-objs := cs42l73.o +snd-soc-cs42l83-i2c-objs := cs42l83-i2c.o snd-soc-cs4234-objs := cs4234.o snd-soc-cs4265-objs := cs4265.o snd-soc-cs4270-objs := cs4270.o @@ -430,6 +431,7 @@ obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o obj-$(CONFIG_SND_SOC_CS42L56) += snd-soc-cs42l56.o obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o +obj-$(CONFIG_SND_SOC_CS42L83) += snd-soc-cs42l83-i2c.o obj-$(CONFIG_SND_SOC_CS4234) += snd-soc-cs4234.o obj-$(CONFIG_SND_SOC_CS4265) += snd-soc-cs4265.o obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o diff --git a/sound/soc/codecs/cs42l42-i2c.c b/sound/soc/codecs/cs42l42-i2c.c index 5f01b6adc17e..35fecff0f74f 100644 --- a/sound/soc/codecs/cs42l42-i2c.c +++ b/sound/soc/codecs/cs42l42-i2c.c @@ -31,6 +31,7 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client) return ret; } + cs42l42->devid = CS42L42_CHIP_ID; cs42l42->dev = dev; cs42l42->regmap = regmap; cs42l42->irq = i2c_client->irq; diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 5d80994de167..0baf98a4236d 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -2318,11 +2318,11 @@ int cs42l42_init(struct cs42l42_private *cs42l42) goto err_disable; } - if (devid != CS42L42_CHIP_ID) { + if (devid != cs42l42->devid) { ret = -ENODEV; dev_err(cs42l42->dev, - "CS42L42 Device ID (%X). Expected %X\n", - devid, CS42L42_CHIP_ID); + "CS42L%x Device ID (%X). Expected %X\n", + cs42l42->devid & 0xff, devid, cs42l42->devid); goto err_disable; } @@ -2333,7 +2333,8 @@ int cs42l42_init(struct cs42l42_private *cs42l42) } dev_info(cs42l42->dev, - "Cirrus Logic CS42L42, Revision: %02X\n", reg & 0xFF); + "Cirrus Logic CS42L%x, Revision: %02X\n", + cs42l42->devid & 0xff, reg & 0xFF); /* Power up the codec */ regmap_update_bits(cs42l42->regmap, CS42L42_PWR_CTL1, diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index be6f979c82ec..bc51bb09da5c 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -31,6 +31,7 @@ struct cs42l42_private { struct completion pdn_done; struct snd_soc_jack *jack; struct mutex irq_lock; + int devid; int irq; int pll_config; u32 sclk; diff --git a/sound/soc/codecs/cs42l83-i2c.c b/sound/soc/codecs/cs42l83-i2c.c new file mode 100644 index 000000000000..ba8772aa51e1 --- /dev/null +++ b/sound/soc/codecs/cs42l83-i2c.c @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * cs42l83-i2c.c -- CS42L83 ALSA SoC audio driver for I2C + * + * Based on cs42l42-i2c.c: + * Copyright 2016, 2022 Cirrus Logic, Inc. + */ + +#include +#include +#include +#include +#include + +#include "cs42l42.h" + +static const struct reg_default cs42l83_reg_defaults[] = { + { CS42L42_FRZ_CTL, 0x00 }, + { CS42L42_SRC_CTL, 0x10 }, + { CS42L42_MCLK_CTL, 0x00 }, /* <- only deviation from CS42L42 */ + { CS42L42_SFTRAMP_RATE, 0xA4 }, + { CS42L42_SLOW_START_ENABLE, 0x70 }, + { CS42L42_I2C_DEBOUNCE, 0x88 }, + { CS42L42_I2C_STRETCH, 0x03 }, + { CS42L42_I2C_TIMEOUT, 0xB7 }, + { CS42L42_PWR_CTL1, 0xFF }, + { CS42L42_PWR_CTL2, 0x84 }, + { CS42L42_PWR_CTL3, 0x20 }, + { CS42L42_RSENSE_CTL1, 0x40 }, + { CS42L42_RSENSE_CTL2, 0x00 }, + { CS42L42_OSC_SWITCH, 0x00 }, + { CS42L42_RSENSE_CTL3, 0x1B }, + { CS42L42_TSENSE_CTL, 0x1B }, + { CS42L42_TSRS_INT_DISABLE, 0x00 }, + { CS42L42_HSDET_CTL1, 0x77 }, + { CS42L42_HSDET_CTL2, 0x00 }, + { CS42L42_HS_SWITCH_CTL, 0xF3 }, + { CS42L42_HS_CLAMP_DISABLE, 0x00 }, + { CS42L42_MCLK_SRC_SEL, 0x00 }, + { CS42L42_SPDIF_CLK_CFG, 0x00 }, + { CS42L42_FSYNC_PW_LOWER, 0x00 }, + { CS42L42_FSYNC_PW_UPPER, 0x00 }, + { CS42L42_FSYNC_P_LOWER, 0xF9 }, + { CS42L42_FSYNC_P_UPPER, 0x00 }, + { CS42L42_ASP_CLK_CFG, 0x00 }, + { CS42L42_ASP_FRM_CFG, 0x10 }, + { CS42L42_FS_RATE_EN, 0x00 }, + { CS42L42_IN_ASRC_CLK, 0x00 }, + { CS42L42_OUT_ASRC_CLK, 0x00 }, + { CS42L42_PLL_DIV_CFG1, 0x00 }, + { CS42L42_ADC_OVFL_INT_MASK, 0x01 }, + { CS42L42_MIXER_INT_MASK, 0x0F }, + { CS42L42_SRC_INT_MASK, 0x0F }, + { CS42L42_ASP_RX_INT_MASK, 0x1F }, + { CS42L42_ASP_TX_INT_MASK, 0x0F }, + { CS42L42_CODEC_INT_MASK, 0x03 }, + { CS42L42_SRCPL_INT_MASK, 0x7F }, + { CS42L42_VPMON_INT_MASK, 0x01 }, + { CS42L42_PLL_LOCK_INT_MASK, 0x01 }, + { CS42L42_TSRS_PLUG_INT_MASK, 0x0F }, + { CS42L42_PLL_CTL1, 0x00 }, + { CS42L42_PLL_DIV_FRAC0, 0x00 }, + { CS42L42_PLL_DIV_FRAC1, 0x00 }, + { CS42L42_PLL_DIV_FRAC2, 0x00 }, + { CS42L42_PLL_DIV_INT, 0x40 }, + { CS42L42_PLL_CTL3, 0x10 }, + { CS42L42_PLL_CAL_RATIO, 0x80 }, + { CS42L42_PLL_CTL4, 0x03 }, + { CS42L42_LOAD_DET_EN, 0x00 }, + { CS42L42_HSBIAS_SC_AUTOCTL, 0x03 }, + { CS42L42_WAKE_CTL, 0xC0 }, + { CS42L42_ADC_DISABLE_MUTE, 0x00 }, + { CS42L42_TIPSENSE_CTL, 0x02 }, + { CS42L42_MISC_DET_CTL, 0x03 }, + { CS42L42_MIC_DET_CTL1, 0x1F }, + { CS42L42_MIC_DET_CTL2, 0x2F }, + { CS42L42_DET_INT1_MASK, 0xE0 }, + { CS42L42_DET_INT2_MASK, 0xFF }, + { CS42L42_HS_BIAS_CTL, 0xC2 }, + { CS42L42_ADC_CTL, 0x00 }, + { CS42L42_ADC_VOLUME, 0x00 }, + { CS42L42_ADC_WNF_HPF_CTL, 0x71 }, + { CS42L42_DAC_CTL1, 0x00 }, + { CS42L42_DAC_CTL2, 0x02 }, + { CS42L42_HP_CTL, 0x0D }, + { CS42L42_CLASSH_CTL, 0x07 }, + { CS42L42_MIXER_CHA_VOL, 0x3F }, + { CS42L42_MIXER_ADC_VOL, 0x3F }, + { CS42L42_MIXER_CHB_VOL, 0x3F }, + { CS42L42_EQ_COEF_IN0, 0x00 }, + { CS42L42_EQ_COEF_IN1, 0x00 }, + { CS42L42_EQ_COEF_IN2, 0x00 }, + { CS42L42_EQ_COEF_IN3, 0x00 }, + { CS42L42_EQ_COEF_RW, 0x00 }, + { CS42L42_EQ_COEF_OUT0, 0x00 }, + { CS42L42_EQ_COEF_OUT1, 0x00 }, + { CS42L42_EQ_COEF_OUT2, 0x00 }, + { CS42L42_EQ_COEF_OUT3, 0x00 }, + { CS42L42_EQ_INIT_STAT, 0x00 }, + { CS42L42_EQ_START_FILT, 0x00 }, + { CS42L42_EQ_MUTE_CTL, 0x00 }, + { CS42L42_SP_RX_CH_SEL, 0x04 }, + { CS42L42_SP_RX_ISOC_CTL, 0x04 }, + { CS42L42_SP_RX_FS, 0x8C }, + { CS42l42_SPDIF_CH_SEL, 0x0E }, + { CS42L42_SP_TX_ISOC_CTL, 0x04 }, + { CS42L42_SP_TX_FS, 0xCC }, + { CS42L42_SPDIF_SW_CTL1, 0x3F }, + { CS42L42_SRC_SDIN_FS, 0x40 }, + { CS42L42_SRC_SDOUT_FS, 0x40 }, + { CS42L42_SPDIF_CTL1, 0x01 }, + { CS42L42_SPDIF_CTL2, 0x00 }, + { CS42L42_SPDIF_CTL3, 0x00 }, + { CS42L42_SPDIF_CTL4, 0x42 }, + { CS42L42_ASP_TX_SZ_EN, 0x00 }, + { CS42L42_ASP_TX_CH_EN, 0x00 }, + { CS42L42_ASP_TX_CH_AP_RES, 0x0F }, + { CS42L42_ASP_TX_CH1_BIT_MSB, 0x00 }, + { CS42L42_ASP_TX_CH1_BIT_LSB, 0x00 }, + { CS42L42_ASP_TX_HIZ_DLY_CFG, 0x00 }, + { CS42L42_ASP_TX_CH2_BIT_MSB, 0x00 }, + { CS42L42_ASP_TX_CH2_BIT_LSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_EN, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH1_AP_RES, 0x03 }, + { CS42L42_ASP_RX_DAI0_CH1_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH1_BIT_LSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH2_AP_RES, 0x03 }, + { CS42L42_ASP_RX_DAI0_CH2_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH2_BIT_LSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH3_AP_RES, 0x03 }, + { CS42L42_ASP_RX_DAI0_CH3_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH3_BIT_LSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH4_AP_RES, 0x03 }, + { CS42L42_ASP_RX_DAI0_CH4_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH4_BIT_LSB, 0x00 }, + { CS42L42_ASP_RX_DAI1_CH1_AP_RES, 0x03 }, + { CS42L42_ASP_RX_DAI1_CH1_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI1_CH1_BIT_LSB, 0x00 }, + { CS42L42_ASP_RX_DAI1_CH2_AP_RES, 0x03 }, + { CS42L42_ASP_RX_DAI1_CH2_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI1_CH2_BIT_LSB, 0x00 }, +}; + +/* + * This is all the same as for CS42L42 but we + * replace the on-reset register defaults. + */ +const struct regmap_config cs42l83_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .readable_reg = cs42l42_readable_register, + .volatile_reg = cs42l42_volatile_register, + + .ranges = &cs42l42_page_range, + .num_ranges = 1, + + .max_register = CS42L42_MAX_REGISTER, + .reg_defaults = cs42l83_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(cs42l83_reg_defaults), + .cache_type = REGCACHE_RBTREE, + + .use_single_read = true, + .use_single_write = true, +}; + +static int cs42l83_i2c_probe(struct i2c_client *i2c_client) +{ + struct device *dev = &i2c_client->dev; + struct cs42l42_private *cs42l83; + struct regmap *regmap; + int ret; + + cs42l83 = devm_kzalloc(dev, sizeof(*cs42l83), GFP_KERNEL); + if (!cs42l83) + return -ENOMEM; + + regmap = devm_regmap_init_i2c(i2c_client, &cs42l83_regmap); + if (IS_ERR(regmap)) + return dev_err_probe(&i2c_client->dev, PTR_ERR(regmap), + "regmap_init() failed\n"); + + cs42l83->devid = CS42L83_CHIP_ID; + cs42l83->dev = dev; + cs42l83->regmap = regmap; + cs42l83->irq = i2c_client->irq; + + ret = cs42l42_common_probe(cs42l83, &cs42l42_soc_component, &cs42l42_dai); + if (ret) + return ret; + + return cs42l42_init(cs42l83); +} + +static int cs42l83_i2c_remove(struct i2c_client *i2c_client) +{ + struct cs42l42_private *cs42l83 = dev_get_drvdata(&i2c_client->dev); + + cs42l42_common_remove(cs42l83); + + return 0; +} + +static int __maybe_unused cs42l83_i2c_resume(struct device *dev) +{ + int ret; + + ret = cs42l42_resume(dev); + if (ret) + return ret; + + cs42l42_resume_restore(dev); + + return 0; +} + +static const struct dev_pm_ops cs42l83_i2c_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(cs42l42_suspend, cs42l83_i2c_resume) +}; + +static const struct of_device_id __maybe_unused cs42l83_of_match[] = { + { .compatible = "cirrus,cs42l83", }, + {} +}; +MODULE_DEVICE_TABLE(of, cs42l83_of_match); + +static struct i2c_driver cs42l83_i2c_driver = { + .driver = { + .name = "cs42l83", + .pm = &cs42l83_i2c_pm_ops, + .of_match_table = of_match_ptr(cs42l83_of_match), + }, + .probe_new = cs42l83_i2c_probe, + .remove = cs42l83_i2c_remove, +}; + +module_i2c_driver(cs42l83_i2c_driver); + +MODULE_DESCRIPTION("ASoC CS42L83 I2C driver"); +MODULE_AUTHOR("Martin Povišer "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(SND_SOC_CS42L42_CORE); -- cgit v1.2.3 From ab2940a72dfa823af09abf593512459afe3da460 Mon Sep 17 00:00:00 2001 From: Martin Povišer Date: Thu, 15 Sep 2022 11:44:43 +0200 Subject: ASoC: cs42l42: Implement 'set_bclk_ratio' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver wants to know the bit rate on the serial bus and takes that to be the value set by 'set_sysclk'. The 'set_bclk_ratio' op is a better fit for figuring out the clocking parameters of the serial bus, so implement that and give it precedence over the prior methods. Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220915094444.11434-11-povik+lin@cutebit.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 17 ++++++++++++++++- sound/soc/codecs/cs42l42.h | 1 + 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 0baf98a4236d..bdc7e6bed6ac 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -898,7 +898,10 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream, cs42l42->srate = params_rate(params); - if (cs42l42->sclk) { + if (cs42l42->bclk_ratio) { + /* machine driver has set the BCLK/samp-rate ratio */ + bclk = cs42l42->bclk_ratio * params_rate(params); + } else if (cs42l42->sclk) { /* machine driver has set the SCLK */ bclk = cs42l42->sclk; } else { @@ -984,6 +987,17 @@ static int cs42l42_set_sysclk(struct snd_soc_dai *dai, return -EINVAL; } +static int cs42l42_set_bclk_ratio(struct snd_soc_dai *dai, + unsigned int bclk_ratio) +{ + struct snd_soc_component *component = dai->component; + struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component); + + cs42l42->bclk_ratio = bclk_ratio; + + return 0; +} + static int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream) { struct snd_soc_component *component = dai->component; @@ -1087,6 +1101,7 @@ static const struct snd_soc_dai_ops cs42l42_ops = { .hw_params = cs42l42_pcm_hw_params, .set_fmt = cs42l42_set_dai_fmt, .set_sysclk = cs42l42_set_sysclk, + .set_bclk_ratio = cs42l42_set_bclk_ratio, .mute_stream = cs42l42_mute_stream, }; diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index bc51bb09da5c..a72136664112 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -35,6 +35,7 @@ struct cs42l42_private { int irq; int pll_config; u32 sclk; + u32 bclk_ratio; u32 srate; u8 plug_state; u8 hs_type; -- cgit v1.2.3 From ac088c31d496b885d8268bd1c9746c3c76bf7078 Mon Sep 17 00:00:00 2001 From: Martin Povišer Date: Thu, 15 Sep 2022 11:44:44 +0200 Subject: ASoC: cs42l42: Switch to dev_err_probe() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace dev_err() with dev_err_probe() in the probe path for consistency with cs42l83-i2c.c. Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220915094444.11434-12-povik+lin@cutebit.org Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42-i2c.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/cs42l42-i2c.c b/sound/soc/codecs/cs42l42-i2c.c index 35fecff0f74f..1900ec75576e 100644 --- a/sound/soc/codecs/cs42l42-i2c.c +++ b/sound/soc/codecs/cs42l42-i2c.c @@ -25,11 +25,9 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client) return -ENOMEM; regmap = devm_regmap_init_i2c(i2c_client, &cs42l42_regmap); - if (IS_ERR(regmap)) { - ret = PTR_ERR(regmap); - dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); - return ret; - } + if (IS_ERR(regmap)) + return dev_err_probe(&i2c_client->dev, PTR_ERR(regmap), + "regmap_init() failed\n"); cs42l42->devid = CS42L42_CHIP_ID; cs42l42->dev = dev; -- cgit v1.2.3 From 9ccbc2e12e01b39b804774c3207d2474dd992d95 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 19 Sep 2022 13:53:47 +0200 Subject: ASoC: SOF: Intel: hda: refine SSP count support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SSP count is incorrect for TGL and MTL devices, the SSP count is limited to 3 (I2SPC parameter in the Integration HAS). Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Link: https://lore.kernel.org/r/20220919115350.43104-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.h | 2 ++ sound/soc/sof/intel/mtl.c | 2 +- sound/soc/sof/intel/tgl.c | 8 ++++---- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index ba6feb1b0d3b..bb9d2af06530 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -435,6 +435,8 @@ #define APL_SSP_COUNT 6 #define CNL_SSP_COUNT 3 #define ICL_SSP_COUNT 6 +#define TGL_SSP_COUNT 3 +#define MTL_SSP_COUNT 3 /* SSP Registers */ #define SSP_SSC1_OFFSET 0x4 diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index 1cc1398336e1..efc91feb83e9 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -784,7 +784,7 @@ const struct sof_intel_dsp_desc mtl_chip_info = { .ipc_ctl = MTL_DSP_REG_HFIPCXCTL, .rom_status_reg = MTL_DSP_ROM_STS, .rom_init_timeout = 300, - .ssp_count = ICL_SSP_COUNT, + .ssp_count = MTL_SSP_COUNT, .ssp_base_offset = CNL_SSP_BASE_OFFSET, .sdw_shim_base = SDW_SHIM_BASE_ACE, .sdw_alh_base = SDW_ALH_BASE_ACE, diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c index 017bf331ed5a..5135e1c7e6cf 100644 --- a/sound/soc/sof/intel/tgl.c +++ b/sound/soc/sof/intel/tgl.c @@ -123,7 +123,7 @@ const struct sof_intel_dsp_desc tgl_chip_info = { .ipc_ctl = CNL_DSP_REG_HIPCCTL, .rom_status_reg = HDA_DSP_SRAM_REG_ROM_STATUS, .rom_init_timeout = 300, - .ssp_count = ICL_SSP_COUNT, + .ssp_count = TGL_SSP_COUNT, .ssp_base_offset = CNL_SSP_BASE_OFFSET, .sdw_shim_base = SDW_SHIM_BASE, .sdw_alh_base = SDW_ALH_BASE, @@ -146,7 +146,7 @@ const struct sof_intel_dsp_desc tglh_chip_info = { .ipc_ctl = CNL_DSP_REG_HIPCCTL, .rom_status_reg = HDA_DSP_SRAM_REG_ROM_STATUS, .rom_init_timeout = 300, - .ssp_count = ICL_SSP_COUNT, + .ssp_count = TGL_SSP_COUNT, .ssp_base_offset = CNL_SSP_BASE_OFFSET, .sdw_shim_base = SDW_SHIM_BASE, .sdw_alh_base = SDW_ALH_BASE, @@ -169,7 +169,7 @@ const struct sof_intel_dsp_desc ehl_chip_info = { .ipc_ctl = CNL_DSP_REG_HIPCCTL, .rom_status_reg = HDA_DSP_SRAM_REG_ROM_STATUS, .rom_init_timeout = 300, - .ssp_count = ICL_SSP_COUNT, + .ssp_count = TGL_SSP_COUNT, .ssp_base_offset = CNL_SSP_BASE_OFFSET, .sdw_shim_base = SDW_SHIM_BASE, .sdw_alh_base = SDW_ALH_BASE, @@ -192,7 +192,7 @@ const struct sof_intel_dsp_desc adls_chip_info = { .ipc_ctl = CNL_DSP_REG_HIPCCTL, .rom_status_reg = HDA_DSP_SRAM_REG_ROM_STATUS, .rom_init_timeout = 300, - .ssp_count = ICL_SSP_COUNT, + .ssp_count = TGL_SSP_COUNT, .ssp_base_offset = CNL_SSP_BASE_OFFSET, .sdw_shim_base = SDW_SHIM_BASE, .sdw_alh_base = SDW_ALH_BASE, -- cgit v1.2.3 From d136949dd8e2e309dc2f186507486b71cbe9acdb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 19 Sep 2022 13:53:48 +0200 Subject: ASoC: SOF: add quirk to override topology mclk_id Some Intel-based platforms rely on a topology file that hard-codes the use of MCLK0. This is incorrect in 10% of the cases. Rather than generating yet another set of topology files, this patch adds a kernel module parameter to override the topology value. In hindsight, we should never have allowed mclks to be specified in topology, this is a hardware-level information that should not have been visible in the topology. Future patches will try to set this value automagically, e.g. by parsing the NHLT content. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Kai Vehmanen Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20220919115350.43104-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.c | 11 +++++++++++ sound/soc/sof/ipc3-topology.c | 7 +++++++ sound/soc/sof/sof-priv.h | 4 ++++ 3 files changed, 22 insertions(+) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 6d4ecbe14adf..ada2e6775749 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -376,6 +376,10 @@ static int dmic_num_override = -1; module_param_named(dmic_num, dmic_num_override, int, 0444); MODULE_PARM_DESC(dmic_num, "SOF HDA DMIC number"); +static int mclk_id_override = -1; +module_param_named(mclk_id, mclk_id_override, int, 0444); +MODULE_PARM_DESC(mclk_id, "SOF SSP mclk_id"); + #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) static bool hda_codec_use_common_hdmi = IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI); module_param_named(use_common_hdmi, hda_codec_use_common_hdmi, bool, 0444); @@ -1565,6 +1569,13 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) sof_pdata->tplg_filename = tplg_filename; } + + /* check if mclk_id should be modified from topology defaults */ + if (mclk_id_override >= 0) { + dev_info(sdev->dev, "Overriding topology with MCLK %d from kernel_parameter\n", mclk_id_override); + sdev->mclk_id_override = true; + sdev->mclk_id_quirk = mclk_id_override; + } } /* diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index 65923e7a5976..a39b43850f0e 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -1249,6 +1249,7 @@ static int sof_link_afe_load(struct snd_soc_component *scomp, struct snd_sof_dai static int sof_link_ssp_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink, struct sof_ipc_dai_config *config, struct snd_sof_dai *dai) { + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs; struct sof_dai_private_data *private = dai->private; u32 size = sizeof(*config); @@ -1273,6 +1274,12 @@ static int sof_link_ssp_load(struct snd_soc_component *scomp, struct snd_sof_dai config[i].hdr.size = size; + if (sdev->mclk_id_override) { + dev_dbg(scomp->dev, "tplg: overriding topology mclk_id %d by quirk %d\n", + config[i].ssp.mclk_id, sdev->mclk_id_quirk); + config[i].ssp.mclk_id = sdev->mclk_id_quirk; + } + /* copy differentiating hw configs to ipc structs */ config[i].ssp.mclk_rate = le32_to_cpu(hw_config[i].mclk_rate); config[i].ssp.bclk_rate = le32_to_cpu(hw_config[i].bclk_rate); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 33165299a20f..de08825915b3 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -601,6 +601,10 @@ struct snd_sof_dev { /* to protect the ipc_rx_handler_list and dsp_state_handler_list list */ struct mutex client_event_handler_mutex; + /* quirks to override topology values */ + bool mclk_id_override; + u16 mclk_id_quirk; /* same size as in IPC3 definitions */ + void *private; /* core does not touch this */ }; -- cgit v1.2.3 From 78091edc1c7806846049e1d480f6a8051507ed94 Mon Sep 17 00:00:00 2001 From: Chunxu Li Date: Sat, 17 Sep 2022 10:26:10 +0800 Subject: ASoC: SOF: mediatek: add pcm_hw_params callback for mt8186 add pcm_hw_params callback for mt8186 to support continue update dma host position Signed-off-by: Chunxu Li Link: https://lore.kernel.org/r/20220917022610.594-1-chunxu.li@mediatek.com Signed-off-by: Mark Brown --- sound/soc/sof/mediatek/mt8186/mt8186.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c index a1be5d74f40b..9ec89fc7fec0 100644 --- a/sound/soc/sof/mediatek/mt8186/mt8186.c +++ b/sound/soc/sof/mediatek/mt8186/mt8186.c @@ -460,6 +460,16 @@ static int mt8186_get_bar_index(struct snd_sof_dev *sdev, u32 type) return type; } +static int mt8186_pcm_hw_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_sof_platform_stream_params *platform_params) +{ + platform_params->cont_update_posn = 1; + + return 0; +} + static struct snd_soc_dai_driver mt8186_dai[] = { { .name = "SOF_DL1", @@ -526,6 +536,7 @@ static struct snd_sof_dsp_ops sof_mt8186_ops = { /* stream callbacks */ .pcm_open = sof_stream_pcm_open, + .pcm_hw_params = mt8186_pcm_hw_params, .pcm_close = sof_stream_pcm_close, /* firmware loading */ -- cgit v1.2.3 From fc6f923ecfa2fafd0600f1b7e2de09baf29865e2 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 19 Sep 2022 15:54:44 +0200 Subject: ALSA: hda/hdmi: Fix the converter allocation for the silent stream Track the converters handling the silent stream using a new variable to avoid mixing of the open/close and silent stream use. This change ensures the proper allocation of the converters. Fixes: 5f80d6bd2b01 ("ALSA: hda/hdmi: Fix the converter reuse for the silent stream") Signed-off-by: Jaroslav Kysela Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20220919135444.3554982-1-perex@perex.cz Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 17f08bf4be14..1eb894e6cdf1 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -54,6 +54,7 @@ MODULE_PARM_DESC(enable_all_pins, "Forcibly enable all pins"); struct hdmi_spec_per_cvt { hda_nid_t cvt_nid; bool assigned; /* the stream has been assigned */ + bool silent_stream; /* silent stream activated */ unsigned int channels_min; unsigned int channels_max; u32 rates; @@ -988,7 +989,8 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, * of the pin. */ static int hdmi_choose_cvt(struct hda_codec *codec, - int pin_idx, int *cvt_id) + int pin_idx, int *cvt_id, + bool silent) { struct hdmi_spec *spec = codec->spec; struct hdmi_spec_per_pin *per_pin; @@ -1003,6 +1005,9 @@ static int hdmi_choose_cvt(struct hda_codec *codec, if (per_pin && per_pin->silent_stream) { cvt_idx = cvt_nid_to_cvt_index(codec, per_pin->cvt_nid); + per_cvt = get_cvt(spec, cvt_idx); + if (per_cvt->assigned && !silent) + return -EBUSY; if (cvt_id) *cvt_id = cvt_idx; return 0; @@ -1013,7 +1018,7 @@ static int hdmi_choose_cvt(struct hda_codec *codec, per_cvt = get_cvt(spec, cvt_idx); /* Must not already be assigned */ - if (per_cvt->assigned) + if (per_cvt->assigned || per_cvt->silent_stream) continue; if (per_pin == NULL) break; @@ -1199,7 +1204,7 @@ static int hdmi_pcm_open_no_pin(struct hda_pcm_stream *hinfo, if (pcm_idx < 0) return -EINVAL; - err = hdmi_choose_cvt(codec, -1, &cvt_idx); + err = hdmi_choose_cvt(codec, -1, &cvt_idx, false); if (err) return err; @@ -1267,7 +1272,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, } } - err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx); + err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx, false); if (err < 0) goto unlock; @@ -1278,7 +1283,6 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, set_bit(pcm_idx, &spec->pcm_in_use); per_pin = get_pin(spec, pin_idx); per_pin->cvt_nid = per_cvt->cvt_nid; - per_pin->silent_stream = false; hinfo->nid = per_cvt->cvt_nid; /* flip stripe flag for the assigned stream if supported */ @@ -1760,14 +1764,14 @@ static void silent_stream_enable(struct hda_codec *codec, } pin_idx = pin_id_to_pin_index(codec, per_pin->pin_nid, per_pin->dev_id); - err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx); + err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx, true); if (err) { codec_err(codec, "hdmi: no free converter to enable silent mode\n"); goto unlock_out; } per_cvt = get_cvt(spec, cvt_idx); - per_cvt->assigned = true; + per_cvt->silent_stream = true; per_pin->cvt_nid = per_cvt->cvt_nid; per_pin->silent_stream = true; @@ -1827,7 +1831,7 @@ static void silent_stream_disable(struct hda_codec *codec, cvt_idx = cvt_nid_to_cvt_index(codec, per_pin->cvt_nid); if (cvt_idx >= 0 && cvt_idx < spec->num_cvts) { per_cvt = get_cvt(spec, cvt_idx); - per_cvt->assigned = false; + per_cvt->silent_stream = false; } if (spec->silent_stream_type == SILENT_STREAM_I915) { -- cgit v1.2.3 From 2ea13c83bf7bb3471e33b2d902b101af977ef2d4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 19 Sep 2022 14:10:34 +0200 Subject: ALSA: hda: make snd_hdac_stream_clear() static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This helper has no users outside of hdac_stream.c. External users should only use snd_hdac_stream_start() and snd_hdac_stream_stop(). No functional change beyond making the function static and removing the symbol export. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20220919121041.43463-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- include/sound/hdaudio.h | 1 - sound/hda/hdac_stream.c | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index 6e74aeafeda4..24c731e53ccb 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -561,7 +561,6 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev); int snd_hdac_stream_set_params(struct hdac_stream *azx_dev, unsigned int format_val); void snd_hdac_stream_start(struct hdac_stream *azx_dev, bool fresh_start); -void snd_hdac_stream_clear(struct hdac_stream *azx_dev); void snd_hdac_stream_stop(struct hdac_stream *azx_dev); void snd_hdac_stop_streams_and_chip(struct hdac_bus *bus); void snd_hdac_stream_reset(struct hdac_stream *azx_dev); diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c index bdf6d4db6769..2dbde3d1cf68 100644 --- a/sound/hda/hdac_stream.c +++ b/sound/hda/hdac_stream.c @@ -112,10 +112,10 @@ void snd_hdac_stream_start(struct hdac_stream *azx_dev, bool fresh_start) EXPORT_SYMBOL_GPL(snd_hdac_stream_start); /** - * snd_hdac_stream_clear - stop a stream DMA + * snd_hdac_stream_clear - helper to clear stream registers and stop DMA transfers * @azx_dev: HD-audio core stream to stop */ -void snd_hdac_stream_clear(struct hdac_stream *azx_dev) +static void snd_hdac_stream_clear(struct hdac_stream *azx_dev) { snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_CTL_DMA_START | SD_INT_MASK, 0); @@ -124,7 +124,6 @@ void snd_hdac_stream_clear(struct hdac_stream *azx_dev) snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, 0); azx_dev->running = false; } -EXPORT_SYMBOL_GPL(snd_hdac_stream_clear); /** * snd_hdac_stream_stop - stop a stream -- cgit v1.2.3 From ea2ddd2559dc6d1c4b66ccd49314add35ece9062 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 19 Sep 2022 14:10:35 +0200 Subject: ALSA: hda: document state machine for hdac_streams MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code in this library is far from self-explanatory, hopefully this state diagram reverse-engineered from the code will help others understand the expected transitions. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20220919121041.43463-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- sound/hda/hdac_stream.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c index 2dbde3d1cf68..2e98f5fd50e5 100644 --- a/sound/hda/hdac_stream.c +++ b/sound/hda/hdac_stream.c @@ -13,6 +13,39 @@ #include #include "trace.h" +/* + * the hdac_stream library is intended to be used with the following + * transitions. The states are not formally defined in the code but loosely + * inspired by boolean variables. Note that the 'prepared' field is not used + * in this library but by the callers during the hw_params/prepare transitions + * + * | + * stream_init() | + * v + * +--+-------+ + * | unused | + * +--+----+--+ + * | ^ + * stream_assign() | | stream_release() + * v | + * +--+----+--+ + * | opened | + * +--+----+--+ + * | ^ + * stream_reset() | | + * stream_setup() | | stream_cleanup() + * v | + * +--+----+--+ + * | prepared | + * +--+----+--+ + * | ^ + * stream_start() | | stream_stop() + * v | + * +--+----+--+ + * | running | + * +----------+ + */ + /** * snd_hdac_get_stream_stripe_ctl - get stripe control value * @bus: HD-audio core bus -- cgit v1.2.3 From 791d132a070a8358227b008c0ddda5f4d6f32cc2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 19 Sep 2022 14:10:36 +0200 Subject: ALSA: hda: ext: make snd_hdac_ext_stream_init() static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are no external users of this helper, move to static and remove sympol export. No functionality change. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20220919121041.43463-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- include/sound/hdaudio_ext.h | 3 --- sound/hda/ext/hdac_ext_stream.c | 7 +++---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h index 07231f0b93b5..4a4bd1d88612 100644 --- a/include/sound/hdaudio_ext.h +++ b/include/sound/hdaudio_ext.h @@ -77,9 +77,6 @@ struct hdac_ext_stream { #define stream_to_hdac_ext_stream(s) \ container_of(s, struct hdac_ext_stream, hstream) -void snd_hdac_ext_stream_init(struct hdac_bus *bus, - struct hdac_ext_stream *hext_stream, int idx, - int direction, int tag); int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx, int num_stream, int dir); void snd_hdac_stream_free_all(struct hdac_bus *bus); diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c index d2b5724b463f..5c665b26f853 100644 --- a/sound/hda/ext/hdac_ext_stream.c +++ b/sound/hda/ext/hdac_ext_stream.c @@ -26,9 +26,9 @@ * initialize the stream, if ppcap is enabled then init those and then * invoke hdac stream initialization routine */ -void snd_hdac_ext_stream_init(struct hdac_bus *bus, - struct hdac_ext_stream *hext_stream, - int idx, int direction, int tag) +static void snd_hdac_ext_stream_init(struct hdac_bus *bus, + struct hdac_ext_stream *hext_stream, + int idx, int direction, int tag) { if (bus->ppcap) { hext_stream->pphc_addr = bus->ppcap + AZX_PPHC_BASE + @@ -56,7 +56,6 @@ void snd_hdac_ext_stream_init(struct hdac_bus *bus, hext_stream->decoupled = false; snd_hdac_stream_init(bus, &hext_stream->hstream, idx, direction, tag); } -EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_init); /** * snd_hdac_ext_stream_init_all - create and initialize the stream objects -- cgit v1.2.3 From 0839a04eff9778c3dc37d3a1bb8014a3386dece7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 19 Sep 2022 14:10:37 +0200 Subject: ALSA: hda: Use hdac_ext prefix in snd_hdac_stream_free_all() for clarity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure there's no ambiguity on layering with the appropriate prefix added. Pure rename, no functionality changed. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20220919121041.43463-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- include/sound/hdaudio_ext.h | 2 +- sound/hda/ext/hdac_ext_stream.c | 6 +++--- sound/soc/intel/avs/core.c | 4 ++-- sound/soc/intel/skylake/skl.c | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h index 4a4bd1d88612..83aed26ab143 100644 --- a/include/sound/hdaudio_ext.h +++ b/include/sound/hdaudio_ext.h @@ -79,7 +79,7 @@ struct hdac_ext_stream { int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx, int num_stream, int dir); -void snd_hdac_stream_free_all(struct hdac_bus *bus); +void snd_hdac_ext_stream_free_all(struct hdac_bus *bus); void snd_hdac_link_free_all(struct hdac_bus *bus); struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream, diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c index 5c665b26f853..9419abd7fc03 100644 --- a/sound/hda/ext/hdac_ext_stream.c +++ b/sound/hda/ext/hdac_ext_stream.c @@ -87,11 +87,11 @@ int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx, EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_init_all); /** - * snd_hdac_stream_free_all - free hdac extended stream objects + * snd_hdac_ext_stream_free_all - free hdac extended stream objects * * @bus: HD-audio core bus */ -void snd_hdac_stream_free_all(struct hdac_bus *bus) +void snd_hdac_ext_stream_free_all(struct hdac_bus *bus) { struct hdac_stream *s, *_s; struct hdac_ext_stream *hext_stream; @@ -103,7 +103,7 @@ void snd_hdac_stream_free_all(struct hdac_bus *bus) kfree(hext_stream); } } -EXPORT_SYMBOL_GPL(snd_hdac_stream_free_all); +EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_free_all); void snd_hdac_ext_stream_decouple_locked(struct hdac_bus *bus, struct hdac_ext_stream *hext_stream, diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c index c50c20fd681a..bb0719c58ca4 100644 --- a/sound/soc/intel/avs/core.c +++ b/sound/soc/intel/avs/core.c @@ -466,7 +466,7 @@ static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) err_acquire_irq: snd_hdac_bus_free_stream_pages(bus); - snd_hdac_stream_free_all(bus); + snd_hdac_ext_stream_free_all(bus); err_init_streams: iounmap(adev->dsp_ba); err_remap_bar4: @@ -502,7 +502,7 @@ static void avs_pci_remove(struct pci_dev *pci) snd_hda_codec_unregister(hdac_to_hda_codec(hdev)); snd_hdac_bus_free_stream_pages(bus); - snd_hdac_stream_free_all(bus); + snd_hdac_ext_stream_free_all(bus); /* reverse ml_capabilities */ snd_hdac_link_free_all(bus); snd_hdac_ext_bus_exit(bus); diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 52a041d6144c..0122926f9c58 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -444,7 +444,7 @@ static int skl_free(struct hdac_bus *bus) if (bus->irq >= 0) free_irq(bus->irq, (void *)bus); snd_hdac_bus_free_stream_pages(bus); - snd_hdac_stream_free_all(bus); + snd_hdac_ext_stream_free_all(bus); snd_hdac_link_free_all(bus); if (bus->remap_addr) -- cgit v1.2.3 From 24ad3835a6db4f8857975effa6bf47730371a5ff Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 19 Sep 2022 14:10:38 +0200 Subject: ALSA: hda: add snd_hdac_stop_streams() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Minor code reuse, no functionality change. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20220919121041.43463-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- include/sound/hdaudio.h | 1 + sound/hda/hdac_stream.c | 17 ++++++++++++++--- sound/pci/hda/hda_controller.c | 4 +--- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index 24c731e53ccb..35459d740f00 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -562,6 +562,7 @@ int snd_hdac_stream_set_params(struct hdac_stream *azx_dev, unsigned int format_val); void snd_hdac_stream_start(struct hdac_stream *azx_dev, bool fresh_start); void snd_hdac_stream_stop(struct hdac_stream *azx_dev); +void snd_hdac_stop_streams(struct hdac_bus *bus); void snd_hdac_stop_streams_and_chip(struct hdac_bus *bus); void snd_hdac_stream_reset(struct hdac_stream *azx_dev); void snd_hdac_stream_sync_trigger(struct hdac_stream *azx_dev, bool set, diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c index 2e98f5fd50e5..c056bcc5543d 100644 --- a/sound/hda/hdac_stream.c +++ b/sound/hda/hdac_stream.c @@ -174,17 +174,28 @@ void snd_hdac_stream_stop(struct hdac_stream *azx_dev) } EXPORT_SYMBOL_GPL(snd_hdac_stream_stop); +/** + * snd_hdac_stop_streams - stop all streams + * @bus: HD-audio core bus + */ +void snd_hdac_stop_streams(struct hdac_bus *bus) +{ + struct hdac_stream *stream; + + list_for_each_entry(stream, &bus->stream_list, list) + snd_hdac_stream_stop(stream); +} +EXPORT_SYMBOL_GPL(snd_hdac_stop_streams); + /** * snd_hdac_stop_streams_and_chip - stop all streams and chip if running * @bus: HD-audio core bus */ void snd_hdac_stop_streams_and_chip(struct hdac_bus *bus) { - struct hdac_stream *stream; if (bus->chip_init) { - list_for_each_entry(stream, &bus->stream_list, list) - snd_hdac_stream_stop(stream); + snd_hdac_stop_streams(bus); snd_hdac_bus_stop_chip(bus); } } diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 75dcb14ff20a..0ff286b7b66b 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -1033,10 +1033,8 @@ EXPORT_SYMBOL_GPL(azx_init_chip); void azx_stop_all_streams(struct azx *chip) { struct hdac_bus *bus = azx_bus(chip); - struct hdac_stream *s; - list_for_each_entry(s, &bus->stream_list, list) - snd_hdac_stream_stop(s); + snd_hdac_stop_streams(bus); } EXPORT_SYMBOL_GPL(azx_stop_all_streams); -- cgit v1.2.3 From 53f4f6b4e56d5fb6ef95a7e14c10ec244a79b996 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 19 Sep 2022 14:10:39 +0200 Subject: ALSA: hda: ext: simplify logic for stream assignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The logic is needlessly complicated, the basic rule is: The host streams can be found by checking the 'opened' boolean. The link streams can be found by checking the 'link_locked' boolean. Once a stream is found, it can be unconditionally decoupled. The snd_hdac_ext_stream_decouple_locked() routine will make sure the register status is modified as needed and the 'decoupled' boolean set. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20220919121041.43463-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- sound/hda/ext/hdac_ext_stream.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c index 9419abd7fc03..254df9a67bd2 100644 --- a/sound/hda/ext/hdac_ext_stream.c +++ b/sound/hda/ext/hdac_ext_stream.c @@ -267,19 +267,15 @@ hdac_ext_link_stream_assign(struct hdac_bus *bus, if (hstream->direction != substream->stream) continue; - /* check if decoupled stream and not in use is available */ - if (hext_stream->decoupled && !hext_stream->link_locked) { - res = hext_stream; - break; - } - + /* check if link stream is available */ if (!hext_stream->link_locked) { - snd_hdac_ext_stream_decouple_locked(bus, hext_stream, true); res = hext_stream; break; } + } if (res) { + snd_hdac_ext_stream_decouple_locked(bus, res, true); res->link_locked = 1; res->link_substream = substream; } @@ -308,13 +304,12 @@ hdac_ext_host_stream_assign(struct hdac_bus *bus, continue; if (!hstream->opened) { - if (!hext_stream->decoupled) - snd_hdac_ext_stream_decouple_locked(bus, hext_stream, true); res = hext_stream; break; } } if (res) { + snd_hdac_ext_stream_decouple_locked(bus, res, true); res->hstream.opened = 1; res->hstream.running = 0; res->hstream.substream = substream; -- cgit v1.2.3 From ac3467ad7f8734a21b65fa1852316a9b1b8c1fad Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 19 Sep 2022 14:10:40 +0200 Subject: ALSA: hda: ext: fix locking in stream_release MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The snd_hdac_ext_stream_release() routine uses the bus reg_lock, but releases it before calling snd_hdac_stream_release() where the bus reg_lock is taken again. This creates a timing window where the link stream release could test an invalid 'opened' boolean status and fail to recouple the host and link parts. Fix by exposing a locked version of snd_hdac_stream_release() and use it without releasing the spinlock. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20220919121041.43463-8-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- include/sound/hdaudio.h | 1 + sound/hda/ext/hdac_ext_stream.c | 2 +- sound/hda/hdac_stream.c | 19 ++++++++++++++++--- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index 35459d740f00..ddff03e546e9 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -551,6 +551,7 @@ void snd_hdac_stream_init(struct hdac_bus *bus, struct hdac_stream *azx_dev, int idx, int direction, int tag); struct hdac_stream *snd_hdac_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream); +void snd_hdac_stream_release_locked(struct hdac_stream *azx_dev); void snd_hdac_stream_release(struct hdac_stream *azx_dev); struct hdac_stream *snd_hdac_get_stream(struct hdac_bus *bus, int dir, int stream_tag); diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c index 254df9a67bd2..9a2bc7e803dd 100644 --- a/sound/hda/ext/hdac_ext_stream.c +++ b/sound/hda/ext/hdac_ext_stream.c @@ -384,8 +384,8 @@ void snd_hdac_ext_stream_release(struct hdac_ext_stream *hext_stream, int type) spin_lock_irq(&bus->reg_lock); if (hext_stream->decoupled && !hext_stream->link_locked) snd_hdac_ext_stream_decouple_locked(bus, hext_stream, false); + snd_hdac_stream_release_locked(&hext_stream->hstream); spin_unlock_irq(&bus->reg_lock); - snd_hdac_stream_release(&hext_stream->hstream); break; case HDAC_EXT_STREAM_TYPE_LINK: diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c index c056bcc5543d..1b8be39c38a9 100644 --- a/sound/hda/hdac_stream.c +++ b/sound/hda/hdac_stream.c @@ -365,6 +365,21 @@ struct hdac_stream *snd_hdac_stream_assign(struct hdac_bus *bus, } EXPORT_SYMBOL_GPL(snd_hdac_stream_assign); +/** + * snd_hdac_stream_release_locked - release the assigned stream + * @azx_dev: HD-audio core stream to release + * + * Release the stream that has been assigned by snd_hdac_stream_assign(). + * The bus->reg_lock needs to be taken at a higher level + */ +void snd_hdac_stream_release_locked(struct hdac_stream *azx_dev) +{ + azx_dev->opened = 0; + azx_dev->running = 0; + azx_dev->substream = NULL; +} +EXPORT_SYMBOL_GPL(snd_hdac_stream_release_locked); + /** * snd_hdac_stream_release - release the assigned stream * @azx_dev: HD-audio core stream to release @@ -376,9 +391,7 @@ void snd_hdac_stream_release(struct hdac_stream *azx_dev) struct hdac_bus *bus = azx_dev->bus; spin_lock_irq(&bus->reg_lock); - azx_dev->opened = 0; - azx_dev->running = 0; - azx_dev->substream = NULL; + snd_hdac_stream_release_locked(azx_dev); spin_unlock_irq(&bus->reg_lock); } EXPORT_SYMBOL_GPL(snd_hdac_stream_release); -- cgit v1.2.3 From c6fe6be65aeaa03c7cdfc807b47c1e59b9c9ea71 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 19 Sep 2022 14:10:41 +0200 Subject: ALSA: hda: ext: remove always-true conditions on host and link release MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By construction a host and link DMA are always decoupled. This decoupling happens in the assign() phase. There's no point in checking if the two parts are decoupled, this is by-design always-true. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20220919121041.43463-9-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- sound/hda/ext/hdac_ext_stream.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c index 9a2bc7e803dd..70f3ad71aaf0 100644 --- a/sound/hda/ext/hdac_ext_stream.c +++ b/sound/hda/ext/hdac_ext_stream.c @@ -382,7 +382,8 @@ void snd_hdac_ext_stream_release(struct hdac_ext_stream *hext_stream, int type) case HDAC_EXT_STREAM_TYPE_HOST: spin_lock_irq(&bus->reg_lock); - if (hext_stream->decoupled && !hext_stream->link_locked) + /* couple link only if not in use */ + if (!hext_stream->link_locked) snd_hdac_ext_stream_decouple_locked(bus, hext_stream, false); snd_hdac_stream_release_locked(&hext_stream->hstream); spin_unlock_irq(&bus->reg_lock); @@ -390,7 +391,8 @@ void snd_hdac_ext_stream_release(struct hdac_ext_stream *hext_stream, int type) case HDAC_EXT_STREAM_TYPE_LINK: spin_lock_irq(&bus->reg_lock); - if (hext_stream->decoupled && !hext_stream->hstream.opened) + /* couple host only if not in use */ + if (!hext_stream->hstream.opened) snd_hdac_ext_stream_decouple_locked(bus, hext_stream, false); hext_stream->link_locked = 0; hext_stream->link_substream = NULL; -- cgit v1.2.3 From 3989ade2d1e7ffc900e3842dc542b9e4bb3618fe Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 20 Sep 2022 06:32:16 +0000 Subject: ASoC: soc.h: remove num_cpus/codecs Current rtd has both dai_link pointer (A) and num_cpus/codecs (B). (A) rtd->dai_link = dai_link; (B) rtd->num_cpus = dai_link->num_cpus; (B) rtd->num_codecs = dai_link->num_codecs; But, we can get num_cpus/codecs (B) via dai_link (A). This means we don't need to keep num_cpus/codecs on rtd. This patch removes these. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87sfkmv9n3.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc.h | 10 ++++------ sound/soc/amd/vangogh/acp5x-mach.c | 2 +- sound/soc/samsung/odroid.c | 2 +- sound/soc/soc-compress.c | 4 ++-- sound/soc/soc-core.c | 4 +--- sound/soc/soc-dapm.c | 4 ++-- sound/soc/soc-generic-dmaengine-pcm.c | 6 +++--- sound/soc/soc-pcm.c | 20 ++++++++++---------- sound/soc/sof/topology.c | 4 ++-- 9 files changed, 26 insertions(+), 30 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 4351d86eedf6..f5e0c402acb7 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1078,8 +1078,6 @@ struct snd_soc_pcm_runtime { * asoc_rtd_to_codec() */ struct snd_soc_dai **dais; - unsigned int num_codecs; - unsigned int num_cpus; struct snd_soc_dapm_widget *playback_widget; struct snd_soc_dapm_widget *capture_widget; @@ -1108,7 +1106,7 @@ struct snd_soc_pcm_runtime { }; /* see soc_new_pcm_runtime() */ #define asoc_rtd_to_cpu(rtd, n) (rtd)->dais[n] -#define asoc_rtd_to_codec(rtd, n) (rtd)->dais[n + (rtd)->num_cpus] +#define asoc_rtd_to_codec(rtd, n) (rtd)->dais[n + (rtd)->dai_link->num_cpus] #define asoc_substream_to_rtd(substream) \ (struct snd_soc_pcm_runtime *)snd_pcm_substream_chip(substream) @@ -1118,15 +1116,15 @@ struct snd_soc_pcm_runtime { (i)++) #define for_each_rtd_cpu_dais(rtd, i, dai) \ for ((i) = 0; \ - ((i) < rtd->num_cpus) && ((dai) = asoc_rtd_to_cpu(rtd, i)); \ + ((i) < rtd->dai_link->num_cpus) && ((dai) = asoc_rtd_to_cpu(rtd, i)); \ (i)++) #define for_each_rtd_codec_dais(rtd, i, dai) \ for ((i) = 0; \ - ((i) < rtd->num_codecs) && ((dai) = asoc_rtd_to_codec(rtd, i)); \ + ((i) < rtd->dai_link->num_codecs) && ((dai) = asoc_rtd_to_codec(rtd, i)); \ (i)++) #define for_each_rtd_dais(rtd, i, dai) \ for ((i) = 0; \ - ((i) < (rtd)->num_cpus + (rtd)->num_codecs) && \ + ((i) < (rtd)->dai_link->num_cpus + (rtd)->dai_link->num_codecs) && \ ((dai) = (rtd)->dais[i]); \ (i)++) diff --git a/sound/soc/amd/vangogh/acp5x-mach.c b/sound/soc/amd/vangogh/acp5x-mach.c index af3737ef9707..eebf2650ad27 100644 --- a/sound/soc/amd/vangogh/acp5x-mach.c +++ b/sound/soc/amd/vangogh/acp5x-mach.c @@ -172,7 +172,7 @@ static int acp5x_cs35l41_hw_params(struct snd_pcm_substream *substream, struct snd_soc_card *card = rtd->card; struct snd_soc_dai *codec_dai; int ret, i; - unsigned int num_codecs = rtd->num_codecs; + unsigned int num_codecs = rtd->dai_link->num_codecs; unsigned int bclk_val; ret = 0; diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c index 4ff12e2e704f..1e0fefa89ad5 100644 --- a/sound/soc/samsung/odroid.c +++ b/sound/soc/samsung/odroid.c @@ -97,7 +97,7 @@ static int odroid_card_be_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; - if (rtd->num_codecs > 1) { + if (rtd->dai_link->num_codecs > 1) { struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 1); ret = snd_soc_dai_set_sysclk(codec_dai, 0, rclk_freq, diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index e9dd25894dc0..870f13e1d389 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -560,8 +560,8 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) BUILD_BUG_ON((int)SNDRV_PCM_STREAM_PLAYBACK != (int)SND_COMPRESS_PLAYBACK); BUILD_BUG_ON((int)SNDRV_PCM_STREAM_CAPTURE != (int)SND_COMPRESS_CAPTURE); - if (rtd->num_cpus > 1 || - rtd->num_codecs > 1) { + if (rtd->dai_link->num_cpus > 1 || + rtd->dai_link->num_codecs > 1) { dev_err(rtd->card->dev, "Compress ASoC: Multi CPU/Codec not supported\n"); return -EINVAL; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index df2bd8098c63..a812487b7b5f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -107,7 +107,7 @@ static umode_t soc_dev_attr_is_visible(struct kobject *kobj, if (attr == &dev_attr_pmdown_time.attr) return attr->mode; /* always visible */ - return rtd->num_codecs ? attr->mode : 0; /* enabled only with codec */ + return rtd->dai_link->num_codecs ? attr->mode : 0; /* enabled only with codec */ } static const struct attribute_group soc_dapm_dev_group = { @@ -482,8 +482,6 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( * asoc_rtd_to_cpu() * asoc_rtd_to_codec() */ - rtd->num_cpus = dai_link->num_cpus; - rtd->num_codecs = dai_link->num_codecs; rtd->card = card; rtd->dai_link = dai_link; rtd->num = card->num_rtd++; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 2d105bfee387..f10133f35c5d 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -4459,11 +4459,11 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) if (rtd->dai_link->dynamic) continue; - if (rtd->num_cpus == 1) { + if (rtd->dai_link->num_cpus == 1) { for_each_rtd_codec_dais(rtd, i, codec_dai) dapm_connect_dai_pair(card, rtd, codec_dai, asoc_rtd_to_cpu(rtd, 0)); - } else if (rtd->num_codecs == rtd->num_cpus) { + } else if (rtd->dai_link->num_codecs == rtd->dai_link->num_cpus) { for_each_rtd_codec_dais(rtd, i, codec_dai) dapm_connect_dai_pair(card, rtd, codec_dai, asoc_rtd_to_cpu(rtd, i)); diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 87858462bba9..3b99f619e37e 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -54,7 +54,7 @@ int snd_dmaengine_pcm_prepare_slave_config(struct snd_pcm_substream *substream, struct snd_dmaengine_dai_dma_data *dma_data; int ret; - if (rtd->num_cpus > 1) { + if (rtd->dai_link->num_cpus > 1) { dev_err(rtd->dev, "%s doesn't support Multi CPU yet\n", __func__); return -EINVAL; @@ -105,7 +105,7 @@ dmaengine_pcm_set_runtime_hwparams(struct snd_soc_component *component, struct snd_dmaengine_dai_dma_data *dma_data; struct snd_pcm_hardware hw; - if (rtd->num_cpus > 1) { + if (rtd->dai_link->num_cpus > 1) { dev_err(rtd->dev, "%s doesn't support Multi CPU yet\n", __func__); return -EINVAL; @@ -179,7 +179,7 @@ static struct dma_chan *dmaengine_pcm_compat_request_channel( struct dmaengine_pcm *pcm = soc_component_to_pcm(component); struct snd_dmaengine_dai_dma_data *dma_data; - if (rtd->num_cpus > 1) { + if (rtd->dai_link->num_cpus > 1) { dev_err(rtd->dev, "%s doesn't support Multi CPU yet\n", __func__); return NULL; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index f8b62487babd..fb87d6d23408 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -84,11 +84,11 @@ static inline void snd_soc_dpcm_stream_unlock_irq(struct snd_soc_pcm_runtime *rt static inline const char *soc_cpu_dai_name(struct snd_soc_pcm_runtime *rtd) { - return (rtd)->num_cpus == 1 ? asoc_rtd_to_cpu(rtd, 0)->name : "multicpu"; + return (rtd)->dai_link->num_cpus == 1 ? asoc_rtd_to_cpu(rtd, 0)->name : "multicpu"; } static inline const char *soc_codec_dai_name(struct snd_soc_pcm_runtime *rtd) { - return (rtd)->num_codecs == 1 ? asoc_rtd_to_codec(rtd, 0)->name : "multicodec"; + return (rtd)->dai_link->num_codecs == 1 ? asoc_rtd_to_codec(rtd, 0)->name : "multicodec"; } #ifdef CONFIG_DEBUG_FS @@ -185,7 +185,7 @@ static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf, int stream; char *buf; - if (fe->num_cpus > 1) { + if (fe->dai_link->num_cpus > 1) { dev_err(fe->dev, "%s doesn't support Multi CPU yet\n", __func__); return -EINVAL; @@ -637,7 +637,7 @@ int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd, * connected to CPU DAI(s), use CPU DAI's directly and let * channel allocation be fixed up later */ - if (rtd->num_codecs > 1) { + if (rtd->dai_link->num_codecs > 1) { hw->channels_min = cpu_chan_min; hw->channels_max = cpu_chan_max; } @@ -1379,7 +1379,7 @@ int dpcm_path_get(struct snd_soc_pcm_runtime *fe, struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0); int paths; - if (fe->num_cpus > 1) { + if (fe->dai_link->num_cpus > 1) { dev_err(fe->dev, "%s doesn't support Multi CPU yet\n", __func__); return -EINVAL; @@ -1751,7 +1751,7 @@ static void dpcm_runtime_setup_be_chan(struct snd_pcm_substream *substream) * chan min/max cannot be enforced if there are multiple CODEC * DAIs connected to a single CPU DAI, use CPU DAI's directly */ - if (be->num_codecs == 1) { + if (be->dai_link->num_codecs == 1) { struct snd_soc_pcm_stream *codec_stream = snd_soc_dai_get_pcm_stream( asoc_rtd_to_codec(be, 0), stream); @@ -2590,7 +2590,7 @@ static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new) if (!fe->dai_link->dynamic) return 0; - if (fe->num_cpus > 1) { + if (fe->dai_link->num_cpus > 1) { dev_err(fe->dev, "%s doesn't support Multi CPU yet\n", __func__); return -EINVAL; @@ -2734,7 +2734,7 @@ static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *cpu_dai; int i; - if (rtd->dai_link->dynamic && rtd->num_cpus > 1) { + if (rtd->dai_link->dynamic && rtd->dai_link->num_cpus > 1) { dev_err(rtd->dev, "DPCM doesn't support Multi CPU for Front-Ends yet\n"); return -EINVAL; @@ -2786,9 +2786,9 @@ static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd, SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; for_each_rtd_codec_dais(rtd, i, codec_dai) { - if (rtd->num_cpus == 1) { + if (rtd->dai_link->num_cpus == 1) { cpu_dai = asoc_rtd_to_cpu(rtd, 0); - } else if (rtd->num_cpus == rtd->num_codecs) { + } else if (rtd->dai_link->num_cpus == rtd->dai_link->num_codecs) { cpu_dai = asoc_rtd_to_cpu(rtd, i); } else { dev_err(rtd->card->dev, diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 6087483deb48..1982a3d379bf 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1029,7 +1029,7 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp, break; } } - if (i == rtd->num_cpus) { + if (i == rtd->dai_link->num_cpus) { dev_err(scomp->dev, "error: can't find BE for DAI %s\n", w->name); @@ -1051,7 +1051,7 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp, break; } } - if (i == rtd->num_cpus) { + if (i == rtd->dai_link->num_cpus) { dev_err(scomp->dev, "error: can't find BE for DAI %s\n", w->name); -- cgit v1.2.3 From a26ec2acb2043a52c41d2b651b30d2df475f4263 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 20 Sep 2022 06:32:25 +0000 Subject: ASoC: soc.h: use defined number instead of direct number snd_soc_pcm_runtime has dpcm for Playback/Capture, but it is defined directly "2". It should use defined number. struct snd_soc_pcm_runtime { ... => struct snd_soc_dpcm_runtime dpcm[2]; ... } This patch fixup it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87r106v9mv.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index f5e0c402acb7..4adb6236860c 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1062,7 +1062,7 @@ struct snd_soc_pcm_runtime { unsigned int params_select; /* currently selected param for dai link */ /* Dynamic PCM BE runtime data */ - struct snd_soc_dpcm_runtime dpcm[2]; + struct snd_soc_dpcm_runtime dpcm[SNDRV_PCM_STREAM_LAST + 1]; long pmdown_time; -- cgit v1.2.3 From 3289dc026a8cf5d6469eb49d838bc971f4370f9d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 20 Sep 2022 06:32:36 +0000 Subject: ASoC: soc.h: use array instead of playback/capture_widget snd_soc_pcm_runtime has playback/capture_widget for Codec2Coddec. The naming is unclear. This patch names it as c2c_widget and uses array. struct snd_soc_pcm_runtime { ... => struct snd_soc_dapm_widget *playback_widget; => struct snd_soc_dapm_widget *capture_widget; ... } Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87pmfqv9mk.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc.h | 4 +--- sound/soc/soc-dapm.c | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 4adb6236860c..37bbfc8b45cb 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1063,6 +1063,7 @@ struct snd_soc_pcm_runtime { /* Dynamic PCM BE runtime data */ struct snd_soc_dpcm_runtime dpcm[SNDRV_PCM_STREAM_LAST + 1]; + struct snd_soc_dapm_widget *c2c_widget[SNDRV_PCM_STREAM_LAST + 1]; long pmdown_time; @@ -1079,9 +1080,6 @@ struct snd_soc_pcm_runtime { */ struct snd_soc_dai **dais; - struct snd_soc_dapm_widget *playback_widget; - struct snd_soc_dapm_widget *capture_widget; - struct delayed_work delayed_work; void (*close_delayed_work_func)(struct snd_soc_pcm_runtime *rtd); #ifdef CONFIG_DEBUG_FS diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index f10133f35c5d..d515e7a78ea8 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -4361,6 +4361,7 @@ static void dapm_connect_dai_pair(struct snd_soc_card *card, struct snd_soc_dapm_widget *dai, *codec, *playback_cpu, *capture_cpu; struct snd_pcm_substream *substream; struct snd_pcm_str *streams = rtd->pcm->streams; + int stream; if (dai_link->params) { playback_cpu = cpu_dai->capture_widget; @@ -4371,37 +4372,39 @@ static void dapm_connect_dai_pair(struct snd_soc_card *card, } /* connect BE DAI playback if widgets are valid */ + stream = SNDRV_PCM_STREAM_PLAYBACK; codec = codec_dai->playback_widget; if (playback_cpu && codec) { - if (dai_link->params && !rtd->playback_widget) { - substream = streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + if (dai_link->params && !rtd->c2c_widget[stream]) { + substream = streams[stream].substream; dai = snd_soc_dapm_new_dai(card, substream, "playback"); if (IS_ERR(dai)) goto capture; - rtd->playback_widget = dai; + rtd->c2c_widget[stream] = dai; } dapm_connect_dai_routes(&card->dapm, cpu_dai, playback_cpu, - rtd->playback_widget, + rtd->c2c_widget[stream], codec_dai, codec); } capture: /* connect BE DAI capture if widgets are valid */ + stream = SNDRV_PCM_STREAM_CAPTURE; codec = codec_dai->capture_widget; if (codec && capture_cpu) { - if (dai_link->params && !rtd->capture_widget) { - substream = streams[SNDRV_PCM_STREAM_CAPTURE].substream; + if (dai_link->params && !rtd->c2c_widget[stream]) { + substream = streams[stream].substream; dai = snd_soc_dapm_new_dai(card, substream, "capture"); if (IS_ERR(dai)) return; - rtd->capture_widget = dai; + rtd->c2c_widget[stream] = dai; } dapm_connect_dai_routes(&card->dapm, codec_dai, codec, - rtd->capture_widget, + rtd->c2c_widget[stream], cpu_dai, capture_cpu); } } -- cgit v1.2.3 From 72176fccd5de1d9cf61e42771bb00567723f3353 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 19 Sep 2022 13:53:49 +0200 Subject: ALSA: hda: intel-nhlt: add intel_nhlt_ssp_mclk_mask() SOF topologies hard-code the MCLK used for SSP connections. That was a bad idea in hindsight, this information should really come from BIOS and/or machine driver. This patch introduces a helper to scan all SSP endpoints connected to a codec, and all formats to see what MCLK is used. When BIT(0) of the mdivc offset if set in the SSP blob, MCLK0 is used, and likewise when BIT(1) is set MCLK1 is used. The case where both MCLKs are used is possible but has never been seen in practice so should be treated as an error by the caller. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Kai Vehmanen Reviewed-by: Bard Liao Reviewed-by: Takashi Iwai Link: https://lore.kernel.org/r/20220919115350.43104-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/sound/intel-nhlt.h | 7 ++++ sound/hda/intel-nhlt.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/include/sound/intel-nhlt.h b/include/sound/intel-nhlt.h index 3d5cf201cd80..53470d6a28d6 100644 --- a/include/sound/intel-nhlt.h +++ b/include/sound/intel-nhlt.h @@ -136,6 +136,8 @@ bool intel_nhlt_has_endpoint_type(struct nhlt_acpi_table *nhlt, u8 link_type); int intel_nhlt_ssp_endpoint_mask(struct nhlt_acpi_table *nhlt, u8 device_type); +int intel_nhlt_ssp_mclk_mask(struct nhlt_acpi_table *nhlt, int ssp_num); + struct nhlt_specific_cfg * intel_nhlt_get_endpoint_blob(struct device *dev, struct nhlt_acpi_table *nhlt, u32 bus_id, u8 link_type, u8 vbps, u8 bps, @@ -169,6 +171,11 @@ static inline int intel_nhlt_ssp_endpoint_mask(struct nhlt_acpi_table *nhlt, u8 return 0; } +static inline int intel_nhlt_ssp_mclk_mask(struct nhlt_acpi_table *nhlt, int ssp_num) +{ + return 0; +} + static inline struct nhlt_specific_cfg * intel_nhlt_get_endpoint_blob(struct device *dev, struct nhlt_acpi_table *nhlt, u32 bus_id, u8 link_type, u8 vbps, u8 bps, diff --git a/sound/hda/intel-nhlt.c b/sound/hda/intel-nhlt.c index 13bb0ccfb36c..2c4dfc0b7e34 100644 --- a/sound/hda/intel-nhlt.c +++ b/sound/hda/intel-nhlt.c @@ -157,6 +157,85 @@ int intel_nhlt_ssp_endpoint_mask(struct nhlt_acpi_table *nhlt, u8 device_type) } EXPORT_SYMBOL(intel_nhlt_ssp_endpoint_mask); +#define SSP_BLOB_V1_0_SIZE 84 +#define SSP_BLOB_V1_0_MDIVC_OFFSET 19 /* offset in u32 */ + +#define SSP_BLOB_V1_5_SIZE 96 +#define SSP_BLOB_V1_5_MDIVC_OFFSET 21 /* offset in u32 */ +#define SSP_BLOB_VER_1_5 0xEE000105 + +#define SSP_BLOB_V2_0_SIZE 88 +#define SSP_BLOB_V2_0_MDIVC_OFFSET 20 /* offset in u32 */ +#define SSP_BLOB_VER_2_0 0xEE000200 + +int intel_nhlt_ssp_mclk_mask(struct nhlt_acpi_table *nhlt, int ssp_num) +{ + struct nhlt_endpoint *epnt; + struct nhlt_fmt *fmt; + struct nhlt_fmt_cfg *cfg; + int mclk_mask = 0; + int i, j; + + if (!nhlt) + return 0; + + epnt = (struct nhlt_endpoint *)nhlt->desc; + for (i = 0; i < nhlt->endpoint_count; i++) { + + /* we only care about endpoints connected to an audio codec over SSP */ + if (epnt->linktype == NHLT_LINK_SSP && + epnt->device_type == NHLT_DEVICE_I2S && + epnt->virtual_bus_id == ssp_num) { + + fmt = (struct nhlt_fmt *)(epnt->config.caps + epnt->config.size); + cfg = fmt->fmt_config; + + /* + * In theory all formats should use the same MCLK but it doesn't hurt to + * double-check that the configuration is consistent + */ + for (j = 0; j < fmt->fmt_count; j++) { + u32 *blob; + int mdivc_offset; + int size; + + /* first check we have enough data to read the blob type */ + if (cfg->config.size < 8) + return -EINVAL; + + blob = (u32 *)cfg->config.caps; + + if (blob[1] == SSP_BLOB_VER_2_0) { + mdivc_offset = SSP_BLOB_V2_0_MDIVC_OFFSET; + size = SSP_BLOB_V2_0_SIZE; + } else if (blob[1] == SSP_BLOB_VER_1_5) { + mdivc_offset = SSP_BLOB_V1_5_MDIVC_OFFSET; + size = SSP_BLOB_V1_5_SIZE; + } else { + mdivc_offset = SSP_BLOB_V1_0_MDIVC_OFFSET; + size = SSP_BLOB_V1_0_SIZE; + } + + /* make sure we have enough data for the fixed part of the blob */ + if (cfg->config.size < size) + return -EINVAL; + + mclk_mask |= blob[mdivc_offset] & GENMASK(1, 0); + + cfg = (struct nhlt_fmt_cfg *)(cfg->config.caps + cfg->config.size); + } + } + epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); + } + + /* make sure only one MCLK is used */ + if (hweight_long(mclk_mask) != 1) + return -EINVAL; + + return mclk_mask; +} +EXPORT_SYMBOL(intel_nhlt_ssp_mclk_mask); + static struct nhlt_specific_cfg * nhlt_get_specific_cfg(struct device *dev, struct nhlt_fmt *fmt, u8 num_ch, u32 rate, u8 vbps, u8 bps) -- cgit v1.2.3 From d9252772cdc811beedabbcf21ef856d09b87d1dd Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 19 Sep 2022 13:53:50 +0200 Subject: ASoC: SOF: Intel: hda: override mclk_id after parsing NHLT SSP blob The NHLT is already used to determine which SSP is connected to an audio codec, we can parse the SSP blob to get the mclk_id from NHLT. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Kai Vehmanen Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20220919115350.43104-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index ada2e6775749..dfb3b424fb5e 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -753,6 +753,18 @@ static int check_nhlt_ssp_mask(struct snd_sof_dev *sdev) return ssp_mask; } +static int check_nhlt_ssp_mclk_mask(struct snd_sof_dev *sdev, int ssp_num) +{ + struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; + struct nhlt_acpi_table *nhlt; + + nhlt = hdev->nhlt; + if (!nhlt) + return 0; + + return intel_nhlt_ssp_mclk_mask(nhlt, ssp_num); +} + #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) || IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) static const char *fixup_tplg_name(struct snd_sof_dev *sdev, @@ -1533,6 +1545,7 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) mach->mach_params.i2s_link_mask) { const struct sof_intel_dsp_desc *chip = get_chip_info(sdev->pdata); int ssp_num; + int mclk_mask; if (hweight_long(mach->mach_params.i2s_link_mask) > 1 && !(mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_SSP_MSB)) @@ -1557,6 +1570,21 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) sof_pdata->tplg_filename = tplg_filename; add_extension = true; + + mclk_mask = check_nhlt_ssp_mclk_mask(sdev, ssp_num); + + if (mclk_mask < 0) { + dev_err(sdev->dev, "Invalid MCLK configuration\n"); + return NULL; + } + + dev_dbg(sdev->dev, "MCLK mask %#x found in NHLT\n", mclk_mask); + + if (mclk_mask) { + dev_info(sdev->dev, "Overriding topology with MCLK mask %#x from NHLT\n", mclk_mask); + sdev->mclk_id_override = true; + sdev->mclk_id_quirk = (mclk_mask & BIT(0)) ? 0 : 1; + } } if (tplg_fixup && add_extension) { -- cgit v1.2.3 From 96ecdc718649fe01940e7f5dc4fc15dacd18cada Mon Sep 17 00:00:00 2001 From: ye xingchen Date: Tue, 20 Sep 2022 06:46:05 +0000 Subject: ALSA: es18xx: Remove the unneeded result variable Return the value inb() directly instead of storing it in another redundant variable. Reported-by: Zeal Robot Signed-off-by: ye xingchen Link: https://lore.kernel.org/r/20220920064605.215318-1-ye.xingchen@zte.com.cn Signed-off-by: Takashi Iwai --- sound/isa/es18xx.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index 3fcd168480b6..0a32845b1017 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -1344,11 +1344,8 @@ ES18XX_SINGLE("GPO1 Switch", 0, ES18XX_PM, 1, 1, ES18XX_FL_PMPORT), static int snd_es18xx_config_read(struct snd_es18xx *chip, unsigned char reg) { - int data; - outb(reg, chip->ctrl_port); - data = inb(chip->ctrl_port + 1); - return data; + return inb(chip->ctrl_port + 1); } static void snd_es18xx_config_write(struct snd_es18xx *chip, -- cgit v1.2.3 From 01a72aefbacca4d6e169caa776c87d3c1f6faf4a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 20 Sep 2022 13:42:43 +0200 Subject: Revert "ALSA: usb-audio: Clean up endpoint setups at PCM prepare" This reverts commit 32eeeed963ad4f41b422b3e314d96ded7283b201. As the fix for endpoint configuration split is reverted at next, do another revert here for a clean patch application. Signed-off-by: Takashi Iwai --- sound/usb/pcm.c | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 4ed53a3dc922..b604f7e95e82 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -433,6 +433,35 @@ static void close_endpoints(struct snd_usb_audio *chip, } } +static int configure_endpoints(struct snd_usb_audio *chip, + struct snd_usb_substream *subs) +{ + int err; + + if (subs->data_endpoint->need_setup) { + /* stop any running stream beforehand */ + if (stop_endpoints(subs, false)) + sync_pending_stops(subs); + if (subs->sync_endpoint) { + err = snd_usb_endpoint_prepare(chip, subs->sync_endpoint); + if (err < 0) + return err; + } + err = snd_usb_endpoint_prepare(chip, subs->data_endpoint); + if (err < 0) + return err; + snd_usb_set_format_quirk(subs, subs->cur_audiofmt); + } else { + if (subs->sync_endpoint) { + err = snd_usb_endpoint_prepare(chip, subs->sync_endpoint); + if (err < 0) + return err; + } + } + + return 0; +} + /* * hw_params callback * @@ -611,18 +640,9 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) goto unlock; } - if (subs->sync_endpoint) { - ret = snd_usb_endpoint_prepare(chip, subs->sync_endpoint); - if (ret < 0) - goto unlock; - } - - ret = snd_usb_endpoint_prepare(chip, subs->data_endpoint); + ret = configure_endpoints(chip, subs); if (ret < 0) goto unlock; - else if (ret > 0) - snd_usb_set_format_quirk(subs, subs->cur_audiofmt); - ret = 0; /* reset the pointer */ subs->buffer_bytes = frames_to_bytes(runtime, runtime->buffer_size); -- cgit v1.2.3 From 556eb41622b01c50dbc330e03bad2b0a5a082428 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 20 Sep 2022 15:16:57 +0200 Subject: ASoC: SOF: Intel: hda-dsp: expose functions for SKL support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation of the IPCv4 IPC support, this patch adds exposes two functions required by the SKL/KBL boot and code loader. Co-developed-by: Ranjani Sridharan Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Reviewed-by: Péter Ujfalusi Link: https://lore.kernel.org/r/20220920131700.133103-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dsp.c | 4 ++-- sound/soc/sof/intel/hda.h | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 1319c8e34021..f85ac55536fa 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -114,7 +114,7 @@ static int hda_dsp_core_reset_leave(struct snd_sof_dev *sdev, unsigned int core_ return ret; } -static int hda_dsp_core_stall_reset(struct snd_sof_dev *sdev, unsigned int core_mask) +int hda_dsp_core_stall_reset(struct snd_sof_dev *sdev, unsigned int core_mask) { /* stall core */ snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, @@ -126,7 +126,7 @@ static int hda_dsp_core_stall_reset(struct snd_sof_dev *sdev, unsigned int core_ return hda_dsp_core_reset_enter(sdev, core_mask); } -static bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev, unsigned int core_mask) +bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev, unsigned int core_mask) { int val; bool is_enable; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index bb9d2af06530..04b730f754d7 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -565,6 +565,7 @@ int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev, 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); +bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev, unsigned int core_mask); int hda_dsp_set_power_state(struct snd_sof_dev *sdev, const struct sof_dsp_power_state *target_state); @@ -833,6 +834,8 @@ extern int sof_hda_position_quirk; void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops); void hda_ops_free(struct snd_sof_dev *sdev); +int hda_dsp_core_stall_reset(struct snd_sof_dev *sdev, unsigned int core_mask); + /* IPC4 */ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context); int cnl_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg); -- cgit v1.2.3 From c712be3427ca7b76800f335a6cfabdddab380c27 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 20 Sep 2022 15:16:58 +0200 Subject: ASoC: SOF: Intel: add SKL/KBL hardware code loader This patch adds support for the SkyLake and KabyLake code loader on top of the SOF IPC4. The work was initially contributed in 2018 by Liam Girdwood and Zhu Yingjiang, and abandoned due to firmware signature issues. With the existing support of IPC v4, it's time to re-add this capability. This patch uses the newly added FSR (Firmware State Register) definitions for DSP state handling and targeting, ass well as new state definition for SKL which indicates that the firmware has been started (similar to FW_ENTERED on other platforms). Co-developed-by: Ranjani Sridharan Signed-off-by: Ranjani Sridharan Co-developed-by: Peter Ujfalusi Signed-off-by: Peter Ujfalusi Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220920131700.133103-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-loader-skl.c | 583 +++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/hda.h | 6 + 2 files changed, 589 insertions(+) create mode 100644 sound/soc/sof/intel/hda-loader-skl.c diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c new file mode 100644 index 000000000000..6f7e7444f11c --- /dev/null +++ b/sound/soc/sof/intel/hda-loader-skl.c @@ -0,0 +1,583 @@ +// 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) 2018-2022 Intel Corporation. All rights reserved. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../sof-priv.h" +#include "../ops.h" +#include "hda.h" + +#define HDA_SKL_WAIT_TIMEOUT 500 /* 500 msec */ +#define HDA_SKL_CLDMA_MAX_BUFFER_SIZE (32 * PAGE_SIZE) + +/* Stream Reset */ +#define HDA_CL_SD_CTL_SRST_SHIFT 0 +#define HDA_CL_SD_CTL_SRST(x) (((x) & 0x1) << \ + HDA_CL_SD_CTL_SRST_SHIFT) + +/* Stream Run */ +#define HDA_CL_SD_CTL_RUN_SHIFT 1 +#define HDA_CL_SD_CTL_RUN(x) (((x) & 0x1) << \ + HDA_CL_SD_CTL_RUN_SHIFT) + +/* Interrupt On Completion Enable */ +#define HDA_CL_SD_CTL_IOCE_SHIFT 2 +#define HDA_CL_SD_CTL_IOCE(x) (((x) & 0x1) << \ + HDA_CL_SD_CTL_IOCE_SHIFT) + +/* FIFO Error Interrupt Enable */ +#define HDA_CL_SD_CTL_FEIE_SHIFT 3 +#define HDA_CL_SD_CTL_FEIE(x) (((x) & 0x1) << \ + HDA_CL_SD_CTL_FEIE_SHIFT) + +/* Descriptor Error Interrupt Enable */ +#define HDA_CL_SD_CTL_DEIE_SHIFT 4 +#define HDA_CL_SD_CTL_DEIE(x) (((x) & 0x1) << \ + HDA_CL_SD_CTL_DEIE_SHIFT) + +/* FIFO Limit Change */ +#define HDA_CL_SD_CTL_FIFOLC_SHIFT 5 +#define HDA_CL_SD_CTL_FIFOLC(x) (((x) & 0x1) << \ + HDA_CL_SD_CTL_FIFOLC_SHIFT) + +/* Stripe Control */ +#define HDA_CL_SD_CTL_STRIPE_SHIFT 16 +#define HDA_CL_SD_CTL_STRIPE(x) (((x) & 0x3) << \ + HDA_CL_SD_CTL_STRIPE_SHIFT) + +/* Traffic Priority */ +#define HDA_CL_SD_CTL_TP_SHIFT 18 +#define HDA_CL_SD_CTL_TP(x) (((x) & 0x1) << \ + HDA_CL_SD_CTL_TP_SHIFT) + +/* Bidirectional Direction Control */ +#define HDA_CL_SD_CTL_DIR_SHIFT 19 +#define HDA_CL_SD_CTL_DIR(x) (((x) & 0x1) << \ + HDA_CL_SD_CTL_DIR_SHIFT) + +/* Stream Number */ +#define HDA_CL_SD_CTL_STRM_SHIFT 20 +#define HDA_CL_SD_CTL_STRM(x) (((x) & 0xf) << \ + HDA_CL_SD_CTL_STRM_SHIFT) + +#define HDA_CL_SD_CTL_INT(x) \ + (HDA_CL_SD_CTL_IOCE(x) | \ + HDA_CL_SD_CTL_FEIE(x) | \ + HDA_CL_SD_CTL_DEIE(x)) + +#define HDA_CL_SD_CTL_INT_MASK \ + (HDA_CL_SD_CTL_IOCE(1) | \ + HDA_CL_SD_CTL_FEIE(1) | \ + HDA_CL_SD_CTL_DEIE(1)) + +#define DMA_ADDRESS_128_BITS_ALIGNMENT 7 +#define BDL_ALIGN(x) ((x) >> DMA_ADDRESS_128_BITS_ALIGNMENT) + +/* Buffer Descriptor List Lower Base Address */ +#define HDA_CL_SD_BDLPLBA_SHIFT 7 +#define HDA_CL_SD_BDLPLBA_MASK (0x1ffffff << HDA_CL_SD_BDLPLBA_SHIFT) +#define HDA_CL_SD_BDLPLBA(x) \ + ((BDL_ALIGN(lower_32_bits(x)) << HDA_CL_SD_BDLPLBA_SHIFT) & \ + HDA_CL_SD_BDLPLBA_MASK) + +/* Buffer Descriptor List Upper Base Address */ +#define HDA_CL_SD_BDLPUBA_SHIFT 0 +#define HDA_CL_SD_BDLPUBA_MASK (0xffffffff << HDA_CL_SD_BDLPUBA_SHIFT) +#define HDA_CL_SD_BDLPUBA(x) \ + ((upper_32_bits(x) << HDA_CL_SD_BDLPUBA_SHIFT) & \ + HDA_CL_SD_BDLPUBA_MASK) + +/* Software Position in Buffer Enable */ +#define HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT 0 +#define HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_MASK \ + (1 << HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) + +#define HDA_CL_SPBFIFO_SPBFCCTL_SPIBE(x) \ + (((x) << HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) & \ + HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_MASK) + +#define HDA_CL_DMA_SD_INT_COMPLETE 0x4 + +static int cl_skl_cldma_setup_bdle(struct snd_sof_dev *sdev, + struct snd_dma_buffer *dmab_data, + __le32 **bdlp, int size, int with_ioc) +{ + phys_addr_t addr = virt_to_phys(dmab_data->area); + __le32 *bdl = *bdlp; + + /* + * This code is simplified by using one fragment of physical memory and assuming + * all the code fits. This could be improved with scatter-gather but the firmware + * size is limited by DSP memory anyways + */ + bdl[0] = cpu_to_le32(lower_32_bits(addr)); + bdl[1] = cpu_to_le32(upper_32_bits(addr)); + bdl[2] = cpu_to_le32(size); + bdl[3] = (!with_ioc) ? 0 : cpu_to_le32(0x01); + + return 1; /* one fragment */ +} + +static void cl_skl_cldma_stream_run(struct snd_sof_dev *sdev, bool enable) +{ + int sd_offset = SOF_HDA_ADSP_LOADER_BASE; + unsigned char val; + int retries; + u32 run = enable ? 0x1 : 0; + + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL, + HDA_CL_SD_CTL_RUN(1), HDA_CL_SD_CTL_RUN(run)); + + retries = 300; + do { + udelay(3); + + /* waiting for hardware to report the stream Run bit set */ + val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL); + val &= HDA_CL_SD_CTL_RUN(1); + if (enable && val) + break; + else if (!enable && !val) + break; + } while (--retries); + + if (retries == 0) + dev_err(sdev->dev, "%s: failed to set Run bit=%d enable=%d\n", + __func__, val, enable); +} + +static void cl_skl_cldma_stream_clear(struct snd_sof_dev *sdev) +{ + int sd_offset = SOF_HDA_ADSP_LOADER_BASE; + + /* make sure Run bit is cleared before setting stream register */ + cl_skl_cldma_stream_run(sdev, 0); + + /* Disable the Interrupt On Completion, FIFO Error Interrupt, + * Descriptor Error Interrupt and set the cldma stream number to 0. + */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL, + HDA_CL_SD_CTL_INT_MASK, HDA_CL_SD_CTL_INT(0)); + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL, + HDA_CL_SD_CTL_STRM(0xf), HDA_CL_SD_CTL_STRM(0)); + + snd_sof_dsp_write(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, HDA_CL_SD_BDLPLBA(0)); + snd_sof_dsp_write(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, 0); + + /* Set the Cyclic Buffer Length to 0. */ + snd_sof_dsp_write(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_CBL, 0); + /* Set the Last Valid Index. */ + snd_sof_dsp_write(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI, 0); +} + +static void cl_skl_cldma_setup_spb(struct snd_sof_dev *sdev, + unsigned int size, bool enable) +{ + int sd_offset = SOF_DSP_REG_CL_SPBFIFO; + + if (enable) + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SPBFIFO_SPBFCCTL, + HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_MASK, + HDA_CL_SPBFIFO_SPBFCCTL_SPIBE(1)); + + snd_sof_dsp_write(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SPBFIFO_SPIB, size); +} + +static void cl_skl_cldma_set_intr(struct snd_sof_dev *sdev, bool enable) +{ + u32 val = enable ? HDA_DSP_ADSPIC_CL_DMA : 0; + + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, + HDA_DSP_ADSPIC_CL_DMA, val); +} + +static void cl_skl_cldma_cleanup_spb(struct snd_sof_dev *sdev) +{ + int sd_offset = SOF_DSP_REG_CL_SPBFIFO; + + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SPBFIFO_SPBFCCTL, + HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_MASK, + HDA_CL_SPBFIFO_SPBFCCTL_SPIBE(0)); + + snd_sof_dsp_write(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SPBFIFO_SPIB, 0); +} + +static void cl_skl_cldma_setup_controller(struct snd_sof_dev *sdev, + struct snd_dma_buffer *dmab_bdl, + unsigned int max_size, u32 count) +{ + int sd_offset = SOF_HDA_ADSP_LOADER_BASE; + + /* Clear the stream first and then set it. */ + cl_skl_cldma_stream_clear(sdev); + + /* setting the stream register */ + snd_sof_dsp_write(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, + HDA_CL_SD_BDLPLBA(dmab_bdl->addr)); + snd_sof_dsp_write(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, + HDA_CL_SD_BDLPUBA(dmab_bdl->addr)); + + /* Set the Cyclic Buffer Length. */ + snd_sof_dsp_write(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_CBL, max_size); + /* Set the Last Valid Index. */ + snd_sof_dsp_write(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI, count - 1); + + /* Set the Interrupt On Completion, FIFO Error Interrupt, + * Descriptor Error Interrupt and the cldma stream number. + */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL, + HDA_CL_SD_CTL_INT_MASK, HDA_CL_SD_CTL_INT(1)); + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL, + HDA_CL_SD_CTL_STRM(0xf), + HDA_CL_SD_CTL_STRM(1)); +} + +static int cl_stream_prepare_skl(struct snd_sof_dev *sdev, + struct snd_dma_buffer *dmab, + struct snd_dma_buffer *dmab_bdl) + +{ + unsigned int bufsize = HDA_SKL_CLDMA_MAX_BUFFER_SIZE; + __le32 *bdl; + int frags; + int ret; + + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->dev, bufsize, dmab); + if (ret < 0) { + dev_err(sdev->dev, "%s: failed to alloc fw buffer: %x\n", __func__, ret); + return ret; + } + + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->dev, bufsize, dmab_bdl); + if (ret < 0) { + dev_err(sdev->dev, "%s: failed to alloc blde: %x\n", __func__, ret); + snd_dma_free_pages(dmab); + return ret; + } + + bdl = (__le32 *)dmab_bdl->area; + frags = cl_skl_cldma_setup_bdle(sdev, dmab, &bdl, bufsize, 1); + cl_skl_cldma_setup_controller(sdev, dmab_bdl, bufsize, frags); + + return ret; +} + +static void cl_cleanup_skl(struct snd_sof_dev *sdev, + struct snd_dma_buffer *dmab, + struct snd_dma_buffer *dmab_bdl) +{ + cl_skl_cldma_cleanup_spb(sdev); + cl_skl_cldma_stream_clear(sdev); + snd_dma_free_pages(dmab); + snd_dma_free_pages(dmab_bdl); +} + +static int cl_dsp_init_skl(struct snd_sof_dev *sdev, + struct snd_dma_buffer *dmab, + struct snd_dma_buffer *dmab_bdl) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; + unsigned int status; + u32 flags; + int ret; + + /* check if the init_core is already enabled, if yes, reset and make it run, + * if not, powerdown and enable it again. + */ + if (hda_dsp_core_is_enabled(sdev, chip->init_core_mask)) { + /* if enabled, reset it, and run the init_core. */ + ret = hda_dsp_core_stall_reset(sdev, chip->init_core_mask); + if (ret < 0) + goto err; + + ret = hda_dsp_core_run(sdev, chip->init_core_mask); + if (ret < 0) { + dev_err(sdev->dev, "%s: dsp core start failed %d\n", __func__, ret); + goto err; + } + } else { + /* if not enabled, power down it first and then powerup and run + * the init_core. + */ + ret = hda_dsp_core_reset_power_down(sdev, chip->init_core_mask); + if (ret < 0) { + dev_err(sdev->dev, "%s: dsp core0 disable fail: %d\n", __func__, ret); + goto err; + } + ret = hda_dsp_enable_core(sdev, chip->init_core_mask); + if (ret < 0) { + dev_err(sdev->dev, "%s: dsp core0 enable fail: %d\n", __func__, ret); + goto err; + } + } + + /* prepare DMA for code loader stream */ + ret = cl_stream_prepare_skl(sdev, dmab, dmab_bdl); + if (ret < 0) { + dev_err(sdev->dev, "%s: dma prepare fw loading err: %x\n", __func__, ret); + return ret; + } + + /* enable the interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, + HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); + + /* enable IPC DONE interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, + HDA_DSP_REG_HIPCCTL_DONE, + HDA_DSP_REG_HIPCCTL_DONE); + + /* enable IPC BUSY interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, + HDA_DSP_REG_HIPCCTL_BUSY, + HDA_DSP_REG_HIPCCTL_BUSY); + + /* polling the ROM init status information. */ + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + chip->rom_status_reg, status, + (FSR_TO_STATE_CODE(status) + == FSR_STATE_INIT_DONE), + HDA_DSP_REG_POLL_INTERVAL_US, + chip->rom_init_timeout * + USEC_PER_MSEC); + if (ret < 0) + goto err; + + return ret; + +err: + flags = SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX; + + snd_sof_dsp_dbg_dump(sdev, "Boot failed\n", flags); + cl_cleanup_skl(sdev, dmab, dmab_bdl); + hda_dsp_core_reset_power_down(sdev, chip->init_core_mask); + return ret; +} + +static void cl_skl_cldma_fill_buffer(struct snd_sof_dev *sdev, + struct snd_dma_buffer *dmab, + unsigned int bufsize, + unsigned int copysize, + const void *curr_pos, + bool intr_enable) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + + /* copy the image into the buffer with the maximum buffer size. */ + unsigned int size = (bufsize == copysize) ? bufsize : copysize; + + memcpy(dmab->area, curr_pos, size); + + /* Set the wait condition for every load. */ + hda->code_loading = 1; + + /* Set the interrupt. */ + if (intr_enable) + cl_skl_cldma_set_intr(sdev, true); + + /* Set the SPB. */ + cl_skl_cldma_setup_spb(sdev, size, true); + + /* Trigger the code loading stream. */ + cl_skl_cldma_stream_run(sdev, true); +} + +static int cl_skl_cldma_wait_interruptible(struct snd_sof_dev *sdev, + bool intr_wait) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; + int sd_offset = SOF_HDA_ADSP_LOADER_BASE; + u8 cl_dma_intr_status; + + /* + * Wait for CLDMA interrupt to inform the binary segment transfer is + * complete. + */ + if (!wait_event_timeout(hda->waitq, !hda->code_loading, + msecs_to_jiffies(HDA_SKL_WAIT_TIMEOUT))) { + dev_err(sdev->dev, "cldma copy timeout\n"); + dev_err(sdev->dev, "ROM code=%#x: FW status=%#x\n", + snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_ROM_ERROR), + snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->rom_status_reg)); + return -EIO; + } + + /* now check DMA interrupt status */ + cl_dma_intr_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS); + + if (!(cl_dma_intr_status & HDA_CL_DMA_SD_INT_COMPLETE)) { + dev_err(sdev->dev, "cldma copy failed\n"); + return -EIO; + } + + dev_dbg(sdev->dev, "cldma buffer copy complete\n"); + return 0; +} + +static int +cl_skl_cldma_copy_to_buf(struct snd_sof_dev *sdev, + struct snd_dma_buffer *dmab, + const void *bin, + u32 total_size, u32 bufsize) +{ + unsigned int bytes_left = total_size; + const void *curr_pos = bin; + int ret; + + if (total_size <= 0) + return -EINVAL; + + while (bytes_left > 0) { + if (bytes_left > bufsize) { + dev_dbg(sdev->dev, "cldma copy %#x bytes\n", bufsize); + + cl_skl_cldma_fill_buffer(sdev, dmab, bufsize, bufsize, curr_pos, true); + + ret = cl_skl_cldma_wait_interruptible(sdev, false); + if (ret < 0) { + dev_err(sdev->dev, "%s: fw failed to load. %#x bytes remaining\n", + __func__, bytes_left); + return ret; + } + + bytes_left -= bufsize; + curr_pos += bufsize; + } else { + dev_dbg(sdev->dev, "cldma copy %#x bytes\n", bytes_left); + + cl_skl_cldma_set_intr(sdev, false); + cl_skl_cldma_fill_buffer(sdev, dmab, bufsize, bytes_left, curr_pos, false); + return 0; + } + } + + return bytes_left; +} + +static int cl_copy_fw_skl(struct snd_sof_dev *sdev, + struct snd_dma_buffer *dmab) + +{ + struct snd_sof_pdata *plat_data = sdev->pdata; + const struct firmware *fw = plat_data->fw; + struct firmware stripped_firmware; + unsigned int bufsize = HDA_SKL_CLDMA_MAX_BUFFER_SIZE; + int ret; + + stripped_firmware.data = plat_data->fw->data + plat_data->fw_offset; + stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset; + + dev_dbg(sdev->dev, "firmware size: %#zx buffer size %#x\n", fw->size, bufsize); + + ret = cl_skl_cldma_copy_to_buf(sdev, dmab, stripped_firmware.data, + stripped_firmware.size, bufsize); + if (ret < 0) + dev_err(sdev->dev, "%s: fw copy failed %d\n", __func__, ret); + + return ret; +} + +int hda_dsp_cl_boot_firmware_skl(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 snd_dma_buffer dmab_bdl; + struct snd_dma_buffer dmab; + unsigned int reg; + u32 flags; + int ret; + + ret = cl_dsp_init_skl(sdev, &dmab, &dmab_bdl); + + /* retry enabling core and ROM load. seemed to help */ + if (ret < 0) { + ret = cl_dsp_init_skl(sdev, &dmab, &dmab_bdl); + if (ret < 0) { + dev_err(sdev->dev, "Error code=%#x: FW status=%#x\n", + snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_ROM_ERROR), + snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->rom_status_reg)); + dev_err(sdev->dev, "Core En/ROM load fail:%d\n", ret); + return ret; + } + } + + dev_dbg(sdev->dev, "ROM init successful\n"); + + /* at this point DSP ROM has been initialized and should be ready for + * code loading and firmware boot + */ + ret = cl_copy_fw_skl(sdev, &dmab); + if (ret < 0) { + dev_err(sdev->dev, "%s: load firmware failed : %d\n", __func__, ret); + goto err; + } + + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + chip->rom_status_reg, reg, + (FSR_TO_STATE_CODE(reg) + == FSR_STATE_ROM_BASEFW_ENTERED), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_BASEFW_TIMEOUT_US); + + dev_dbg(sdev->dev, "Firmware download successful, booting...\n"); + + cl_skl_cldma_stream_run(sdev, false); + cl_cleanup_skl(sdev, &dmab, &dmab_bdl); + + if (!ret) + return chip->init_core_mask; + + return ret; + +err: + flags = SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX; + + snd_sof_dsp_dbg_dump(sdev, "Boot failed\n", flags); + + /* power down DSP */ + hda_dsp_core_reset_power_down(sdev, chip->init_core_mask); + cl_skl_cldma_stream_run(sdev, false); + cl_cleanup_skl(sdev, &dmab, &dmab_bdl); + + dev_err(sdev->dev, "%s: load fw failed err: %d\n", __func__, ret); + return ret; +} diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 04b730f754d7..6ad8dafce098 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -229,6 +229,7 @@ #define FSR_STATE_ROM_GET_LOAD_OFFSET 0x7 #define FSR_STATE_ROM_FETCH_ROM_EXT 0x8 #define FSR_STATE_ROM_FETCH_ROM_EXT_DONE 0x9 +#define FSR_STATE_ROM_BASEFW_ENTERED 0xf /* SKL */ /* (ROM) CSE states */ #define FSR_STATE_ROM_CSE_IMR_REQUEST 0x10 @@ -514,6 +515,9 @@ struct sof_intel_hda_dev { /* FW clock config, 0:HPRO, 1:LPRO */ bool clk_config_lpro; + wait_queue_head_t waitq; + bool code_loading; + /* Intel NHLT information */ struct nhlt_acpi_table *nhlt; }; @@ -834,6 +838,8 @@ extern int sof_hda_position_quirk; void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops); void hda_ops_free(struct snd_sof_dev *sdev); +/* SKL/KBL */ +int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev); int hda_dsp_core_stall_reset(struct snd_sof_dev *sdev, unsigned int core_mask); /* IPC4 */ -- cgit v1.2.3 From e2379d4a83da44816009971e932db31e665d41a1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 20 Sep 2022 15:16:59 +0200 Subject: ASoC: SOF: Intel: add initial SKL/KBL hardware support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation of the IPCv4 IPC support, this patch adds support for SkyLake and KabyLake boot and descriptors used when probing the PCI driver. The work was initially contributed in 2018 by Liam Girdwood and Zhu Yingjiang, and abandoned due to firmware signature issues. With the upcoming support of IPC v4, and hence the Intel closed-source firmware, it's time to re-add this capability. The SKL ops will be added in the next patch. Tested with the IPC4 and closed-source firmware on Dell XPS 9350 and KBL NUC with HDaudio codecs. The SSP and DMIC interfaces are not supported at this time. Co-developed-by: Ranjani Sridharan Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Reviewed-by: Péter Ujfalusi Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220920131700.133103-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/Kconfig | 25 ++++++++++ sound/soc/sof/intel/Makefile | 4 ++ sound/soc/sof/intel/hda-ipc.c | 8 ++++ sound/soc/sof/intel/hda-loader-skl.c | 7 +-- sound/soc/sof/intel/hda.c | 2 + sound/soc/sof/intel/hda.h | 4 ++ sound/soc/sof/intel/pci-skl.c | 89 ++++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/skl.c | 70 ++++++++++++++++++++++++++++ 8 files changed, 204 insertions(+), 5 deletions(-) create mode 100644 sound/soc/sof/intel/pci-skl.c create mode 100644 sound/soc/sof/intel/skl.c diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 3f54678e810b..7af495fb6125 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -95,6 +95,31 @@ config SND_SOC_SOF_MERRIFIELD Say Y if you have such a device. If unsure select "N". +config SND_SOC_SOF_INTEL_SKL + tristate + select SND_SOC_SOF_HDA_COMMON + select SND_SOC_SOF_INTEL_IPC4 + +config SND_SOC_SOF_SKYLAKE + tristate "SOF support for SkyLake" + default SND_SOC_SOF_PCI + select SND_SOC_SOF_INTEL_SKL + help + This adds support for the Intel(R) platforms using the SkyLake processors. + Say Y if you have such a device. + If unsure select "N". + This is intended only for developers and not a recommend option for distros. + +config SND_SOC_SOF_KABYLAKE + tristate "SOF support for KabyLake" + default SND_SOC_SOF_PCI + select SND_SOC_SOF_INTEL_SKL + help + This adds support for the Intel(R) platforms using the KabyLake processors. + Say Y if you have such a device. + If unsure select "N". + This is intended only for developers and not a recommend option for distros. + config SND_SOC_SOF_INTEL_APL tristate select SND_SOC_SOF_HDA_COMMON diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile index a079159bb2f0..8b8ea0361785 100644 --- a/sound/soc/sof/intel/Makefile +++ b/sound/soc/sof/intel/Makefile @@ -6,7 +6,9 @@ snd-sof-acpi-intel-bdw-objs := bdw.o snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \ hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \ hda-dai.o hda-bus.o \ + skl.o hda-loader-skl.o \ apl.o cnl.o tgl.o icl.o mtl.o hda-common-ops.o + snd-sof-intel-hda-common-$(CONFIG_SND_SOC_SOF_HDA_PROBES) += hda-probes.o snd-sof-intel-hda-objs := hda-codec.o @@ -20,6 +22,7 @@ obj-$(CONFIG_SND_SOC_SOF_HDA_COMMON) += snd-sof-intel-hda-common.o obj-$(CONFIG_SND_SOC_SOF_HDA) += snd-sof-intel-hda.o snd-sof-pci-intel-tng-objs := pci-tng.o +snd-sof-pci-intel-skl-objs := pci-skl.o snd-sof-pci-intel-apl-objs := pci-apl.o snd-sof-pci-intel-cnl-objs := pci-cnl.o snd-sof-pci-intel-icl-objs := pci-icl.o @@ -27,6 +30,7 @@ snd-sof-pci-intel-tgl-objs := pci-tgl.o snd-sof-pci-intel-mtl-objs := pci-mtl.o obj-$(CONFIG_SND_SOC_SOF_MERRIFIELD) += snd-sof-pci-intel-tng.o +obj-$(CONFIG_SND_SOC_SOF_INTEL_SKL) += snd-sof-pci-intel-skl.o obj-$(CONFIG_SND_SOC_SOF_INTEL_APL) += snd-sof-pci-intel-apl.o obj-$(CONFIG_SND_SOC_SOF_INTEL_CNL) += snd-sof-pci-intel-cnl.o obj-$(CONFIG_SND_SOC_SOF_INTEL_ICL) += snd-sof-pci-intel-icl.o diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index c597ef491d38..9b3667c705e4 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -304,6 +304,7 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) /* Check if an IPC IRQ occurred */ bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev) { + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; bool ret = false; u32 irq_status; @@ -319,6 +320,13 @@ bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev) if (irq_status & HDA_DSP_ADSPIS_IPC) ret = true; + /* CLDMA message ? */ + if (irq_status & HDA_DSP_ADSPIS_CL_DMA) { + hda->code_loading = 0; + wake_up(&hda->waitq); + ret = false; + } + out: return ret; } diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c index 6f7e7444f11c..0193fb3964a0 100644 --- a/sound/soc/sof/intel/hda-loader-skl.c +++ b/sound/soc/sof/intel/hda-loader-skl.c @@ -93,17 +93,14 @@ /* Buffer Descriptor List Lower Base Address */ #define HDA_CL_SD_BDLPLBA_SHIFT 7 -#define HDA_CL_SD_BDLPLBA_MASK (0x1ffffff << HDA_CL_SD_BDLPLBA_SHIFT) +#define HDA_CL_SD_BDLPLBA_MASK GENMASK(31, 7) #define HDA_CL_SD_BDLPLBA(x) \ ((BDL_ALIGN(lower_32_bits(x)) << HDA_CL_SD_BDLPLBA_SHIFT) & \ HDA_CL_SD_BDLPLBA_MASK) /* Buffer Descriptor List Upper Base Address */ -#define HDA_CL_SD_BDLPUBA_SHIFT 0 -#define HDA_CL_SD_BDLPUBA_MASK (0xffffffff << HDA_CL_SD_BDLPUBA_SHIFT) #define HDA_CL_SD_BDLPUBA(x) \ - ((upper_32_bits(x) << HDA_CL_SD_BDLPUBA_SHIFT) & \ - HDA_CL_SD_BDLPUBA_MASK) + (upper_32_bits(x)) /* Software Position in Buffer Enable */ #define HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT 0 diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index eec54c8bb0e9..f7068a7e2e81 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -1136,6 +1136,8 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) INIT_DELAYED_WORK(&hdev->d0i3_work, hda_dsp_d0i3_work); + init_waitqueue_head(&hdev->waitq); + hdev->nhlt = intel_nhlt_init(sdev->dev); return 0; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 6ad8dafce098..2013a94020c6 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -419,6 +419,7 @@ #endif /* Intel HD Audio SRAM Window 0*/ +#define HDA_DSP_SRAM_REG_ROM_STATUS_SKL 0x8000 #define HDA_ADSP_SRAM0_BASE_SKL 0x8000 /* Firmware status window */ @@ -774,6 +775,8 @@ int hda_dsp_dais_suspend(struct snd_sof_dev *sdev); */ extern struct snd_sof_dsp_ops sof_hda_common_ops; +extern struct snd_sof_dsp_ops sof_skl_ops; +int sof_skl_ops_init(struct snd_sof_dev *sdev); extern struct snd_sof_dsp_ops sof_apl_ops; int sof_apl_ops_init(struct snd_sof_dev *sdev); extern struct snd_sof_dsp_ops sof_cnl_ops; @@ -785,6 +788,7 @@ int sof_icl_ops_init(struct snd_sof_dev *sdev); extern struct snd_sof_dsp_ops sof_mtl_ops; int sof_mtl_ops_init(struct snd_sof_dev *sdev); +extern const struct sof_intel_dsp_desc skl_chip_info; extern const struct sof_intel_dsp_desc apl_chip_info; extern const struct sof_intel_dsp_desc cnl_chip_info; extern const struct sof_intel_dsp_desc icl_chip_info; diff --git a/sound/soc/sof/intel/pci-skl.c b/sound/soc/sof/intel/pci-skl.c new file mode 100644 index 000000000000..2b803f8b32e9 --- /dev/null +++ b/sound/soc/sof/intel/pci-skl.c @@ -0,0 +1,89 @@ +// 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) 2018-2022 Intel Corporation. All rights reserved. +// + +#include +#include +#include +#include +#include +#include "../ops.h" +#include "../sof-pci-dev.h" + +/* platform specific devices */ +#include "hda.h" + +static struct sof_dev_desc skl_desc = { + .machines = snd_soc_acpi_intel_skl_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .chip_info = &skl_chip_info, + .irqindex_host_ipc = -1, + .ipc_supported_mask = BIT(SOF_INTEL_IPC4), + .ipc_default = SOF_INTEL_IPC4, + .default_fw_path = { + [SOF_INTEL_IPC4] = "intel/avs/skl", + }, + .default_tplg_path = { + [SOF_INTEL_IPC4] = "intel/avs-tplg", + }, + .default_fw_filename = { + [SOF_INTEL_IPC4] = "dsp_basefw.bin", + }, + .nocodec_tplg_filename = "sof-skl-nocodec.tplg", + .ops = &sof_skl_ops, +}; + +static struct sof_dev_desc kbl_desc = { + .machines = snd_soc_acpi_intel_kbl_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .chip_info = &skl_chip_info, + .irqindex_host_ipc = -1, + .ipc_supported_mask = BIT(SOF_INTEL_IPC4), + .ipc_default = SOF_INTEL_IPC4, + .default_fw_path = { + [SOF_INTEL_IPC4] = "intel/avs/kbl", + }, + .default_tplg_path = { + [SOF_INTEL_IPC4] = "intel/avs-tplg", + }, + .default_fw_filename = { + [SOF_INTEL_IPC4] = "dsp_basefw.bin", + }, + .nocodec_tplg_filename = "sof-kbl-nocodec.tplg", + .ops = &sof_skl_ops, +}; + +/* PCI IDs */ +static const struct pci_device_id sof_pci_ids[] = { + /* Sunrise Point-LP */ + { PCI_DEVICE(0x8086, 0x9d70), .driver_data = (unsigned long)&skl_desc}, + /* KBL */ + { PCI_DEVICE(0x8086, 0x9d71), .driver_data = (unsigned long)&kbl_desc}, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, sof_pci_ids); + +/* pci_driver definition */ +static struct pci_driver snd_sof_pci_intel_skl_driver = { + .name = "sof-audio-pci-intel-skl", + .id_table = sof_pci_ids, + .probe = hda_pci_intel_probe, + .remove = sof_pci_remove, + .shutdown = sof_pci_shutdown, + .driver = { + .pm = &sof_pci_pm, + }, +}; +module_pci_driver(snd_sof_pci_intel_skl_driver); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON); +MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c new file mode 100644 index 000000000000..446a7afddfdb --- /dev/null +++ b/sound/soc/sof/intel/skl.c @@ -0,0 +1,70 @@ +// 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) 2018-2022 Intel Corporation. All rights reserved. +// + +/* + * Hardware interface for audio DSP on Skylake and Kabylake. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../sof-priv.h" +#include "../ops.h" +#include "hda.h" +#include "../sof-audio.h" + +#define SRAM_MEMORY_WINDOW_BASE 0x8000 + +static const __maybe_unused struct snd_sof_debugfs_map skl_dsp_debugfs[] = { + {"hda", HDA_DSP_HDA_BAR, 0, 0x4000}, + {"pp", HDA_DSP_PP_BAR, 0, 0x1000}, + {"dsp", HDA_DSP_BAR, 0, 0x10000}, +}; + +static int __maybe_unused skl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id) +{ + return SRAM_MEMORY_WINDOW_BASE + (0x2000 * id); +} + +/* skylake ops */ +struct snd_sof_dsp_ops sof_skl_ops = { + /* + * the ops are left empty at this stage since the SOF releases do not + * support SKL/KBL. + * The ops will be populated when support for the Intel IPC4 is added + * to the SOF driver + */ +}; +EXPORT_SYMBOL(sof_skl_ops); + +const struct sof_intel_dsp_desc skl_chip_info = { + .cores_num = 2, + .init_core_mask = 1, + .host_managed_cores_mask = GENMASK(1, 0), + .ipc_req = HDA_DSP_REG_HIPCI, + .ipc_req_mask = HDA_DSP_REG_HIPCI_BUSY, + .ipc_ack = HDA_DSP_REG_HIPCIE, + .ipc_ack_mask = HDA_DSP_REG_HIPCIE_DONE, + .ipc_ctl = HDA_DSP_REG_HIPCCTL, + .rom_status_reg = HDA_DSP_SRAM_REG_ROM_STATUS_SKL, + .rom_init_timeout = 300, + .check_ipc_irq = hda_dsp_check_ipc_irq, + .hw_ip_version = SOF_INTEL_CAVS_1_5, +}; +EXPORT_SYMBOL_NS(skl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); -- cgit v1.2.3 From 52d7939d10f25bc6635caa4d390e79a034626f79 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 20 Sep 2022 15:17:00 +0200 Subject: ASoC: SOF: Intel: add ops for SKL/KBL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add ops and ops_init for SKL and KBL. Tested on Dell XPS-13-9350 and KBL NUC. Note: currently only SOF_IPC4_MTRACE_INTEL_CAVS_2 type is supported by the ipc4-mtrace driver, which is used by CAVS 2.x platforms (ICL, TGL, ADL) and ACE (MTL). Signed-off-by: Ranjani Sridharan Signed-off-by: Péter Ujfalusi Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220920131700.133103-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/pci-skl.c | 2 ++ sound/soc/sof/intel/skl.c | 64 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 57 insertions(+), 9 deletions(-) diff --git a/sound/soc/sof/intel/pci-skl.c b/sound/soc/sof/intel/pci-skl.c index 2b803f8b32e9..3a99dc444f92 100644 --- a/sound/soc/sof/intel/pci-skl.c +++ b/sound/soc/sof/intel/pci-skl.c @@ -37,6 +37,7 @@ static struct sof_dev_desc skl_desc = { }, .nocodec_tplg_filename = "sof-skl-nocodec.tplg", .ops = &sof_skl_ops, + .ops_init = sof_skl_ops_init, }; static struct sof_dev_desc kbl_desc = { @@ -59,6 +60,7 @@ static struct sof_dev_desc kbl_desc = { }, .nocodec_tplg_filename = "sof-kbl-nocodec.tplg", .ops = &sof_skl_ops, + .ops_init = sof_skl_ops_init, }; /* PCI IDs */ diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index 446a7afddfdb..f05905e00368 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -23,8 +23,10 @@ #include #include #include +#include #include "../sof-priv.h" +#include "../ipc4-priv.h" #include "../ops.h" #include "hda.h" #include "../sof-audio.h" @@ -37,21 +39,65 @@ static const __maybe_unused struct snd_sof_debugfs_map skl_dsp_debugfs[] = { {"dsp", HDA_DSP_BAR, 0, 0x10000}, }; -static int __maybe_unused skl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id) +static int skl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id) { return SRAM_MEMORY_WINDOW_BASE + (0x2000 * id); } +static int skl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) +{ + return SRAM_MEMORY_WINDOW_BASE + 0x1000; +} + /* skylake ops */ -struct snd_sof_dsp_ops sof_skl_ops = { - /* - * the ops are left empty at this stage since the SOF releases do not - * support SKL/KBL. - * The ops will be populated when support for the Intel IPC4 is added - * to the SOF driver - */ +struct snd_sof_dsp_ops sof_skl_ops; +EXPORT_SYMBOL_NS(sof_skl_ops, SND_SOC_SOF_INTEL_HDA_COMMON); + +int sof_skl_ops_init(struct snd_sof_dev *sdev) +{ + struct sof_ipc4_fw_data *ipc4_data; + + /* common defaults */ + memcpy(&sof_skl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops)); + + /* probe/remove/shutdown */ + sof_skl_ops.shutdown = hda_dsp_shutdown; + + sdev->private = devm_kzalloc(sdev->dev, sizeof(*ipc4_data), GFP_KERNEL); + if (!sdev->private) + return -ENOMEM; + + ipc4_data = sdev->private; + ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET_CAVS_1_5; + + ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_1_5; + + sof_skl_ops.get_window_offset = skl_dsp_ipc_get_window_offset; + sof_skl_ops.get_mailbox_offset = skl_dsp_ipc_get_mailbox_offset; + + /* doorbell */ + sof_skl_ops.irq_thread = hda_dsp_ipc4_irq_thread; + + /* ipc */ + sof_skl_ops.send_msg = hda_dsp_ipc4_send_msg; + + /* set DAI driver ops */ + hda_set_dai_drv_ops(sdev, &sof_skl_ops); + + /* debug */ + sof_skl_ops.debug_map = skl_dsp_debugfs; + sof_skl_ops.debug_map_count = ARRAY_SIZE(skl_dsp_debugfs); + sof_skl_ops.ipc_dump = hda_ipc_dump; + + /* firmware run */ + sof_skl_ops.run = hda_dsp_cl_boot_firmware_skl; + + /* pre/post fw run */ + sof_skl_ops.post_fw_run = hda_dsp_post_fw_run; + + return 0; }; -EXPORT_SYMBOL(sof_skl_ops); +EXPORT_SYMBOL_NS(sof_skl_ops_init, SND_SOC_SOF_INTEL_HDA_COMMON); const struct sof_intel_dsp_desc skl_chip_info = { .cores_num = 2, -- cgit v1.2.3 From ce59804d26432d7e2c1a8c906245a230a2b4505c Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Tue, 20 Sep 2022 17:01:06 +0200 Subject: ASoC: SOF: clear prepare state when widget is unprepared Playback can't work after the first try sometimes. The reason is that some widgets don't have ipc_unprepare ops and driver will jump to sink_prepare so miss to set prepare state to false. Next time these widgets will not be prepared and it will result to error with different format of audio file since the last setting is not applicable. This patch makes sure that widget prepare state will be cleared to false when it is unprepared. Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220920150107.2090695-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-audio.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index a3d3dd7a0037..71cea83889fb 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -271,14 +271,16 @@ sof_unprepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widg struct snd_sof_widget *swidget = widget->dobj.private; struct snd_soc_dapm_path *p; - if (!widget_ops[widget->id].ipc_unprepare || !swidget->prepared) - goto sink_unprepare; + /* it is already unprepared */ + if (!swidget->prepared) + return; + + if (widget_ops[widget->id].ipc_unprepare) + /* unprepare the source widget */ + widget_ops[widget->id].ipc_unprepare(swidget); - /* unprepare the source widget */ - widget_ops[widget->id].ipc_unprepare(swidget); swidget->prepared = false; -sink_unprepare: /* unprepare all widgets in the sink paths */ snd_soc_dapm_widget_for_each_sink_path(widget, p) { if (!p->walking && p->sink->dobj.private) { -- cgit v1.2.3 From 9862dcf70245c2d03764012b81966d8c2ea95a48 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Tue, 20 Sep 2022 17:01:07 +0200 Subject: ASoC: SOF: don't unprepare widget used other pipelines If multiple pipeline are mixed into one, we can't unprepare the widget used by other pipelines. This patch checks use_count to address this case. Reviewed-by: Bard Liao Reviewed-by: Ranjani Sridharan Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220920150107.2090695-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-audio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 71cea83889fb..62092e2d609c 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -271,8 +271,8 @@ sof_unprepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widg struct snd_sof_widget *swidget = widget->dobj.private; struct snd_soc_dapm_path *p; - /* it is already unprepared */ - if (!swidget->prepared) + /* return if the widget is in use or if it is already unprepared */ + if (!swidget->prepared || swidget->use_count > 1) return; if (widget_ops[widget->id].ipc_unprepare) -- cgit v1.2.3 From 80d53171f85a8e97b2aa1d50045dbc1b5dd1bc97 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 20 Sep 2022 16:54:04 +0200 Subject: ASoC: SOF: ipc4-topology: clarify calculation precedence cppcheck warning: sound/soc/sof/ipc4-topology.c:334:64: style: Clarify calculation precedence for '&' and '?'. [clarifyCalculation] type = fw_module->man4_module_entry.type & SOF_IPC4_MODULE_DP ? 1 : 0; ^ Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Chao Song Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20220920145405.2089147-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 64929dc9af39..1503e3c49e70 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -331,7 +331,7 @@ static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_ msg->extension = SOF_IPC4_MOD_EXT_PPL_ID(swidget->pipeline_id); msg->extension |= SOF_IPC4_MOD_EXT_CORE_ID(swidget->core); - type = fw_module->man4_module_entry.type & SOF_IPC4_MODULE_DP ? 1 : 0; + type = (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_DP) ? 1 : 0; msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(type); return 0; -- cgit v1.2.3 From 7738211bce7ae43624121fcf121aec87b2149af1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 20 Sep 2022 16:54:05 +0200 Subject: ASoC: SOF: ipc4-topology: remove useless assignment cppcheck warning: sound/soc/sof/ipc4-topology.c:1533:12: style: Variable 'pipeline' is assigned a value that is never used. [unreadVariable] pipeline = pipe_widget->private; ^ Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Chao Song Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20220920145405.2089147-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 1503e3c49e70..66bbe101680c 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1447,7 +1447,6 @@ static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_contr static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) { - struct snd_sof_widget *pipe_widget = swidget->pipe_widget; struct sof_ipc4_pipeline *pipeline; struct sof_ipc4_msg *msg; void *ipc_data = NULL; @@ -1530,7 +1529,7 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget swidget->widget->name); return ret; } - pipeline = pipe_widget->private; + msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK; msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id); -- cgit v1.2.3 From 9b9def51e1a6de6cd336ae08884f580ebab7d2b2 Mon Sep 17 00:00:00 2001 From: Alexander Martinz Date: Tue, 20 Sep 2022 13:50:14 +0200 Subject: ASoC: codecs: tfa989x: fix register access comments Fix comments regarding register access based on review feedback[1]. [1]: https://lore.kernel.org/all/YppQ7BiqlBDMNsuc@gerhold.net/ Signed-off-by: Alexander Martinz Link: https://lore.kernel.org/r/20220920115014.952062-1-amartinz@shiftphones.com Signed-off-by: Mark Brown --- sound/soc/codecs/tfa989x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/tfa989x.c b/sound/soc/codecs/tfa989x.c index 1c27429b9af6..b853507e65a8 100644 --- a/sound/soc/codecs/tfa989x.c +++ b/sound/soc/codecs/tfa989x.c @@ -193,7 +193,7 @@ static int tfa9890_init(struct regmap *regmap) { int ret; - /* unhide keys to allow updating them */ + /* temporarily allow access to hidden registers */ ret = regmap_write(regmap, TFA989X_HIDE_UNHIDE_KEY, 0x5a6b); if (ret) return ret; @@ -203,7 +203,7 @@ static int tfa9890_init(struct regmap *regmap) if (ret) return ret; - /* hide keys again */ + /* hide registers again */ ret = regmap_write(regmap, TFA989X_HIDE_UNHIDE_KEY, 0x0000); if (ret) return ret; -- cgit v1.2.3 From e7ff7307bb9aaf157d6bea5807a58673dee94a61 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 20 Sep 2022 09:46:17 +0200 Subject: ASoC: Intel: soc-acpi-intel-rpl-match: add rpl_sdca_3_in_1 support Add rpl_sdca_3_in_1 match information. Reviewed-by: Rander Wang Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220920074617.10300-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-rpl-match.c | 80 +++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c index 0b77401e4e6f..9ccf7370157b 100644 --- a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c @@ -15,6 +15,20 @@ static const struct snd_soc_acpi_endpoint single_endpoint = { .group_id = 0, }; +static const struct snd_soc_acpi_endpoint spk_l_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 0, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_r_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 1, + .group_id = 1, +}; + static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { { .adr = 0x000020025D071100ull, @@ -33,6 +47,66 @@ static const struct snd_soc_acpi_link_adr rpl_rvp[] = { {} }; +static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = { + { + .adr = 0x000030025D071101ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt711" + } +}; + +static const struct snd_soc_acpi_adr_device rt1316_1_group1_adr[] = { + { + .adr = 0x000131025D131601ull, /* unique ID is set for some reason */ + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "rt1316-1" + } +}; + +static const struct snd_soc_acpi_adr_device rt1316_3_group1_adr[] = { + { + .adr = 0x000330025D131601ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1316-2" + } +}; + +static const struct snd_soc_acpi_adr_device rt714_2_adr[] = { + { + .adr = 0x000230025D071401ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt714" + } +}; + +static const struct snd_soc_acpi_link_adr rpl_sdca_3_in_1[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_sdca_0_adr), + .adr_d = rt711_sdca_0_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1316_1_group1_adr), + .adr_d = rt1316_1_group1_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt714_2_adr), + .adr_d = rt714_2_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt1316_3_group1_adr), + .adr_d = rt1316_3_group1_adr, + }, + {} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = { {}, }; @@ -40,6 +114,12 @@ EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_rpl_machines); /* this table is used when there is no I2S codec present */ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_sdw_machines[] = { + { + .link_mask = 0xF, /* 4 active links required */ + .links = rpl_sdca_3_in_1, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-rpl-rt711-l0-rt1316-l13-rt714-l2.tplg", + }, { .link_mask = 0x1, /* link0 required */ .links = rpl_rvp, -- cgit v1.2.3 From 2be79d58645465351af5320eb14c70a94724c5ef Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 20 Sep 2022 20:11:06 +0200 Subject: ALSA: usb-audio: Split endpoint setups for hw_params and prepare (take#2) This is a second attempt to fix the bug appearing on Android with the recent kernel; the first try was ff878b408a03 and reverted at commit 79764ec772bc. The details taken from the v1 patch: One of the former changes for the endpoint management was the more consistent setup of endpoints at hw_params. snd_usb_endpoint_configure() is a single function that does the full setup, and it's called from both PCM hw_params and prepare callbacks. Although the EP setup at the prepare phase is usually skipped (by checking need_setup flag), it may be still effective in some cases like suspend/resume that requires the interface setup again. As it's a full and single setup, the invocation of snd_usb_endpoint_configure() includes not only the USB interface setup but also the buffer release and allocation. OTOH, doing the buffer release and re-allocation at PCM prepare phase is rather superfluous, and better to be done only in the hw_params phase. For those optimizations, this patch splits the endpoint setup to two phases: snd_usb_endpoint_set_params() and snd_usb_endpoint_prepare(), to be called from hw_params and from prepare, respectively. Note that this patch changes the driver operation slightly, effectively moving the USB interface setup again to PCM prepare stage instead of hw_params stage, while the buffer allocation and such initializations are still done at hw_params stage. And, the change of the USB interface setup timing (moving to prepare) gave an interesting "fix", too: it was reported that the recent kernels caused silent output at the beginning on playbacks on some devices on Android, and this change casually fixed the regression. It seems that those devices are picky about the sample rate change (or the interface change?), and don't follow the too immediate rate changes. Meanwhile, Android operates the PCM in the following order: - open, then hw_params with the possibly highest sample rate - close without prepare - re-open, hw_params with the normal sample rate - prepare, and start streaming This procedure ended up the hw_params twice with different rates, and because the recent kernel did set up the sample rate twice one and after, it screwed up the device. OTOH, the earlier kernels didn't set up the USB interface at hw_params, hence this problem didn't appear. Now, with this patch, the USB interface setup is again back to the prepare phase, and it works around the problem automagically. Although we should address the sample rate problem in a more solid way in future, let's keep things working as before for now. *** What's new in the take#2 patch: - The regression caused by the v1 patch (bko#216500) was due to the missing check of need_setup flag at hw_params. Now the check is added, and the snd_usb_endpoint_set_params() call is skipped when the running EP is re-opened. - There was another bug in v1 where the clock reference rate wasn't updated at hw_params phase, which may lead to a lack of the proper hw constraints when an application doesn't issue the prepare but only the hw_params call. This patch fixes it as well by tracking the clock rate change in the prepare callback with a new flag "need_update" for the clock reference object, just like others. - The configure_endpoints() are simplified and folded back into snd_usb_pcm_prepare(). Fixes: bf6313a0ff76 ("ALSA: usb-audio: Refactor endpoint management") Fixes: ff878b408a03 ("ALSA: usb-audio: Split endpoint setups for hw_params and prepare") Reported-by: chihhao chen Link: https://lore.kernel.org/r/87e6d6ae69d68dc588ac9acc8c0f24d6188375c3.camel@mediatek.com Link: https://lore.kernel.org/r/20220901124136.4984-1-tiwai@suse.de Link: https://bugzilla.kernel.org/show_bug.cgi?id=216500 Link: https://lore.kernel.org/r/20220920181106.4894-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/endpoint.c | 76 +++++++++++++++++++++++++++++++--------------------- sound/usb/endpoint.h | 6 +++-- sound/usb/pcm.c | 51 ++++++++++++++--------------------- 3 files changed, 70 insertions(+), 63 deletions(-) diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index eb71df9da831..0c94ebc98e90 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -40,6 +40,7 @@ struct snd_usb_clock_ref { unsigned char clock; atomic_t locked; int rate; + bool need_setup; struct list_head list; }; @@ -758,7 +759,8 @@ bool snd_usb_endpoint_compatible(struct snd_usb_audio *chip, * The endpoint needs to be closed via snd_usb_endpoint_close() later. * * Note that this function doesn't configure the endpoint. The substream - * needs to set it up later via snd_usb_endpoint_configure(). + * needs to set it up later via snd_usb_endpoint_set_params() and + * snd_usb_endpoint_prepare(). */ struct snd_usb_endpoint * snd_usb_endpoint_open(struct snd_usb_audio *chip, @@ -1289,15 +1291,39 @@ out_of_memory: return -ENOMEM; } +/* update the rate of the referred clock; return the actual rate */ +static int update_clock_ref_rate(struct snd_usb_audio *chip, + struct snd_usb_endpoint *ep) +{ + struct snd_usb_clock_ref *clock = ep->clock_ref; + int rate = ep->cur_rate; + + if (!clock || clock->rate == rate) + return rate; + if (clock->rate) { + if (atomic_read(&clock->locked)) + return clock->rate; + if (clock->rate != rate) { + usb_audio_err(chip, "Mismatched sample rate %d vs %d for EP 0x%x\n", + clock->rate, rate, ep->ep_num); + return clock->rate; + } + } + clock->rate = rate; + clock->need_setup = true; + return rate; +} + /* * snd_usb_endpoint_set_params: configure an snd_usb_endpoint * + * It's called either from hw_params callback. * Determine the number of URBs to be used on this endpoint. * An endpoint must be configured before it can be started. * An endpoint that is already running can not be reconfigured. */ -static int snd_usb_endpoint_set_params(struct snd_usb_audio *chip, - struct snd_usb_endpoint *ep) +int snd_usb_endpoint_set_params(struct snd_usb_audio *chip, + struct snd_usb_endpoint *ep) { const struct audioformat *fmt = ep->cur_audiofmt; int err; @@ -1349,49 +1375,46 @@ static int snd_usb_endpoint_set_params(struct snd_usb_audio *chip, ep->maxframesize = ep->maxpacksize / ep->cur_frame_bytes; ep->curframesize = ep->curpacksize / ep->cur_frame_bytes; - return 0; + return update_clock_ref_rate(chip, ep); } static int init_sample_rate(struct snd_usb_audio *chip, struct snd_usb_endpoint *ep) { struct snd_usb_clock_ref *clock = ep->clock_ref; - int err; + int rate, err; - if (clock) { - if (atomic_read(&clock->locked)) - return 0; - if (clock->rate == ep->cur_rate) - return 0; - if (clock->rate && clock->rate != ep->cur_rate) { - usb_audio_dbg(chip, "Mismatched sample rate %d vs %d for EP 0x%x\n", - clock->rate, ep->cur_rate, ep->ep_num); - return -EINVAL; - } - } + rate = update_clock_ref_rate(chip, ep); + if (rate < 0) + return rate; + if (clock && !clock->need_setup) + return 0; - err = snd_usb_init_sample_rate(chip, ep->cur_audiofmt, ep->cur_rate); - if (err < 0) + err = snd_usb_init_sample_rate(chip, ep->cur_audiofmt, rate); + if (err < 0) { + if (clock) + clock->rate = 0; /* reset rate */ return err; + } if (clock) - clock->rate = ep->cur_rate; + clock->need_setup = false; return 0; } /* - * snd_usb_endpoint_configure: Configure the endpoint + * snd_usb_endpoint_prepare: Prepare the endpoint * * This function sets up the EP to be fully usable state. - * It's called either from hw_params or prepare callback. + * It's called either from prepare callback. * The function checks need_setup flag, and performs nothing unless needed, * so it's safe to call this multiple times. * * This returns zero if unchanged, 1 if the configuration has changed, * or a negative error code. */ -int snd_usb_endpoint_configure(struct snd_usb_audio *chip, - struct snd_usb_endpoint *ep) +int snd_usb_endpoint_prepare(struct snd_usb_audio *chip, + struct snd_usb_endpoint *ep) { bool iface_first; int err = 0; @@ -1412,9 +1435,6 @@ int snd_usb_endpoint_configure(struct snd_usb_audio *chip, if (err < 0) goto unlock; } - err = snd_usb_endpoint_set_params(chip, ep); - if (err < 0) - goto unlock; goto done; } @@ -1442,10 +1462,6 @@ int snd_usb_endpoint_configure(struct snd_usb_audio *chip, if (err < 0) goto unlock; - err = snd_usb_endpoint_set_params(chip, ep); - if (err < 0) - goto unlock; - err = snd_usb_select_mode_quirk(chip, ep->cur_audiofmt); if (err < 0) goto unlock; diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h index 6a9af04cf175..e67ea28faa54 100644 --- a/sound/usb/endpoint.h +++ b/sound/usb/endpoint.h @@ -17,8 +17,10 @@ snd_usb_endpoint_open(struct snd_usb_audio *chip, bool is_sync_ep); void snd_usb_endpoint_close(struct snd_usb_audio *chip, struct snd_usb_endpoint *ep); -int snd_usb_endpoint_configure(struct snd_usb_audio *chip, - struct snd_usb_endpoint *ep); +int snd_usb_endpoint_set_params(struct snd_usb_audio *chip, + struct snd_usb_endpoint *ep); +int snd_usb_endpoint_prepare(struct snd_usb_audio *chip, + struct snd_usb_endpoint *ep); int snd_usb_endpoint_get_clock_rate(struct snd_usb_audio *chip, int clock); bool snd_usb_endpoint_compatible(struct snd_usb_audio *chip, diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index d45d1d7e6664..e721fc12acde 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -433,35 +433,6 @@ static void close_endpoints(struct snd_usb_audio *chip, } } -static int configure_endpoints(struct snd_usb_audio *chip, - struct snd_usb_substream *subs) -{ - int err; - - if (subs->data_endpoint->need_setup) { - /* stop any running stream beforehand */ - if (stop_endpoints(subs, false)) - sync_pending_stops(subs); - if (subs->sync_endpoint) { - err = snd_usb_endpoint_configure(chip, subs->sync_endpoint); - if (err < 0) - return err; - } - err = snd_usb_endpoint_configure(chip, subs->data_endpoint); - if (err < 0) - return err; - snd_usb_set_format_quirk(subs, subs->cur_audiofmt); - } else { - if (subs->sync_endpoint) { - err = snd_usb_endpoint_configure(chip, subs->sync_endpoint); - if (err < 0) - return err; - } - } - - return 0; -} - /* * hw_params callback * @@ -551,7 +522,16 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, subs->cur_audiofmt = fmt; mutex_unlock(&chip->mutex); - ret = configure_endpoints(chip, subs); + if (!subs->data_endpoint->need_setup) + goto unlock; + + if (subs->sync_endpoint) { + ret = snd_usb_endpoint_set_params(chip, subs->sync_endpoint); + if (ret < 0) + goto unlock; + } + + ret = snd_usb_endpoint_set_params(chip, subs->data_endpoint); unlock: if (ret < 0) @@ -634,9 +614,18 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) goto unlock; } - ret = configure_endpoints(chip, subs); + if (subs->sync_endpoint) { + ret = snd_usb_endpoint_prepare(chip, subs->sync_endpoint); + if (ret < 0) + goto unlock; + } + + ret = snd_usb_endpoint_prepare(chip, subs->data_endpoint); if (ret < 0) goto unlock; + else if (ret > 0) + snd_usb_set_format_quirk(subs, subs->cur_audiofmt); + ret = 0; /* reset the pointer */ subs->buffer_bytes = frames_to_bytes(runtime, runtime->buffer_size); -- cgit v1.2.3 From 9a737e7f8b371e97eb649904276407cee2c9cf30 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 20 Sep 2022 20:11:26 +0200 Subject: ALSA: usb-audio: Properly refcounting clock rate We fixed the bug introduced by the patch for managing the shared clocks at the commit 809f44a0cc5a ("ALSA: usb-audio: Clear fixed clock rate at closing EP"), but it was merely a workaround. By this change, the clock reference rate is cleared at each EP close, hence the still remaining EP may need a re-setup of rate unnecessarily. This patch introduces the proper refcounting for the clock reference object so that the clock setup is done only when needed. Fixes: 809f44a0cc5a ("ALSA: usb-audio: Clear fixed clock rate at closing EP") Fixes: c11117b634f4 ("ALSA: usb-audio: Refcount multiple accesses on the single clock") Link: https://lore.kernel.org/r/20220920181126.4912-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/endpoint.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 0c94ebc98e90..b2d0b42b581f 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -39,6 +39,7 @@ struct snd_usb_iface_ref { struct snd_usb_clock_ref { unsigned char clock; atomic_t locked; + int opened; int rate; bool need_setup; struct list_head list; @@ -803,6 +804,7 @@ snd_usb_endpoint_open(struct snd_usb_audio *chip, ep = NULL; goto unlock; } + ep->clock_ref->opened++; } ep->cur_audiofmt = fp; @@ -926,8 +928,10 @@ void snd_usb_endpoint_close(struct snd_usb_audio *chip, endpoint_set_interface(chip, ep, false); if (!--ep->opened) { - if (ep->clock_ref && !atomic_read(&ep->clock_ref->locked)) - ep->clock_ref->rate = 0; + if (ep->clock_ref) { + if (!--ep->clock_ref->opened) + ep->clock_ref->rate = 0; + } ep->iface = 0; ep->altsetting = 0; ep->cur_audiofmt = NULL; @@ -1649,8 +1653,7 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, bool keep_pending) WRITE_ONCE(ep->sync_source->sync_sink, NULL); stop_urbs(ep, false, keep_pending); if (ep->clock_ref) - if (!atomic_dec_return(&ep->clock_ref->locked)) - ep->clock_ref->rate = 0; + atomic_dec(&ep->clock_ref->locked); } } -- cgit v1.2.3 From 4da6b033f5454ccbac2d5795d7edfb3f2a777104 Mon Sep 17 00:00:00 2001 From: Ajit Kumar Pandey Date: Tue, 13 Sep 2022 20:13:15 +0530 Subject: ASoC: SOF: amd: Make ACP core code generic for newer SOC transition Newer AMD SOC differs slightly in terms of few registers offset and configuration. Add offsets into chip_info struct to make core ACP code more generic and resusable on newer SOC. Signed-off-by: Ajit Kumar Pandey Signed-off-by: V sujith kumar Reddy Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220913144319.1055302-2-Vsujithkumar.Reddy@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/Makefile | 2 +- sound/soc/sof/amd/acp-common.c | 110 +++++++++++++++++++++++++++++++++++++ sound/soc/sof/amd/acp-dsp-offset.h | 25 +++++---- sound/soc/sof/amd/acp-ipc.c | 16 ++++-- sound/soc/sof/amd/acp-loader.c | 13 +++-- sound/soc/sof/amd/acp-stream.c | 3 +- sound/soc/sof/amd/acp.c | 37 ++++++++----- sound/soc/sof/amd/acp.h | 26 +++++++-- sound/soc/sof/amd/pci-rn.c | 11 ++++ sound/soc/sof/amd/renoir.c | 101 ++++------------------------------ 10 files changed, 210 insertions(+), 134 deletions(-) create mode 100644 sound/soc/sof/amd/acp-common.c diff --git a/sound/soc/sof/amd/Makefile b/sound/soc/sof/amd/Makefile index 7b9f1a0af3c8..efea92f62a86 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 acp-trace.o +snd-sof-amd-acp-objs := acp.o acp-loader.o acp-ipc.o acp-pcm.o acp-stream.o acp-trace.o acp-common.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-common.c b/sound/soc/sof/amd/acp-common.c new file mode 100644 index 000000000000..12bdd97c1aae --- /dev/null +++ b/sound/soc/sof/amd/acp-common.c @@ -0,0 +1,110 @@ +// 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) 2022 Advanced Micro Devices, Inc. +// +// Authors: Ajit Kumar Pandey +// V sujith kumar Reddy + +/* ACP-specific Common code */ + +#include "../sof-priv.h" +#include "../sof-audio.h" +#include "../ops.h" +#include "../sof-audio.h" +#include "acp.h" +#include "acp-dsp-offset.h" + +int acp_dai_probe(struct snd_soc_dai *dai) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); + const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); + unsigned int val; + + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->i2s_pin_config_offset); + if (val != desc->i2s_mode) { + dev_err(sdev->dev, "I2S Mode is not supported (I2S_PIN_CONFIG: %#x)\n", val); + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_NS(acp_dai_probe, SND_SOC_SOF_AMD_COMMON); + +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; + 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 NULL; + } + + sof_pdata->tplg_filename = mach->sof_tplg_filename; + sof_pdata->fw_filename = mach->fw_filename; + + return mach; +} + +/* AMD Common DSP ops */ +struct snd_sof_dsp_ops sof_acp_common_ops = { + /* probe and remove */ + .probe = amd_sof_acp_probe, + .remove = amd_sof_acp_remove, + + /* Register IO */ + .write = sof_io_write, + .read = sof_io_read, + + /* Block IO */ + .block_read = acp_dsp_block_read, + .block_write = acp_dsp_block_write, + + /*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, + + /*IPC */ + .send_msg = acp_sof_ipc_send_msg, + .ipc_msg_data = acp_sof_ipc_msg_data, + .get_mailbox_offset = acp_sof_ipc_get_mailbox_offset, + .irq_thread = acp_sof_ipc_irq_thread, + + /* 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, + + /* Machine driver callbacks */ + .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, + + /* PM */ + .suspend = amd_sof_acp_suspend, + .resume = amd_sof_acp_resume, +}; +EXPORT_SYMBOL_NS(sof_acp_common_ops, SND_SOC_SOF_AMD_COMMON); + +MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON); +MODULE_DESCRIPTION("ACP SOF COMMON Driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h index 56cefd4a84fc..47151a84f90b 100644 --- a/sound/soc/sof/amd/acp-dsp-offset.h +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -48,22 +48,23 @@ #define ACP_SOFT_RESET 0x1000 #define ACP_CONTROL 0x1004 -#define ACP_I2S_PIN_CONFIG 0x1400 +#define ACP3X_I2S_PIN_CONFIG 0x1400 -/* Registers from ACP_PGFSM block */ -#define ACP_PGFSM_CONTROL 0x141C -#define ACP_PGFSM_STATUS 0x1420 -#define ACP_CLKMUX_SEL 0x1424 +/* Registers offsets from ACP_PGFSM block */ +#define ACP3X_PGFSM_BASE 0x141C +#define PGFSM_CONTROL_OFFSET 0x0 +#define PGFSM_STATUS_OFFSET 0x4 +#define ACP3X_CLKMUX_SEL 0x1424 /* 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 +#define ACP3X_EXT_INTR_STAT 0x1808 + +#define ACP3X_DSP_SW_INTR_BASE 0x1814 +#define DSP_SW_INTR_CNTL_OFFSET 0x0 +#define DSP_SW_INTR_STAT_OFFSET 0x4 +#define DSP_SW_INTR_TRIG_OFFSET 0x8 #define ACP_ERROR_STATUS 0x18C4 -#define ACP_AXI2DAGB_SEM_0 0x1880 +#define ACP3X_AXI2DAGB_SEM_0 0x1880 /* Registers from ACP_SHA block */ #define ACP_SHA_DSP_FW_QUALIFIER 0x1C70 diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c index e1842f037083..e09392498f4c 100644 --- a/sound/soc/sof/amd/acp-ipc.c +++ b/sound/soc/sof/amd/acp-ipc.c @@ -30,11 +30,14 @@ 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; + const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); u32 swintr_trigger; - swintr_trigger = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SW_INTR_TRIG); + swintr_trigger = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->dsp_intr_base + + DSP_SW_INTR_TRIG_OFFSET); swintr_trigger |= 0x01; - snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SW_INTR_TRIG, swintr_trigger); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->dsp_intr_base + DSP_SW_INTR_TRIG_OFFSET, + swintr_trigger); } static void acp_ipc_host_msg_set(struct snd_sof_dev *sdev) @@ -61,10 +64,11 @@ static void acp_dsp_ipc_dsp_done(struct snd_sof_dev *sdev) 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; + const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); unsigned int offset = offsetof(struct scratch_ipc_conf, sof_in_box); unsigned int count = ACP_HW_SEM_RETRY_COUNT; - while (snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_AXI2DAGB_SEM_0)) { + while (snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset)) { /* Wait until acquired HW Semaphore Lock or timeout*/ count--; if (!count) { @@ -80,7 +84,7 @@ int acp_sof_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) acpbus_trigger_host_to_dsp_swintr(adata); /* Unlock or Release HW Semaphore */ - snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_AXI2DAGB_SEM_0, 0x0); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset, 0x0); return 0; } @@ -186,7 +190,9 @@ EXPORT_SYMBOL_NS(acp_sof_ipc_msg_data, SND_SOC_SOF_AMD_COMMON); int acp_sof_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) { - return ACP_SCRATCH_MEMORY_ADDRESS; + const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); + + return desc->sram_pte_offset; } EXPORT_SYMBOL_NS(acp_sof_ipc_get_mailbox_offset, SND_SOC_SOF_AMD_COMMON); diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c index 7ca51e0f3b1b..f372f93094f3 100644 --- a/sound/soc/sof/amd/acp-loader.c +++ b/sound/soc/sof/amd/acp-loader.c @@ -30,9 +30,10 @@ 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) { + const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); switch (blk_type) { case SOF_FW_BLK_TYPE_SRAM: - offset = offset - ACP_SCRATCH_MEMORY_ADDRESS; + offset = offset - desc->sram_pte_offset; memcpy_from_scratch(sdev, offset, dest, size); break; default: @@ -49,6 +50,7 @@ int acp_dsp_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_t { struct snd_sof_pdata *plat_data = sdev->pdata; struct pci_dev *pci = to_pci_dev(sdev->dev); + const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); struct acp_dev_data *adata; void *dest; u32 dma_size, page_count; @@ -84,7 +86,7 @@ int acp_dsp_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_t adata->fw_data_bin_size = size + offset; break; case SOF_FW_BLK_TYPE_SRAM: - offset = offset - ACP_SCRATCH_MEMORY_ADDRESS; + offset = offset - desc->sram_pte_offset; memcpy_to_scratch(sdev, offset, src, size); return 0; default: @@ -105,14 +107,13 @@ 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; + struct snd_sof_dev *sdev = adata->dev; + const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); 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; @@ -129,7 +130,7 @@ static void configure_pte_for_fw_loading(int type, int num_pages, struct acp_dev /* Group Enable */ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACPAXI2AXI_ATU_BASE_ADDR_GRP_1, - ACP_SRAM_PTE_OFFSET | BIT(31)); + desc->sram_pte_offset | BIT(31)); snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1, PAGE_SIZE_4K_ENABLE); diff --git a/sound/soc/sof/amd/acp-stream.c b/sound/soc/sof/amd/acp-stream.c index b3ca4a90dbf8..f71b4e660b14 100644 --- a/sound/soc/sof/amd/acp-stream.c +++ b/sound/soc/sof/amd/acp-stream.c @@ -26,6 +26,7 @@ int acp_dsp_stream_config(struct snd_sof_dev *sdev, struct acp_dsp_stream *stream) { + const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); unsigned int pte_reg, pte_size, phy_addr_offset, index; int stream_tag = stream->stream_tag; u32 low, high, offset, reg_val; @@ -96,7 +97,7 @@ int acp_dsp_stream_config(struct snd_sof_dev *sdev, struct acp_dsp_stream *strea phy_addr_offset, stream->reg_offset); /* Group Enable */ - reg_val = ACP_SRAM_PTE_OFFSET + offset; + reg_val = desc->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); diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index c40d2900dd36..47eaabc95aa5 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -39,9 +39,10 @@ static int smn_read(struct pci_dev *dev, u32 smn_addr, u32 *data) static void init_dma_descriptor(struct acp_dev_data *adata) { struct snd_sof_dev *sdev = adata->dev; + const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); unsigned int addr; - addr = ACP_SRAM_PTE_OFFSET + offsetof(struct scratch_reg_conf, dma_desc); + addr = desc->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); @@ -300,8 +301,9 @@ void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, static int acp_memory_init(struct snd_sof_dev *sdev) { struct acp_dev_data *adata = sdev->pdata->hw_pdata; + const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); - snd_sof_dsp_update_bits(sdev, ACP_DSP_BAR, ACP_DSP_SW_INTR_CNTL, + snd_sof_dsp_update_bits(sdev, ACP_DSP_BAR, desc->dsp_intr_base + DSP_SW_INTR_CNTL_OFFSET, ACP_DSP_INTR_EN_MASK, ACP_DSP_INTR_EN_MASK); init_dma_descriptor(adata); @@ -311,18 +313,20 @@ static int acp_memory_init(struct snd_sof_dev *sdev) static irqreturn_t acp_irq_thread(int irq, void *context) { struct snd_sof_dev *sdev = context; + const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); + unsigned int base = desc->dsp_intr_base; unsigned int val, count = ACP_HW_SEM_RETRY_COUNT; - val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_EXTERNAL_INTR_STAT); + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_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); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, val); return IRQ_HANDLED; } - val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_DSP_SW_INTR_STAT); + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET); if (val & ACP_DSP_TO_HOST_IRQ) { - while (snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_AXI2DAGB_SEM_0)) { + while (snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset)) { /* Wait until acquired HW Semaphore lock or timeout */ count--; if (!count) { @@ -333,10 +337,10 @@ static irqreturn_t acp_irq_thread(int irq, void *context) 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); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET, val); /* Unlock or Release HW Semaphore */ - snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_AXI2DAGB_SEM_0, 0x0); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset, 0x0); return IRQ_HANDLED; } @@ -347,9 +351,11 @@ static irqreturn_t acp_irq_thread(int irq, void *context) static irqreturn_t acp_irq_handler(int irq, void *dev_id) { struct snd_sof_dev *sdev = dev_id; + const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); + unsigned int base = desc->dsp_intr_base; unsigned int val; - val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_DSP_SW_INTR_STAT); + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET); if (val) return IRQ_WAKE_THREAD; @@ -358,20 +364,22 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id) static int acp_power_on(struct snd_sof_dev *sdev) { + const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); + unsigned int base = desc->pgfsm_base; unsigned int val; int ret; - val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_PGFSM_STATUS); + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + PGFSM_STATUS_OFFSET); if (val == ACP_POWERED_ON) return 0; if (val & ACP_PGFSM_STATUS_MASK) - snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_PGFSM_CONTROL, + snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + PGFSM_CONTROL_OFFSET, 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); + ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, base + PGFSM_STATUS_OFFSET, 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"); @@ -437,6 +445,7 @@ EXPORT_SYMBOL_NS(amd_sof_acp_suspend, SND_SOC_SOF_AMD_COMMON); int amd_sof_acp_resume(struct snd_sof_dev *sdev) { + const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); int ret; ret = acp_init(sdev); @@ -445,7 +454,7 @@ int amd_sof_acp_resume(struct snd_sof_dev *sdev) return ret; } - snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CLKMUX_SEL, 0x03); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_clkmux_sel, 0x03); ret = acp_memory_init(sdev); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 4c42b8fd6abf..bc024be76e09 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -30,7 +30,7 @@ #define ACP_SOFT_RESET_DONE_MASK 0x00010001 #define ACP_DSP_INTR_EN_MASK 0x00000001 -#define ACP_SRAM_PTE_OFFSET 0x02050000 +#define ACP3X_SRAM_PTE_OFFSET 0x02050000 #define PAGE_SIZE_4K_ENABLE 0x2 #define ACP_PAGE_SIZE 0x1000 #define ACP_DMA_CH_RUN 0x02 @@ -45,7 +45,7 @@ #define ACPBUS_REG_BASE_OFFSET ACP_DMA_CNTL_0 #define ACP_DEFAULT_DRAM_LENGTH 0x00080000 -#define ACP_SCRATCH_MEMORY_ADDRESS 0x02050000 +#define ACP3X_SCRATCH_MEMORY_ADDRESS 0x02050000 #define ACP_SYSTEM_MEMORY_WINDOW 0x4000000 #define ACP_IRAM_BASE_ADDRESS 0x000000 #define ACP_DATA_RAM_BASE_ADDRESS 0x01000000 @@ -139,6 +139,19 @@ struct acp_dsp_stream { unsigned int reg_offset; }; +struct sof_amd_acp_desc { + unsigned int rev; + unsigned int host_bridge_id; + unsigned int i2s_mode; + u32 pgfsm_base; + u32 ext_intr_stat; + u32 dsp_intr_base; + u32 sram_pte_offset; + u32 i2s_pin_config_offset; + u32 hw_semaphore_offset; + u32 acp_clkmux_sel; +}; + /* Common device data struct for ACP devices */ struct acp_dev_data { struct snd_sof_dev *dev; @@ -206,8 +219,13 @@ int acp_pcm_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substr struct snd_pcm_hw_params *params, struct snd_sof_platform_stream_params *platform_params); +extern struct snd_sof_dsp_ops sof_acp_common_ops; + extern struct snd_sof_dsp_ops sof_renoir_ops; +int sof_renoir_ops_init(struct snd_sof_dev *sdev); +int acp_dai_probe(struct snd_soc_dai *dai); +struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev); /* Machine configuration */ int snd_amd_acp_find_config(struct pci_dev *pci); @@ -220,10 +238,6 @@ int acp_sof_trace_release(struct snd_sof_dev *sdev); int amd_sof_acp_suspend(struct snd_sof_dev *sdev, u32 target_state); int amd_sof_acp_resume(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; diff --git a/sound/soc/sof/amd/pci-rn.c b/sound/soc/sof/amd/pci-rn.c index 3a7fed25a226..fca40b261671 100644 --- a/sound/soc/sof/amd/pci-rn.c +++ b/sound/soc/sof/amd/pci-rn.c @@ -21,6 +21,7 @@ #include "../sof-pci-dev.h" #include "../../amd/mach-config.h" #include "acp.h" +#include "acp-dsp-offset.h" #define ACP3x_REG_START 0x1240000 #define ACP3x_REG_END 0x125C000 @@ -44,7 +45,16 @@ static const struct resource renoir_res[] = { }; static const struct sof_amd_acp_desc renoir_chip_info = { + .rev = 3, .host_bridge_id = HOST_BRIDGE_CZN, + .i2s_mode = 0x04, + .pgfsm_base = ACP3X_PGFSM_BASE, + .ext_intr_stat = ACP3X_EXT_INTR_STAT, + .dsp_intr_base = ACP3X_DSP_SW_INTR_BASE, + .sram_pte_offset = ACP3X_SRAM_PTE_OFFSET, + .i2s_pin_config_offset = ACP3X_I2S_PIN_CONFIG, + .hw_semaphore_offset = ACP3X_AXI2DAGB_SEM_0, + .acp_clkmux_sel = ACP3X_CLKMUX_SEL, }; static const struct sof_dev_desc renoir_desc = { @@ -68,6 +78,7 @@ static const struct sof_dev_desc renoir_desc = { }, .nocodec_tplg_filename = "sof-acp.tplg", .ops = &sof_renoir_ops, + .ops_init = sof_renoir_ops_init, }; static int acp_pci_rn_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) diff --git a/sound/soc/sof/amd/renoir.c b/sound/soc/sof/amd/renoir.c index 9261c8bc2236..6ea8727f977e 100644 --- a/sound/soc/sof/amd/renoir.c +++ b/sound/soc/sof/amd/renoir.c @@ -23,22 +23,6 @@ #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, @@ -62,7 +46,7 @@ static struct snd_soc_dai_driver renoir_sof_dai[] = { .rate_min = 8000, .rate_max = 48000, }, - .probe = &renoir_dai_probe, + .probe = &acp_dai_probe, }, [I2S_SP_INSTANCE] = { @@ -87,7 +71,7 @@ static struct snd_soc_dai_driver renoir_sof_dai[] = { .rate_min = 8000, .rate_max = 48000, }, - .probe = &renoir_dai_probe, + .probe = &acp_dai_probe, }, [PDM_DMIC_INSTANCE] = { @@ -104,82 +88,21 @@ static struct snd_soc_dai_driver renoir_sof_dai[] = { }, }; -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; - struct snd_soc_acpi_mach *mach; +/* Renoir ops */ +struct snd_sof_dsp_ops sof_renoir_ops; +EXPORT_SYMBOL_NS(sof_renoir_ops, SND_SOC_SOF_AMD_COMMON); - mach = snd_soc_acpi_find_machine(desc->machines); - if (!mach) { - dev_warn(sdev->dev, "No matching ASoC machine driver found\n"); - return NULL; - } +int sof_renoir_ops_init(struct snd_sof_dev *sdev) +{ + /* common defaults */ + memcpy(&sof_renoir_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops)); - sof_pdata->tplg_filename = mach->sof_tplg_filename; - sof_pdata->fw_filename = mach->fw_filename; + sof_renoir_ops.drv = renoir_sof_dai; + sof_renoir_ops.num_drv = ARRAY_SIZE(renoir_sof_dai); - return mach; + return 0; } -/* AMD Renoir DSP ops */ -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, - - /* Block IO */ - .block_read = acp_dsp_block_read, - .block_write = acp_dsp_block_write, - - /*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, - - /*IPC */ - .send_msg = acp_sof_ipc_send_msg, - .ipc_msg_data = acp_sof_ipc_msg_data, - .get_mailbox_offset = acp_sof_ipc_get_mailbox_offset, - .irq_thread = acp_sof_ipc_irq_thread, - - /* 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, - - /* Machine driver callbacks */ - .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, - - /* PM */ - .suspend = amd_sof_acp_suspend, - .resume = amd_sof_acp_resume, -}; -EXPORT_SYMBOL(sof_renoir_ops); - MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON); MODULE_DESCRIPTION("RENOIR SOF Driver"); MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3 From 41cb85bc4b526bb228579c04857bc58213e5f9b5 Mon Sep 17 00:00:00 2001 From: V sujith kumar Reddy Date: Tue, 13 Sep 2022 20:13:16 +0530 Subject: ASoC: SOF: amd: Add support for Rembrandt plaform. Add pci driver and platform driver to enable SOF support on ACP6x architecture based Rembrandt platform. Signed-off-by: Ajit Kumar Pandey Signed-off-by: V sujith kumar Reddy Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220913144319.1055302-3-Vsujithkumar.Reddy@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/Kconfig | 10 ++ sound/soc/sof/amd/Makefile | 2 + sound/soc/sof/amd/acp-dsp-offset.h | 8 +- sound/soc/sof/amd/acp-loader.c | 7 ++ sound/soc/sof/amd/acp.h | 5 + sound/soc/sof/amd/pci-rmb.c | 186 +++++++++++++++++++++++++++++++++++++ sound/soc/sof/amd/rembrandt.c | 134 ++++++++++++++++++++++++++ 7 files changed, 351 insertions(+), 1 deletion(-) create mode 100644 sound/soc/sof/amd/pci-rmb.c create mode 100644 sound/soc/sof/amd/rembrandt.c diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig index 190c85d57047..a305ea6efea9 100644 --- a/sound/soc/sof/amd/Kconfig +++ b/sound/soc/sof/amd/Kconfig @@ -31,4 +31,14 @@ config SND_SOC_SOF_AMD_RENOIR select SND_SOC_SOF_AMD_COMMON help Select this option for SOF support on AMD Renoir platform + +config SND_SOC_SOF_AMD_REMBRANDT + tristate "SOF support for REMBRANDT" + depends on SND_SOC_SOF_PCI + select SND_SOC_SOF_AMD_COMMON + help + Select this option for SOF support on AMD Rembrandt platform + Say Y if you want to enable SOF on Rembrandt. + If unsure select "N". + endif diff --git a/sound/soc/sof/amd/Makefile b/sound/soc/sof/amd/Makefile index efea92f62a86..5626d13b3e69 100644 --- a/sound/soc/sof/amd/Makefile +++ b/sound/soc/sof/amd/Makefile @@ -6,6 +6,8 @@ snd-sof-amd-acp-objs := acp.o acp-loader.o acp-ipc.o acp-pcm.o acp-stream.o acp-trace.o acp-common.o snd-sof-amd-renoir-objs := pci-rn.o renoir.o +snd-sof-amd-rembrandt-objs := pci-rmb.o rembrandt.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 +obj-$(CONFIG_SND_SOC_SOF_AMD_REMBRANDT) +=snd-sof-amd-rembrandt.o diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h index 47151a84f90b..de5726251dc6 100644 --- a/sound/soc/sof/amd/acp-dsp-offset.h +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -49,22 +49,28 @@ #define ACP_CONTROL 0x1004 #define ACP3X_I2S_PIN_CONFIG 0x1400 +#define ACP6X_I2S_PIN_CONFIG 0x1440 /* Registers offsets from ACP_PGFSM block */ #define ACP3X_PGFSM_BASE 0x141C +#define ACP6X_PGFSM_BASE 0x1024 #define PGFSM_CONTROL_OFFSET 0x0 #define PGFSM_STATUS_OFFSET 0x4 #define ACP3X_CLKMUX_SEL 0x1424 +#define ACP6X_CLKMUX_SEL 0x102C /* Registers from ACP_INTR block */ #define ACP3X_EXT_INTR_STAT 0x1808 +#define ACP6X_EXT_INTR_STAT 0x1A0C #define ACP3X_DSP_SW_INTR_BASE 0x1814 +#define ACP6X_DSP_SW_INTR_BASE 0x1808 #define DSP_SW_INTR_CNTL_OFFSET 0x0 #define DSP_SW_INTR_STAT_OFFSET 0x4 #define DSP_SW_INTR_TRIG_OFFSET 0x8 #define ACP_ERROR_STATUS 0x18C4 #define ACP3X_AXI2DAGB_SEM_0 0x1880 +#define ACP6X_AXI2DAGB_SEM_0 0x1874 /* Registers from ACP_SHA block */ #define ACP_SHA_DSP_FW_QUALIFIER 0x1C70 @@ -78,5 +84,5 @@ #define ACP_SHA_PSP_ACK 0x1C74 #define ACP_SCRATCH_REG_0 0x10000 - +#define ACP6X_DSP_FUSION_RUNSTALL 0x0644 #endif diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c index f372f93094f3..d1e74baf5d8b 100644 --- a/sound/soc/sof/amd/acp-loader.c +++ b/sound/soc/sof/amd/acp-loader.c @@ -198,12 +198,19 @@ EXPORT_SYMBOL_NS(acp_dsp_pre_fw_run, SND_SOC_SOF_AMD_COMMON); int acp_sof_dsp_run(struct snd_sof_dev *sdev) { + const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); 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); + /* Some platforms won't support fusion DSP,keep offset zero for no support */ + if (desc->fusion_dsp_offset) { + snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->fusion_dsp_offset, ACP_DSP_RUN); + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->fusion_dsp_offset); + dev_dbg(sdev->dev, "ACP_DSP0_FUSION_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 bc024be76e09..e59a8655d859 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -31,6 +31,7 @@ #define ACP_DSP_INTR_EN_MASK 0x00000001 #define ACP3X_SRAM_PTE_OFFSET 0x02050000 +#define ACP6X_SRAM_PTE_OFFSET 0x03800000 #define PAGE_SIZE_4K_ENABLE 0x2 #define ACP_PAGE_SIZE 0x1000 #define ACP_DMA_CH_RUN 0x02 @@ -54,6 +55,7 @@ #define ACP_DSP_TO_HOST_IRQ 0x04 #define HOST_BRIDGE_CZN 0x1630 +#define HOST_BRIDGE_RMB 0x14B5 #define ACP_SHA_STAT 0x8000 #define ACP_PSP_TIMEOUT_COUNTER 5 #define ACP_EXT_INTR_ERROR_STAT 0x20000000 @@ -150,6 +152,7 @@ struct sof_amd_acp_desc { u32 i2s_pin_config_offset; u32 hw_semaphore_offset; u32 acp_clkmux_sel; + u32 fusion_dsp_offset; }; /* Common device data struct for ACP devices */ @@ -223,6 +226,8 @@ extern struct snd_sof_dsp_ops sof_acp_common_ops; extern struct snd_sof_dsp_ops sof_renoir_ops; int sof_renoir_ops_init(struct snd_sof_dev *sdev); +extern struct snd_sof_dsp_ops sof_rembrandt_ops; +int sof_rembrandt_ops_init(struct snd_sof_dev *sdev); int acp_dai_probe(struct snd_soc_dai *dai); struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev); diff --git a/sound/soc/sof/amd/pci-rmb.c b/sound/soc/sof/amd/pci-rmb.c new file mode 100644 index 000000000000..4e1de462b431 --- /dev/null +++ b/sound/soc/sof/amd/pci-rmb.c @@ -0,0 +1,186 @@ +// 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) 2022 Advanced Micro Devices, Inc. All rights reserved. +// +// Authors: Ajit Kumar Pandey + +/*. + * PCI interface for Rembrandt ACP device + */ + +#include +#include +#include +#include +#include + +#include "../ops.h" +#include "../sof-pci-dev.h" +#include "../../amd/mach-config.h" +#include "acp.h" +#include "acp-dsp-offset.h" + +#define ACP6x_REG_START 0x1240000 +#define ACP6x_REG_END 0x125C000 + +static struct platform_device *dmic_dev; +static struct platform_device *pdev; + +static const struct resource rembrandt_res[] = { + { + .start = 0, + .end = ACP6x_REG_END - ACP6x_REG_START, + .name = "acp_mem", + .flags = IORESOURCE_MEM, + }, + { + .start = 0, + .end = 0, + .name = "acp_dai_irq", + .flags = IORESOURCE_IRQ, + }, +}; + +static const struct sof_amd_acp_desc rembrandt_chip_info = { + .rev = 6, + .host_bridge_id = HOST_BRIDGE_RMB, + .i2s_mode = 0x0a, + .pgfsm_base = ACP6X_PGFSM_BASE, + .ext_intr_stat = ACP6X_EXT_INTR_STAT, + .dsp_intr_base = ACP6X_DSP_SW_INTR_BASE, + .sram_pte_offset = ACP6X_SRAM_PTE_OFFSET, + .i2s_pin_config_offset = ACP6X_I2S_PIN_CONFIG, + .hw_semaphore_offset = ACP6X_AXI2DAGB_SEM_0, + .acp_clkmux_sel = ACP6X_CLKMUX_SEL, + .fusion_dsp_offset = ACP6X_DSP_FUSION_RUNSTALL, +}; + +static const struct sof_dev_desc rembrandt_desc = { + .machines = snd_soc_acpi_amd_rmb_sof_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .chip_info = &rembrandt_chip_info, + .ipc_supported_mask = BIT(SOF_IPC), + .ipc_default = SOF_IPC, + .default_fw_path = { + [SOF_IPC] = "amd/sof", + }, + .default_tplg_path = { + [SOF_IPC] = "amd/sof-tplg", + }, + .default_fw_filename = { + [SOF_IPC] = "sof-rmb.ri", + }, + .nocodec_tplg_filename = "sof-acp.tplg", + .ops = &sof_rembrandt_ops, + .ops_init = sof_rembrandt_ops_init, +}; + +static int acp_pci_rmb_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(rembrandt_res), + GFP_KERNEL); + if (!res) { + platform_device_unregister(dmic_dev); + sof_pci_remove(pci); + return -ENOMEM; + } + + res_i2s = rembrandt_res; + for (i = 0; i < ARRAY_SIZE(rembrandt_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_rembrandt"; + pdevinfo.id = 0; + pdevinfo.parent = &pci->dev; + pdevinfo.num_res = ARRAY_SIZE(rembrandt_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); + platform_device_unregister(dmic_dev); + sof_pci_remove(pci); + ret = PTR_ERR(pdev); + } + + return ret; +}; + +static void acp_pci_rmb_remove(struct pci_dev *pci) +{ + if (dmic_dev) + platform_device_unregister(dmic_dev); + if (pdev) + platform_device_unregister(pdev); + + sof_pci_remove(pci); +} + +/* PCI IDs */ +static const struct pci_device_id rmb_pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_PCI_DEV_ID), + .driver_data = (unsigned long)&rembrandt_desc}, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, rmb_pci_ids); + +/* pci_driver definition */ +static struct pci_driver snd_sof_pci_amd_rmb_driver = { + .name = KBUILD_MODNAME, + .id_table = rmb_pci_ids, + .probe = acp_pci_rmb_probe, + .remove = acp_pci_rmb_remove, +}; +module_pci_driver(snd_sof_pci_amd_rmb_driver); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON); +MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); diff --git a/sound/soc/sof/amd/rembrandt.c b/sound/soc/sof/amd/rembrandt.c new file mode 100644 index 000000000000..dcb64a23e121 --- /dev/null +++ b/sound/soc/sof/amd/rembrandt.c @@ -0,0 +1,134 @@ +// 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) 2022 Advanced Micro Devices, Inc. +// +// Authors: Ajit Kumar Pandey + +/* + * Hardware interface for Audio DSP on Rembrandt platform + */ + +#include +#include + +#include "../ops.h" +#include "../sof-audio.h" +#include "acp.h" +#include "acp-dsp-offset.h" + +#define I2S_HS_INSTANCE 0 +#define I2S_BT_INSTANCE 1 +#define I2S_SP_INSTANCE 2 +#define PDM_DMIC_INSTANCE 3 + +static struct snd_soc_dai_driver rembrandt_sof_dai[] = { + [I2S_HS_INSTANCE] = { + .id = I2S_HS_INSTANCE, + .name = "acp-sof-hs", + .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 HS controller capture */ + .channels_min = 2, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 48000, + }, + .probe = &acp_dai_probe, + }, + + [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 = &acp_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 = &acp_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, + }, + }, +}; + +/* Rembrandt ops */ +struct snd_sof_dsp_ops sof_rembrandt_ops; +EXPORT_SYMBOL_NS(sof_rembrandt_ops, SND_SOC_SOF_AMD_COMMON); + +int sof_rembrandt_ops_init(struct snd_sof_dev *sdev) +{ + /* common defaults */ + memcpy(&sof_rembrandt_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops)); + + sof_rembrandt_ops.drv = rembrandt_sof_dai; + sof_rembrandt_ops.num_drv = ARRAY_SIZE(rembrandt_sof_dai); + + return 0; +} + +MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON); +MODULE_DESCRIPTION("REMBRANDT SOF Driver"); +MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3 From ed2562c64b4f2cb434420f7d2818d0388250ac1a Mon Sep 17 00:00:00 2001 From: V sujith kumar Reddy Date: Tue, 13 Sep 2022 20:13:17 +0530 Subject: ASoC: SOF: Adding amd HS functionality to the sof core Add I2S HS control instance to the sof core. This will help the amd topology to use the I2S HS Dai. Signed-off-by: V sujith kumar Reddy Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220913144319.1055302-4-Vsujithkumar.Reddy@amd.com Signed-off-by: Mark Brown --- include/sound/sof/dai.h | 2 ++ sound/soc/sof/ipc3-pcm.c | 9 +++++++++ sound/soc/sof/ipc3-topology.c | 33 +++++++++++++++++++++++++++++++++ sound/soc/sof/topology.c | 1 + 4 files changed, 45 insertions(+) diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h index 21d98f31a9ca..83fd81c82e4c 100644 --- a/include/sound/sof/dai.h +++ b/include/sound/sof/dai.h @@ -84,6 +84,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_AMD_HS, /**< Amd HS */ SOF_DAI_MEDIATEK_AFE, /**< Mediatek AFE */ }; @@ -112,6 +113,7 @@ struct sof_ipc_dai_config { struct sof_ipc_dai_acp_params acpbt; struct sof_ipc_dai_acp_params acpsp; struct sof_ipc_dai_acpdmic_params acpdmic; + struct sof_ipc_dai_acp_params acphs; struct sof_ipc_dai_mtk_afe_params afe; }; } __packed; diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c index 9c6a84bdeca7..dad57bef38f6 100644 --- a/sound/soc/sof/ipc3-pcm.c +++ b/sound/soc/sof/ipc3-pcm.c @@ -346,6 +346,15 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, dev_dbg(component->dev, "AMD_SP channels_min: %d channels_max: %d\n", channels->min, channels->max); break; + case SOF_DAI_AMD_HS: + rate->min = private->dai_config->acphs.fsync_rate; + rate->max = private->dai_config->acphs.fsync_rate; + channels->min = private->dai_config->acphs.tdm_slots; + channels->max = private->dai_config->acphs.tdm_slots; + + dev_dbg(component->dev, + "AMD_HS channel_max: %d rate_max: %d\n", channels->max, rate->max); + break; case SOF_DAI_AMD_DMIC: rate->min = private->dai_config->acpdmic.pdm_rate; rate->max = private->dai_config->acpdmic.pdm_rate; diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index a39b43850f0e..c148715aa0f9 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -1217,6 +1217,36 @@ static int sof_link_acp_sp_load(struct snd_soc_component *scomp, struct snd_sof_ return 0; } +static int sof_link_acp_hs_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink, + struct sof_ipc_dai_config *config, struct snd_sof_dai *dai) +{ + struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs; + struct sof_dai_private_data *private = dai->private; + u32 size = sizeof(*config); + + /* Configures the DAI hardware format and inverted clocks */ + sof_dai_set_format(hw_config, config); + + /* init IPC */ + memset(&config->acphs, 0, sizeof(config->acphs)); + config->hdr.size = size; + + config->acphs.fsync_rate = le32_to_cpu(hw_config->fsync_rate); + config->acphs.tdm_slots = le32_to_cpu(hw_config->tdm_slots); + + dev_info(scomp->dev, "ACP_HS config ACP%d channel %d rate %d\n", + config->dai_index, config->acphs.tdm_slots, + config->acphs.fsync_rate); + + dai->number_configs = 1; + dai->current_config = 0; + private->dai_config = kmemdup(config, size, GFP_KERNEL); + if (!private->dai_config) + return -ENOMEM; + + return 0; +} + static int sof_link_afe_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink, struct sof_ipc_dai_config *config, struct snd_sof_dai *dai) { @@ -1517,6 +1547,9 @@ static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget) case SOF_DAI_AMD_SP: ret = sof_link_acp_sp_load(scomp, slink, config, dai); break; + case SOF_DAI_AMD_HS: + ret = sof_link_acp_hs_load(scomp, slink, config, dai); + break; case SOF_DAI_AMD_DMIC: ret = sof_link_acp_dmic_load(scomp, slink, config, dai); break; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 6087483deb48..51deda74dd26 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -287,6 +287,7 @@ static const struct sof_dai_types sof_dais[] = { {"ACP", SOF_DAI_AMD_BT}, {"ACPSP", SOF_DAI_AMD_SP}, {"ACPDMIC", SOF_DAI_AMD_DMIC}, + {"ACPHS", SOF_DAI_AMD_HS}, {"AFE", SOF_DAI_MEDIATEK_AFE}, }; -- cgit v1.2.3 From 40d3c041e2f871b3d2d78c8e360224f788ac17ab Mon Sep 17 00:00:00 2001 From: V sujith kumar Reddy Date: Tue, 13 Sep 2022 20:13:18 +0530 Subject: ASoC: SOF: amd: increase SRAM inbox and outbox size to 1024 Increase inbox and outbox mailbox size from 512 to 1024 to support thirdparty DTS integration ipc tx/rx messages communication. This is done through firmware window get info. Signed-off-by: V sujith kumar Reddy Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220913144319.1055302-5-Vsujithkumar.Reddy@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp-common.c | 1 + sound/soc/sof/amd/acp-ipc.c | 33 +++++++++++++++++++++++++-------- sound/soc/sof/amd/acp-pcm.c | 3 ++- sound/soc/sof/amd/acp-stream.c | 4 +++- sound/soc/sof/amd/acp.c | 17 ++++++++++++++--- sound/soc/sof/amd/acp.h | 7 +++---- 6 files changed, 48 insertions(+), 17 deletions(-) diff --git a/sound/soc/sof/amd/acp-common.c b/sound/soc/sof/amd/acp-common.c index 12bdd97c1aae..27b95187356e 100644 --- a/sound/soc/sof/amd/acp-common.c +++ b/sound/soc/sof/amd/acp-common.c @@ -77,6 +77,7 @@ struct snd_sof_dsp_ops sof_acp_common_ops = { .send_msg = acp_sof_ipc_send_msg, .ipc_msg_data = acp_sof_ipc_msg_data, .get_mailbox_offset = acp_sof_ipc_get_mailbox_offset, + .get_window_offset = acp_sof_ipc_get_window_offset, .irq_thread = acp_sof_ipc_irq_thread, /* stream callbacks */ diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c index e09392498f4c..dd030566e372 100644 --- a/sound/soc/sof/amd/acp-ipc.c +++ b/sound/soc/sof/amd/acp-ipc.c @@ -42,21 +42,24 @@ static void acpbus_trigger_host_to_dsp_swintr(struct acp_dev_data *adata) 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); + unsigned int host_msg = sdev->debug_box.offset + + 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); + unsigned int dsp_msg = sdev->debug_box.offset + + 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); + unsigned int dsp_ack = sdev->debug_box.offset + + offsetof(struct scratch_ipc_conf, sof_dsp_ack_write); snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_ack, 0); } @@ -65,7 +68,7 @@ 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; const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); - unsigned int offset = offsetof(struct scratch_ipc_conf, sof_in_box); + unsigned int offset = sdev->host_box.offset; unsigned int count = ACP_HW_SEM_RETRY_COUNT; while (snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset)) { @@ -95,7 +98,7 @@ 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); + unsigned int offset = sdev->host_box.offset; int ret = 0; /* @@ -145,11 +148,19 @@ out: 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); + unsigned int dsp_msg_write = sdev->debug_box.offset + + offsetof(struct scratch_ipc_conf, sof_dsp_msg_write); + unsigned int dsp_ack_write = sdev->debug_box.offset + + offsetof(struct scratch_ipc_conf, sof_dsp_ack_write); bool ipc_irq = false; int dsp_msg, dsp_ack; + if (sdev->first_boot && sdev->fw_state != SOF_FW_BOOT_COMPLETE) { + snd_sof_ipc_msgs_rx(sdev); + acp_dsp_ipc_host_done(sdev); + return IRQ_HANDLED; + } + 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); @@ -179,7 +190,7 @@ 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); + unsigned int offset = sdev->dsp_box.offset; if (!substream || !sdev->stream_box.size) acp_mailbox_read(sdev, offset, p, sz); @@ -196,4 +207,10 @@ int acp_sof_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) } EXPORT_SYMBOL_NS(acp_sof_ipc_get_mailbox_offset, SND_SOC_SOF_AMD_COMMON); +int acp_sof_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id) +{ + return 0; +} +EXPORT_SYMBOL_NS(acp_sof_ipc_get_window_offset, SND_SOC_SOF_AMD_COMMON); + MODULE_DESCRIPTION("AMD ACP sof-ipc driver"); diff --git a/sound/soc/sof/amd/acp-pcm.c b/sound/soc/sof/amd/acp-pcm.c index 0ba8ae46bd76..727c3a784a20 100644 --- a/sound/soc/sof/amd/acp-pcm.c +++ b/sound/soc/sof/amd/acp-pcm.c @@ -42,7 +42,8 @@ int acp_pcm_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substr /* write buffer size of stream in scratch memory */ - buf_offset = offsetof(struct scratch_reg_conf, buf_size); + buf_offset = sdev->debug_box.offset + + offsetof(struct scratch_reg_conf, buf_size); index = stream->stream_tag - 1; buf_offset = buf_offset + index * 4; diff --git a/sound/soc/sof/amd/acp-stream.c b/sound/soc/sof/amd/acp-stream.c index f71b4e660b14..6f40ef7ba85e 100644 --- a/sound/soc/sof/amd/acp-stream.c +++ b/sound/soc/sof/amd/acp-stream.c @@ -89,7 +89,8 @@ int acp_dsp_stream_config(struct snd_sof_dev *sdev, struct acp_dsp_stream *strea /* write phy_addr in scratch memory */ - phy_addr_offset = offsetof(struct scratch_reg_conf, reg_offset); + phy_addr_offset = sdev->debug_box.offset + + offsetof(struct scratch_reg_conf, reg_offset); index = stream_tag - 1; phy_addr_offset = phy_addr_offset + index * 4; @@ -97,6 +98,7 @@ int acp_dsp_stream_config(struct snd_sof_dev *sdev, struct acp_dsp_stream *strea phy_addr_offset, stream->reg_offset); /* Group Enable */ + offset = offset + sdev->debug_box.offset; reg_val = desc->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); diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 47eaabc95aa5..36966643e36a 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -42,7 +42,8 @@ static void init_dma_descriptor(struct acp_dev_data *adata) const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); unsigned int addr; - addr = desc->sram_pte_offset + offsetof(struct scratch_reg_conf, dma_desc); + addr = desc->sram_pte_offset + sdev->debug_box.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); @@ -54,8 +55,9 @@ static void configure_dma_descriptor(struct acp_dev_data *adata, unsigned short 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); + offset = ACP_SCRATCH_REG_0 + sdev->debug_box.offset + + 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); @@ -516,6 +518,15 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) return ret; } + sdev->dsp_box.offset = 0; + sdev->dsp_box.size = BOX_SIZE_512; + + sdev->host_box.offset = sdev->dsp_box.offset + sdev->dsp_box.size; + sdev->host_box.size = BOX_SIZE_512; + + sdev->debug_box.offset = sdev->host_box.offset + sdev->host_box.size; + sdev->debug_box.size = BOX_SIZE_1024; + acp_memory_init(sdev); acp_dsp_stream_init(sdev); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index e59a8655d859..dd3c072d0172 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -66,6 +66,9 @@ #define MBOX_READY_MASK 0x80000000 #define MBOX_STATUS_MASK 0xFFFF +#define BOX_SIZE_512 0x200 +#define BOX_SIZE_1024 0x400 + struct acp_atu_grp_pte { u32 low; u32 high; @@ -90,10 +93,6 @@ struct dma_descriptor { /* 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*/ -- cgit v1.2.3 From 4df5b13dec9e1b5a12db47ee92eb3f7da5c3deb5 Mon Sep 17 00:00:00 2001 From: Xiaoyan Li Date: Tue, 20 Sep 2022 15:14:34 -0500 Subject: ASoC: amd: yc: Add ASUS UM5302TA into DMI table ASUS Zenbook S 13 OLED (UM5302TA) needs this quirk to get the built-in microphone working properly. Link: https://bugzilla.kernel.org/show_bug.cgi?id=216270 Signed-off-by: Xiaoyan Li Suggested-by: Mario Limonciello Reviewed-by: Mario Limonciello Signed-off-by: Mario Limonciello Link: https://lore.kernel.org/r/20220920201436.19734-2-mario.limonciello@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/yc/acp6x-mach.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c index e0b24e1daef3..5eab3baf3573 100644 --- a/sound/soc/amd/yc/acp6x-mach.c +++ b/sound/soc/amd/yc/acp6x-mach.c @@ -171,6 +171,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "21J6"), } }, + { + .driver_data = &acp6x_card, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "UM5302TA"), + } + }, {} }; -- cgit v1.2.3 From 2232b2dd8cd4f1e6d554b2c3f6899ce36f791b67 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 20 Sep 2022 15:14:35 -0500 Subject: ASoC: amd: yc: Add Lenovo Yoga Slim 7 Pro X to quirks table Lenovo Yoga Slim 7 Pro X has an ACP DMIC that isn't specified in the ASL or existing quirk list. Add it to the quirk table to let DMIC work on these systems. Link: https://bugzilla.kernel.org/show_bug.cgi?id=216299 Tested-by: Sebastian S Reported-and-tested-by: Travis Glenn Hansen Signed-off-by: Mario Limonciello Link: https://lore.kernel.org/r/20220920201436.19734-3-mario.limonciello@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/yc/acp6x-mach.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c index 5eab3baf3573..2cb50d5cf1a9 100644 --- a/sound/soc/amd/yc/acp6x-mach.c +++ b/sound/soc/amd/yc/acp6x-mach.c @@ -171,6 +171,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "21J6"), } }, + { + .driver_data = &acp6x_card, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "82"), + } + }, { .driver_data = &acp6x_card, .matches = { -- cgit v1.2.3 From 2edd66eccfeab9734512fac352b50d17366246f5 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 20 Sep 2022 23:14:13 +0800 Subject: ASoC: rt5682s: simplify the return of rt5682s_probe() After commit bfc5e8b860ad ("ASoC: rt5682s: Reduce coupling of Micbias and Vref2 settings"), the return of rt5682s_probe() can be simplified. No functional changed. Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20220920151413.3455255-1-yangyingliang@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682s.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c index 2831f2f61aba..3b91a3442c68 100644 --- a/sound/soc/codecs/rt5682s.c +++ b/sound/soc/codecs/rt5682s.c @@ -2864,15 +2864,10 @@ static inline int rt5682s_dai_probe_clks(struct snd_soc_component *component) static int rt5682s_probe(struct snd_soc_component *component) { struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); - int ret; rt5682s->component = component; - ret = rt5682s_dai_probe_clks(component); - if (ret) - return ret; - - return 0; + return rt5682s_dai_probe_clks(component); } static void rt5682s_remove(struct snd_soc_component *component) -- cgit v1.2.3 From d20fa87e80c363a1c9534afb31df2fa90087e51d Mon Sep 17 00:00:00 2001 From: Astrid Rost Date: Wed, 21 Sep 2022 10:18:34 +0200 Subject: ASoC: ts3a227e: add parameters to control debounce times Add devicetree parameters to control the insert, release and press debounce times. Signed-off-by: Astrid Rost Link: https://lore.kernel.org/r/20220921081834.22009-4-astrid.rost@axis.com Signed-off-by: Mark Brown --- sound/soc/codecs/ts3a227e.c | 61 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c index d8ab0810fceb..2305a472d132 100644 --- a/sound/soc/codecs/ts3a227e.c +++ b/sound/soc/codecs/ts3a227e.c @@ -78,12 +78,20 @@ static const int ts3a227e_buttons[] = { #define ADC_COMPLETE_INT_DISABLE 0x04 #define INTB_DISABLE 0x08 +/* TS3A227E_REG_SETTING_1 0x4 */ +#define DEBOUNCE_INSERTION_SETTING_SFT (0) +#define DEBOUNCE_INSERTION_SETTING_MASK (0x7 << DEBOUNCE_PRESS_SETTING_SFT) + /* TS3A227E_REG_SETTING_2 0x05 */ #define KP_ENABLE 0x04 /* TS3A227E_REG_SETTING_3 0x06 */ -#define MICBIAS_SETTING_SFT (3) +#define MICBIAS_SETTING_SFT 3 #define MICBIAS_SETTING_MASK (0x7 << MICBIAS_SETTING_SFT) +#define DEBOUNCE_RELEASE_SETTING_SFT 2 +#define DEBOUNCE_RELEASE_SETTING_MASK (0x1 << DEBOUNCE_RELEASE_SETTING_SFT) +#define DEBOUNCE_PRESS_SETTING_SFT 0 +#define DEBOUNCE_PRESS_SETTING_MASK (0x3 << DEBOUNCE_PRESS_SETTING_SFT) /* TS3A227E_REG_ACCESSORY_STATUS 0x0b */ #define TYPE_3_POLE 0x01 @@ -136,7 +144,7 @@ static bool ts3a227e_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { case TS3A227E_REG_INTERRUPT ... TS3A227E_REG_INTERRUPT_DISABLE: - case TS3A227E_REG_SETTING_2: + case TS3A227E_REG_SETTING_1 ... TS3A227E_REG_SETTING_2: case TS3A227E_REG_SWITCH_STATUS_1 ... TS3A227E_REG_ADC_OUTPUT: return true; default: @@ -269,14 +277,55 @@ static const struct regmap_config ts3a227e_regmap_config = { static int ts3a227e_parse_device_property(struct ts3a227e *ts3a227e, struct device *dev) { - u32 micbias; + u32 value; + u32 value_ms; + u32 setting3_value = 0; + u32 setting3_mask = 0; int err; - err = device_property_read_u32(dev, "ti,micbias", &micbias); + err = device_property_read_u32(dev, "ti,micbias", &value); + if (!err) { + setting3_mask = MICBIAS_SETTING_MASK; + setting3_value = (value << MICBIAS_SETTING_SFT) & + MICBIAS_SETTING_MASK; + } + + err = device_property_read_u32(dev, "ti,debounce-release-ms", + &value_ms); if (!err) { + value = (value_ms > 10); + setting3_mask |= DEBOUNCE_RELEASE_SETTING_MASK; + setting3_value |= (value << DEBOUNCE_RELEASE_SETTING_SFT) & + DEBOUNCE_RELEASE_SETTING_MASK; + } + + err = device_property_read_u32(dev, "ti,debounce-press-ms", &value_ms); + if (!err) { + value = (value_ms + 20) / 40; + if (value > 3) + value = 3; + setting3_mask |= DEBOUNCE_PRESS_SETTING_MASK; + setting3_value |= (value << DEBOUNCE_PRESS_SETTING_SFT) & + DEBOUNCE_PRESS_SETTING_MASK; + } + + if (setting3_mask) regmap_update_bits(ts3a227e->regmap, TS3A227E_REG_SETTING_3, - MICBIAS_SETTING_MASK, - (micbias & 0x07) << MICBIAS_SETTING_SFT); + setting3_mask, setting3_value); + + err = device_property_read_u32(dev, "ti,debounce-insertion-ms", + &value_ms); + if (!err) { + if (value_ms < 165) + value = (value_ms + 15) / 30; + else if (value_ms < 1500) + value = 6; + else + value = 7; + regmap_update_bits(ts3a227e->regmap, TS3A227E_REG_SETTING_1, + DEBOUNCE_INSERTION_SETTING_MASK, + (value << DEBOUNCE_INSERTION_SETTING_SFT) & + DEBOUNCE_INSERTION_SETTING_MASK); } return 0; -- cgit v1.2.3 From be541bd473618f64fa14138dc7f63b0643363f7b Mon Sep 17 00:00:00 2001 From: Astrid Rost Date: Wed, 21 Sep 2022 10:18:32 +0200 Subject: ASoC: ti,ts3a227e: convert to yaml Convert from ts3a227e.txt to yaml. Signed-off-by: Astrid Rost Link: https://lore.kernel.org/r/20220921081834.22009-2-astrid.rost@axis.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/ti,ts3a227e.yaml | 65 ++++++++++++++++++++++ .../devicetree/bindings/sound/ts3a227e.txt | 30 ---------- 2 files changed, 65 insertions(+), 30 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/ti,ts3a227e.yaml delete mode 100644 Documentation/devicetree/bindings/sound/ts3a227e.txt diff --git a/Documentation/devicetree/bindings/sound/ti,ts3a227e.yaml b/Documentation/devicetree/bindings/sound/ti,ts3a227e.yaml new file mode 100644 index 000000000000..327d204cf957 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ti,ts3a227e.yaml @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/ti,ts3a227e.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments TS3A227E + Autonomous Audio Accessory Detection and Configuration Switch + +maintainers: + - Dylan Reid + +description: | + The TS3A227E detect headsets of 3-ring and 4-ring standards and + switches automatically to route the microphone correctly. It also + handles key press detection in accordance with the Android audio + headset specification v1.0. + +properties: + compatible: + enum: + - ti,ts3a227e + + reg: + const: 0x3b + + interrupts: + maxItems: 1 + + ti,micbias: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Intended MICBIAS voltage (datasheet section 9.6.7). + enum: + - 0 # 2.1 V + - 1 # 2.2 V + - 2 # 2.3 V + - 3 # 2.4 V + - 4 # 2.5 V + - 5 # 2.6 V + - 6 # 2.7 V + - 7 # 2.8 V + default: 1 + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + codec: audio-controller@3b { + compatible = "ti,ts3a227e"; + reg = <0x3b>; + interrupt-parent = <&gpio1>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/ts3a227e.txt b/Documentation/devicetree/bindings/sound/ts3a227e.txt deleted file mode 100644 index 21ab45bc7e8f..000000000000 --- a/Documentation/devicetree/bindings/sound/ts3a227e.txt +++ /dev/null @@ -1,30 +0,0 @@ -Texas Instruments TS3A227E -Autonomous Audio Accessory Detection and Configuration Switch - -The TS3A227E detect headsets of 3-ring and 4-ring standards and -switches automatically to route the microphone correctly. It also -handles key press detection in accordance with the Android audio -headset specification v1.0. - -Required properties: - - - compatible: Should contain "ti,ts3a227e". - - reg: The i2c address. Should contain <0x3b>. - - interrupts: Interrupt number for /INT pin from the 227e - -Optional properies: - - ti,micbias: Intended MICBIAS voltage (datasheet section 9.6.7). - Select 0/1/2/3/4/5/6/7 to specify MICBIAS voltage - 2.1V/2.2V/2.3V/2.4V/2.5V/2.6V/2.7V/2.8V - Default value is "1" (2.2V). - -Examples: - - i2c { - ts3a227e@3b { - compatible = "ti,ts3a227e"; - reg = <0x3b>; - interrupt-parent = <&gpio>; - interrupts = <3 IRQ_TYPE_LEVEL_LOW>; - }; - }; -- cgit v1.2.3 From 6a47412d0798735b0715d224574d216dba9e630c Mon Sep 17 00:00:00 2001 From: Astrid Rost Date: Wed, 21 Sep 2022 10:18:33 +0200 Subject: ASoC: ti,ts3a227e: add control of debounce Add devicetree parameters to control the insertion, release and press debounce times. Signed-off-by: Astrid Rost Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220921081834.22009-3-astrid.rost@axis.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/ti,ts3a227e.yaml | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/ti,ts3a227e.yaml b/Documentation/devicetree/bindings/sound/ti,ts3a227e.yaml index 327d204cf957..785930658029 100644 --- a/Documentation/devicetree/bindings/sound/ti,ts3a227e.yaml +++ b/Documentation/devicetree/bindings/sound/ti,ts3a227e.yaml @@ -41,6 +41,35 @@ properties: - 7 # 2.8 V default: 1 + ti,debounce-release-ms: + description: key release debounce time in ms (datasheet section 9.6.7). + enum: + - 0 + - 20 + default: 20 + + ti,debounce-press-ms: + description: key press debounce time in ms (datasheet section 9.6.7). + enum: + - 2 + - 40 + - 80 + - 120 + default: 80 + + ti,debounce-insertion-ms: + description: headset insertion debounce time in ms (datasheet section 9.6.5). + enum: + - 2 + - 30 + - 60 + - 90 + - 120 + - 150 + - 1000 + - 2000 + default: 90 + required: - compatible - reg -- cgit v1.2.3 From ee81cfb58286c1aed3263d2fc94b321e7d963f08 Mon Sep 17 00:00:00 2001 From: Zeng Heng Date: Wed, 21 Sep 2022 11:38:19 +0800 Subject: ASoC: sunxi: fix declaration compile error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just fix compile error without any logic changes. sound/soc/sunxi/sun50i-dmic.c:62:1: error: ‘static’ is not at beginning of declaration [-Werror=old-style-declaration] 62 | const static struct dmic_rate dmic_rate_s[] = { | ^~~~~ Signed-off-by: Zeng Heng Link: https://lore.kernel.org/r/20220921033819.2188233-1-zengheng4@huawei.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun50i-dmic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sunxi/sun50i-dmic.c b/sound/soc/sunxi/sun50i-dmic.c index cd3c07f2070f..86cff5a5b1bd 100644 --- a/sound/soc/sunxi/sun50i-dmic.c +++ b/sound/soc/sunxi/sun50i-dmic.c @@ -59,7 +59,7 @@ struct dmic_rate { unsigned int rate_bit; }; -const static struct dmic_rate dmic_rate_s[] = { +static const struct dmic_rate dmic_rate_s[] = { {48000, 0x0}, {44100, 0x0}, {32000, 0x1}, -- cgit v1.2.3 From 9bf320f0cf872bf23d9f03abefeff2130acbd6c5 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 21 Sep 2022 11:33:22 +0200 Subject: ALSA: hda/hdmi: Simplify the pcm_idx condition in hdmi_pcm_setup_pin() Make the code more readable. Signed-off-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20220921093322.82609-1-perex@perex.cz Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 1eb894e6cdf1..11c22dfced06 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1472,10 +1472,9 @@ static void hdmi_pcm_setup_pin(struct hdmi_spec *spec, int mux_idx; bool non_pcm; - if (per_pin->pcm_idx >= 0 && per_pin->pcm_idx < spec->pcm_used) - pcm = get_pcm_rec(spec, per_pin->pcm_idx); - else + if (per_pin->pcm_idx < 0 || per_pin->pcm_idx >= spec->pcm_used) return; + pcm = get_pcm_rec(spec, per_pin->pcm_idx); if (!pcm->pcm) return; if (!test_bit(per_pin->pcm_idx, &spec->pcm_in_use)) -- cgit v1.2.3 From 2fa22c3c755fb06a0c4507320c929616bbae1ec3 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 21 Sep 2022 11:33:49 +0200 Subject: ALSA: hda/hdmi: ELD procfs - print the codec NIDs It is useful for the debugging to print also the used HDA codec NIDs used for the given HDMI device. With the dynamic converter assignment the converter NID is changed dynamically. Signed-off-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20220921093349.82680-1-perex@perex.cz Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 6 +++++- sound/pci/hda/hda_local.h | 3 ++- sound/pci/hda/patch_hdmi.c | 3 ++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 9e97443795f8..1d108ed5c6f2 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -440,7 +440,8 @@ static void hdmi_print_sad_info(int i, struct cea_sad *a, } void snd_hdmi_print_eld_info(struct hdmi_eld *eld, - struct snd_info_buffer *buffer) + struct snd_info_buffer *buffer, + hda_nid_t pin_nid, int dev_id, hda_nid_t cvt_nid) { struct parsed_hdmi_eld *e = &eld->info; char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; @@ -462,6 +463,9 @@ void snd_hdmi_print_eld_info(struct hdmi_eld *eld, snd_iprintf(buffer, "monitor_present\t\t%d\n", eld->monitor_present); snd_iprintf(buffer, "eld_valid\t\t%d\n", eld->eld_valid); + snd_iprintf(buffer, "codec_pin_nid\t\t0x%x\n", pin_nid); + snd_iprintf(buffer, "codec_dev_id\t\t0x%x\n", dev_id); + snd_iprintf(buffer, "codec_cvt_nid\t\t0x%x\n", cvt_nid); if (!eld->eld_valid) return; snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name); diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 682dca2057db..53a5a62b78fa 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -712,7 +712,8 @@ int snd_hdmi_get_eld_ati(struct hda_codec *codec, hda_nid_t nid, #ifdef CONFIG_SND_PROC_FS void snd_hdmi_print_eld_info(struct hdmi_eld *eld, - struct snd_info_buffer *buffer); + struct snd_info_buffer *buffer, + hda_nid_t pin_nid, int dev_id, hda_nid_t cvt_nid); void snd_hdmi_write_eld_info(struct hdmi_eld *eld, struct snd_info_buffer *buffer); #endif diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 11c22dfced06..d2c6ba2634f1 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -496,7 +496,8 @@ static void print_eld_info(struct snd_info_entry *entry, struct hdmi_spec_per_pin *per_pin = entry->private_data; mutex_lock(&per_pin->lock); - snd_hdmi_print_eld_info(&per_pin->sink_eld, buffer); + snd_hdmi_print_eld_info(&per_pin->sink_eld, buffer, per_pin->pin_nid, + per_pin->dev_id, per_pin->cvt_nid); mutex_unlock(&per_pin->lock); } -- cgit v1.2.3 From 61eb0add28023119773d6aab8f402e149473920c Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 21 Sep 2022 14:27:51 +0300 Subject: ASoC: SOF: ipc4-topology: Free the ida when IPC fails in sof_ipc4_widget_setup() The allocated ida needs to be freed up if the IPC message fails since next time when we try again to set up the widget we are going to try to allocate another ID and given enough tries, we are going to run out of unique IDs. Fixes: 711d0427c713 ("ASoC: SOF: ipc4-topology: move ida allocate/free to widget_setup/free") Signed-off-by: Peter Ujfalusi Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220921112751.9253-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 66bbe101680c..a81af5f73a4b 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1543,9 +1543,16 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget msg->data_ptr = ipc_data; ret = sof_ipc_tx_message(sdev->ipc, msg, ipc_size, NULL, 0); - if (ret < 0) + if (ret < 0) { dev_err(sdev->dev, "failed to create module %s\n", swidget->widget->name); + if (swidget->id != snd_soc_dapm_scheduler) { + struct sof_ipc4_fw_module *fw_module = swidget->module_info; + + ida_free(&fw_module->m_ida, swidget->instance_id); + } + } + return ret; } -- cgit v1.2.3 From a921986f445ad611b441c8ee7749dc6dfc770481 Mon Sep 17 00:00:00 2001 From: Chunxu Li Date: Wed, 21 Sep 2022 20:02:39 +0800 Subject: ASoC: SOF: mediatek: add pcm_pointer callback for mt8186 add pcm_pointer callback for mt8186 to support read host position from DSP Signed-off-by: Chunxu Li Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220921120239.31934-1-chunxu.li@mediatek.com Signed-off-by: Mark Brown --- sound/soc/sof/mediatek/mt8186/mt8186.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c index 9ec89fc7fec0..181189e00e02 100644 --- a/sound/soc/sof/mediatek/mt8186/mt8186.c +++ b/sound/soc/sof/mediatek/mt8186/mt8186.c @@ -470,6 +470,38 @@ static int mt8186_pcm_hw_params(struct snd_sof_dev *sdev, return 0; } +static snd_pcm_uframes_t mt8186_pcm_pointer(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + int ret; + snd_pcm_uframes_t pos; + struct snd_sof_pcm *spcm; + struct sof_ipc_stream_posn posn; + struct snd_sof_pcm_stream *stream; + struct snd_soc_component *scomp = sdev->component; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + + spcm = snd_sof_find_spcm_dai(scomp, rtd); + if (!spcm) { + dev_warn_ratelimited(sdev->dev, "warn: can't find PCM with DAI ID %d\n", + rtd->dai_link->id); + return 0; + } + + stream = &spcm->stream[substream->stream]; + ret = snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn)); + if (ret < 0) { + dev_warn(sdev->dev, "failed to read stream position: %d\n", ret); + return 0; + } + + memcpy(&stream->posn, &posn, sizeof(posn)); + pos = spcm->stream[substream->stream].posn.host_posn; + pos = bytes_to_frames(substream->runtime, pos); + + return pos; +} + static struct snd_soc_dai_driver mt8186_dai[] = { { .name = "SOF_DL1", @@ -537,6 +569,7 @@ static struct snd_sof_dsp_ops sof_mt8186_ops = { /* stream callbacks */ .pcm_open = sof_stream_pcm_open, .pcm_hw_params = mt8186_pcm_hw_params, + .pcm_pointer = mt8186_pcm_pointer, .pcm_close = sof_stream_pcm_close, /* firmware loading */ -- cgit v1.2.3 From 6de0b0292b548010b09917e8cdfc337a6dcf67ce Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 22 Sep 2022 11:59:12 +0200 Subject: ASoC: es8316: fix register sync error in suspend/resume tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SOF CI tests report failures with the following error thrown kernel: es8316 i2c-ESSX8336:00: Unable to sync registers 0x0-0x1. -121 ES8336 only supports I2C read/write one byte a time, so we do need to set the .use_single_read and .use_single_write flags to avoid this sync issue. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Péter Ujfalusi Reviewed-by: FRED OH Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20220922095912.27010-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8316.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index de7185f73e1e..10a204255b6a 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -793,6 +793,8 @@ static const struct regmap_access_table es8316_volatile_table = { static const struct regmap_config es8316_regmap = { .reg_bits = 8, .val_bits = 8, + .use_single_read = true, + .use_single_write = true, .max_register = 0x53, .volatile_table = &es8316_volatile_table, .cache_type = REGCACHE_RBTREE, -- cgit v1.2.3 From 1c9a057eb7f45f8d233ae847d1e9fd64d163bd1c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 22 Sep 2022 12:02:53 +0200 Subject: ASoC: SOF: Intel: pci-tgl: reorder PCI IDs No functionality change, just sort ADL PCI IDs by increasing order. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20220922100254.27159-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/pci-tgl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c index aac47cd007e8..2729dd925327 100644 --- a/sound/soc/sof/intel/pci-tgl.c +++ b/sound/soc/sof/intel/pci-tgl.c @@ -231,8 +231,6 @@ static const struct pci_device_id sof_pci_ids[] = { .driver_data = (unsigned long)&rpls_desc}, { PCI_DEVICE(0x8086, 0x51c8), /* ADL-P */ .driver_data = (unsigned long)&adl_desc}, - { PCI_DEVICE(0x8086, 0x51cd), /* ADL-P */ - .driver_data = (unsigned long)&adl_desc}, { PCI_DEVICE(0x8086, 0x51c9), /* ADL-PS */ .driver_data = (unsigned long)&adl_desc}, { PCI_DEVICE(0x8086, 0x51ca), /* RPL-P */ @@ -241,6 +239,8 @@ static const struct pci_device_id sof_pci_ids[] = { .driver_data = (unsigned long)&rpl_desc}, { PCI_DEVICE(0x8086, 0x51cc), /* ADL-M */ .driver_data = (unsigned long)&adl_desc}, + { PCI_DEVICE(0x8086, 0x51cd), /* ADL-P */ + .driver_data = (unsigned long)&adl_desc}, { PCI_DEVICE(0x8086, 0x54c8), /* ADL-N */ .driver_data = (unsigned long)&adl_desc}, { 0, } -- cgit v1.2.3 From e2f0b9277810685f6a67201847082ec9852853bd Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 22 Sep 2022 12:02:54 +0200 Subject: ASoC: SOF: pci-tgl: add missing PCI IDs for RPL Add IDs for RPL-M and RPL-PX Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20220922100254.27159-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/pci-tgl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c index 2729dd925327..2d63cc236a68 100644 --- a/sound/soc/sof/intel/pci-tgl.c +++ b/sound/soc/sof/intel/pci-tgl.c @@ -241,6 +241,10 @@ static const struct pci_device_id sof_pci_ids[] = { .driver_data = (unsigned long)&adl_desc}, { PCI_DEVICE(0x8086, 0x51cd), /* ADL-P */ .driver_data = (unsigned long)&adl_desc}, + { PCI_DEVICE(0x8086, 0x51ce), /* RPL-M */ + .driver_data = (unsigned long)&rpl_desc}, + { PCI_DEVICE(0x8086, 0x51cf), /* RPL-PX */ + .driver_data = (unsigned long)&rpl_desc}, { PCI_DEVICE(0x8086, 0x54c8), /* ADL-N */ .driver_data = (unsigned long)&adl_desc}, { 0, } -- cgit v1.2.3 From b5eee17cf7ddaf7b29a031b2c48277038e7a171a Mon Sep 17 00:00:00 2001 From: ye xingchen Date: Thu, 22 Sep 2022 11:28:46 +0000 Subject: ALSA: hda/ca0132 - remove the unneeded result variable Return the value dsp_allocate_ports() directly instead of storing it in another redundant variable. Reported-by: Zeal Robot Signed-off-by: ye xingchen Link: https://lore.kernel.org/r/20220922112846.236987-1-ye.xingchen@zte.com.cn Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 208933792787..9580fe00cbd9 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -2962,7 +2962,6 @@ static int dsp_allocate_ports_format(struct hda_codec *codec, const unsigned short fmt, unsigned int *port_map) { - int status; unsigned int num_chans; unsigned int sample_rate_div = ((get_hdafmt_rate(fmt) >> 0) & 3) + 1; @@ -2976,9 +2975,7 @@ static int dsp_allocate_ports_format(struct hda_codec *codec, num_chans = get_hdafmt_chs(fmt) + 1; - status = dsp_allocate_ports(codec, num_chans, rate_multi, port_map); - - return status; + return dsp_allocate_ports(codec, num_chans, rate_multi, port_map); } /* -- cgit v1.2.3 From ef6f5494faf6a37c74990689a3bb3cee76d2544c Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 22 Sep 2022 10:40:17 +0200 Subject: ALSA: hda/hdmi: Use only dynamic PCM device allocation Per discussion on the alsa-devel mailing list [1], the legacy PIN to PCM device mapping is obsolete nowadays. The maximum number of the simultaneously usable PCM devices is equal to the HDMI codec converters. Remove the extra PCM devices (beyond the detected converters) and force the use of the dynamic PCM device allocation. The legacy code is removed. I believe that all HDMI codecs have the jack sensing feature. Move the check to the codec probe function and print a warning, if a codec without this feature is detected. [1] https://lore.kernel.org/alsa-devel/2f37e0b2-1e82-8c0b-2bbd-1e5038d6ecc6@perex.cz/ Cc: Kai Vehmanen Signed-off-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20220922084017.25925-1-perex@perex.cz Signed-off-by: Takashi Iwai --- include/sound/hda_codec.h | 1 - sound/pci/hda/patch_hdmi.c | 153 ++++++++------------------------------------ sound/soc/codecs/hda.c | 3 - sound/soc/codecs/hdac_hda.c | 3 - 4 files changed, 28 insertions(+), 132 deletions(-) diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h index 2a8fe7240f10..25ec8c181688 100644 --- a/include/sound/hda_codec.h +++ b/include/sound/hda_codec.h @@ -258,7 +258,6 @@ struct hda_codec { unsigned int link_down_at_suspend:1; /* link down at runtime suspend */ unsigned int relaxed_resume:1; /* don't resume forcibly for jack */ unsigned int forced_resume:1; /* forced resume for jack */ - unsigned int mst_no_extra_pcms:1; /* no backup PCMs for DP-MST */ #ifdef CONFIG_PM unsigned long power_on_acct; diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index d2c6ba2634f1..1863836b2685 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -167,8 +167,6 @@ struct hdmi_spec { struct hdmi_ops ops; bool dyn_pin_out; - bool dyn_pcm_assign; - bool dyn_pcm_no_legacy; /* hdmi interrupt trigger control flag for Nvidia codec */ bool hdmi_intr_trig_ctrl; bool nv_dp_workaround; /* workaround DP audio infoframe for Nvidia */ @@ -1188,9 +1186,7 @@ static void pin_cvt_fixup(struct hda_codec *codec, spec->ops.pin_cvt_fixup(codec, per_pin, cvt_nid); } -/* called in hdmi_pcm_open when no pin is assigned to the PCM - * in dyn_pcm_assign mode. - */ +/* called in hdmi_pcm_open when no pin is assigned to the PCM */ static int hdmi_pcm_open_no_pin(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream) @@ -1258,19 +1254,12 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, mutex_lock(&spec->pcm_lock); pin_idx = hinfo_to_pin_index(codec, hinfo); - if (!spec->dyn_pcm_assign) { - if (snd_BUG_ON(pin_idx < 0)) { - err = -EINVAL; - goto unlock; - } - } else { - /* no pin is assigned to the PCM - * PA need pcm open successfully when probe - */ - if (pin_idx < 0) { - err = hdmi_pcm_open_no_pin(hinfo, codec, substream); - goto unlock; - } + /* no pin is assigned to the PCM + * PA need pcm open successfully when probe + */ + if (pin_idx < 0) { + err = hdmi_pcm_open_no_pin(hinfo, codec, substream); + goto unlock; } err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx, false); @@ -1375,43 +1364,6 @@ static int hdmi_find_pcm_slot(struct hdmi_spec *spec, { int i; - /* on the new machines, try to assign the pcm slot dynamically, - * not use the preferred fixed map (legacy way) anymore. - */ - if (spec->dyn_pcm_no_legacy) - goto last_try; - - /* - * generic_hdmi_build_pcms() may allocate extra PCMs on some - * platforms (with maximum of 'num_nids + dev_num - 1') - * - * The per_pin of pin_nid_idx=n and dev_id=m prefers to get pcm-n - * if m==0. This guarantees that dynamic pcm assignments are compatible - * with the legacy static per_pin-pcm assignment that existed in the - * days before DP-MST. - * - * Intel DP-MST prefers this legacy behavior for compatibility, too. - * - * per_pin of m!=0 prefers to get pcm=(num_nids + (m - 1)). - */ - - if (per_pin->dev_id == 0 || spec->intel_hsw_fixup) { - if (!test_bit(per_pin->pin_nid_idx, &spec->pcm_bitmap)) - return per_pin->pin_nid_idx; - } else { - i = spec->num_nids + (per_pin->dev_id - 1); - if (i < spec->pcm_used && !(test_bit(i, &spec->pcm_bitmap))) - return i; - } - - /* have a second try; check the area over num_nids */ - for (i = spec->num_nids; i < spec->pcm_used; i++) { - if (!test_bit(i, &spec->pcm_bitmap)) - return i; - } - - last_try: - /* the last try; check the empty slots in pins */ for (i = 0; i < spec->pcm_used; i++) { if (!test_bit(i, &spec->pcm_bitmap)) return i; @@ -1573,14 +1525,12 @@ static void update_eld(struct hda_codec *codec, */ pcm_jack = pin_idx_to_pcm_jack(codec, per_pin); - if (spec->dyn_pcm_assign) { - if (eld->eld_valid) { - hdmi_attach_hda_pcm(spec, per_pin); - hdmi_pcm_setup_pin(spec, per_pin); - } else { - hdmi_pcm_reset_pin(spec, per_pin); - hdmi_detach_hda_pcm(spec, per_pin); - } + if (eld->eld_valid) { + hdmi_attach_hda_pcm(spec, per_pin); + hdmi_pcm_setup_pin(spec, per_pin); + } else { + hdmi_pcm_reset_pin(spec, per_pin); + hdmi_detach_hda_pcm(spec, per_pin); } /* if pcm_idx == -1, it means this is in monitor connection event * we can get the correct pcm_idx now. @@ -1942,7 +1892,7 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) * structures based on worst case. */ dev_num = spec->dev_num; - } else if (spec->dyn_pcm_assign && codec->dp_mst) { + } else if (codec->dp_mst) { dev_num = snd_hda_get_num_devices(codec, pin_nid) + 1; /* * spec->dev_num is the maxinum number of device entries @@ -1967,13 +1917,8 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) if (!per_pin) return -ENOMEM; - if (spec->dyn_pcm_assign) { - per_pin->pcm = NULL; - per_pin->pcm_idx = -1; - } else { - per_pin->pcm = get_hdmi_pcm(spec, pin_idx); - per_pin->pcm_idx = pin_idx; - } + per_pin->pcm = NULL; + per_pin->pcm_idx = -1; per_pin->pin_nid = pin_nid; per_pin->pin_nid_idx = spec->num_nids; per_pin->dev_id = i; @@ -1982,6 +1927,8 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) err = hdmi_read_pin_conn(codec, pin_idx); if (err < 0) return err; + if (!is_jack_detectable(codec, pin_nid)) + codec_warn(codec, "HDMI: pin NID 0x%x - jack not detectable\n", pin_nid); spec->num_pins++; } spec->num_nids++; @@ -2129,10 +2076,9 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, mutex_lock(&spec->pcm_lock); pin_idx = hinfo_to_pin_index(codec, hinfo); - if (spec->dyn_pcm_assign && pin_idx < 0) { - /* when dyn_pcm_assign and pcm is not bound to a pin - * skip pin setup and return 0 to make audio playback - * be ongoing + if (pin_idx < 0) { + /* when pcm is not bound to a pin skip pin setup and return 0 + * to make audio playback be ongoing */ pin_cvt_fixup(codec, NULL, cvt_nid); snd_hda_codec_setup_stream(codec, cvt_nid, @@ -2235,7 +2181,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, snd_hda_spdif_ctls_unassign(codec, pcm_idx); clear_bit(pcm_idx, &spec->pcm_in_use); pin_idx = hinfo_to_pin_index(codec, hinfo); - if (spec->dyn_pcm_assign && pin_idx < 0) + if (pin_idx < 0) goto unlock; if (snd_BUG_ON(pin_idx < 0)) { @@ -2333,21 +2279,8 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec) struct hdmi_spec *spec = codec->spec; int idx, pcm_num; - /* - * for non-mst mode, pcm number is the same as before - * for DP MST mode without extra PCM, pcm number is same - * for DP MST mode with extra PCMs, pcm number is - * (nid number + dev_num - 1) - * dev_num is the device entry number in a pin - */ - - if (spec->dyn_pcm_no_legacy && codec->mst_no_extra_pcms) - pcm_num = spec->num_cvts; - else if (codec->mst_no_extra_pcms) - pcm_num = spec->num_nids; - else - pcm_num = spec->num_nids + spec->dev_num - 1; - + /* limit the PCM devices to the codec converters */ + pcm_num = spec->num_cvts; codec_dbg(codec, "hdmi: pcm_num set to %d\n", pcm_num); for (idx = 0; idx < pcm_num; idx++) { @@ -2386,17 +2319,12 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pcm_idx) { char hdmi_str[32] = "HDMI/DP"; struct hdmi_spec *spec = codec->spec; - struct hdmi_spec_per_pin *per_pin = get_pin(spec, pcm_idx); struct snd_jack *jack; int pcmdev = get_pcm_rec(spec, pcm_idx)->device; int err; if (pcmdev > 0) sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev); - if (!spec->dyn_pcm_assign && - !is_jack_detectable(codec, per_pin->pin_nid)) - strncat(hdmi_str, " Phantom", - sizeof(hdmi_str) - strlen(hdmi_str) - 1); err = snd_jack_new(codec->card, hdmi_str, SND_JACK_AVOUT, &jack, true, false); @@ -2429,18 +2357,9 @@ static int generic_hdmi_build_controls(struct hda_codec *codec) /* create the spdif for each pcm * pin will be bound when monitor is connected */ - if (spec->dyn_pcm_assign) - err = snd_hda_create_dig_out_ctls(codec, + err = snd_hda_create_dig_out_ctls(codec, 0, spec->cvt_nids[0], HDA_PCM_TYPE_HDMI); - else { - struct hdmi_spec_per_pin *per_pin = - get_pin(spec, pcm_idx); - err = snd_hda_create_dig_out_ctls(codec, - per_pin->pin_nid, - per_pin->mux_nids[0], - HDA_PCM_TYPE_HDMI); - } if (err < 0) return err; snd_hda_spdif_ctls_unassign(codec, pcm_idx); @@ -2560,11 +2479,7 @@ static void generic_hdmi_free(struct hda_codec *codec) for (pcm_idx = 0; pcm_idx < spec->pcm_used; pcm_idx++) { if (spec->pcm_rec[pcm_idx].jack == NULL) continue; - if (spec->dyn_pcm_assign) - snd_device_free(codec->card, - spec->pcm_rec[pcm_idx].jack); - else - spec->pcm_rec[pcm_idx].jack = NULL; + snd_device_free(codec->card, spec->pcm_rec[pcm_idx].jack); } generic_spec_free(codec); @@ -3044,7 +2959,6 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid, return err; spec = codec->spec; codec->dp_mst = true; - spec->dyn_pcm_assign = true; spec->vendor_nid = vendor_nid; spec->port_map = port_map; spec->port_num = port_num; @@ -3108,17 +3022,9 @@ static int patch_i915_tgl_hdmi(struct hda_codec *codec) * the index indicate the port number. */ static const int map[] = {0x4, 0x6, 0x8, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}; - int ret; - - ret = intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 4, - enable_silent_stream); - if (!ret) { - struct hdmi_spec *spec = codec->spec; - spec->dyn_pcm_no_legacy = true; - } - - return ret; + return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 4, + enable_silent_stream); } static int patch_i915_adlp_hdmi(struct hda_codec *codec) @@ -3758,7 +3664,6 @@ static int patch_nvhdmi(struct hda_codec *codec) codec->dp_mst = true; spec = codec->spec; - spec->dyn_pcm_assign = true; err = hdmi_parse_codec(codec); if (err < 0) { @@ -4038,10 +3943,8 @@ static int patch_tegra234_hdmi(struct hda_codec *codec) return err; codec->dp_mst = true; - codec->mst_no_extra_pcms = true; spec = codec->spec; spec->dyn_pin_out = true; - spec->dyn_pcm_assign = true; spec->hdmi_intr_trig_ctrl = true; return tegra_hdmi_init(codec); diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c index ad20a3dff9b7..61e8e9be6b8d 100644 --- a/sound/soc/codecs/hda.c +++ b/sound/soc/codecs/hda.c @@ -224,9 +224,6 @@ static int hda_codec_probe(struct snd_soc_component *component) goto err; } - /* configure codec for 1:1 PCM:DAI mapping */ - codec->mst_no_extra_pcms = 1; - ret = snd_hda_codec_parse_pcms(codec); if (ret < 0) { dev_err(&hdev->dev, "unable to map pcms to dai %d\n", ret); diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index 77df4c5b274a..8af434e14bfb 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -461,9 +461,6 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) dev_dbg(&hdev->dev, "no patch file found\n"); } - /* configure codec for 1:1 PCM:DAI mapping */ - hcodec->mst_no_extra_pcms = 1; - ret = snd_hda_codec_parse_pcms(hcodec); if (ret < 0) { dev_err(&hdev->dev, "unable to map pcms to dai %d\n", ret); -- cgit v1.2.3 From ea8ef003aa53ad23e7705c5cab1c4e664faa6c79 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 21 Sep 2022 16:53:53 +0200 Subject: ASoC: wcd9335: fix order of Slimbus unprepare/disable Slimbus streams are first prepared and then enabled, so the cleanup path should reverse it. The unprepare sets stream->num_ports to 0 and frees the stream->ports. Calling disable after unprepare was not really effective (channels was not deactivated) and could lead to further issues due to making transfers on unprepared stream. Fixes: 20aedafdf492 ("ASoC: wcd9335: add support to wcd9335 codec") Cc: Signed-off-by: Krzysztof Kozlowski Reviewed-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220921145354.1683791-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index beeeb35e8032..8a1f741de948 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -1974,8 +1974,8 @@ static int wcd9335_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - slim_stream_unprepare(dai_data->sruntime); slim_stream_disable(dai_data->sruntime); + slim_stream_unprepare(dai_data->sruntime); break; default: break; -- cgit v1.2.3 From e96bca7eaa5747633ec638b065630ff83728982a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 21 Sep 2022 16:53:54 +0200 Subject: ASoC: wcd934x: fix order of Slimbus unprepare/disable Slimbus streams are first prepared and then enabled, so the cleanup path should reverse it. The unprepare sets stream->num_ports to 0 and frees the stream->ports. Calling disable after unprepare was not really effective (channels was not deactivated) and could lead to further issues due to making transfers on unprepared stream. Fixes: a61f3b4f476e ("ASoC: wcd934x: add support to wcd9340/wcd9341 codec") Cc: Signed-off-by: Krzysztof Kozlowski Reviewed-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220921145354.1683791-2-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd934x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index f56907d0942d..28175c746b9a 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -1913,8 +1913,8 @@ static int wcd934x_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - slim_stream_unprepare(dai_data->sruntime); slim_stream_disable(dai_data->sruntime); + slim_stream_unprepare(dai_data->sruntime); break; default: break; -- cgit v1.2.3 From 194ff8db03782d1dae41b7b42ea65da5748884c2 Mon Sep 17 00:00:00 2001 From: "Nícolas F. R. A. Prado" Date: Thu, 22 Sep 2022 19:59:46 -0400 Subject: ASoC: mediatek: mt8192-mt6359: Expose individual headset jack pins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rt5682 codec is able to distinguish between two event types: headphone insertion/removal and headset microphone insertion/removal. However, currently, the mt8192-mt6359 driver exposes a single kcontrol for the headset jack, so userspace isn't able to differentiate between the two events. Add a definition for the headset jack pins, so that a separate jack kcontrol is created for each one, allowing userspace to track and handle them individually. Signed-off-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Tested-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220922235951.252532-2-nfraprado@collabora.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c index 044d6ab71f0a..ff40ccd36f7e 100644 --- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c +++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c @@ -41,6 +41,18 @@ struct mt8192_mt6359_priv { struct snd_soc_jack hdmi_jack; }; +/* Headset jack detection DAPM pins */ +static struct snd_soc_jack_pin mt8192_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int mt8192_rt1015_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -326,11 +338,12 @@ static int mt8192_rt5682_init(struct snd_soc_pcm_runtime *rtd) return ret; } - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, - jack); + jack, mt8192_jack_pins, + ARRAY_SIZE(mt8192_jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; -- cgit v1.2.3 From aa51e3c127a43cf4862db5f0081da281f1aa6429 Mon Sep 17 00:00:00 2001 From: "Nícolas F. R. A. Prado" Date: Thu, 22 Sep 2022 19:59:47 -0400 Subject: ASoC: mediatek: mt8195: Expose individual headset jack pins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rt5682 codec is able to distinguish between two event types: headphone insertion/removal and headset microphone insertion/removal. However, currently, the mt8195 ASoC driver exposes a single kcontrol for the headset jack, so userspace isn't able to differentiate between the two events. Add a definition for the headset jack pins, so that a separate jack kcontrol is created for each one, allowing userspace to track and handle them individually. Signed-off-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Tested-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220922235951.252532-3-nfraprado@collabora.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8195/mt8195-mt6359.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359.c b/sound/soc/mediatek/mt8195/mt8195-mt6359.c index 961e769602d6..17d4c4108a9d 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359.c @@ -63,6 +63,18 @@ struct mt8195_mt6359_priv { struct clk *i2so1_mclk; }; +/* Headset jack detection DAPM pins */ +static struct snd_soc_jack_pin mt8195_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static const struct snd_soc_dapm_widget mt8195_mt6359_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), @@ -563,11 +575,12 @@ static int mt8195_rt5682_init(struct snd_soc_pcm_runtime *rtd) priv->i2so1_mclk = afe_priv->clk[MT8195_CLK_TOP_APLL12_DIV2]; - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, - jack); + jack, mt8195_jack_pins, + ARRAY_SIZE(mt8195_jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; -- cgit v1.2.3 From 13bee4a16ac5c5f0e3a5db868df991be57e74aa5 Mon Sep 17 00:00:00 2001 From: "Nícolas F. R. A. Prado" Date: Thu, 22 Sep 2022 19:59:48 -0400 Subject: ASoC: mediatek: mt8186-da7219: Add headset widgets with switches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add DAPM widgets for headphones and headset microphone, with matching switches, to allow toggling these paths based on the jack connection status. Note that differently from others (mt8192, mt8195 and mt8186-rt5682), the widget here is named "Headphones" (with an 's'), since "Headphone Switch" was already registered by da7219. Signed-off-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220922235951.252532-4-nfraprado@collabora.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c index 6f93f9dd4623..8d428bc4a3b2 100644 --- a/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c +++ b/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c @@ -950,6 +950,8 @@ static struct snd_soc_dai_link mt8186_mt6366_da7219_max98357_dai_links[] = { static const struct snd_soc_dapm_widget mt8186_mt6366_da7219_max98357_widgets[] = { SND_SOC_DAPM_SPK("Speakers", NULL), + SND_SOC_DAPM_HP("Headphones", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_OUTPUT("HDMI1"), SND_SOC_DAPM_MIXER(SOF_DMA_DL1, SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER(SOF_DMA_DL2, SND_SOC_NOPM, 0, 0, NULL, 0), @@ -961,6 +963,10 @@ static const struct snd_soc_dapm_route mt8186_mt6366_da7219_max98357_routes[] = { /* SPK */ { "Speakers", NULL, "Speaker"}, + /* Headset */ + { "Headphones", NULL, "HPL" }, + { "Headphones", NULL, "HPR" }, + { "MIC", NULL, "Headset Mic" }, /* HDMI */ { "HDMI1", NULL, "TX"}, /* SOF Uplink */ @@ -976,6 +982,8 @@ mt8186_mt6366_da7219_max98357_routes[] = { static const struct snd_kcontrol_new mt8186_mt6366_da7219_max98357_controls[] = { SOC_DAPM_PIN_SWITCH("Speakers"), + SOC_DAPM_PIN_SWITCH("Headphones"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("HDMI1"), }; -- cgit v1.2.3 From 8e986748680629a82398c65da0c5bda4c6a01b3d Mon Sep 17 00:00:00 2001 From: "Nícolas F. R. A. Prado" Date: Thu, 22 Sep 2022 19:59:49 -0400 Subject: ASoC: mediatek: mt8186-da7219: Expose individual headset jack pins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The da7219 codec is able to distinguish between two event types: headphone insertion/removal and headset microphone insertion/removal. However, currently, the mt8186-da7219 driver exposes a single kcontrol for the headset jack, so userspace isn't able to differentiate between the two events. Add a definition for the headset jack pins, so that a separate jack kcontrol is created for each one, allowing userspace to track and handle them individually. Signed-off-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220922235951.252532-5-nfraprado@collabora.com Signed-off-by: Mark Brown --- .../soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c index 8d428bc4a3b2..cfca6bdee834 100644 --- a/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c +++ b/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c @@ -37,6 +37,18 @@ struct mt8186_mt6366_da7219_max98357_priv { struct snd_soc_jack headset_jack, hdmi_jack; }; +/* Headset jack detection DAPM pins */ +static struct snd_soc_jack_pin mt8186_jack_pins[] = { + { + .pin = "Headphones", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static struct snd_soc_codec_conf mt8186_mt6366_da7219_max98357_codec_conf[] = { { .dlc = COMP_CODEC_CONF("mt6358-sound"), @@ -72,11 +84,12 @@ static int mt8186_da7219_init(struct snd_soc_pcm_runtime *rtd) } /* Enable Headset and 4 Buttons Jack detection */ - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, - jack); + jack, mt8186_jack_pins, + ARRAY_SIZE(mt8186_jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; -- cgit v1.2.3 From d888e7afa03f06d8091ecdd43f87d5396dfbf907 Mon Sep 17 00:00:00 2001 From: "Nícolas F. R. A. Prado" Date: Thu, 22 Sep 2022 19:59:50 -0400 Subject: ASoC: mediatek: mt8186-rt5682: Add headset widgets with switches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add DAPM widgets for headphones and headset microphone, with matching switches, to allow toggling these paths based on the jack connection status. Signed-off-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220922235951.252532-6-nfraprado@collabora.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c index 247f20f594d9..4360871bfc44 100644 --- a/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c +++ b/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c @@ -926,6 +926,8 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { static const struct snd_soc_dapm_widget mt8186_mt6366_rt1019_rt5682s_widgets[] = { SND_SOC_DAPM_SPK("Speakers", NULL), + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_OUTPUT("HDMI1"), SND_SOC_DAPM_MIXER(SOF_DMA_DL1, SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER(SOF_DMA_DL2, SND_SOC_NOPM, 0, 0, NULL, 0), @@ -937,6 +939,10 @@ static const struct snd_soc_dapm_route mt8186_mt6366_rt1019_rt5682s_routes[] = { /* SPK */ { "Speakers", NULL, "Speaker" }, + /* Headset */ + { "Headphone", NULL, "HPOL" }, + { "Headphone", NULL, "HPOR" }, + { "IN1P", NULL, "Headset Mic" }, /* HDMI */ { "HDMI1", NULL, "TX" }, /* SOF Uplink */ @@ -952,6 +958,8 @@ mt8186_mt6366_rt1019_rt5682s_routes[] = { static const struct snd_kcontrol_new mt8186_mt6366_rt1019_rt5682s_controls[] = { SOC_DAPM_PIN_SWITCH("Speakers"), + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("HDMI1"), }; -- cgit v1.2.3 From 42de42c22453064ffc9b72c259b2ab901dd766dc Mon Sep 17 00:00:00 2001 From: "Nícolas F. R. A. Prado" Date: Thu, 22 Sep 2022 19:59:51 -0400 Subject: ASoC: mediatek: mt8186-rt5682: Expose individual headset jack pins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rt5682 codec is able to distinguish between two event types: headphone insertion/removal and headset microphone insertion/removal. However, currently, the mt8186-rt5682 driver exposes a single kcontrol for the headset jack, so userspace isn't able to differentiate between the two events. Add a definition for the headset jack pins, so that a separate jack kcontrol is created for each one, allowing userspace to track and handle them individually. Signed-off-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220922235951.252532-7-nfraprado@collabora.com Signed-off-by: Mark Brown --- .../soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c index 4360871bfc44..2414c5b77233 100644 --- a/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c +++ b/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c @@ -41,6 +41,18 @@ struct mt8186_mt6366_rt1019_rt5682s_priv { struct snd_soc_jack headset_jack, hdmi_jack; }; +/* Headset jack detection DAPM pins */ +static struct snd_soc_jack_pin mt8186_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static struct snd_soc_codec_conf mt8186_mt6366_rt1019_rt5682s_codec_conf[] = { { .dlc = COMP_CODEC_CONF("mt6358-sound"), @@ -75,11 +87,12 @@ static int mt8186_rt5682s_init(struct snd_soc_pcm_runtime *rtd) return ret; } - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, - jack); + jack, mt8186_jack_pins, + ARRAY_SIZE(mt8186_jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; -- cgit v1.2.3 From af62eaf2872bf2c381f322c61f7ff751162797f6 Mon Sep 17 00:00:00 2001 From: Fred Oh Date: Thu, 22 Sep 2022 14:36:35 -0700 Subject: ASoC: SOF: Intel: introduce new op to handle dsp power down DSP core power down sequences are different between cavs platforms and MTL. Signed-off-by: Fred Oh Reviewed-by: Rander Wang Reviewed-by: Bard Liao Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220922213644.666315-2-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/shim.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h index 638159bee864..c7b4b1e0a824 100644 --- a/sound/soc/sof/intel/shim.h +++ b/sound/soc/sof/intel/shim.h @@ -186,6 +186,7 @@ struct sof_intel_dsp_desc { enum sof_intel_hw_ip_version hw_ip_version; bool (*check_sdw_irq)(struct snd_sof_dev *sdev); bool (*check_ipc_irq)(struct snd_sof_dev *sdev); + int (*power_down_dsp)(struct snd_sof_dev *sdev); int (*cl_init)(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot); }; -- cgit v1.2.3 From c714031f936e11ef9e5695efdb73cd1f45eedb69 Mon Sep 17 00:00:00 2001 From: Fred Oh Date: Thu, 22 Sep 2022 14:36:36 -0700 Subject: ASoC: SOF: Intel: define and set power_down_dsp op for HDA platforms hda_power_down_dsp is set for power_down_dsp op for all HDA platforms. Signed-off-by: Fred Oh Reviewed-by: Rander Wang Reviewed-by: Bard Liao Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220922213644.666315-3-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/apl.c | 1 + sound/soc/sof/intel/cnl.c | 2 ++ sound/soc/sof/intel/hda.c | 8 ++++++++ sound/soc/sof/intel/hda.h | 1 + sound/soc/sof/intel/icl.c | 1 + sound/soc/sof/intel/skl.c | 1 + sound/soc/sof/intel/tgl.c | 4 ++++ 7 files changed, 18 insertions(+) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 295df44be271..886eb79ebdf1 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -104,6 +104,7 @@ const struct sof_intel_dsp_desc apl_chip_info = { .quirks = SOF_INTEL_PROCEN_FMT_QUIRK, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, + .power_down_dsp = hda_power_down_dsp, .hw_ip_version = SOF_INTEL_CAVS_1_5_PLUS, }; EXPORT_SYMBOL_NS(apl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 180001d0a38a..dbdd96901377 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -412,6 +412,7 @@ const struct sof_intel_dsp_desc cnl_chip_info = { .check_sdw_irq = hda_common_check_sdw_irq, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, + .power_down_dsp = hda_power_down_dsp, .hw_ip_version = SOF_INTEL_CAVS_1_8, }; EXPORT_SYMBOL_NS(cnl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); @@ -442,6 +443,7 @@ const struct sof_intel_dsp_desc jsl_chip_info = { .check_sdw_irq = hda_common_check_sdw_irq, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, + .power_down_dsp = hda_power_down_dsp, .hw_ip_version = SOF_INTEL_CAVS_2_0, }; EXPORT_SYMBOL_NS(jsl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index f7068a7e2e81..c7fe13dee06c 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -1219,6 +1219,14 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) return 0; } +int hda_power_down_dsp(struct snd_sof_dev *sdev) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; + + return hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask); +} + #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) static void hda_generic_machine_select(struct snd_sof_dev *sdev, struct snd_soc_acpi_mach **mach) diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 2013a94020c6..65b6faff2153 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -567,6 +567,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_power_down_dsp(struct snd_sof_dev *sdev); 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 59ce3132fada..ea10ae7a7e1a 100644 --- a/sound/soc/sof/intel/icl.c +++ b/sound/soc/sof/intel/icl.c @@ -175,6 +175,7 @@ const struct sof_intel_dsp_desc icl_chip_info = { .check_sdw_irq = hda_common_check_sdw_irq, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, + .power_down_dsp = hda_power_down_dsp, .hw_ip_version = SOF_INTEL_CAVS_2_0, }; EXPORT_SYMBOL_NS(icl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index f05905e00368..fdf1814747c4 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -111,6 +111,7 @@ const struct sof_intel_dsp_desc skl_chip_info = { .rom_status_reg = HDA_DSP_SRAM_REG_ROM_STATUS_SKL, .rom_init_timeout = 300, .check_ipc_irq = hda_dsp_check_ipc_irq, + .power_down_dsp = hda_power_down_dsp, .hw_ip_version = SOF_INTEL_CAVS_1_5, }; EXPORT_SYMBOL_NS(skl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c index 5135e1c7e6cf..3d675e78c5fe 100644 --- a/sound/soc/sof/intel/tgl.c +++ b/sound/soc/sof/intel/tgl.c @@ -130,6 +130,7 @@ const struct sof_intel_dsp_desc tgl_chip_info = { .check_sdw_irq = hda_common_check_sdw_irq, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, + .power_down_dsp = hda_power_down_dsp, .hw_ip_version = SOF_INTEL_CAVS_2_5, }; EXPORT_SYMBOL_NS(tgl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); @@ -153,6 +154,7 @@ const struct sof_intel_dsp_desc tglh_chip_info = { .check_sdw_irq = hda_common_check_sdw_irq, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, + .power_down_dsp = hda_power_down_dsp, .hw_ip_version = SOF_INTEL_CAVS_2_5, }; EXPORT_SYMBOL_NS(tglh_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); @@ -176,6 +178,7 @@ const struct sof_intel_dsp_desc ehl_chip_info = { .check_sdw_irq = hda_common_check_sdw_irq, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, + .power_down_dsp = hda_power_down_dsp, .hw_ip_version = SOF_INTEL_CAVS_2_5, }; EXPORT_SYMBOL_NS(ehl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); @@ -199,6 +202,7 @@ const struct sof_intel_dsp_desc adls_chip_info = { .check_sdw_irq = hda_common_check_sdw_irq, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, + .power_down_dsp = hda_power_down_dsp, .hw_ip_version = SOF_INTEL_CAVS_2_5, }; EXPORT_SYMBOL_NS(adls_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); -- cgit v1.2.3 From 2090cb9bf57471900d5cdf11b47dd1a121f021bf Mon Sep 17 00:00:00 2001 From: Fred Oh Date: Thu, 22 Sep 2022 14:36:37 -0700 Subject: ASoC: SOF: Intel: mtl: define and set power_down_dsp op For MTL platform, dsp cores need to go power down first then dsp subsystem also need to set power down. Signed-off-by: Fred Oh Reviewed-by: Rander Wang Reviewed-by: Bard Liao Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220922213644.666315-4-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/mtl.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index 5408c34b04ef..8cc20e617117 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -406,6 +406,33 @@ static int mtl_dsp_core_power_down(struct snd_sof_dev *sdev, int core) return ret; } +static int mtl_power_down_dsp(struct snd_sof_dev *sdev) +{ + u32 dsphfdsscs, cpa; + int ret; + + /* first power down core */ + ret = mtl_dsp_core_power_down(sdev, SOF_DSP_PRIMARY_CORE); + if (ret) { + dev_err(sdev->dev, "mtl dsp power down error, %d\n", ret); + return ret; + } + + /* Set the DSP subsystem power down */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFDSSCS, + MTL_HFDSSCS_SPA_MASK, 0); + + /* Wait for unstable CPA read (1 then 0 then 1) just after setting SPA bit */ + usleep_range(1000, 1010); + + /* poll with timeout to check if operation successful */ + cpa = MTL_HFDSSCS_CPA_MASK; + dsphfdsscs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFDSSCS); + return snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_HFDSSCS, dsphfdsscs, + (dsphfdsscs & cpa) == 0, HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_RESET_TIMEOUT_US); +} + static int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot) { struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; @@ -792,6 +819,7 @@ const struct sof_intel_dsp_desc mtl_chip_info = { .check_sdw_irq = mtl_dsp_check_sdw_irq, .check_ipc_irq = mtl_dsp_check_ipc_irq, .cl_init = mtl_dsp_cl_init, + .power_down_dsp = mtl_power_down_dsp, .hw_ip_version = SOF_INTEL_ACE_1_0, }; EXPORT_SYMBOL_NS(mtl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); -- cgit v1.2.3 From e32de6402e5b51cd6a24861987b1846606beec13 Mon Sep 17 00:00:00 2001 From: Fred Oh Date: Thu, 22 Sep 2022 14:36:38 -0700 Subject: ASoC: SOF: Intel: use power_down_dsp op in hda_dsp_remove Use power_down_dsp op to differentiate power down sequences in platforms. Signed-off-by: Fred Oh Reviewed-by: Rander Wang Reviewed-by: Bard Liao Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220922213644.666315-5-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index c7fe13dee06c..35f074aa69da 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -1191,9 +1191,9 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, 0); - /* disable cores */ - if (chip) - hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask); + /* no need to check for error as the DSP will be disabled anyway */ + if (chip && chip->power_down_dsp) + chip->power_down_dsp(sdev); /* disable DSP */ snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, -- cgit v1.2.3 From 423693a6c351f4abb869d1dbf5df7374766aaa1a Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 22 Sep 2022 14:36:39 -0700 Subject: ASoC: SOF: Intel: Add a new op for disabling interrupts The sequence for disabling DSP interrupts varies between different IP versions. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Rander Wang Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220922213644.666315-6-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/shim.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h index c7b4b1e0a824..3ceba5c39317 100644 --- a/sound/soc/sof/intel/shim.h +++ b/sound/soc/sof/intel/shim.h @@ -187,6 +187,7 @@ struct sof_intel_dsp_desc { bool (*check_sdw_irq)(struct snd_sof_dev *sdev); bool (*check_ipc_irq)(struct snd_sof_dev *sdev); int (*power_down_dsp)(struct snd_sof_dev *sdev); + int (*disable_interrupts)(struct snd_sof_dev *sdev); int (*cl_init)(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot); }; -- cgit v1.2.3 From b2520dbcb0d3646e70fedcaab2bdfb33df1c8508 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 22 Sep 2022 14:36:40 -0700 Subject: ASoC: SOF: Intel: define and set the disable_interrupts op for cavs platforms Disable the IPC and SDW nterrupts in the disable_interrupts op for cavs platforms. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Rander Wang Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220922213644.666315-7-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/apl.c | 1 + sound/soc/sof/intel/cnl.c | 2 ++ sound/soc/sof/intel/hda-dsp.c | 8 ++++++++ sound/soc/sof/intel/hda.h | 1 + sound/soc/sof/intel/icl.c | 1 + sound/soc/sof/intel/skl.c | 1 + sound/soc/sof/intel/tgl.c | 4 ++++ 7 files changed, 18 insertions(+) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 886eb79ebdf1..44934675ec48 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -105,6 +105,7 @@ const struct sof_intel_dsp_desc apl_chip_info = { .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, + .disable_interrupts = hda_dsp_disable_interrupts, .hw_ip_version = SOF_INTEL_CAVS_1_5_PLUS, }; EXPORT_SYMBOL_NS(apl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index dbdd96901377..d41d02677ea5 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -413,6 +413,7 @@ const struct sof_intel_dsp_desc cnl_chip_info = { .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, + .disable_interrupts = hda_dsp_disable_interrupts, .hw_ip_version = SOF_INTEL_CAVS_1_8, }; EXPORT_SYMBOL_NS(cnl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); @@ -444,6 +445,7 @@ const struct sof_intel_dsp_desc jsl_chip_info = { .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, + .disable_interrupts = hda_dsp_disable_interrupts, .hw_ip_version = SOF_INTEL_CAVS_2_0, }; EXPORT_SYMBOL_NS(jsl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index f85ac55536fa..2ab2200fc44a 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -989,3 +989,11 @@ power_down: return ret; } + +int hda_dsp_disable_interrupts(struct snd_sof_dev *sdev) +{ + hda_sdw_int_enable(sdev, false); + hda_dsp_ipc_int_disable(sdev); + + return 0; +} diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 65b6faff2153..0b965799ea0d 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -587,6 +587,7 @@ void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags); void hda_ipc_dump(struct snd_sof_dev *sdev); void hda_ipc_irq_dump(struct snd_sof_dev *sdev); void hda_dsp_d0i3_work(struct work_struct *work); +int hda_dsp_disable_interrupts(struct snd_sof_dev *sdev); /* * DSP PCM Operations. diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c index ea10ae7a7e1a..f099a018ffb0 100644 --- a/sound/soc/sof/intel/icl.c +++ b/sound/soc/sof/intel/icl.c @@ -176,6 +176,7 @@ const struct sof_intel_dsp_desc icl_chip_info = { .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, + .disable_interrupts = hda_dsp_disable_interrupts, .hw_ip_version = SOF_INTEL_CAVS_2_0, }; EXPORT_SYMBOL_NS(icl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index fdf1814747c4..4ed7a85e6dd0 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -112,6 +112,7 @@ const struct sof_intel_dsp_desc skl_chip_info = { .rom_init_timeout = 300, .check_ipc_irq = hda_dsp_check_ipc_irq, .power_down_dsp = hda_power_down_dsp, + .disable_interrupts = hda_dsp_disable_interrupts, .hw_ip_version = SOF_INTEL_CAVS_1_5, }; EXPORT_SYMBOL_NS(skl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c index 3d675e78c5fe..2f34662015fd 100644 --- a/sound/soc/sof/intel/tgl.c +++ b/sound/soc/sof/intel/tgl.c @@ -131,6 +131,7 @@ const struct sof_intel_dsp_desc tgl_chip_info = { .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, + .disable_interrupts = hda_dsp_disable_interrupts, .hw_ip_version = SOF_INTEL_CAVS_2_5, }; EXPORT_SYMBOL_NS(tgl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); @@ -155,6 +156,7 @@ const struct sof_intel_dsp_desc tglh_chip_info = { .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, + .disable_interrupts = hda_dsp_disable_interrupts, .hw_ip_version = SOF_INTEL_CAVS_2_5, }; EXPORT_SYMBOL_NS(tglh_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); @@ -179,6 +181,7 @@ const struct sof_intel_dsp_desc ehl_chip_info = { .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, + .disable_interrupts = hda_dsp_disable_interrupts, .hw_ip_version = SOF_INTEL_CAVS_2_5, }; EXPORT_SYMBOL_NS(ehl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); @@ -203,6 +206,7 @@ const struct sof_intel_dsp_desc adls_chip_info = { .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, + .disable_interrupts = hda_dsp_disable_interrupts, .hw_ip_version = SOF_INTEL_CAVS_2_5, }; EXPORT_SYMBOL_NS(adls_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); -- cgit v1.2.3 From 39df087f6fa9436926b540d7d4022c09d0b8fde7 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 22 Sep 2022 14:36:41 -0700 Subject: ASoC: SOF: Intel: MTL: define and set the disable_interrupts op Disable the IPC and SDW interrupts in the disable_interrupts op. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Rander Wang Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220922213644.666315-8-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/mtl.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index 8cc20e617117..107c1f42f421 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -741,6 +741,12 @@ static void mtl_ipc_dump(struct snd_sof_dev *sdev) hipcida, hipctdr, hipcctl); } +static int mtl_dsp_disable_interrupts(struct snd_sof_dev *sdev) +{ + mtl_disable_ipc_interrupts(sdev); + return mtl_disable_interrupts(sdev); +} + /* Meteorlake ops */ struct snd_sof_dsp_ops sof_mtl_ops; EXPORT_SYMBOL_NS(sof_mtl_ops, SND_SOC_SOF_INTEL_HDA_COMMON); @@ -820,6 +826,7 @@ const struct sof_intel_dsp_desc mtl_chip_info = { .check_ipc_irq = mtl_dsp_check_ipc_irq, .cl_init = mtl_dsp_cl_init, .power_down_dsp = mtl_power_down_dsp, + .disable_interrupts = mtl_dsp_disable_interrupts, .hw_ip_version = SOF_INTEL_ACE_1_0, }; EXPORT_SYMBOL_NS(mtl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); -- cgit v1.2.3 From 0fbd539f666a7783b55507675b6c68673db27766 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 22 Sep 2022 14:36:42 -0700 Subject: ASoC: SOF: Intel: HDA: use IPC version-specific ops Use the IP-specific ops for disabling interrupts and powering down the DSP in hda_suspend. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Rander Wang Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220922213644.666315-9-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dsp.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 2ab2200fc44a..3c76f843454b 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -629,10 +629,9 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) sdev->fw_state == SOF_FW_BOOT_FAILED) hda->skip_imr_boot = true; - hda_sdw_int_enable(sdev, false); - - /* disable IPC interrupts */ - hda_dsp_ipc_int_disable(sdev); + ret = chip->disable_interrupts(sdev); + if (ret < 0) + return ret; #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) hda_codec_jack_wake_enable(sdev, runtime_suspend); @@ -641,11 +640,9 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) snd_hdac_ext_bus_link_power_down_all(bus); #endif - /* power down DSP */ - ret = hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask); + ret = chip->power_down_dsp(sdev); if (ret < 0) { - dev_err(sdev->dev, - "error: failed to power down core during suspend\n"); + dev_err(sdev->dev, "failed to power down DSP during suspend\n"); return ret; } -- cgit v1.2.3 From 6ae87bab269b347c725893ee162a0ad03ecca97c Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 22 Sep 2022 14:36:43 -0700 Subject: ASoC: SOF: Intel: MTL: reuse the common ops for PM Now that the disabling of interrupts and powering down the DSP has been abstracted, re-use the common ops for PM for MTL as well. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Rander Wang Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220922213644.666315-10-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/mtl.c | 150 ---------------------------------------------- 1 file changed, 150 deletions(-) diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index 107c1f42f421..eb4e00af74a3 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -579,150 +579,6 @@ static int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id) return MTL_SRAM_WINDOW_OFFSET(id); } -static int mtl_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) -{ - struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; - const struct sof_intel_dsp_desc *chip = hda->desc; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - struct hdac_bus *bus = sof_to_bus(sdev); -#endif - u32 dsphfdsscs; - u32 cpa; - int ret; - int i; - - mtl_disable_ipc_interrupts(sdev); - ret = mtl_disable_interrupts(sdev); - if (ret) - return ret; - -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - hda_codec_jack_wake_enable(sdev, runtime_suspend); - /* power down all hda link */ - snd_hdac_ext_bus_link_power_down_all(bus); -#endif - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFPWRCTL, - MTL_HFPWRCTL_WPDSPHPXPG, 0); - - /* Set the DSP subsystem power down */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFDSSCS, - MTL_HFDSSCS_SPA_MASK, 0); - - /* Wait for unstable CPA read (1 then 0 then 1) just after setting SPA bit */ - usleep_range(1000, 1010); - - /* poll with timeout to check if operation successful */ - cpa = MTL_HFDSSCS_CPA_MASK; - dsphfdsscs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFDSSCS); - ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_HFDSSCS, dsphfdsscs, - (dsphfdsscs & cpa) == 0, HDA_DSP_REG_POLL_INTERVAL_US, - HDA_DSP_RESET_TIMEOUT_US); - if (ret < 0) - dev_err(sdev->dev, "failed to disable DSP subsystem\n"); - - /* reset ref counts for all cores */ - for (i = 0; i < chip->cores_num; i++) - sdev->dsp_core_ref_count[i] = 0; - - /* TODO: need to reset controller? */ - - /* display codec can be powered off after link reset */ - hda_codec_i915_display_power(sdev, false); - - return 0; -} - -static int mtl_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state) -{ - const struct sof_dsp_power_state target_dsp_state = { - .state = target_state, - .substate = target_state == SOF_DSP_PM_D0 ? - SOF_HDA_DSP_PM_D0I3 : 0, - }; - int ret; - - ret = mtl_suspend(sdev, false); - if (ret < 0) - return ret; - - return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); -} - -static int mtl_dsp_runtime_suspend(struct snd_sof_dev *sdev) -{ - const struct sof_dsp_power_state target_state = { - .state = SOF_DSP_PM_D3, - }; - int ret; - - ret = mtl_suspend(sdev, true); - if (ret < 0) - return ret; - - return snd_sof_dsp_set_power_state(sdev, &target_state); -} - -static int mtl_resume(struct snd_sof_dev *sdev, bool runtime_resume) -{ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - struct hdac_bus *bus = sof_to_bus(sdev); - struct hdac_ext_link *hlink = NULL; -#endif - - /* display codec must be powered before link reset */ - hda_codec_i915_display_power(sdev, true); - -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - /* check jack status */ - if (runtime_resume) { - hda_codec_jack_wake_enable(sdev, false); - if (sdev->system_suspend_target == SOF_SUSPEND_NONE) - hda_codec_jack_check(sdev); - } - - /* turn off the links that were off before suspend */ - list_for_each_entry(hlink, &bus->hlink_list, list) { - if (!hlink->ref_count) - snd_hdac_ext_bus_link_power_down(hlink); - } - - /* check dma status and clean up CORB/RIRB buffers */ - if (!bus->cmd_dma_state) - snd_hdac_bus_stop_cmd_io(bus); -#endif - - return 0; -} - -static int mtl_dsp_resume(struct snd_sof_dev *sdev) -{ - const struct sof_dsp_power_state target_state = { - .state = SOF_DSP_PM_D0, - .substate = SOF_HDA_DSP_PM_D0I0, - }; - int ret; - - ret = mtl_resume(sdev, false); - if (ret < 0) - return ret; - - return snd_sof_dsp_set_power_state(sdev, &target_state); -} - -static int mtl_dsp_runtime_resume(struct snd_sof_dev *sdev) -{ - const struct sof_dsp_power_state target_state = { - .state = SOF_DSP_PM_D0, - }; - int ret; - - ret = mtl_resume(sdev, true); - if (ret < 0) - return ret; - - return snd_sof_dsp_set_power_state(sdev, &target_state); -} - static void mtl_ipc_dump(struct snd_sof_dev *sdev) { u32 hipcctl; @@ -785,12 +641,6 @@ int sof_mtl_ops_init(struct snd_sof_dev *sdev) /* dsp core get/put */ /* TODO: add core_get and core_put */ - /* PM */ - sof_mtl_ops.suspend = mtl_dsp_suspend; - sof_mtl_ops.resume = mtl_dsp_resume; - sof_mtl_ops.runtime_suspend = mtl_dsp_runtime_suspend; - sof_mtl_ops.runtime_resume = mtl_dsp_runtime_resume; - sdev->private = devm_kzalloc(sdev->dev, sizeof(struct sof_ipc4_fw_data), GFP_KERNEL); if (!sdev->private) return -ENOMEM; -- cgit v1.2.3 From 68fb254e9ccca9e3f832f86b707eb2551aa5b86d Mon Sep 17 00:00:00 2001 From: Yong Zhi Date: Thu, 22 Sep 2022 14:36:44 -0700 Subject: ASoC: SOF: Intel: MTL: remove the unnecessary snd_sof_dsp_read() The return val of snd_sof_dsp_read() right before polling the same register is not used, so remove the redundant call. Signed-off-by: Yong Zhi Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220922213644.666315-11-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/mtl.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index eb4e00af74a3..27ec171cb586 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -144,7 +144,6 @@ static int mtl_enable_interrupts(struct snd_sof_dev *sdev) /* check if operation was successful */ host_ipc = MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK; - irqinten = snd_sof_dsp_read(sdev, HDA_DSP_BAR, hfintipptr); ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, hfintipptr, irqinten, (irqinten & host_ipc) == host_ipc, HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); @@ -159,7 +158,6 @@ static int mtl_enable_interrupts(struct snd_sof_dev *sdev) /* check if operation was successful */ host_ipc = MTL_DSP_REG_HfHIPCIE_IE_MASK; - hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE); ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, hipcie, (hipcie & host_ipc) == host_ipc, HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); @@ -171,7 +169,6 @@ static int mtl_enable_interrupts(struct snd_sof_dev *sdev) snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, MTL_DSP_REG_HfSNDWIE_IE_MASK, MTL_DSP_REG_HfSNDWIE_IE_MASK); host_ipc = MTL_DSP_REG_HfSNDWIE_IE_MASK; - hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE); ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, hipcie, (hipcie & host_ipc) == host_ipc, HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); @@ -199,7 +196,6 @@ static int mtl_disable_interrupts(struct snd_sof_dev *sdev) /* check if operation was successful */ host_ipc = MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK; - irqinten = snd_sof_dsp_read(sdev, HDA_DSP_BAR, hfintipptr); ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, hfintipptr, irqinten, (irqinten & host_ipc) == 0, HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); @@ -213,7 +209,6 @@ static int mtl_disable_interrupts(struct snd_sof_dev *sdev) /* check if operation was successful */ host_ipc = MTL_DSP_REG_HfHIPCIE_IE_MASK; - hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE); ret1 = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, hipcie, (hipcie & host_ipc) == 0, HDA_DSP_REG_POLL_INTERVAL_US, @@ -228,7 +223,6 @@ static int mtl_disable_interrupts(struct snd_sof_dev *sdev) snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, MTL_DSP_REG_HfSNDWIE_IE_MASK, 0); host_ipc = MTL_DSP_REG_HfSNDWIE_IE_MASK; - hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE); ret1 = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, hipcie, (hipcie & host_ipc) == 0, HDA_DSP_REG_POLL_INTERVAL_US, @@ -260,7 +254,6 @@ static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) /* poll with timeout to check if operation successful */ cpa = MTL_HFDSSCS_CPA_MASK; - dsphfdsscs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFDSSCS); ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_HFDSSCS, dsphfdsscs, (dsphfdsscs & cpa) == cpa, HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); @@ -277,7 +270,6 @@ static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) /* poll with timeout to check if operation successful */ pgs = MTL_HFPWRSTS_DSPHPXPGS_MASK; - dsphfpwrsts = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFPWRSTS); ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_HFPWRSTS, dsphfpwrsts, (dsphfpwrsts & pgs) == pgs, HDA_DSP_REG_POLL_INTERVAL_US, -- cgit v1.2.3 From 14ed837b9740cc6ec25910980d67c22894b4ff56 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 22 Sep 2022 12:35:02 +0200 Subject: ASoC: mediatek: mt8195-mt6359: Use snd_soc_pm_ops instead of custom ops It is possible to use the standard snd_soc_pm_ops for this card: remove the custom mt8195_mt6359_pm_ops. Signed-off-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220922103502.49981-1-angelogioacchino.delregno@collabora.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8195/mt8195-mt6359.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359.c b/sound/soc/mediatek/mt8195/mt8195-mt6359.c index 961e769602d6..23bdde6acd1c 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359.c @@ -1532,16 +1532,11 @@ static const struct of_device_id mt8195_mt6359_dt_match[] = { {}, }; -static const struct dev_pm_ops mt8195_mt6359_pm_ops = { - .poweroff = snd_soc_poweroff, - .restore = snd_soc_resume, -}; - static struct platform_driver mt8195_mt6359_driver = { .driver = { .name = "mt8195_mt6359", .of_match_table = mt8195_mt6359_dt_match, - .pm = &mt8195_mt6359_pm_ops, + .pm = &snd_soc_pm_ops, }, .probe = mt8195_mt6359_dev_probe, }; -- cgit v1.2.3 From 4f865485e8ef1d04de23fc1def1fa4e39fb00b91 Mon Sep 17 00:00:00 2001 From: Gaosheng Cui Date: Fri, 23 Sep 2022 17:03:55 +0800 Subject: ASoC: fsl: Remove unused inline function imx_pcm_dma_params_init_data() The imx_pcm_dma_params_init_data() are no longer used since commit c31da0b196f9 ("ASoC: imx-ssi: Remove unused driver"), and the function is used to initialize some members of "struct imx_dma_data", it's more readable to assign the value directly, imx_pcm_dma_params_init_data is useless, so remove it. Signed-off-by: Gaosheng Cui Link: https://lore.kernel.org/r/20220923090355.507648-1-cuigaosheng1@huawei.com Signed-off-by: Mark Brown --- sound/soc/fsl/imx-pcm.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/sound/soc/fsl/imx-pcm.h b/sound/soc/fsl/imx-pcm.h index 06b25f4b26b6..ac5f57c3cc55 100644 --- a/sound/soc/fsl/imx-pcm.h +++ b/sound/soc/fsl/imx-pcm.h @@ -18,15 +18,6 @@ #define IMX_DEFAULT_DMABUF_SIZE (64 * 1024) -static inline void -imx_pcm_dma_params_init_data(struct imx_dma_data *dma_data, - int dma, enum sdma_peripheral_type peripheral_type) -{ - dma_data->dma_request = dma; - dma_data->priority = DMA_PRIO_HIGH; - dma_data->peripheral_type = peripheral_type; -} - struct imx_pcm_fiq_params { int irq; void __iomem *base; -- cgit v1.2.3 From 0402cca4828dd9556d36ddef67710993b7063f7c Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 22 Sep 2022 08:37:52 -0700 Subject: ASoC: Intel: sof_da7219_mx98360a: Access num_codecs through dai_link After commit 3989ade2d1e7 ("ASoC: soc.h: remove num_cpus/codecs"), the following build error occurs: sound/soc/intel/boards/sof_da7219_max98373.c:198:27: error: no member named 'num_codecs' in 'struct snd_soc_pcm_runtime' for (j = 0; j < runtime->num_codecs; j++) { ~~~~~~~ ^ 1 error generated. This conversion was missed by the aforementioned change. Do it now to fix the build error. Fixes: 3989ade2d1e7 ("ASoC: soc.h: remove num_cpus/codecs") Signed-off-by: Nathan Chancellor Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220922153752.336193-1-nathan@kernel.org Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_da7219_max98373.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/sof_da7219_max98373.c b/sound/soc/intel/boards/sof_da7219_max98373.c index 34cf849a8344..e048e789e633 100644 --- a/sound/soc/intel/boards/sof_da7219_max98373.c +++ b/sound/soc/intel/boards/sof_da7219_max98373.c @@ -195,7 +195,7 @@ static int ssp1_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream); int ret, j; - for (j = 0; j < runtime->num_codecs; j++) { + for (j = 0; j < runtime->dai_link->num_codecs; j++) { struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, j); if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) { -- cgit v1.2.3 From fdc972d4a754b32cdf05294669ae0d6036242826 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 6 Sep 2022 18:01:01 +0100 Subject: ASoC: codecs: wsa-macro: handle swr_reset correctly Reset soundwire block on frame sync generation clock reset. Without this we are hitting read/write timeouts randomly during runtime pm. Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220906170112.1984-2-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-wsa-macro.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index 27da6c6c3c5a..130d25b334ff 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -338,7 +338,6 @@ struct wsa_macro { int ec_hq[WSA_MACRO_RX1 + 1]; u16 prim_int_users[WSA_MACRO_RX1 + 1]; u16 wsa_mclk_users; - bool reset_swr; unsigned long active_ch_mask[WSA_MACRO_MAX_DAIS]; unsigned long active_ch_cnt[WSA_MACRO_MAX_DAIS]; int rx_port_value[WSA_MACRO_RX_MAX]; @@ -2271,23 +2270,16 @@ static int wsa_swrm_clock(struct wsa_macro *wsa, bool enable) wsa_macro_mclk_enable(wsa, true); /* reset swr ip */ - if (wsa->reset_swr) - regmap_update_bits(regmap, - CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, - CDC_WSA_SWR_RST_EN_MASK, - CDC_WSA_SWR_RST_ENABLE); + regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, + CDC_WSA_SWR_RST_EN_MASK, CDC_WSA_SWR_RST_ENABLE); regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, CDC_WSA_SWR_CLK_EN_MASK, CDC_WSA_SWR_CLK_ENABLE); /* Bring out of reset */ - if (wsa->reset_swr) - regmap_update_bits(regmap, - CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, - CDC_WSA_SWR_RST_EN_MASK, - CDC_WSA_SWR_RST_DISABLE); - wsa->reset_swr = false; + regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, + CDC_WSA_SWR_RST_EN_MASK, CDC_WSA_SWR_RST_DISABLE); } else { regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, CDC_WSA_SWR_CLK_EN_MASK, 0); @@ -2431,7 +2423,6 @@ static int wsa_macro_probe(struct platform_device *pdev) dev_set_drvdata(dev, wsa); - wsa->reset_swr = true; wsa->dev = dev; /* set MCLK and NPL rates */ -- cgit v1.2.3 From 1a4e73915a7553d7ffb4f365b8a671bb2fa1f7ef Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 6 Sep 2022 18:01:02 +0100 Subject: ASoC: codecs: rx-macro: handle swr_reset correctly Reset soundwire block on frame sync generation clock reset. Without this we are hitting read/write timeouts randomly during runtime pm. Along with this remove a swr_reset redundant flag. Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220906170112.1984-3-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-rx-macro.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index 3143f9cd7277..338e3f0cad12 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -596,7 +596,6 @@ struct rx_macro { int rx_port_value[RX_MACRO_PORTS_MAX]; u16 prim_int_users[INTERP_MAX]; int rx_mclk_users; - bool reset_swr; int clsh_users; int rx_mclk_cnt; bool is_ear_mode_on; @@ -3442,18 +3441,15 @@ static int swclk_gate_enable(struct clk_hw *hw) } rx_macro_mclk_enable(rx, true); - if (rx->reset_swr) - regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL, - CDC_RX_SWR_RESET_MASK, - CDC_RX_SWR_RESET); + regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL, + CDC_RX_SWR_RESET_MASK, + CDC_RX_SWR_RESET); regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL, CDC_RX_SWR_CLK_EN_MASK, 1); - if (rx->reset_swr) - regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL, - CDC_RX_SWR_RESET_MASK, 0); - rx->reset_swr = false; + regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL, + CDC_RX_SWR_RESET_MASK, 0); return 0; } @@ -3579,7 +3575,6 @@ static int rx_macro_probe(struct platform_device *pdev) dev_set_drvdata(dev, rx); - rx->reset_swr = true; rx->dev = dev; /* set MCLK and NPL rates */ @@ -3701,7 +3696,6 @@ static int __maybe_unused rx_macro_runtime_resume(struct device *dev) } regcache_cache_only(rx->regmap, false); regcache_sync(rx->regmap); - rx->reset_swr = true; return 0; err_fsgen: -- cgit v1.2.3 From d83a7201412d32e2ac76f20439470976b2edf699 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 6 Sep 2022 18:01:03 +0100 Subject: ASoC: codecs: tx-macro: handle swr_reset correctly Reset soundwire block on frame sync generation clock reset. Without this we are hitting read/write timeouts randomly during runtime pm. Along with this remove a swr_reset redundant flag. Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220906170112.1984-4-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-tx-macro.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c index 55503ba480bb..c19bb19b717b 100644 --- a/sound/soc/codecs/lpass-tx-macro.c +++ b/sound/soc/codecs/lpass-tx-macro.c @@ -268,7 +268,6 @@ struct tx_macro { struct clk *fsgen; struct clk_hw hw; bool dec_active[NUM_DECIMATORS]; - bool reset_swr; int tx_mclk_users; u16 dmic_clk_div; bool bcs_enable; @@ -1702,18 +1701,14 @@ static int swclk_gate_enable(struct clk_hw *hw) } tx_macro_mclk_enable(tx, true); - if (tx->reset_swr) - regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL, - CDC_TX_SWR_RESET_MASK, - CDC_TX_SWR_RESET_ENABLE); + regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL, + CDC_TX_SWR_RESET_MASK, CDC_TX_SWR_RESET_ENABLE); regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL, CDC_TX_SWR_CLK_EN_MASK, CDC_TX_SWR_CLK_ENABLE); - if (tx->reset_swr) - regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL, - CDC_TX_SWR_RESET_MASK, 0x0); - tx->reset_swr = false; + regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL, + CDC_TX_SWR_RESET_MASK, 0x0); return 0; } @@ -1855,7 +1850,6 @@ static int tx_macro_probe(struct platform_device *pdev) dev_set_drvdata(dev, tx); - tx->reset_swr = true; tx->dev = dev; /* set MCLK and NPL rates */ @@ -1970,7 +1964,6 @@ static int __maybe_unused tx_macro_runtime_resume(struct device *dev) regcache_cache_only(tx->regmap, false); regcache_sync(tx->regmap); - tx->reset_swr = true; return 0; err_fsgen: -- cgit v1.2.3 From 1c6a7f5250ce81f11a248f9bf88fdbca8b6b0b5d Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 6 Sep 2022 18:01:04 +0100 Subject: ASoC: codecs: tx-macro: fix active_decimator array currently active_decimator[] is unsigned long however we store negative values when there is no decimator setup -1. This is first bug, and the second bug is that we do not check if the decimator is valid before writing to register using decimator as offset in CDC_TXn_TX_PATH_CTL() Fix these both by making active_decimator as integer array and adding check in tx_macro_digital_mute() before accessing CDC_TXn_TX_PATH_CTL() register. Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220906170112.1984-5-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-tx-macro.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c index c19bb19b717b..5c03ef8d88b3 100644 --- a/sound/soc/codecs/lpass-tx-macro.c +++ b/sound/soc/codecs/lpass-tx-macro.c @@ -259,7 +259,7 @@ struct tx_macro { struct tx_mute_work tx_mute_dwork[NUM_DECIMATORS]; unsigned long active_ch_mask[TX_MACRO_MAX_DAIS]; unsigned long active_ch_cnt[TX_MACRO_MAX_DAIS]; - unsigned long active_decimator[TX_MACRO_MAX_DAIS]; + int active_decimator[TX_MACRO_MAX_DAIS]; struct regmap *regmap; struct clk *mclk; struct clk *npl; @@ -1117,6 +1117,10 @@ static int tx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream) struct tx_macro *tx = snd_soc_component_get_drvdata(component); u16 decimator; + /* active decimator not set yet */ + if (tx->active_decimator[dai->id] == -1) + return 0; + decimator = tx->active_decimator[dai->id]; if (mute) -- cgit v1.2.3 From c1057a08af438e0cf5450c1d977a3011198ed2f8 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 6 Sep 2022 18:01:05 +0100 Subject: ASoC: codecs: tx-macro: fix kcontrol put tx_macro_tx_mixer_put() and tx_macro_dec_mode_put() currently returns zero eventhough it changes the value. Fix this, so that change notifications are sent correctly. Fixes: d207bdea0ca9 ("ASoC: codecs: lpass-tx-macro: add dapm widgets and route") Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220906170112.1984-6-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-tx-macro.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c index 5c03ef8d88b3..7f9370ed126f 100644 --- a/sound/soc/codecs/lpass-tx-macro.c +++ b/sound/soc/codecs/lpass-tx-macro.c @@ -822,17 +822,23 @@ static int tx_macro_tx_mixer_put(struct snd_kcontrol *kcontrol, struct tx_macro *tx = snd_soc_component_get_drvdata(component); if (enable) { + if (tx->active_decimator[dai_id] == dec_id) + return 0; + set_bit(dec_id, &tx->active_ch_mask[dai_id]); tx->active_ch_cnt[dai_id]++; tx->active_decimator[dai_id] = dec_id; } else { + if (tx->active_decimator[dai_id] == -1) + return 0; + tx->active_ch_cnt[dai_id]--; clear_bit(dec_id, &tx->active_ch_mask[dai_id]); tx->active_decimator[dai_id] = -1; } snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, update); - return 0; + return 1; } static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w, @@ -1018,9 +1024,12 @@ static int tx_macro_dec_mode_put(struct snd_kcontrol *kcontrol, int path = e->shift_l; struct tx_macro *tx = snd_soc_component_get_drvdata(component); + if (tx->dec_mode[path] == value) + return 0; + tx->dec_mode[path] = value; - return 0; + return 1; } static int tx_macro_get_bcs(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From 3e29fb7479760d6d03380125d500b60081ccb5e9 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 6 Sep 2022 18:01:06 +0100 Subject: ASoC: codecs: wsa883x: add clock stop support WSA883x does support clock stop, so remove code that reset the Codec during runtime pm suspend and add flag to mark clock stop support. Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220906170112.1984-7-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wsa883x.c | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c index 63e1d7aa6137..c7b10bbfba7e 100644 --- a/sound/soc/codecs/wsa883x.c +++ b/sound/soc/codecs/wsa883x.c @@ -415,7 +415,6 @@ #define WSA883X_NUM_REGISTERS (WSA883X_EMEM_63 + 1) #define WSA883X_MAX_REGISTER (WSA883X_NUM_REGISTERS - 1) -#define WSA883X_PROBE_TIMEOUT 1000 #define WSA883X_VERSION_1_0 0 #define WSA883X_VERSION_1_1 1 @@ -1409,6 +1408,7 @@ static int wsa883x_probe(struct sdw_slave *pdev, wsa883x->sconfig.type = SDW_STREAM_PDM; pdev->prop.sink_ports = GENMASK(WSA883X_MAX_SWR_PORTS, 0); + pdev->prop.simple_clk_stop_capable = true; pdev->prop.sink_dpn_prop = wsa_sink_dpn_prop; pdev->prop.scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; gpiod_direction_output(wsa883x->sd_n, 1); @@ -1440,43 +1440,17 @@ err: static int __maybe_unused wsa883x_runtime_suspend(struct device *dev) { struct regmap *regmap = dev_get_regmap(dev, NULL); - struct wsa883x_priv *wsa883x = dev_get_drvdata(dev); - - gpiod_direction_output(wsa883x->sd_n, 0); regcache_cache_only(regmap, true); regcache_mark_dirty(regmap); - regulator_disable(wsa883x->vdd); return 0; } static int __maybe_unused wsa883x_runtime_resume(struct device *dev) { - struct sdw_slave *slave = dev_to_sdw_dev(dev); struct regmap *regmap = dev_get_regmap(dev, NULL); - struct wsa883x_priv *wsa883x = dev_get_drvdata(dev); - unsigned long time; - int ret; - - ret = regulator_enable(wsa883x->vdd); - if (ret) { - dev_err(dev, "Failed to enable vdd regulator (%d)\n", ret); - return ret; - } - - gpiod_direction_output(wsa883x->sd_n, 1); - - time = wait_for_completion_timeout(&slave->initialization_complete, - msecs_to_jiffies(WSA883X_PROBE_TIMEOUT)); - if (!time) { - dev_err(dev, "Initialization not complete, timed out\n"); - gpiod_direction_output(wsa883x->sd_n, 0); - regulator_disable(wsa883x->vdd); - return -ETIMEDOUT; - } - usleep_range(20000, 20010); regcache_cache_only(regmap, false); regcache_sync(regmap); -- cgit v1.2.3 From 473d218b56559934ef4720a6fc086c8ad0da9d38 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 6 Sep 2022 18:01:07 +0100 Subject: ASoC: qcom: dt-bindings: add sm8450 and sc8280xp compatibles This patch adds SM8450 and SC8280XP compatible entry for LPASS TX, RX, WSA and VA codec macros. Signed-off-by: Srinivas Kandagatla Acked-by: Rob Herring Link: https://lore.kernel.org/r/20220906170112.1984-8-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml | 2 ++ Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml | 2 ++ Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml | 2 ++ Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml | 2 ++ 4 files changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml index a6905bcf89d2..1de11e7f33bb 100644 --- a/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml @@ -14,6 +14,8 @@ properties: enum: - qcom,sc7280-lpass-rx-macro - qcom,sm8250-lpass-rx-macro + - qcom,sm8450-lpass-rx-macro + - qcom,sc8280xp-lpass-rx-macro reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml index 324595a62ae8..de8297b358e8 100644 --- a/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml @@ -14,6 +14,8 @@ properties: enum: - qcom,sc7280-lpass-tx-macro - qcom,sm8250-lpass-tx-macro + - qcom,sm8450-lpass-tx-macro + - qcom,sc8280xp-lpass-tx-macro reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml index 7b4cc84eda8c..9f473c08cb2e 100644 --- a/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml @@ -14,6 +14,8 @@ properties: enum: - qcom,sc7280-lpass-va-macro - qcom,sm8250-lpass-va-macro + - qcom,sm8450-lpass-va-macro + - qcom,sc8280xp-lpass-va-macro reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml index 13cdb8a10687..4959ad658eac 100644 --- a/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml @@ -14,6 +14,8 @@ properties: enum: - qcom,sc7280-lpass-wsa-macro - qcom,sm8250-lpass-wsa-macro + - qcom,sm8450-lpass-wsa-macro + - qcom,sc8280xp-lpass-wsa-macro reg: maxItems: 1 -- cgit v1.2.3 From 8d2be441ebc1078eaa9f2b7aa7c6d3880973851e Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 6 Sep 2022 18:01:08 +0100 Subject: ASoC: codecs: wsa-macro: add support for sm8450 and sc8280xp Add compatible for sm8450 and sc8280xp. Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220906170112.1984-9-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-wsa-macro.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index 130d25b334ff..5e0abefe7cce 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -2552,6 +2552,8 @@ static const struct dev_pm_ops wsa_macro_pm_ops = { static const struct of_device_id wsa_macro_dt_match[] = { {.compatible = "qcom,sc7280-lpass-wsa-macro"}, {.compatible = "qcom,sm8250-lpass-wsa-macro"}, + {.compatible = "qcom,sm8450-lpass-wsa-macro"}, + {.compatible = "qcom,sc8280xp-lpass-wsa-macro" }, {} }; MODULE_DEVICE_TABLE(of, wsa_macro_dt_match); -- cgit v1.2.3 From 7ca36514752fa5bdf0d237436dc0042aefbf42ad Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 6 Sep 2022 18:01:09 +0100 Subject: ASoC: codecs: tx-macro: add support for sm8450 and sc8280xp Add compatible for sm8450 and sc8280xp. Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220906170112.1984-10-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-tx-macro.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c index 7f9370ed126f..ee15cf6b98bb 100644 --- a/sound/soc/codecs/lpass-tx-macro.c +++ b/sound/soc/codecs/lpass-tx-macro.c @@ -1994,6 +1994,8 @@ static const struct dev_pm_ops tx_macro_pm_ops = { static const struct of_device_id tx_macro_dt_match[] = { { .compatible = "qcom,sc7280-lpass-tx-macro" }, { .compatible = "qcom,sm8250-lpass-tx-macro" }, + { .compatible = "qcom,sm8450-lpass-tx-macro" }, + { .compatible = "qcom,sc8280xp-lpass-tx-macro" }, { } }; MODULE_DEVICE_TABLE(of, tx_macro_dt_match); -- cgit v1.2.3 From c0bcaa72fabab1f2900aecc8643f33212c0072cc Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 6 Sep 2022 18:01:10 +0100 Subject: ASoC: codecs: rx-macro: add support for sm8450 and sc8280xp Add compatible for sm8450 and sc8280xp. Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220906170112.1984-11-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-rx-macro.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index 338e3f0cad12..a9ef9d5ffcc5 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -3654,6 +3654,8 @@ static int rx_macro_remove(struct platform_device *pdev) static const struct of_device_id rx_macro_dt_match[] = { { .compatible = "qcom,sc7280-lpass-rx-macro" }, { .compatible = "qcom,sm8250-lpass-rx-macro" }, + { .compatible = "qcom,sm8450-lpass-rx-macro" }, + { .compatible = "qcom,sc8280xp-lpass-rx-macro" }, { } }; MODULE_DEVICE_TABLE(of, rx_macro_dt_match); -- cgit v1.2.3 From c55b7381d7932eb303dbd97691f89c1a9c452956 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 6 Sep 2022 18:01:11 +0100 Subject: ASoC: codecs: va-macro: clear the frame sync counter before enabling Clear the frame sync counter before enabling it. Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220906170112.1984-12-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-va-macro.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c index 1ea10dc70748..a35f684053d2 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -23,6 +23,7 @@ #define CDC_VA_MCLK_CONTROL_EN BIT(0) #define CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL (0x0004) #define CDC_VA_FS_CONTROL_EN BIT(0) +#define CDC_VA_FS_COUNTER_CLR BIT(1) #define CDC_VA_CLK_RST_CTRL_SWR_CONTROL (0x0008) #define CDC_VA_TOP_CSR_TOP_CFG0 (0x0080) #define CDC_VA_FS_BROADCAST_EN BIT(1) @@ -423,9 +424,12 @@ static int va_clk_rsc_fs_gen_request(struct va_macro *va, bool enable) regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_MCLK_CONTROL, CDC_VA_MCLK_CONTROL_EN, CDC_VA_MCLK_CONTROL_EN); - + /* clear the fs counter */ + regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL, + CDC_VA_FS_CONTROL_EN | CDC_VA_FS_COUNTER_CLR, + CDC_VA_FS_CONTROL_EN | CDC_VA_FS_COUNTER_CLR); regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL, - CDC_VA_FS_CONTROL_EN, + CDC_VA_FS_CONTROL_EN | CDC_VA_FS_COUNTER_CLR, CDC_VA_FS_CONTROL_EN); regmap_update_bits(regmap, CDC_VA_TOP_CSR_TOP_CFG0, -- cgit v1.2.3 From 0f47dd211938d5646f4041407089390bf89b96e8 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 6 Sep 2022 18:01:12 +0100 Subject: ASoC: codecs: va-macro: add support for sm8450 and sc8280xp LPASS VA Macro now has soundwire master to deal with access to analog mic in low power island use cases. This is added after sc8280xp, add support for this. Along with this also add compatibles for sm8450 and sc8280xp. Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220906170112.1984-13-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-va-macro.c | 74 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c index a35f684053d2..b0b6cf29cba3 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -25,6 +25,10 @@ #define CDC_VA_FS_CONTROL_EN BIT(0) #define CDC_VA_FS_COUNTER_CLR BIT(1) #define CDC_VA_CLK_RST_CTRL_SWR_CONTROL (0x0008) +#define CDC_VA_SWR_RESET_MASK BIT(1) +#define CDC_VA_SWR_RESET_ENABLE BIT(1) +#define CDC_VA_SWR_CLK_EN_MASK BIT(0) +#define CDC_VA_SWR_CLK_ENABLE BIT(0) #define CDC_VA_TOP_CSR_TOP_CFG0 (0x0080) #define CDC_VA_FS_BROADCAST_EN BIT(1) #define CDC_VA_TOP_CSR_DMIC0_CTL (0x0084) @@ -66,6 +70,8 @@ #define CDC_VA_TOP_CSR_SWR_MIC_CTL0 (0x00D0) #define CDC_VA_TOP_CSR_SWR_MIC_CTL1 (0x00D4) #define CDC_VA_TOP_CSR_SWR_MIC_CTL2 (0x00D8) +#define CDC_VA_SWR_MIC_CLK_SEL_0_1_MASK (0xEE) +#define CDC_VA_SWR_MIC_CLK_SEL_0_1_DIV1 (0xCC) #define CDC_VA_TOP_CSR_SWR_CTRL (0x00DC) #define CDC_VA_INP_MUX_ADC_MUX0_CFG0 (0x0100) #define CDC_VA_INP_MUX_ADC_MUX0_CFG1 (0x0104) @@ -194,6 +200,7 @@ struct va_macro { unsigned long active_ch_mask[VA_MACRO_MAX_DAIS]; unsigned long active_ch_cnt[VA_MACRO_MAX_DAIS]; u16 dmic_clk_div; + bool has_swr_master; int dec_mode[VA_MACRO_NUM_DECIMATORS]; struct regmap *regmap; @@ -216,6 +223,18 @@ struct va_macro { #define to_va_macro(_hw) container_of(_hw, struct va_macro, hw) +struct va_macro_data { + bool has_swr_master; +}; + +static const struct va_macro_data sm8250_va_data = { + .has_swr_master = false, +}; + +static const struct va_macro_data sm8450_va_data = { + .has_swr_master = true, +}; + static bool va_is_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { @@ -325,6 +344,9 @@ static bool va_is_rw_register(struct device *dev, unsigned int reg) case CDC_VA_TOP_CSR_DMIC2_CTL: case CDC_VA_TOP_CSR_DMIC3_CTL: case CDC_VA_TOP_CSR_DMIC_CFG: + case CDC_VA_TOP_CSR_SWR_MIC_CTL0: + case CDC_VA_TOP_CSR_SWR_MIC_CTL1: + case CDC_VA_TOP_CSR_SWR_MIC_CTL2: case CDC_VA_TOP_CSR_DEBUG_BUS: case CDC_VA_TOP_CSR_DEBUG_EN: case CDC_VA_TOP_CSR_TX_I2S_CTL: @@ -1306,12 +1328,36 @@ static const struct snd_soc_component_driver va_macro_component_drv = { static int fsgen_gate_enable(struct clk_hw *hw) { - return va_macro_mclk_enable(to_va_macro(hw), true); + struct va_macro *va = to_va_macro(hw); + struct regmap *regmap = va->regmap; + int ret; + + ret = va_macro_mclk_enable(va, true); + if (!va->has_swr_master) + return ret; + + regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL, + CDC_VA_SWR_RESET_MASK, CDC_VA_SWR_RESET_ENABLE); + + regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL, + CDC_VA_SWR_CLK_EN_MASK, + CDC_VA_SWR_CLK_ENABLE); + regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL, + CDC_VA_SWR_RESET_MASK, 0x0); + + return ret; } static void fsgen_gate_disable(struct clk_hw *hw) { - va_macro_mclk_enable(to_va_macro(hw), false); + struct va_macro *va = to_va_macro(hw); + struct regmap *regmap = va->regmap; + + if (va->has_swr_master) + regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL, + CDC_VA_SWR_CLK_EN_MASK, 0x0); + + va_macro_mclk_enable(va, false); } static int fsgen_gate_is_enabled(struct clk_hw *hw) @@ -1405,6 +1451,7 @@ undefined_rate: static int va_macro_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + const struct va_macro_data *data; struct va_macro *va; void __iomem *base; u32 sample_rate = 0; @@ -1459,6 +1506,9 @@ static int va_macro_probe(struct platform_device *pdev) dev_set_drvdata(dev, va); + data = of_device_get_match_data(dev); + va->has_swr_master = data->has_swr_master; + /* mclk rate */ clk_set_rate(va->mclk, 2 * VA_MACRO_MCLK_FREQ); @@ -1484,6 +1534,20 @@ static int va_macro_probe(struct platform_device *pdev) goto err_clkout; } + if (va->has_swr_master) { + /* Set default CLK div to 1 */ + regmap_update_bits(va->regmap, CDC_VA_TOP_CSR_SWR_MIC_CTL0, + CDC_VA_SWR_MIC_CLK_SEL_0_1_MASK, + CDC_VA_SWR_MIC_CLK_SEL_0_1_DIV1); + regmap_update_bits(va->regmap, CDC_VA_TOP_CSR_SWR_MIC_CTL1, + CDC_VA_SWR_MIC_CLK_SEL_0_1_MASK, + CDC_VA_SWR_MIC_CLK_SEL_0_1_DIV1); + regmap_update_bits(va->regmap, CDC_VA_TOP_CSR_SWR_MIC_CTL2, + CDC_VA_SWR_MIC_CLK_SEL_0_1_MASK, + CDC_VA_SWR_MIC_CLK_SEL_0_1_DIV1); + + } + ret = devm_snd_soc_register_component(dev, &va_macro_component_drv, va_macro_dais, ARRAY_SIZE(va_macro_dais)); @@ -1558,8 +1622,10 @@ static const struct dev_pm_ops va_macro_pm_ops = { }; static const struct of_device_id va_macro_dt_match[] = { - { .compatible = "qcom,sc7280-lpass-va-macro" }, - { .compatible = "qcom,sm8250-lpass-va-macro" }, + { .compatible = "qcom,sc7280-lpass-va-macro", .data = &sm8250_va_data }, + { .compatible = "qcom,sm8250-lpass-va-macro", .data = &sm8250_va_data }, + { .compatible = "qcom,sm8450-lpass-va-macro", .data = &sm8450_va_data }, + { .compatible = "qcom,sc8280xp-lpass-va-macro", .data = &sm8450_va_data }, {} }; MODULE_DEVICE_TABLE(of, va_macro_dt_match); -- cgit v1.2.3 From a996a333ad74d1f26c3831f1edd94a5d16798a0c Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 23 Sep 2022 16:36:11 +0300 Subject: ASoC: SOF: Intel: cnl: Add separate ops for ipc_dump for IPC4 The use of the IPC registers are different between IPC3 and IPC4. The ipc_dump needs to use different prints depending on the used IPC protocol. Signed-off-by: Peter Ujfalusi Reviewed-by: Ranjani Sridharan Reviewed-by: Kai Vehmanen Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20220923133616.26267-2-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/cnl.c | 28 +++++++++++++++++++++++++++- sound/soc/sof/intel/hda-ipc.h | 1 + sound/soc/sof/intel/icl.c | 7 ++++++- sound/soc/sof/intel/tgl.c | 7 ++++++- 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 180001d0a38a..1e71f6dc604e 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -332,6 +332,27 @@ void cnl_ipc_dump(struct snd_sof_dev *sdev) hipcida, hipctdr, hipcctl); } +void cnl_ipc4_dump(struct snd_sof_dev *sdev) +{ + u32 hipcidr, hipcidd, hipcida, hipctdr, hipctdd, hipctda, hipcctl; + + hda_ipc_irq_dump(sdev); + + hipcidr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR); + hipcidd = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDD); + hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA); + hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR); + hipctdd = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDD); + hipctda = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDA); + hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCCTL); + + /* dump the IPC regs */ + /* TODO: parse the raw msg */ + dev_err(sdev->dev, + "Host IPC initiator: %#x|%#x|%#x, target: %#x|%#x|%#x, ctl: %#x\n", + hipcidr, hipcidd, hipcida, hipctdr, hipctdd, hipctda, hipcctl); +} + /* cannonlake ops */ struct snd_sof_dsp_ops sof_cnl_ops; EXPORT_SYMBOL_NS(sof_cnl_ops, SND_SOC_SOF_INTEL_HDA_COMMON); @@ -351,6 +372,9 @@ int sof_cnl_ops_init(struct snd_sof_dev *sdev) /* ipc */ sof_cnl_ops.send_msg = cnl_ipc_send_msg; + + /* debug */ + sof_cnl_ops.ipc_dump = cnl_ipc_dump; } if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) { @@ -370,6 +394,9 @@ int sof_cnl_ops_init(struct snd_sof_dev *sdev) /* ipc */ sof_cnl_ops.send_msg = cnl_ipc4_send_msg; + + /* debug */ + sof_cnl_ops.ipc_dump = cnl_ipc4_dump; } /* set DAI driver ops */ @@ -378,7 +405,6 @@ int sof_cnl_ops_init(struct snd_sof_dev *sdev) /* debug */ sof_cnl_ops.debug_map = cnl_dsp_debugfs; sof_cnl_ops.debug_map_count = ARRAY_SIZE(cnl_dsp_debugfs); - sof_cnl_ops.ipc_dump = cnl_ipc_dump; /* pre/post fw run */ sof_cnl_ops.post_fw_run = hda_dsp_post_fw_run; diff --git a/sound/soc/sof/intel/hda-ipc.h b/sound/soc/sof/intel/hda-ipc.h index 10fbca5939db..8ec5e9f6f8d7 100644 --- a/sound/soc/sof/intel/hda-ipc.h +++ b/sound/soc/sof/intel/hda-ipc.h @@ -51,5 +51,6 @@ irqreturn_t cnl_ipc_irq_thread(int irq, void *context); int cnl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg); void cnl_ipc_dump(struct snd_sof_dev *sdev); +void cnl_ipc4_dump(struct snd_sof_dev *sdev); #endif diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c index 59ce3132fada..f1018c6db5c2 100644 --- a/sound/soc/sof/intel/icl.c +++ b/sound/soc/sof/intel/icl.c @@ -113,6 +113,9 @@ int sof_icl_ops_init(struct snd_sof_dev *sdev) /* ipc */ sof_icl_ops.send_msg = cnl_ipc_send_msg; + + /* debug */ + sof_icl_ops.ipc_dump = cnl_ipc_dump; } if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) { @@ -132,12 +135,14 @@ int sof_icl_ops_init(struct snd_sof_dev *sdev) /* ipc */ sof_icl_ops.send_msg = cnl_ipc4_send_msg; + + /* debug */ + sof_icl_ops.ipc_dump = cnl_ipc4_dump; } /* debug */ sof_icl_ops.debug_map = icl_dsp_debugfs; sof_icl_ops.debug_map_count = ARRAY_SIZE(icl_dsp_debugfs); - sof_icl_ops.ipc_dump = cnl_ipc_dump; /* pre/post fw run */ sof_icl_ops.post_fw_run = icl_dsp_post_fw_run; diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c index 5135e1c7e6cf..c606c3691de7 100644 --- a/sound/soc/sof/intel/tgl.c +++ b/sound/soc/sof/intel/tgl.c @@ -68,6 +68,9 @@ int sof_tgl_ops_init(struct snd_sof_dev *sdev) /* ipc */ sof_tgl_ops.send_msg = cnl_ipc_send_msg; + + /* debug */ + sof_tgl_ops.ipc_dump = cnl_ipc_dump; } if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) { @@ -87,6 +90,9 @@ int sof_tgl_ops_init(struct snd_sof_dev *sdev) /* ipc */ sof_tgl_ops.send_msg = cnl_ipc4_send_msg; + + /* debug */ + sof_tgl_ops.ipc_dump = cnl_ipc4_dump; } /* set DAI driver ops */ @@ -95,7 +101,6 @@ int sof_tgl_ops_init(struct snd_sof_dev *sdev) /* debug */ sof_tgl_ops.debug_map = tgl_dsp_debugfs; sof_tgl_ops.debug_map_count = ARRAY_SIZE(tgl_dsp_debugfs); - sof_tgl_ops.ipc_dump = cnl_ipc_dump; /* pre/post fw run */ sof_tgl_ops.post_fw_run = hda_dsp_post_fw_run; -- cgit v1.2.3 From 32b97c07c2a3b7cccc0c7e9a5b23970bd9a52c5d Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 23 Sep 2022 16:36:12 +0300 Subject: ASoC: SOF: Intel: hda: Add separate ops for ipc_dump for IPC4 The use of the IPC registers are different between IPC3 and IPC4. The ipc_dump needs to use different prints depending on the used IPC protocol. Signed-off-by: Peter Ujfalusi Reviewed-by: Ranjani Sridharan Reviewed-by: Kai Vehmanen Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20220923133616.26267-3-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/apl.c | 7 ++++++- sound/soc/sof/intel/hda.c | 18 ++++++++++++++++++ sound/soc/sof/intel/hda.h | 1 + 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 295df44be271..37d12e821c10 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -45,6 +45,9 @@ int sof_apl_ops_init(struct snd_sof_dev *sdev) /* ipc */ sof_apl_ops.send_msg = hda_dsp_ipc_send_msg; + + /* debug */ + sof_apl_ops.ipc_dump = hda_ipc_dump; } if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) { @@ -64,6 +67,9 @@ int sof_apl_ops_init(struct snd_sof_dev *sdev) /* ipc */ sof_apl_ops.send_msg = hda_dsp_ipc4_send_msg; + + /* debug */ + sof_apl_ops.ipc_dump = hda_ipc4_dump; } /* set DAI driver ops */ @@ -72,7 +78,6 @@ int sof_apl_ops_init(struct snd_sof_dev *sdev) /* debug */ sof_apl_ops.debug_map = apl_dsp_debugfs; sof_apl_ops.debug_map_count = ARRAY_SIZE(apl_dsp_debugfs); - sof_apl_ops.ipc_dump = hda_ipc_dump; /* firmware run */ sof_apl_ops.run = hda_dsp_cl_boot_firmware; diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index f7068a7e2e81..ca648d2a9da7 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -662,6 +662,24 @@ void hda_ipc_dump(struct snd_sof_dev *sdev) hipcie, hipct, hipcctl); } +void hda_ipc4_dump(struct snd_sof_dev *sdev) +{ + u32 hipci, hipcie, hipct, hipcte, hipcctl; + + hda_ipc_irq_dump(sdev); + + hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI); + hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE); + hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT); + hipcte = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCTE); + hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL); + + /* dump the IPC regs */ + /* TODO: parse the raw msg */ + dev_err(sdev->dev, "Host IPC initiator: %#x|%#x, target: %#x|%#x, ctl: %#x\n", + hipci, hipcie, hipct, hipcte, hipcctl); +} + static int hda_init(struct snd_sof_dev *sdev) { struct hda_bus *hbus; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 2013a94020c6..c3a9f89b726d 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -851,6 +851,7 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context); int cnl_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg); irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context); int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg); +void hda_ipc4_dump(struct snd_sof_dev *sdev); extern struct sdw_intel_ops sdw_callback; #endif -- cgit v1.2.3 From 6759f35b234aa94e26e122afcd402ba2a39bd9d3 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 23 Sep 2022 16:36:13 +0300 Subject: ASoC: SOF: Intel: skl: Use the ipc4 version of the ipc_dump The use of the IPC registers are different between IPC3 and IPC4. The ipc_dump needs to use different prints depending on the used IPC protocol. Signed-off-by: Peter Ujfalusi Reviewed-by: Ranjani Sridharan Reviewed-by: Kai Vehmanen Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20220923133616.26267-4-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/skl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index f05905e00368..eba166fe4d33 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -87,7 +87,7 @@ int sof_skl_ops_init(struct snd_sof_dev *sdev) /* debug */ sof_skl_ops.debug_map = skl_dsp_debugfs; sof_skl_ops.debug_map_count = ARRAY_SIZE(skl_dsp_debugfs); - sof_skl_ops.ipc_dump = hda_ipc_dump; + sof_skl_ops.ipc_dump = hda_ipc4_dump; /* firmware run */ sof_skl_ops.run = hda_dsp_cl_boot_firmware_skl; -- cgit v1.2.3 From d01784ee680c558938baf6c4f184bee2bc612798 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 23 Sep 2022 16:36:14 +0300 Subject: ASoC: SOF: Intel: mtl: Print relevant register in ipc_dump The use of the IPC registers are different between IPC3 and IPC4. The ipc_dump needs to use different prints depending on the used IPC protocol. The existing code was printing registers relevant for IPC3, which is not even supported on MTL. Signed-off-by: Peter Ujfalusi Reviewed-by: Ranjani Sridharan Reviewed-by: Kai Vehmanen Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20220923133616.26267-5-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/mtl.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index 5408c34b04ef..61bcaa1556f6 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -698,20 +698,19 @@ static int mtl_dsp_runtime_resume(struct snd_sof_dev *sdev) static void mtl_ipc_dump(struct snd_sof_dev *sdev) { - u32 hipcctl; - u32 hipcida; - u32 hipctdr; + u32 hipcidr, hipcidd, hipcida, hipctdr, hipctdd, hipctda, hipcctl; - /* read IPC status */ + hipcidr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDR); + hipcidd = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDDY); hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDA); - hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXCTL); hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDR); + hipctdd = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDDY); + hipctda = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDA); + hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXCTL); - /* dump the IPC regs */ - /* TODO: parse the raw msg */ dev_err(sdev->dev, - "error: host status 0x%8.8x dsp status 0x%8.8x mask 0x%8.8x\n", - hipcida, hipctdr, hipcctl); + "Host IPC initiator: %#x|%#x|%#x, target: %#x|%#x|%#x, ctl: %#x\n", + hipcidr, hipcidd, hipcida, hipctdr, hipctdd, hipctda, hipcctl); } /* Meteorlake ops */ -- cgit v1.2.3 From 01fb69d09afb896579e00c3dbc3c1aa74613dd86 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 23 Sep 2022 16:36:15 +0300 Subject: ASoC: SOF: Intel: hda: Only dump firmware registers for IPC3 The firmware register dump is IPC3 specific, it is not available for other IPC versions. Signed-off-by: Peter Ujfalusi Reviewed-by: Ranjani Sridharan Reviewed-by: Kai Vehmanen Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20220923133616.26267-6-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index ca648d2a9da7..e00062f3b21c 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -598,7 +598,8 @@ void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags) /* print ROM/FW status */ hda_dsp_get_state(sdev, level); - if (flags & SOF_DBG_DUMP_REGS) { + /* The firmware register dump only available with IPC3 */ + if (flags & SOF_DBG_DUMP_REGS && sdev->pdata->ipc_type == SOF_IPC) { u32 status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_FW_STATUS); u32 panic = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_FW_TRACEP); -- cgit v1.2.3 From 4245fdba89b82befee0d963a85f7494c70432ee9 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 23 Sep 2022 16:36:16 +0300 Subject: ASoC: SOF: ipc4: Call snd_sof_handle_fw_exception() in case of timeout It can help debugging IPC timeout issues (like we do with IPC3) if we dump the IPC and DSP information. Signed-off-by: Peter Ujfalusi Reviewed-by: Ranjani Sridharan Reviewed-by: Kai Vehmanen Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20220923133616.26267-7-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c index 0d830020556d..6eaa18e27e5a 100644 --- a/sound/soc/sof/ipc4.c +++ b/sound/soc/sof/ipc4.c @@ -295,6 +295,7 @@ static int ipc4_wait_tx_done(struct snd_sof_ipc *ipc, void *reply_data) if (ret == 0) { dev_err(sdev->dev, "ipc timed out for %#x|%#x\n", ipc4_msg->primary, ipc4_msg->extension); + snd_sof_handle_fw_exception(ipc->sdev, "IPC timeout"); return -ETIMEDOUT; } -- cgit v1.2.3 From 086ceada2107b482df437d76f581062b547eb7f2 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Tue, 6 Sep 2022 14:49:21 +0800 Subject: ASoC: fsl_audmux: Fix amixer write errors This reverts commit 944c517b8c8388 ("ASoC: fsl_audmix: make clock and output src write only"). There is error after making clock and output src write only $amixer -c imxaudmix cset numid=1 1 amixer: Cannot read the given element from control sysdefault:3 Which is worse than before, so let's revert the change. Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1662446961-20799-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_audmix.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c index 43857b7a81c9..672148dd4b23 100644 --- a/sound/soc/fsl/fsl_audmix.c +++ b/sound/soc/fsl/fsl_audmix.c @@ -199,18 +199,10 @@ static int fsl_audmix_put_out_src(struct snd_kcontrol *kcontrol, static const struct snd_kcontrol_new fsl_audmix_snd_controls[] = { /* FSL_AUDMIX_CTR controls */ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Mixing Clock Source", - .info = snd_soc_info_enum_double, - .access = SNDRV_CTL_ELEM_ACCESS_WRITE, - .put = fsl_audmix_put_mix_clk_src, - .private_value = (unsigned long)&fsl_audmix_enum[0] }, - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Output Source", - .info = snd_soc_info_enum_double, - .access = SNDRV_CTL_ELEM_ACCESS_WRITE, - .put = fsl_audmix_put_out_src, - .private_value = (unsigned long)&fsl_audmix_enum[1] }, + SOC_ENUM_EXT("Mixing Clock Source", fsl_audmix_enum[0], + snd_soc_get_enum_double, fsl_audmix_put_mix_clk_src), + SOC_ENUM_EXT("Output Source", fsl_audmix_enum[1], + snd_soc_get_enum_double, fsl_audmix_put_out_src), SOC_ENUM("Output Width", fsl_audmix_enum[2]), SOC_ENUM("Frame Rate Diff Error", fsl_audmix_enum[3]), SOC_ENUM("Clock Freq Diff Error", fsl_audmix_enum[4]), -- cgit v1.2.3 From 08fc2a7448afc1660ec2f1b5c437fcd14155a7ee Mon Sep 17 00:00:00 2001 From: Zhang Qilong Date: Thu, 22 Sep 2022 22:58:46 +0800 Subject: ASoC: soc-component: using pm_runtime_resume_and_get instead of pm_runtime_get_sync Using the newest pm_runtime_resume_and_get is more appropriate for simplifing code here. Signed-off-by: Zhang Qilong Link: https://lore.kernel.org/r/20220922145846.114312-1-zhangqilong3@huawei.com Signed-off-by: Mark Brown --- sound/soc/soc-component.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index e12f8244242b..659b9ade4158 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -1213,11 +1213,9 @@ int snd_soc_pcm_component_pm_runtime_get(struct snd_soc_pcm_runtime *rtd, int i; for_each_rtd_components(rtd, i, component) { - int ret = pm_runtime_get_sync(component->dev); - if (ret < 0 && ret != -EACCES) { - pm_runtime_put_noidle(component->dev); + int ret = pm_runtime_resume_and_get(component->dev); + if (ret < 0 && ret != -EACCES) return soc_component_ret(component, ret); - } /* mark stream if succeeded */ soc_component_mark_push(component, stream, pm); } -- cgit v1.2.3 From 1849a1505533501ea39ed0538c2d35eba4704baa Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 23 Sep 2022 18:15:47 +0800 Subject: ASoC: fsl_asrc_dma: fully initialize structs The driver uses two statically ininitialized struct dma_slave_config, but only one of them is initialized to zero. Initialize config_be to zero as well to make sure that no fields are filled with random values. Let the compiler do this instead of explicitly calling memset() which makes it easier to read. Signed-off-by: Sascha Hauer Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1663928147-10106-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_asrc_dma.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index 12ddf2320f2d..3b81a465814a 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c @@ -139,7 +139,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, struct dma_chan *tmp_chan = NULL, *be_chan = NULL; struct snd_soc_component *component_be = NULL; struct fsl_asrc *asrc = pair->asrc; - struct dma_slave_config config_fe, config_be; + struct dma_slave_config config_fe = {}, config_be = {}; struct sdma_peripheral_config audio_config; enum asrc_pair_index index = pair->index; struct device *dev = component->dev; @@ -183,7 +183,6 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, return -EINVAL; } - memset(&config_fe, 0, sizeof(config_fe)); ret = snd_dmaengine_pcm_prepare_slave_config(substream, params, &config_fe); if (ret) { dev_err(dev, "failed to prepare DMA config for Front-End\n"); -- cgit v1.2.3 From abb4e4349afe7eecdb0499582f1c777031e3a7c8 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Thu, 22 Sep 2022 21:44:57 +0200 Subject: ASoC: da7219: Fix an error handling path in da7219_register_dai_clks() If clk_hw_register() fails, the corresponding clk should not be unregistered. To handle errors from loops, clean up partial iterations before doing the goto. So add a clk_hw_unregister(). Then use a while (--i >= 0) loop in the unwind section. Fixes: 78013a1cf297 ("ASoC: da7219: Fix clock handling around codec level probe") Reported-by: Dan Carpenter Signed-off-by: Christophe JAILLET Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/e4acceab57a0d9e477a8d5890a45c5309e553e7c.1663875789.git.christophe.jaillet@wanadoo.fr Signed-off-by: Mark Brown --- sound/soc/codecs/da7219.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 50ecf30e6136..4746c8700451 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -2196,6 +2196,7 @@ static int da7219_register_dai_clks(struct snd_soc_component *component) dai_clk_lookup = clkdev_hw_create(dai_clk_hw, init.name, "%s", dev_name(dev)); if (!dai_clk_lookup) { + clk_hw_unregister(dai_clk_hw); ret = -ENOMEM; goto err; } else { @@ -2217,12 +2218,12 @@ static int da7219_register_dai_clks(struct snd_soc_component *component) return 0; err: - do { + while (--i >= 0) { if (da7219->dai_clks_lookup[i]) clkdev_drop(da7219->dai_clks_lookup[i]); clk_hw_unregister(&da7219->dai_clks_hw[i]); - } while (i-- > 0); + } if (np) kfree(da7219->clk_hw_data); -- cgit v1.2.3 From d508260e89a7d1889bbb5788fdfc52cc3eb8ddb6 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Fri, 16 Sep 2022 22:07:57 +0800 Subject: ASoC: Intel: skylake: remove unnecessary dev_set_drvdata() Remove unnecessary dev_set_drvdata() in skl_remove(), the driver_data will be set to NULL in device_unbind_cleanup() after calling ->remove(). Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20220916140757.681414-1-yangyingliang@huawei.com Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 3997af4eaa89..5707dfee603f 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -1127,7 +1127,6 @@ static void skl_remove(struct pci_dev *pci) if (skl->nhlt) intel_nhlt_free(skl->nhlt); skl_free(bus); - dev_set_drvdata(&pci->dev, NULL); } /* PCI IDs */ -- cgit v1.2.3 From 1e1f26635e5459db4134952369b76b8d59c50438 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 19 Sep 2022 19:58:03 -0700 Subject: ASoC: ssm2518: drop support for platform data There are currently no users of this driver's platform data in the mainline kernel, so let's drop it. Newer devices should use DT, ACPI, or static software properties to describe the hardware. Signed-off-by: Dmitry Torokhov Link: https://lore.kernel.org/r/20220920025804.1788667-1-dmitry.torokhov@gmail.com Signed-off-by: Mark Brown --- include/linux/platform_data/ssm2518.h | 21 --------------------- sound/soc/codecs/ssm2518.c | 6 +----- 2 files changed, 1 insertion(+), 26 deletions(-) delete mode 100644 include/linux/platform_data/ssm2518.h diff --git a/include/linux/platform_data/ssm2518.h b/include/linux/platform_data/ssm2518.h deleted file mode 100644 index 3f9e632d6f63..000000000000 --- a/include/linux/platform_data/ssm2518.h +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * SSM2518 amplifier audio driver - * - * Copyright 2013 Analog Devices Inc. - * Author: Lars-Peter Clausen - */ - -#ifndef __LINUX_PLATFORM_DATA_SSM2518_H__ -#define __LINUX_PLATFORM_DATA_SSM2518_H__ - -/** - * struct ssm2518_platform_data - Platform data for the ssm2518 driver - * @enable_gpio: GPIO connected to the nSD pin. Set to -1 if the nSD pin is - * hardwired. - */ -struct ssm2518_platform_data { - int enable_gpio; -}; - -#endif diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c index 6d8847848299..feee28207e5d 100644 --- a/sound/soc/codecs/ssm2518.c +++ b/sound/soc/codecs/ssm2518.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -736,7 +735,6 @@ static const struct regmap_config ssm2518_regmap_config = { static int ssm2518_i2c_probe(struct i2c_client *i2c) { - struct ssm2518_platform_data *pdata = i2c->dev.platform_data; struct ssm2518 *ssm2518; int ret; @@ -744,9 +742,7 @@ static int ssm2518_i2c_probe(struct i2c_client *i2c) if (ssm2518 == NULL) return -ENOMEM; - if (pdata) { - ssm2518->enable_gpio = pdata->enable_gpio; - } else if (i2c->dev.of_node) { + if (i2c->dev.of_node) { ssm2518->enable_gpio = of_get_gpio(i2c->dev.of_node, 0); if (ssm2518->enable_gpio < 0 && ssm2518->enable_gpio != -ENOENT) return ssm2518->enable_gpio; -- cgit v1.2.3 From 179f69fa37bb4ba7e5e6ecd04096cdec53c2fe12 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 19 Sep 2022 19:58:04 -0700 Subject: ASoC: ssm2518: switch to using gpiod API This patch converts the driver to newer gpiod API, so that we can stop exporting OF-specific legacy gpio API. Signed-off-by: Dmitry Torokhov Link: https://lore.kernel.org/r/20220920025804.1788667-2-dmitry.torokhov@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/ssm2518.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c index feee28207e5d..22cb3b7c8283 100644 --- a/sound/soc/codecs/ssm2518.c +++ b/sound/soc/codecs/ssm2518.c @@ -6,13 +6,13 @@ * Author: Lars-Peter Clausen */ +#include #include #include #include #include #include -#include -#include +#include #include #include #include @@ -113,7 +113,7 @@ struct ssm2518 { unsigned int sysclk; const struct snd_pcm_hw_constraint_list *constraints; - int enable_gpio; + struct gpio_desc *enable_gpio; }; static const struct reg_default ssm2518_reg_defaults[] = { @@ -482,8 +482,8 @@ static int ssm2518_set_power(struct ssm2518 *ssm2518, bool enable) regcache_mark_dirty(ssm2518->regmap); } - if (gpio_is_valid(ssm2518->enable_gpio)) - gpio_set_value(ssm2518->enable_gpio, enable); + if (ssm2518->enable_gpio) + gpiod_set_value_cansleep(ssm2518->enable_gpio, enable); regcache_cache_only(ssm2518->regmap, !enable); @@ -742,20 +742,14 @@ static int ssm2518_i2c_probe(struct i2c_client *i2c) if (ssm2518 == NULL) return -ENOMEM; - if (i2c->dev.of_node) { - ssm2518->enable_gpio = of_get_gpio(i2c->dev.of_node, 0); - if (ssm2518->enable_gpio < 0 && ssm2518->enable_gpio != -ENOENT) - return ssm2518->enable_gpio; - } else { - ssm2518->enable_gpio = -1; - } + /* Start with enabling the chip */ + ssm2518->enable_gpio = devm_gpiod_get_optional(&i2c->dev, NULL, + GPIOD_OUT_HIGH); + ret = PTR_ERR_OR_ZERO(ssm2518->enable_gpio); + if (ret) + return ret; - if (gpio_is_valid(ssm2518->enable_gpio)) { - ret = devm_gpio_request_one(&i2c->dev, ssm2518->enable_gpio, - GPIOF_OUT_INIT_HIGH, "SSM2518 nSD"); - if (ret) - return ret; - } + gpiod_set_consumer_name(ssm2518->enable_gpio, "SSM2518 nSD"); i2c_set_clientdata(i2c, ssm2518); -- cgit v1.2.3 From b23975e60a944e1a3ef419a01838fca51a29baf3 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 23 Sep 2022 10:22:36 +0200 Subject: ALSA: hda/hdmi: Limit the maximal count of PCM devices to 8 The current hardware has up to 4 converters. Save little space. The limit 8 is enough even for a more improved hardware. Signed-off-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20220923082236.61024-1-perex@perex.cz Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 1863836b2685..c172640c8a41 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -151,7 +151,7 @@ struct hdmi_spec { */ int dev_num; struct snd_array pins; /* struct hdmi_spec_per_pin */ - struct hdmi_pcm pcm_rec[16]; + struct hdmi_pcm pcm_rec[8]; struct mutex pcm_lock; struct mutex bind_lock; /* for audio component binding */ /* pcm_bitmap means which pcms have been assigned to pins*/ @@ -2299,8 +2299,8 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec) pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK]; pstr->substreams = 1; pstr->ops = generic_ops; - /* pcm number is less than 16 */ - if (spec->pcm_used >= 16) + /* pcm number is less than pcm_rec array size */ + if (spec->pcm_used >= ARRAY_SIZE(spec->pcm_rec)) break; /* other pstr fields are set in open */ } -- cgit v1.2.3 From a61c7d88d38cf3b9c88cf667c4f8a389a57744d4 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 23 Sep 2022 18:35:01 +0300 Subject: ALSA: memalloc: use __GFP_RETRY_MAYFAIL for DMA mem allocs Use __GFP_RETRY_MAYFAIL instead of __GFP__NORETRY in snd_dma_dev_alloc(), snd_dma_wc_alloc() and friends, to allocate pages for device memory. The MAYFAIL flag retains the semantics of not triggering the OOM killer, but lowers the risk of alloc failure. MAYFAIL flag was added in commit dcda9b04713c3 ("mm, tree wide: replace __GFP_REPEAT by __GFP_RETRY_MAYFAIL with more useful semantic"). This change addresses recurring failures with SOF audio driver in test cases where a system suspend-resume stress test is run, combined with an active high memory-load use-case. The failure typically shows up as: [ 379.480229] sof-audio-pci-intel-tgl 0000:00:1f.3: booting DSP firmware [ 379.484803] sof-audio-pci-intel-tgl 0000:00:1f.3: error: memory alloc failed: -12 [ 379.484810] sof-audio-pci-intel-tgl 0000:00:1f.3: error: dma prepare for ICCMAX stream failed Multiple fixes to reduce the memory usage of DSP boot have been identified in SOF driver, but even with those fixes, debug on affected systems has shown that even a single page alloc may fail with __GFP_NORETRY. When this occurs, system is under significant load on physical memory, but a lot of reclaimable pages are available, so the system has not run out of memory. With __GFP_RETRY_MAYFAIL, the errors are not hit in these stress tests. The alloc failure is severe as audio capability is completely lost if alloc failure is hit at system resume. An alternative solution was considered where the resources for DSP boot would be kept allocated until driver is unbound. This would avoid the allocation failure, but consume memory that is only needed temporarily at probe and resume time. It seems better to not hang on to the memory, but rather work a bit harder for allocating the pages at resume. BugLink: https://github.com/thesofproject/linux/issues/3844 Signed-off-by: Kai Vehmanen Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220923153501.3326041-1-kai.vehmanen@linux.intel.com Signed-off-by: Takashi Iwai --- sound/core/memalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index 2c11413bea61..03cffe771366 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -21,7 +21,7 @@ #define DEFAULT_GFP \ (GFP_KERNEL | \ __GFP_COMP | /* compound page lets parts be mapped */ \ - __GFP_NORETRY | /* don't trigger OOM-killer */ \ + __GFP_RETRY_MAYFAIL | /* don't trigger OOM-killer */ \ __GFP_NOWARN) /* no stack trace print - this call is non-critical */ static const struct snd_malloc_ops *snd_dma_get_ops(struct snd_dma_buffer *dmab); -- cgit v1.2.3 From 978a7144ae8497b40d833a3c0110b18810499f95 Mon Sep 17 00:00:00 2001 From: Chunxu Li Date: Sat, 24 Sep 2022 11:35:58 +0800 Subject: ASoC: SOF: mediatek: mt8195: Add pcm_hw_params callback Add pcm_hw_params callback for mt8195 to support continue update dma host position Signed-off-by: Chunxu Li Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220924033559.26599-2-chunxu.li@mediatek.com Signed-off-by: Mark Brown --- sound/soc/sof/mediatek/mt8195/mt8195.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index c12192c8a6f8..882fde741cf5 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -496,6 +496,16 @@ static int mt8195_get_bar_index(struct snd_sof_dev *sdev, u32 type) return type; } +static int mt8195_pcm_hw_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_sof_platform_stream_params *platform_params) +{ + platform_params->cont_update_posn = 1; + + return 0; +} + static void mt8195_adsp_dump(struct snd_sof_dev *sdev, u32 flags) { u32 dbg_pc, dbg_data, dbg_bus0, dbg_bus1, dbg_inst; @@ -588,6 +598,7 @@ static struct snd_sof_dsp_ops sof_mt8195_ops = { /* stream callbacks */ .pcm_open = sof_stream_pcm_open, + .pcm_hw_params = mt8195_pcm_hw_params, .pcm_close = sof_stream_pcm_close, /* firmware loading */ -- cgit v1.2.3 From f7c91bf65388547f61888b7a67169966fc698ce1 Mon Sep 17 00:00:00 2001 From: Chunxu Li Date: Sat, 24 Sep 2022 11:35:59 +0800 Subject: ASoC: SOF: mediatek: mt8195: Add pcm_pointer callback Add pcm_pointer callback for mt8195 to support read host position from DSP Signed-off-by: Chunxu Li Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220924033559.26599-3-chunxu.li@mediatek.com Signed-off-by: Mark Brown --- sound/soc/sof/mediatek/mt8195/mt8195.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index 882fde741cf5..3c81e84fcecf 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -506,6 +506,38 @@ static int mt8195_pcm_hw_params(struct snd_sof_dev *sdev, return 0; } +static snd_pcm_uframes_t mt8195_pcm_pointer(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + int ret; + snd_pcm_uframes_t pos; + struct snd_sof_pcm *spcm; + struct sof_ipc_stream_posn posn; + struct snd_sof_pcm_stream *stream; + struct snd_soc_component *scomp = sdev->component; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + + spcm = snd_sof_find_spcm_dai(scomp, rtd); + if (!spcm) { + dev_warn_ratelimited(sdev->dev, "warn: can't find PCM with DAI ID %d\n", + rtd->dai_link->id); + return 0; + } + + stream = &spcm->stream[substream->stream]; + ret = snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn)); + if (ret < 0) { + dev_warn(sdev->dev, "failed to read stream position: %d\n", ret); + return 0; + } + + memcpy(&stream->posn, &posn, sizeof(posn)); + pos = spcm->stream[substream->stream].posn.host_posn; + pos = bytes_to_frames(substream->runtime, pos); + + return pos; +} + static void mt8195_adsp_dump(struct snd_sof_dev *sdev, u32 flags) { u32 dbg_pc, dbg_data, dbg_bus0, dbg_bus1, dbg_inst; @@ -599,6 +631,7 @@ static struct snd_sof_dsp_ops sof_mt8195_ops = { /* stream callbacks */ .pcm_open = sof_stream_pcm_open, .pcm_hw_params = mt8195_pcm_hw_params, + .pcm_pointer = mt8195_pcm_pointer, .pcm_close = sof_stream_pcm_close, /* firmware loading */ -- cgit v1.2.3 From 4d73b97b8dbaf09af6e5878ce3288ba93956a3fd Mon Sep 17 00:00:00 2001 From: Ren Zhijie Date: Mon, 26 Sep 2022 07:40:42 +0000 Subject: ASoC: codecs: wcd934x: Fix Kconfig dependency If CONFIG_REGMAP_SLIMBUS is not set, make ARCH=x86_64 CROSS_COMPILE=x86_64-linux-gnu-, will be failed, like this: sound/soc/codecs/wcd934x.o: In function `wcd934x_codec_probe': wcd934x.c:(.text+0x3310): undefined reference to `__regmap_init_slimbus' make: *** [vmlinux] Error 1 Add select REGMAP_SLIMBUS to config SND_SOC_WCD934X. Fixes: a61f3b4f476e ("ASoC: wcd934x: add support to wcd9340/wcd9341 codec") Signed-off-by: Ren Zhijie Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220926074042.13297-1-renzhijie2@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 444cee829a26..e3b90c425faf 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1757,6 +1757,7 @@ config SND_SOC_WCD934X tristate "WCD9340/WCD9341 Codec" depends on COMMON_CLK depends on SLIMBUS + select REGMAP_SLIMBUS select SND_SOC_WCD_MBHC depends on MFD_WCD934X || COMPILE_TEST help -- cgit v1.2.3 From 2b381b4a91e94bd1d328de6e66cf97dec13bb40c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 23 Sep 2022 22:31:40 +0200 Subject: ASoC: MAINTAINERS: add bindings and APR to Qualcomm Audio entry Extend the Qualcomm Audio maintainer entry to include sound related bindings and the Qualcomm APR/GPR (Asynchronous/Generic Packet Router) IPC driver, which is tightly related to the Audio DSP. Signed-off-by: Krzysztof Kozlowski Acked-by: Bjorn Andersson Link: https://lore.kernel.org/r/20220923203140.514730-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- MAINTAINERS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 6cfb1cba0caa..3e7a651a0a08 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16630,6 +16630,9 @@ M: Srinivas Kandagatla M: Banajit Goswami L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Supported +F: Documentation/devicetree/bindings/soc/qcom/qcom,apr.yaml +F: Documentation/devicetree/bindings/sound/qcom,* +F: drivers/soc/qcom/apr.c F: include/dt-bindings/sound/qcom,wcd9335.h F: sound/soc/codecs/lpass-rx-macro.* F: sound/soc/codecs/lpass-tx-macro.* -- cgit v1.2.3 From 1dd0dd0b1fefd1e51cfaddf62316f759fde7de7d Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 25 Sep 2022 14:57:51 +0200 Subject: ALSA: firewire: Remove some left-over license text in sound/firewire There is already a SPDX-License-Identifier tag, so the corresponding license text can be removed. While at it, be more consistent and: - add a missing .c (ff-protocol-latter) - remove an empty line (motu-protocol-v1) Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/2bfe76c7eeb0f5205a1427e280bf8d9da0354a62.1664110649.git.christophe.jaillet@wanadoo.fr Signed-off-by: Takashi Iwai --- sound/firewire/dice/dice-harman.c | 2 -- sound/firewire/dice/dice-presonus.c | 2 -- sound/firewire/fireface/ff-protocol-former.c | 2 -- sound/firewire/fireface/ff-protocol-latter.c | 4 +--- sound/firewire/motu/motu-protocol-v1.c | 3 --- 5 files changed, 1 insertion(+), 12 deletions(-) diff --git a/sound/firewire/dice/dice-harman.c b/sound/firewire/dice/dice-harman.c index a8ca00c397e8..212ae77dfca2 100644 --- a/sound/firewire/dice/dice-harman.c +++ b/sound/firewire/dice/dice-harman.c @@ -2,8 +2,6 @@ // dice-harman.c - a part of driver for DICE based devices // // Copyright (c) 2021 Takashi Sakamoto -// -// Licensed under the terms of the GNU General Public License, version 2. #include "dice.h" diff --git a/sound/firewire/dice/dice-presonus.c b/sound/firewire/dice/dice-presonus.c index 503f462a83f4..967cc3119a64 100644 --- a/sound/firewire/dice/dice-presonus.c +++ b/sound/firewire/dice/dice-presonus.c @@ -2,8 +2,6 @@ // dice-presonus.c - a part of driver for DICE based devices // // Copyright (c) 2019 Takashi Sakamoto -// -// Licensed under the terms of the GNU General Public License, version 2. #include "dice.h" diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c index bf44cad7985e..8900ffe517ed 100644 --- a/sound/firewire/fireface/ff-protocol-former.c +++ b/sound/firewire/fireface/ff-protocol-former.c @@ -2,8 +2,6 @@ // ff-protocol-former.c - a part of driver for RME Fireface series // // Copyright (c) 2019 Takashi Sakamoto -// -// Licensed under the terms of the GNU General Public License, version 2. #include diff --git a/sound/firewire/fireface/ff-protocol-latter.c b/sound/firewire/fireface/ff-protocol-latter.c index 7ddb7b97f02d..76c3eab36d4e 100644 --- a/sound/firewire/fireface/ff-protocol-latter.c +++ b/sound/firewire/fireface/ff-protocol-latter.c @@ -1,9 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 -// ff-protocol-latter - a part of driver for RME Fireface series +// ff-protocol-latter.c - a part of driver for RME Fireface series // // Copyright (c) 2019 Takashi Sakamoto -// -// Licensed under the terms of the GNU General Public License, version 2. #include diff --git a/sound/firewire/motu/motu-protocol-v1.c b/sound/firewire/motu/motu-protocol-v1.c index f1d6a326dc07..e811629f167b 100644 --- a/sound/firewire/motu/motu-protocol-v1.c +++ b/sound/firewire/motu/motu-protocol-v1.c @@ -1,10 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only - // motu-protocol-v1.c - a part of driver for MOTU FireWire series // // Copyright (c) 2021 Takashi Sakamoto -// -// Licensed under the terms of the GNU General Public License, version 2. #include "motu.h" -- cgit v1.2.3 From 69ab6f5b00b1804ea42b375ca30d818d169cae82 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 25 Sep 2022 15:20:46 +0200 Subject: ALSA: Remove some left-over license text in include/uapi/sound/ There is already a SPDX-License-Identifier tag, so the corresponding license text can be removed. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/203c1db92c470925f31e361f6e7d180812501f2e.1664112023.git.christophe.jaillet@wanadoo.fr Signed-off-by: Takashi Iwai --- include/uapi/sound/asequencer.h | 16 --------------- include/uapi/sound/asoc.h | 4 ---- include/uapi/sound/asound.h | 16 --------------- include/uapi/sound/asound_fm.h | 15 -------------- include/uapi/sound/compress_offload.h | 17 ---------------- include/uapi/sound/compress_params.h | 38 ++--------------------------------- include/uapi/sound/emu10k1.h | 16 --------------- include/uapi/sound/hdsp.h | 14 ------------- include/uapi/sound/hdspm.h | 15 -------------- include/uapi/sound/sb16_csp.h | 15 -------------- include/uapi/sound/sfnt_info.h | 15 -------------- include/uapi/sound/snd_sst_tokens.h | 10 --------- include/uapi/sound/tlv.h | 11 ---------- include/uapi/sound/usb_stream.h | 14 ------------- 14 files changed, 2 insertions(+), 214 deletions(-) diff --git a/include/uapi/sound/asequencer.h b/include/uapi/sound/asequencer.h index a75e14edc957..6d4a2c60808d 100644 --- a/include/uapi/sound/asequencer.h +++ b/include/uapi/sound/asequencer.h @@ -3,22 +3,6 @@ * Main header file for the ALSA sequencer * Copyright (c) 1998-1999 by Frank van de Pol * (c) 1998-1999 by Jaroslav Kysela - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #ifndef _UAPI__SOUND_ASEQUENCER_H #define _UAPI__SOUND_ASEQUENCER_H diff --git a/include/uapi/sound/asoc.h b/include/uapi/sound/asoc.h index 053949287ce8..9f35bedafcff 100644 --- a/include/uapi/sound/asoc.h +++ b/include/uapi/sound/asoc.h @@ -5,10 +5,6 @@ * Copyright (C) 2012 Texas Instruments Inc. * Copyright (C) 2015 Intel Corporation. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Simple file API to load FW that includes mixers, coefficients, DAPM graphs, * algorithms, equalisers, DAIs, widgets etc. */ diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index 3974a2a911cc..de6810e94abe 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -3,22 +3,6 @@ * Advanced Linux Sound Architecture - ALSA - Driver * Copyright (c) 1994-2003 by Jaroslav Kysela , * Abramo Bagnara - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #ifndef _UAPI__SOUND_ASOUND_H diff --git a/include/uapi/sound/asound_fm.h b/include/uapi/sound/asound_fm.h index 8471f404ff0b..25ec5e38af5c 100644 --- a/include/uapi/sound/asound_fm.h +++ b/include/uapi/sound/asound_fm.h @@ -10,21 +10,6 @@ * 4Front Technologies * * Direct FM control - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #define SNDRV_DM_FM_MODE_OPL2 0x00 diff --git a/include/uapi/sound/compress_offload.h b/include/uapi/sound/compress_offload.h index 3aef123dbd7f..d185957f3fe0 100644 --- a/include/uapi/sound/compress_offload.h +++ b/include/uapi/sound/compress_offload.h @@ -5,23 +5,6 @@ * Copyright (C) 2011 Intel Corporation * Authors: Vinod Koul * Pierre-Louis Bossart - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * */ #ifndef __COMPRESS_OFFLOAD_H #define __COMPRESS_OFFLOAD_H diff --git a/include/uapi/sound/compress_params.h b/include/uapi/sound/compress_params.h index 726361716919..ddc77322d571 100644 --- a/include/uapi/sound/compress_params.h +++ b/include/uapi/sound/compress_params.h @@ -7,47 +7,13 @@ * Authors: Pierre-Louis Bossart * Vinod Koul * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * The definitions in this file are derived from the OpenMAX AL version 1.1 - * and OpenMAX IL v 1.1.2 header files which contain the copyright notice below. + * and OpenMAX IL v 1.1.2 header files which contain the copyright notice below + * and are licensed under the MIT license. * * Copyright (c) 2007-2010 The Khronos Group Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and/or associated documentation files (the - * "Materials "), to deal in the Materials without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Materials, and to - * permit persons to whom the Materials are furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Materials. - * - * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. - * */ #ifndef __SND_COMPRESS_PARAMS_H #define __SND_COMPRESS_PARAMS_H diff --git a/include/uapi/sound/emu10k1.h b/include/uapi/sound/emu10k1.h index 88609cc0524c..1c1f1dd44611 100644 --- a/include/uapi/sound/emu10k1.h +++ b/include/uapi/sound/emu10k1.h @@ -3,22 +3,6 @@ * Copyright (c) by Jaroslav Kysela , * Creative Labs, Inc. * Definitions for EMU10K1 (SB Live!) chips - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #ifndef _UAPI__SOUND_EMU10K1_H #define _UAPI__SOUND_EMU10K1_H diff --git a/include/uapi/sound/hdsp.h b/include/uapi/sound/hdsp.h index b8df62b60f4d..0961954658d6 100644 --- a/include/uapi/sound/hdsp.h +++ b/include/uapi/sound/hdsp.h @@ -4,20 +4,6 @@ /* * Copyright (C) 2003 Thomas Charbonnel (thomas@undata.org) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifdef __linux__ diff --git a/include/uapi/sound/hdspm.h b/include/uapi/sound/hdspm.h index 14af3d00ea3f..7043bb3d435a 100644 --- a/include/uapi/sound/hdspm.h +++ b/include/uapi/sound/hdspm.h @@ -4,21 +4,6 @@ /* * Copyright (C) 2003 Winfried Ritsch (IEM) * based on hdsp.h from Thomas Charbonnel (thomas@undata.org) - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifdef __linux__ diff --git a/include/uapi/sound/sb16_csp.h b/include/uapi/sound/sb16_csp.h index e64851481d88..5a80f5ec02ee 100644 --- a/include/uapi/sound/sb16_csp.h +++ b/include/uapi/sound/sb16_csp.h @@ -4,21 +4,6 @@ * Takashi Iwai * * SB16ASP/AWE32 CSP control - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #ifndef _UAPI__SOUND_SB16_CSP_H #define _UAPI__SOUND_SB16_CSP_H diff --git a/include/uapi/sound/sfnt_info.h b/include/uapi/sound/sfnt_info.h index c9a810a6ef48..f2b5e13fb5a7 100644 --- a/include/uapi/sound/sfnt_info.h +++ b/include/uapi/sound/sfnt_info.h @@ -6,21 +6,6 @@ * Patch record compatible with AWE driver on OSS * * Copyright (C) 1999-2000 Takashi Iwai - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #include diff --git a/include/uapi/sound/snd_sst_tokens.h b/include/uapi/sound/snd_sst_tokens.h index ff3748e9308a..defeb0c6ed20 100644 --- a/include/uapi/sound/snd_sst_tokens.h +++ b/include/uapi/sound/snd_sst_tokens.h @@ -4,16 +4,6 @@ * * Copyright (C) 2016 Intel Corp * Author: Shreyas NC - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as version 2, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. */ #ifndef __SND_SST_TOKENS_H__ #define __SND_SST_TOKENS_H__ diff --git a/include/uapi/sound/tlv.h b/include/uapi/sound/tlv.h index 7d6d65f60a42..b99a2414b53d 100644 --- a/include/uapi/sound/tlv.h +++ b/include/uapi/sound/tlv.h @@ -1,15 +1,4 @@ /* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ #ifndef __UAPI_SOUND_TLV_H #define __UAPI_SOUND_TLV_H diff --git a/include/uapi/sound/usb_stream.h b/include/uapi/sound/usb_stream.h index ffdd3ea1e31d..50609016185a 100644 --- a/include/uapi/sound/usb_stream.h +++ b/include/uapi/sound/usb_stream.h @@ -1,20 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ /* * Copyright (C) 2007, 2008 Karsten Wiese - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef _UAPI__SOUND_USB_STREAM_H -- cgit v1.2.3 From f0061c18c169f0c32d96b59485c3edee85e343ed Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 26 Sep 2022 15:55:48 +0200 Subject: ALSA: pcm: Avoid reference to status->state In the PCM core and driver code, there are lots place referring to the current PCM state via runtime->status->state. This patch introduced a local PCM state in runtime itself and replaces those references with runtime->state. It has improvements in two aspects: - The reduction of a indirect access leads to more code optimization - It avoids a possible (unexpected) modification of the state via mmap of the status record The status->state is updated together with runtime->state, so that user-space can still read the current state via mmap like before, too. This patch touches only the ALSA core code. The changes in each driver will follow in later patches. Reviewed-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20220926135558.26580-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 20 +++++++- sound/core/oss/pcm_oss.c | 42 ++++++++-------- sound/core/pcm.c | 9 ++-- sound/core/pcm_compat.c | 4 +- sound/core/pcm_lib.c | 16 +++--- sound/core/pcm_native.c | 127 ++++++++++++++++++++++++----------------------- 6 files changed, 118 insertions(+), 100 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 8c48a5bce88c..7b1a022910e8 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -346,6 +346,8 @@ static inline void snd_pcm_pack_audio_tstamp_report(__u32 *data, __u32 *accuracy struct snd_pcm_runtime { /* -- Status -- */ + snd_pcm_state_t state; /* stream state */ + snd_pcm_state_t suspended_state; /* suspended stream state */ struct snd_pcm_substream *trigger_master; struct timespec64 trigger_tstamp; /* trigger timestamp */ bool trigger_tstamp_latched; /* trigger timestamp latched in low-level driver/hardware */ @@ -678,11 +680,25 @@ void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream, */ static inline int snd_pcm_running(struct snd_pcm_substream *substream) { - return (substream->runtime->status->state == SNDRV_PCM_STATE_RUNNING || - (substream->runtime->status->state == SNDRV_PCM_STATE_DRAINING && + return (substream->runtime->state == SNDRV_PCM_STATE_RUNNING || + (substream->runtime->state == SNDRV_PCM_STATE_DRAINING && substream->stream == SNDRV_PCM_STREAM_PLAYBACK)); } +/** + * __snd_pcm_set_state - Change the current PCM state + * @runtime: PCM runtime to set + * @state: the current state to set + * + * Call within the stream lock + */ +static inline void __snd_pcm_set_state(struct snd_pcm_runtime *runtime, + snd_pcm_state_t state) +{ + runtime->state = state; + runtime->status->state = state; /* copy for mmap */ +} + /** * bytes_to_samples - Unit conversion of the size from bytes to samples * @runtime: PCM runtime instance diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 02df915eb3c6..ac2efeb63a39 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -1237,12 +1237,12 @@ snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, const struct snd_pcm_runtime *runtime = substream->runtime; int ret; while (1) { - if (runtime->status->state == SNDRV_PCM_STATE_XRUN || - runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { + if (runtime->state == SNDRV_PCM_STATE_XRUN || + runtime->state == SNDRV_PCM_STATE_SUSPENDED) { #ifdef OSS_DEBUG pcm_dbg(substream->pcm, "pcm_oss: write: recovering from %s\n", - runtime->status->state == SNDRV_PCM_STATE_XRUN ? + runtime->state == SNDRV_PCM_STATE_XRUN ? "XRUN" : "SUSPEND"); #endif ret = snd_pcm_oss_prepare(substream); @@ -1257,7 +1257,7 @@ snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, const break; /* test, if we can't store new data, because the stream */ /* has not been started */ - if (runtime->status->state == SNDRV_PCM_STATE_PREPARED) + if (runtime->state == SNDRV_PCM_STATE_PREPARED) return -EAGAIN; } return ret; @@ -1269,18 +1269,18 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p snd_pcm_sframes_t delay; int ret; while (1) { - if (runtime->status->state == SNDRV_PCM_STATE_XRUN || - runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { + if (runtime->state == SNDRV_PCM_STATE_XRUN || + runtime->state == SNDRV_PCM_STATE_SUSPENDED) { #ifdef OSS_DEBUG pcm_dbg(substream->pcm, "pcm_oss: read: recovering from %s\n", - runtime->status->state == SNDRV_PCM_STATE_XRUN ? + runtime->state == SNDRV_PCM_STATE_XRUN ? "XRUN" : "SUSPEND"); #endif ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL); if (ret < 0) break; - } else if (runtime->status->state == SNDRV_PCM_STATE_SETUP) { + } else if (runtime->state == SNDRV_PCM_STATE_SETUP) { ret = snd_pcm_oss_prepare(substream); if (ret < 0) break; @@ -1293,7 +1293,7 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p frames, in_kernel); mutex_lock(&runtime->oss.params_lock); if (ret == -EPIPE) { - if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) { + if (runtime->state == SNDRV_PCM_STATE_DRAINING) { ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); if (ret < 0) break; @@ -1312,12 +1312,12 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void struct snd_pcm_runtime *runtime = substream->runtime; int ret; while (1) { - if (runtime->status->state == SNDRV_PCM_STATE_XRUN || - runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { + if (runtime->state == SNDRV_PCM_STATE_XRUN || + runtime->state == SNDRV_PCM_STATE_SUSPENDED) { #ifdef OSS_DEBUG pcm_dbg(substream->pcm, "pcm_oss: writev: recovering from %s\n", - runtime->status->state == SNDRV_PCM_STATE_XRUN ? + runtime->state == SNDRV_PCM_STATE_XRUN ? "XRUN" : "SUSPEND"); #endif ret = snd_pcm_oss_prepare(substream); @@ -1330,7 +1330,7 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void /* test, if we can't store new data, because the stream */ /* has not been started */ - if (runtime->status->state == SNDRV_PCM_STATE_PREPARED) + if (runtime->state == SNDRV_PCM_STATE_PREPARED) return -EAGAIN; } return ret; @@ -1341,18 +1341,18 @@ snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void * struct snd_pcm_runtime *runtime = substream->runtime; int ret; while (1) { - if (runtime->status->state == SNDRV_PCM_STATE_XRUN || - runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { + if (runtime->state == SNDRV_PCM_STATE_XRUN || + runtime->state == SNDRV_PCM_STATE_SUSPENDED) { #ifdef OSS_DEBUG pcm_dbg(substream->pcm, "pcm_oss: readv: recovering from %s\n", - runtime->status->state == SNDRV_PCM_STATE_XRUN ? + runtime->state == SNDRV_PCM_STATE_XRUN ? "XRUN" : "SUSPEND"); #endif ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL); if (ret < 0) break; - } else if (runtime->status->state == SNDRV_PCM_STATE_SETUP) { + } else if (runtime->state == SNDRV_PCM_STATE_SETUP) { ret = snd_pcm_oss_prepare(substream); if (ret < 0) break; @@ -1635,7 +1635,7 @@ static int snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size) result = 0; set_current_state(TASK_INTERRUPTIBLE); snd_pcm_stream_lock_irq(substream); - state = runtime->status->state; + state = runtime->state; snd_pcm_stream_unlock_irq(substream); if (state != SNDRV_PCM_STATE_RUNNING) { set_current_state(TASK_RUNNING); @@ -2854,8 +2854,8 @@ static __poll_t snd_pcm_oss_poll(struct file *file, poll_table * wait) struct snd_pcm_runtime *runtime = psubstream->runtime; poll_wait(file, &runtime->sleep, wait); snd_pcm_stream_lock_irq(psubstream); - if (runtime->status->state != SNDRV_PCM_STATE_DRAINING && - (runtime->status->state != SNDRV_PCM_STATE_RUNNING || + if (runtime->state != SNDRV_PCM_STATE_DRAINING && + (runtime->state != SNDRV_PCM_STATE_RUNNING || snd_pcm_oss_playback_ready(psubstream))) mask |= EPOLLOUT | EPOLLWRNORM; snd_pcm_stream_unlock_irq(psubstream); @@ -2865,7 +2865,7 @@ static __poll_t snd_pcm_oss_poll(struct file *file, poll_table * wait) snd_pcm_state_t ostate; poll_wait(file, &runtime->sleep, wait); snd_pcm_stream_lock_irq(csubstream); - ostate = runtime->status->state; + ostate = runtime->state; if (ostate != SNDRV_PCM_STATE_RUNNING || snd_pcm_oss_capture_ready(csubstream)) mask |= EPOLLIN | EPOLLRDNORM; diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 82925709fa12..9d95e3731123 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -387,7 +387,7 @@ static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry, snd_iprintf(buffer, "closed\n"); goto unlock; } - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { + if (runtime->state == SNDRV_PCM_STATE_OPEN) { snd_iprintf(buffer, "no setup\n"); goto unlock; } @@ -424,7 +424,7 @@ static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry, snd_iprintf(buffer, "closed\n"); goto unlock; } - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { + if (runtime->state == SNDRV_PCM_STATE_OPEN) { snd_iprintf(buffer, "no setup\n"); goto unlock; } @@ -970,7 +970,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, init_waitqueue_head(&runtime->sleep); init_waitqueue_head(&runtime->tsleep); - runtime->status->state = SNDRV_PCM_STATE_OPEN; + __snd_pcm_set_state(runtime, SNDRV_PCM_STATE_OPEN); mutex_init(&runtime->buffer_mutex); atomic_set(&runtime->buffer_accessing, 0); @@ -1112,7 +1112,8 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) if (snd_pcm_running(substream)) snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); /* to be sure, set the state unconditionally */ - substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED; + __snd_pcm_set_state(substream->runtime, + SNDRV_PCM_STATE_DISCONNECTED); wake_up(&substream->runtime->sleep); wake_up(&substream->runtime->tsleep); } diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index 917c5b4f19d7..42c2ada8e888 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c @@ -295,7 +295,7 @@ static int snd_pcm_ioctl_xferi_compat(struct snd_pcm_substream *substream, return -ENOTTY; if (substream->stream != dir) return -EINVAL; - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) + if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; if (get_user(buf, &data32->buf) || @@ -341,7 +341,7 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream, return -ENOTTY; if (substream->stream != dir) return -EINVAL; - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) + if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; ch = substream->runtime->channels; diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 40751e5aff09..8b6aeb8a78f7 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -186,7 +186,7 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream, avail = snd_pcm_avail(substream); if (avail > runtime->avail_max) runtime->avail_max = avail; - if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) { + if (runtime->state == SNDRV_PCM_STATE_DRAINING) { if (avail >= runtime->buffer_size) { snd_pcm_drain_done(substream); return -EPIPE; @@ -1911,7 +1911,7 @@ static int wait_for_avail(struct snd_pcm_substream *substream, snd_pcm_stream_lock_irq(substream); set_current_state(TASK_INTERRUPTIBLE); - switch (runtime->status->state) { + switch (runtime->state) { case SNDRV_PCM_STATE_SUSPENDED: err = -ESTRPIPE; goto _endloop; @@ -2099,14 +2099,14 @@ static int pcm_sanity_check(struct snd_pcm_substream *substream) runtime = substream->runtime; if (snd_BUG_ON(!substream->ops->copy_user && !runtime->dma_area)) return -EINVAL; - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) + if (runtime->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; return 0; } static int pcm_accessible_state(struct snd_pcm_runtime *runtime) { - switch (runtime->status->state) { + switch (runtime->state) { case SNDRV_PCM_STATE_PREPARED: case SNDRV_PCM_STATE_RUNNING: case SNDRV_PCM_STATE_PAUSED: @@ -2225,7 +2225,7 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, goto _end_unlock; runtime->twake = runtime->control->avail_min ? : 1; - if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) + if (runtime->state == SNDRV_PCM_STATE_RUNNING) snd_pcm_update_hw_ptr(substream); /* @@ -2233,7 +2233,7 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, * thread may start capture */ if (!is_playback && - runtime->status->state == SNDRV_PCM_STATE_PREPARED && + runtime->state == SNDRV_PCM_STATE_PREPARED && size >= runtime->start_threshold) { err = snd_pcm_start(substream); if (err < 0) @@ -2247,7 +2247,7 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, snd_pcm_uframes_t cont; if (!avail) { if (!is_playback && - runtime->status->state == SNDRV_PCM_STATE_DRAINING) { + runtime->state == SNDRV_PCM_STATE_DRAINING) { snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); goto _end_unlock; } @@ -2303,7 +2303,7 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, xfer += frames; avail -= frames; if (is_playback && - runtime->status->state == SNDRV_PCM_STATE_PREPARED && + runtime->state == SNDRV_PCM_STATE_PREPARED && snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) { err = snd_pcm_start(substream); if (err < 0) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index ad0541e9e888..d9485b1ab719 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -595,8 +595,8 @@ static void snd_pcm_set_state(struct snd_pcm_substream *substream, snd_pcm_state_t state) { snd_pcm_stream_lock_irq(substream); - if (substream->runtime->status->state != SNDRV_PCM_STATE_DISCONNECTED) - substream->runtime->status->state = state; + if (substream->runtime->state != SNDRV_PCM_STATE_DISCONNECTED) + __snd_pcm_set_state(substream->runtime, state); snd_pcm_stream_unlock_irq(substream); } @@ -724,7 +724,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, if (err < 0) return err; snd_pcm_stream_lock_irq(substream); - switch (runtime->status->state) { + switch (runtime->state) { case SNDRV_PCM_STATE_OPEN: case SNDRV_PCM_STATE_SETUP: case SNDRV_PCM_STATE_PREPARED: @@ -889,7 +889,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream) if (result < 0) return result; snd_pcm_stream_lock_irq(substream); - switch (runtime->status->state) { + switch (runtime->state) { case SNDRV_PCM_STATE_SETUP: case SNDRV_PCM_STATE_PREPARED: if (atomic_read(&substream->mmap_count)) @@ -920,7 +920,7 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, return -ENXIO; runtime = substream->runtime; snd_pcm_stream_lock_irq(substream); - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { + if (runtime->state == SNDRV_PCM_STATE_OPEN) { snd_pcm_stream_unlock_irq(substream); return -EBADFD; } @@ -1013,8 +1013,8 @@ int snd_pcm_status64(struct snd_pcm_substream *substream, } else runtime->audio_tstamp_report.valid = 1; - status->state = runtime->status->state; - status->suspended_state = runtime->status->suspended_state; + status->state = runtime->state; + status->suspended_state = runtime->suspended_state; if (status->state == SNDRV_PCM_STATE_OPEN) goto _end; status->trigger_tstamp_sec = runtime->trigger_tstamp.tv_sec; @@ -1148,7 +1148,7 @@ static int snd_pcm_channel_info(struct snd_pcm_substream *substream, channel = info->channel; runtime = substream->runtime; snd_pcm_stream_lock_irq(substream); - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { + if (runtime->state == SNDRV_PCM_STATE_OPEN) { snd_pcm_stream_unlock_irq(substream); return -EBADFD; } @@ -1411,7 +1411,7 @@ static int snd_pcm_pre_start(struct snd_pcm_substream *substream, snd_pcm_state_t state) { struct snd_pcm_runtime *runtime = substream->runtime; - if (runtime->status->state != SNDRV_PCM_STATE_PREPARED) + if (runtime->state != SNDRV_PCM_STATE_PREPARED) return -EBADFD; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && !snd_pcm_playback_data(substream)) @@ -1444,7 +1444,7 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, runtime->hw_ptr_jiffies = jiffies; runtime->hw_ptr_buffer_jiffies = (runtime->buffer_size * HZ) / runtime->rate; - runtime->status->state = state; + __snd_pcm_set_state(runtime, state); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) snd_pcm_playback_silence(substream, ULONG_MAX); @@ -1485,7 +1485,7 @@ static int snd_pcm_pre_stop(struct snd_pcm_substream *substream, snd_pcm_state_t state) { struct snd_pcm_runtime *runtime = substream->runtime; - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) + if (runtime->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; runtime->trigger_master = substream; return 0; @@ -1506,9 +1506,9 @@ static void snd_pcm_post_stop(struct snd_pcm_substream *substream, snd_pcm_state_t state) { struct snd_pcm_runtime *runtime = substream->runtime; - if (runtime->status->state != state) { + if (runtime->state != state) { snd_pcm_trigger_tstamp(substream); - runtime->status->state = state; + __snd_pcm_set_state(runtime, state); snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSTOP); } wake_up(&runtime->sleep); @@ -1584,9 +1584,9 @@ static int snd_pcm_pre_pause(struct snd_pcm_substream *substream, if (!(runtime->info & SNDRV_PCM_INFO_PAUSE)) return -ENOSYS; if (pause_pushed(state)) { - if (runtime->status->state != SNDRV_PCM_STATE_RUNNING) + if (runtime->state != SNDRV_PCM_STATE_RUNNING) return -EBADFD; - } else if (runtime->status->state != SNDRV_PCM_STATE_PAUSED) + } else if (runtime->state != SNDRV_PCM_STATE_PAUSED) return -EBADFD; runtime->trigger_master = substream; return 0; @@ -1628,12 +1628,12 @@ static void snd_pcm_post_pause(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_trigger_tstamp(substream); if (pause_pushed(state)) { - runtime->status->state = SNDRV_PCM_STATE_PAUSED; + __snd_pcm_set_state(runtime, SNDRV_PCM_STATE_PAUSED); snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MPAUSE); wake_up(&runtime->sleep); wake_up(&runtime->tsleep); } else { - runtime->status->state = SNDRV_PCM_STATE_RUNNING; + __snd_pcm_set_state(runtime, SNDRV_PCM_STATE_RUNNING); snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MCONTINUE); } } @@ -1668,7 +1668,7 @@ static int snd_pcm_pre_suspend(struct snd_pcm_substream *substream, snd_pcm_state_t state) { struct snd_pcm_runtime *runtime = substream->runtime; - switch (runtime->status->state) { + switch (runtime->state) { case SNDRV_PCM_STATE_SUSPENDED: return -EBUSY; /* unresumable PCM state; return -EBUSY for skipping suspend */ @@ -1699,8 +1699,9 @@ static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, { struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_trigger_tstamp(substream); - runtime->status->suspended_state = runtime->status->state; - runtime->status->state = SNDRV_PCM_STATE_SUSPENDED; + runtime->suspended_state = runtime->state; + runtime->status->suspended_state = runtime->suspended_state; + __snd_pcm_set_state(runtime, SNDRV_PCM_STATE_SUSPENDED); snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSUSPEND); wake_up(&runtime->sleep); wake_up(&runtime->tsleep); @@ -1791,8 +1792,8 @@ static int snd_pcm_do_resume(struct snd_pcm_substream *substream, if (runtime->trigger_master != substream) return 0; /* DMA not running previously? */ - if (runtime->status->suspended_state != SNDRV_PCM_STATE_RUNNING && - (runtime->status->suspended_state != SNDRV_PCM_STATE_DRAINING || + if (runtime->suspended_state != SNDRV_PCM_STATE_RUNNING && + (runtime->suspended_state != SNDRV_PCM_STATE_DRAINING || substream->stream != SNDRV_PCM_STREAM_PLAYBACK)) return 0; return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_RESUME); @@ -1811,7 +1812,7 @@ static void snd_pcm_post_resume(struct snd_pcm_substream *substream, { struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_trigger_tstamp(substream); - runtime->status->state = runtime->status->suspended_state; + __snd_pcm_set_state(runtime, runtime->suspended_state); snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MRESUME); } @@ -1848,7 +1849,7 @@ static int snd_pcm_xrun(struct snd_pcm_substream *substream) int result; snd_pcm_stream_lock_irq(substream); - switch (runtime->status->state) { + switch (runtime->state) { case SNDRV_PCM_STATE_XRUN: result = 0; /* already there */ break; @@ -1871,7 +1872,7 @@ static int snd_pcm_pre_reset(struct snd_pcm_substream *substream, snd_pcm_state_t state) { struct snd_pcm_runtime *runtime = substream->runtime; - switch (runtime->status->state) { + switch (runtime->state) { case SNDRV_PCM_STATE_RUNNING: case SNDRV_PCM_STATE_PREPARED: case SNDRV_PCM_STATE_PAUSED: @@ -1933,8 +1934,8 @@ static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; int f_flags = (__force int)state; - if (runtime->status->state == SNDRV_PCM_STATE_OPEN || - runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED) + if (runtime->state == SNDRV_PCM_STATE_OPEN || + runtime->state == SNDRV_PCM_STATE_DISCONNECTED) return -EBADFD; if (snd_pcm_running(substream)) return -EBUSY; @@ -1985,7 +1986,7 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream, f_flags = substream->f_flags; snd_pcm_stream_lock_irq(substream); - switch (substream->runtime->status->state) { + switch (substream->runtime->state) { case SNDRV_PCM_STATE_PAUSED: snd_pcm_pause(substream, false); fallthrough; @@ -2009,7 +2010,7 @@ static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream, snd_pcm_state_t state) { struct snd_pcm_runtime *runtime = substream->runtime; - switch (runtime->status->state) { + switch (runtime->state) { case SNDRV_PCM_STATE_OPEN: case SNDRV_PCM_STATE_DISCONNECTED: case SNDRV_PCM_STATE_SUSPENDED: @@ -2024,28 +2025,28 @@ static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, { struct snd_pcm_runtime *runtime = substream->runtime; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - switch (runtime->status->state) { + switch (runtime->state) { case SNDRV_PCM_STATE_PREPARED: /* start playback stream if possible */ if (! snd_pcm_playback_empty(substream)) { snd_pcm_do_start(substream, SNDRV_PCM_STATE_DRAINING); snd_pcm_post_start(substream, SNDRV_PCM_STATE_DRAINING); } else { - runtime->status->state = SNDRV_PCM_STATE_SETUP; + __snd_pcm_set_state(runtime, SNDRV_PCM_STATE_SETUP); } break; case SNDRV_PCM_STATE_RUNNING: - runtime->status->state = SNDRV_PCM_STATE_DRAINING; + __snd_pcm_set_state(runtime, SNDRV_PCM_STATE_DRAINING); break; case SNDRV_PCM_STATE_XRUN: - runtime->status->state = SNDRV_PCM_STATE_SETUP; + __snd_pcm_set_state(runtime, SNDRV_PCM_STATE_SETUP); break; default: break; } } else { /* stop running stream */ - if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) { + if (runtime->state == SNDRV_PCM_STATE_RUNNING) { snd_pcm_state_t new_state; new_state = snd_pcm_capture_avail(runtime) > 0 ? @@ -2055,7 +2056,7 @@ static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, } } - if (runtime->status->state == SNDRV_PCM_STATE_DRAINING && + if (runtime->state == SNDRV_PCM_STATE_DRAINING && runtime->trigger_master == substream && (runtime->hw.info & SNDRV_PCM_INFO_DRAIN_TRIGGER)) return substream->ops->trigger(substream, @@ -2096,7 +2097,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, card = substream->pcm->card; runtime = substream->runtime; - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) + if (runtime->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; if (file) { @@ -2107,7 +2108,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, snd_pcm_stream_lock_irq(substream); /* resume pause */ - if (runtime->status->state == SNDRV_PCM_STATE_PAUSED) + if (runtime->state == SNDRV_PCM_STATE_PAUSED) snd_pcm_pause(substream, false); /* pre-start/stop - all running streams are changed to DRAINING state */ @@ -2135,7 +2136,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, if (s->stream != SNDRV_PCM_STREAM_PLAYBACK) continue; runtime = s->runtime; - if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) { + if (runtime->state == SNDRV_PCM_STATE_DRAINING) { to_check = runtime; break; } @@ -2174,7 +2175,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, break; } if (tout == 0) { - if (substream->runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) + if (substream->runtime->state == SNDRV_PCM_STATE_SUSPENDED) result = -ESTRPIPE; else { dev_dbg(substream->pcm->card->dev, @@ -2206,13 +2207,13 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream) return -ENXIO; runtime = substream->runtime; - if (runtime->status->state == SNDRV_PCM_STATE_OPEN || - runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED) + if (runtime->state == SNDRV_PCM_STATE_OPEN || + runtime->state == SNDRV_PCM_STATE_DISCONNECTED) return -EBADFD; snd_pcm_stream_lock_irq(substream); /* resume pause */ - if (runtime->status->state == SNDRV_PCM_STATE_PAUSED) + if (runtime->state == SNDRV_PCM_STATE_PAUSED) snd_pcm_pause(substream, false); snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); @@ -2275,8 +2276,8 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) snd_pcm_group_init(group); down_write(&snd_pcm_link_rwsem); - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN || - substream->runtime->status->state != substream1->runtime->status->state || + if (substream->runtime->state == SNDRV_PCM_STATE_OPEN || + substream->runtime->state != substream1->runtime->state || substream->pcm->nonatomic != substream1->pcm->nonatomic) { res = -EBADFD; goto _end; @@ -2700,7 +2701,7 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream) snd_pcm_drop(substream); if (substream->hw_opened) { - if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) + if (substream->runtime->state != SNDRV_PCM_STATE_OPEN) do_hw_free(substream); substream->ops->close(substream); substream->hw_opened = 0; @@ -2904,7 +2905,7 @@ static int snd_pcm_release(struct inode *inode, struct file *file) */ static int do_pcm_hwsync(struct snd_pcm_substream *substream) { - switch (substream->runtime->status->state) { + switch (substream->runtime->state) { case SNDRV_PCM_STATE_DRAINING: if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) return -EBADFD; @@ -3203,7 +3204,7 @@ static int snd_pcm_xferi_frames_ioctl(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_sframes_t result; - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) + if (runtime->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; if (put_user(0, &_xferi->result)) return -EFAULT; @@ -3226,7 +3227,7 @@ static int snd_pcm_xfern_frames_ioctl(struct snd_pcm_substream *substream, void *bufs; snd_pcm_sframes_t result; - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) + if (runtime->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; if (runtime->channels > 128) return -EINVAL; @@ -3290,7 +3291,7 @@ static int snd_pcm_common_ioctl(struct file *file, if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; - if (substream->runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED) + if (substream->runtime->state == SNDRV_PCM_STATE_DISCONNECTED) return -EBADFD; res = snd_power_wait(substream->pcm->card); @@ -3421,7 +3422,7 @@ int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, snd_pcm_uframes_t *frames = arg; snd_pcm_sframes_t result; - if (substream->runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED) + if (substream->runtime->state == SNDRV_PCM_STATE_DISCONNECTED) return -EBADFD; switch (cmd) { @@ -3466,8 +3467,8 @@ static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count, if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; runtime = substream->runtime; - if (runtime->status->state == SNDRV_PCM_STATE_OPEN || - runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED) + if (runtime->state == SNDRV_PCM_STATE_OPEN || + runtime->state == SNDRV_PCM_STATE_DISCONNECTED) return -EBADFD; if (!frame_aligned(runtime, count)) return -EINVAL; @@ -3491,8 +3492,8 @@ static ssize_t snd_pcm_write(struct file *file, const char __user *buf, if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; runtime = substream->runtime; - if (runtime->status->state == SNDRV_PCM_STATE_OPEN || - runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED) + if (runtime->state == SNDRV_PCM_STATE_OPEN || + runtime->state == SNDRV_PCM_STATE_DISCONNECTED) return -EBADFD; if (!frame_aligned(runtime, count)) return -EINVAL; @@ -3518,8 +3519,8 @@ static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to) if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; runtime = substream->runtime; - if (runtime->status->state == SNDRV_PCM_STATE_OPEN || - runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED) + if (runtime->state == SNDRV_PCM_STATE_OPEN || + runtime->state == SNDRV_PCM_STATE_DISCONNECTED) return -EBADFD; if (!iter_is_iovec(to)) return -EINVAL; @@ -3555,8 +3556,8 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from) if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; runtime = substream->runtime; - if (runtime->status->state == SNDRV_PCM_STATE_OPEN || - runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED) + if (runtime->state == SNDRV_PCM_STATE_OPEN || + runtime->state == SNDRV_PCM_STATE_DISCONNECTED) return -EBADFD; if (!iter_is_iovec(from)) return -EINVAL; @@ -3595,7 +3596,7 @@ static __poll_t snd_pcm_poll(struct file *file, poll_table *wait) return ok | EPOLLERR; runtime = substream->runtime; - if (runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED) + if (runtime->state == SNDRV_PCM_STATE_DISCONNECTED) return ok | EPOLLERR; poll_wait(file, &runtime->sleep, wait); @@ -3603,7 +3604,7 @@ static __poll_t snd_pcm_poll(struct file *file, poll_table *wait) mask = 0; snd_pcm_stream_lock_irq(substream); avail = snd_pcm_avail(substream); - switch (runtime->status->state) { + switch (runtime->state) { case SNDRV_PCM_STATE_RUNNING: case SNDRV_PCM_STATE_PREPARED: case SNDRV_PCM_STATE_PAUSED: @@ -3874,7 +3875,7 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, return -EINVAL; } runtime = substream->runtime; - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) + if (runtime->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; if (!(runtime->info & SNDRV_PCM_INFO_MMAP)) return -ENXIO; @@ -3911,7 +3912,7 @@ static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area) substream = pcm_file->substream; if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; - if (substream->runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED) + if (substream->runtime->state == SNDRV_PCM_STATE_DISCONNECTED) return -EBADFD; offset = area->vm_pgoff << PAGE_SHIFT; @@ -3949,7 +3950,7 @@ static int snd_pcm_fasync(int fd, struct file * file, int on) if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; runtime = substream->runtime; - if (runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED) + if (runtime->state == SNDRV_PCM_STATE_DISCONNECTED) return -EBADFD; return snd_fasync_helper(fd, file, on, &runtime->fasync); } -- cgit v1.2.3 From 1be2143fb7b19e247f7c4aa1097f85fe92c132bf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 26 Sep 2022 15:55:49 +0200 Subject: ALSA: pcm: Make mmap status read-only The mmap status record should be read-only. Modifying it from user-space may screw up things unexpectedly, so let's clear the write bits at exposing it. Note that alsa-lib and other known user-space apps access the mmapped status only as read-only, hence this change shouldn't break the existing applications. Reviewed-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20220926135558.26580-3-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index d9485b1ab719..33769ca78cc8 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3668,6 +3668,7 @@ static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file area->vm_ops = &snd_pcm_vm_ops_status; area->vm_private_data = substream; area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; + area->vm_flags &= ~(VM_WRITE | VM_MAYWRITE); return 0; } -- cgit v1.2.3 From f7efa9b8a7d959813c63275b2e980de996b8e626 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 26 Sep 2022 15:55:50 +0200 Subject: ALSA: aloop: Replace runtime->status->state reference to runtime->state The recent change in ALSA core allows drivers to get the current PCM state directly from runtime object. Replace the calls accordingly. Reviewed-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20220926135558.26580-4-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/drivers/aloop.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 12f12a294df5..a38e602b4fc6 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -535,7 +535,7 @@ static void copy_play_buf(struct loopback_pcm *play, /* check if playback is draining, trim the capture copy size * when our pointer is at the end of playback ring buffer */ - if (runtime->status->state == SNDRV_PCM_STATE_DRAINING && + if (runtime->state == SNDRV_PCM_STATE_DRAINING && snd_pcm_playback_hw_avail(runtime) < runtime->buffer_size) { snd_pcm_uframes_t appl_ptr, appl_ptr1, diff; appl_ptr = appl_ptr1 = runtime->control->appl_ptr; @@ -730,7 +730,7 @@ static void loopback_snd_timer_period_elapsed(struct loopback_cable *cable, if (event == SNDRV_TIMER_EVENT_MSTOP) { if (!dpcm_play || - dpcm_play->substream->runtime->status->state != + dpcm_play->substream->runtime->state != SNDRV_PCM_STATE_DRAINING) { spin_unlock_irqrestore(&cable->lock, flags); return; -- cgit v1.2.3 From 23cb0767f0544858169c02cec445d066d4e02e2b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 26 Sep 2022 15:55:51 +0200 Subject: ALSA: firewire: Replace runtime->status->state reference to runtime->state The recent change in ALSA core allows drivers to get the current PCM state directly from runtime object. Replace the calls accordingly. Reviewed-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20220926135558.26580-5-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob_pcm.c | 4 ++-- sound/firewire/dice/dice-pcm.c | 4 ++-- sound/firewire/digi00x/digi00x-pcm.c | 4 ++-- sound/firewire/fireface/ff-pcm.c | 4 ++-- sound/firewire/fireworks/fireworks_pcm.c | 4 ++-- sound/firewire/motu/motu-pcm.c | 4 ++-- sound/firewire/oxfw/oxfw-pcm.c | 8 ++++---- sound/firewire/tascam/tascam-pcm.c | 4 ++-- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c index f8d9a2041264..ce49eef0fcba 100644 --- a/sound/firewire/bebob/bebob_pcm.c +++ b/sound/firewire/bebob/bebob_pcm.c @@ -214,7 +214,7 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, struct snd_bebob *bebob = substream->private_data; int err = 0; - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { + if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); unsigned int frames_per_period = params_period_size(hw_params); unsigned int frames_per_buffer = params_buffer_size(hw_params); @@ -236,7 +236,7 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) mutex_lock(&bebob->mutex); - if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) + if (substream->runtime->state != SNDRV_PCM_STATE_OPEN) bebob->substreams_counter--; snd_bebob_stream_stop_duplex(bebob); diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index a69ca1111b03..d64366217d57 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -266,7 +266,7 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, struct snd_dice *dice = substream->private_data; int err = 0; - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { + if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); unsigned int events_per_period = params_period_size(hw_params); unsigned int events_per_buffer = params_buffer_size(hw_params); @@ -293,7 +293,7 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) mutex_lock(&dice->mutex); - if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) + if (substream->runtime->state != SNDRV_PCM_STATE_OPEN) --dice->substreams_counter; snd_dice_stream_stop_duplex(dice); diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c index b7f6eda09f9f..3bd1575c9d9c 100644 --- a/sound/firewire/digi00x/digi00x-pcm.c +++ b/sound/firewire/digi00x/digi00x-pcm.c @@ -190,7 +190,7 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, struct snd_dg00x *dg00x = substream->private_data; int err = 0; - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { + if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); unsigned int frames_per_period = params_period_size(hw_params); unsigned int frames_per_buffer = params_buffer_size(hw_params); @@ -212,7 +212,7 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) mutex_lock(&dg00x->mutex); - if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) + if (substream->runtime->state != SNDRV_PCM_STATE_OPEN) --dg00x->substreams_counter; snd_dg00x_stream_stop_duplex(dg00x); diff --git a/sound/firewire/fireface/ff-pcm.c b/sound/firewire/fireface/ff-pcm.c index f978cc2fed7d..ec915671a79b 100644 --- a/sound/firewire/fireface/ff-pcm.c +++ b/sound/firewire/fireface/ff-pcm.c @@ -230,7 +230,7 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, struct snd_ff *ff = substream->private_data; int err = 0; - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { + if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); unsigned int frames_per_period = params_period_size(hw_params); unsigned int frames_per_buffer = params_buffer_size(hw_params); @@ -252,7 +252,7 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) mutex_lock(&ff->mutex); - if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) + if (substream->runtime->state != SNDRV_PCM_STATE_OPEN) --ff->substreams_counter; snd_ff_stream_stop_duplex(ff); diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index a0d5db1d8eb2..c3c21860b245 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -250,7 +250,7 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, struct snd_efw *efw = substream->private_data; int err = 0; - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { + if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); unsigned int frames_per_period = params_period_size(hw_params); unsigned int frames_per_buffer = params_buffer_size(hw_params); @@ -272,7 +272,7 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) mutex_lock(&efw->mutex); - if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) + if (substream->runtime->state != SNDRV_PCM_STATE_OPEN) --efw->substreams_counter; snd_efw_stream_stop_duplex(efw); diff --git a/sound/firewire/motu/motu-pcm.c b/sound/firewire/motu/motu-pcm.c index 8e1437371263..d410c2efbde5 100644 --- a/sound/firewire/motu/motu-pcm.c +++ b/sound/firewire/motu/motu-pcm.c @@ -210,7 +210,7 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, struct snd_motu *motu = substream->private_data; int err = 0; - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { + if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); unsigned int frames_per_period = params_period_size(hw_params); unsigned int frames_per_buffer = params_buffer_size(hw_params); @@ -232,7 +232,7 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) mutex_lock(&motu->mutex); - if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) + if (substream->runtime->state != SNDRV_PCM_STATE_OPEN) --motu->substreams_counter; snd_motu_stream_stop_duplex(motu); diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c index 2dfa7e179cb6..5f43a0b826d2 100644 --- a/sound/firewire/oxfw/oxfw-pcm.c +++ b/sound/firewire/oxfw/oxfw-pcm.c @@ -239,7 +239,7 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream, struct snd_oxfw *oxfw = substream->private_data; int err = 0; - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { + if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); unsigned int channels = params_channels(hw_params); unsigned int frames_per_period = params_period_size(hw_params); @@ -262,7 +262,7 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream, struct snd_oxfw *oxfw = substream->private_data; int err = 0; - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { + if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); unsigned int channels = params_channels(hw_params); unsigned int frames_per_period = params_period_size(hw_params); @@ -286,7 +286,7 @@ static int pcm_capture_hw_free(struct snd_pcm_substream *substream) mutex_lock(&oxfw->mutex); - if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) + if (substream->runtime->state != SNDRV_PCM_STATE_OPEN) --oxfw->substreams_count; snd_oxfw_stream_stop_duplex(oxfw); @@ -301,7 +301,7 @@ static int pcm_playback_hw_free(struct snd_pcm_substream *substream) mutex_lock(&oxfw->mutex); - if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) + if (substream->runtime->state != SNDRV_PCM_STATE_OPEN) --oxfw->substreams_count; snd_oxfw_stream_stop_duplex(oxfw); diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c index 36c1353f2494..f6da571707ac 100644 --- a/sound/firewire/tascam/tascam-pcm.c +++ b/sound/firewire/tascam/tascam-pcm.c @@ -119,7 +119,7 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, struct snd_tscm *tscm = substream->private_data; int err = 0; - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { + if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); unsigned int frames_per_period = params_period_size(hw_params); unsigned int frames_per_buffer = params_buffer_size(hw_params); @@ -141,7 +141,7 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) mutex_lock(&tscm->mutex); - if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) + if (substream->runtime->state != SNDRV_PCM_STATE_OPEN) --tscm->substreams_counter; snd_tscm_stream_stop_duplex(tscm); -- cgit v1.2.3 From 38d8be5df88539dc4a024250ab5988028e21826e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 26 Sep 2022 15:55:52 +0200 Subject: ALSA: hda: Replace runtime->status->state reference to runtime->state The recent change in ALSA core allows drivers to get the current PCM state directly from runtime object. Replace the calls accordingly. Reviewed-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20220926135558.26580-6-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/hda/hdmi_chmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/hda/hdmi_chmap.c b/sound/hda/hdmi_chmap.c index aad5c4bf4d34..5d8e1d944b0a 100644 --- a/sound/hda/hdmi_chmap.c +++ b/sound/hda/hdmi_chmap.c @@ -774,7 +774,7 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol, substream = snd_pcm_chmap_substream(info, ctl_idx); if (!substream || !substream->runtime) return 0; /* just for avoiding error from alsactl restore */ - switch (substream->runtime->status->state) { + switch (substream->runtime->state) { case SNDRV_PCM_STATE_OPEN: case SNDRV_PCM_STATE_SETUP: break; -- cgit v1.2.3 From 7246e5c80630bb4dfdd50c7de2c38c4a91fd36fc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 26 Sep 2022 15:55:53 +0200 Subject: ALSA: asihpi: Replace runtime->status->state reference to runtime->state The recent change in ALSA core allows drivers to get the current PCM state directly from runtime object. Replace the calls accordingly. Reviewed-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20220926135558.26580-7-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/asihpi/asihpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index 5e1f9f10051b..8de43aaa10aa 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -632,7 +632,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, /*? workaround linked streams don't transition to SETUP 20070706*/ - s->runtime->status->state = SNDRV_PCM_STATE_SETUP; + __snd_pcm_set_state(s->runtime, SNDRV_PCM_STATE_SETUP); if (card->support_grouping) { snd_printdd("%d group\n", s->number); -- cgit v1.2.3 From d8b4efeeb37ae5e221be6b265a5b93f54c242e82 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 26 Sep 2022 15:55:54 +0200 Subject: ALSA: usb-audio: Replace runtime->status->state reference to runtime->state The recent change in ALSA core allows drivers to get the current PCM state directly from runtime object. Replace the calls accordingly. Reviewed-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20220926135558.26580-8-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index e721fc12acde..8ed165f036a0 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -1395,7 +1395,7 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, transfer_done = subs->transfer_done; if (subs->lowlatency_playback && - runtime->status->state != SNDRV_PCM_STATE_DRAINING) { + runtime->state != SNDRV_PCM_STATE_DRAINING) { unsigned int hwptr = subs->hwptr_done / stride; /* calculate the byte offset-in-buffer of the appl_ptr */ @@ -1583,7 +1583,7 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea return 0; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: - stop_endpoints(subs, substream->runtime->status->state == SNDRV_PCM_STATE_DRAINING); + stop_endpoints(subs, substream->runtime->state == SNDRV_PCM_STATE_DRAINING); snd_usb_endpoint_set_callback(subs->data_endpoint, NULL, NULL, NULL); subs->running = 0; -- cgit v1.2.3 From ca4833c5a21bf419fe505e9798bbf49cbd482e8f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 26 Sep 2022 15:55:55 +0200 Subject: ALSA: usx2y: Replace runtime->status->state reference to runtime->state The recent change in ALSA core allows drivers to get the current PCM state directly from runtime object. Replace the calls accordingly. Reviewed-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20220926135558.26580-9-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/usx2y/usbusx2yaudio.c | 3 +-- sound/usb/usx2y/usx2yhwdeppcm.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index 9cd5e3aae4f7..5197599e7aa6 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -822,8 +822,7 @@ static int snd_usx2y_pcm_hw_free(struct snd_pcm_substream *substream) usx2y_urbs_release(subs); if (!cap_subs->pcm_substream || !cap_subs->pcm_substream->runtime || - !cap_subs->pcm_substream->runtime->status || - cap_subs->pcm_substream->runtime->status->state < SNDRV_PCM_STATE_PREPARED) { + cap_subs->pcm_substream->runtime->state < SNDRV_PCM_STATE_PREPARED) { atomic_set(&cap_subs->state, STATE_STOPPED); usx2y_urbs_release(cap_subs); } diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index 240349b644f3..767a227d54da 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c @@ -374,8 +374,7 @@ static int snd_usx2y_usbpcm_hw_free(struct snd_pcm_substream *substream) usx2y_usbpcm_urbs_release(subs); if (!cap_subs->pcm_substream || !cap_subs->pcm_substream->runtime || - !cap_subs->pcm_substream->runtime->status || - cap_subs->pcm_substream->runtime->status->state < SNDRV_PCM_STATE_PREPARED) { + cap_subs->pcm_substream->runtime->state < SNDRV_PCM_STATE_PREPARED) { atomic_set(&cap_subs->state, STATE_STOPPED); if (cap_subs2) atomic_set(&cap_subs2->state, STATE_STOPPED); -- cgit v1.2.3 From 2bd2dc2672b2d0d45be371430970084330879a46 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 26 Sep 2022 15:55:56 +0200 Subject: ASoC: intel: Replace runtime->status->state reference to runtime->state The recent change in ALSA core allows drivers to get the current PCM state directly from runtime object. Replace the calls accordingly. Reviewed-by: Jaroslav Kysela Acked-by: Mark Brown Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20220926135558.26580-10-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/soc/intel/skylake/skl-pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 9d72ebd812af..1015716f9336 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -275,7 +275,7 @@ static int skl_pcm_prepare(struct snd_pcm_substream *substream, * calls prepare another time, reset the FW pipe to clean state */ if (mconfig && - (substream->runtime->status->state == SNDRV_PCM_STATE_XRUN || + (substream->runtime->state == SNDRV_PCM_STATE_XRUN || mconfig->pipe->state == SKL_PIPE_CREATED || mconfig->pipe->state == SKL_PIPE_PAUSED)) { @@ -593,7 +593,7 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, /* In case of XRUN recovery, reset the FW pipe to clean state */ mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream); if (mconfig && !mconfig->pipe->passthru && - (substream->runtime->status->state == SNDRV_PCM_STATE_XRUN)) + (substream->runtime->state == SNDRV_PCM_STATE_XRUN)) skl_reset_pipe(skl, mconfig->pipe); return 0; -- cgit v1.2.3 From a267fdd0a6ce3edd6419b10ee7bcde61aa15eb43 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 26 Sep 2022 15:55:57 +0200 Subject: ASoC: sh: Replace runtime->status->state reference to runtime->state The recent change in ALSA core allows drivers to get the current PCM state directly from runtime object. Replace the calls accordingly. Reviewed-by: Jaroslav Kysela Acked-by: Mark Brown Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20220926135558.26580-11-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/soc/sh/rz-ssi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sh/rz-ssi.c b/sound/soc/sh/rz-ssi.c index 7ace0c0db5b1..5d6bae33ae34 100644 --- a/sound/soc/sh/rz-ssi.c +++ b/sound/soc/sh/rz-ssi.c @@ -598,7 +598,7 @@ static int rz_ssi_dma_transfer(struct rz_ssi_priv *ssi, return -EINVAL; runtime = substream->runtime; - if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) + if (runtime->state == SNDRV_PCM_STATE_DRAINING) /* * Stream is ending, so do not queue up any more DMA * transfers otherwise we play partial sound clips -- cgit v1.2.3 From 675b7cd16e21ce2452d4a11ed425996c34e5460c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 26 Sep 2022 15:55:58 +0200 Subject: usb: gadget: Replace runtime->status->state reference to runtime->state The recent change in ALSA core allows drivers to get the current PCM state directly from runtime object. Replace the calls accordingly. Reviewed-by: Jaroslav Kysela Reviewed-by: Greg Kroah-Hartman Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20220926135558.26580-12-tiwai@suse.de Signed-off-by: Takashi Iwai --- drivers/usb/gadget/function/u_uac1_legacy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/u_uac1_legacy.c b/drivers/usb/gadget/function/u_uac1_legacy.c index 60ae8b2d3f6a..dd21c251542c 100644 --- a/drivers/usb/gadget/function/u_uac1_legacy.c +++ b/drivers/usb/gadget/function/u_uac1_legacy.c @@ -158,8 +158,8 @@ size_t u_audio_playback(struct gaudio *card, void *buf, size_t count) snd_pcm_sframes_t frames; try_again: - if (runtime->status->state == SNDRV_PCM_STATE_XRUN || - runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { + if (runtime->state == SNDRV_PCM_STATE_XRUN || + runtime->state == SNDRV_PCM_STATE_SUSPENDED) { result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL); if (result < 0) { -- cgit v1.2.3 From d1c442019594692c64a70a86ad88eb5b6db92216 Mon Sep 17 00:00:00 2001 From: Andreas Pape Date: Mon, 26 Sep 2022 18:58:13 +0200 Subject: ALSA: dmaengine: increment buffer pointer atomically Setting pointer and afterwards checking for wraparound leads to the possibility of returning the inconsistent pointer position. This patch increments buffer pointer atomically to avoid this issue. Fixes: e7f73a1613567a ("ASoC: Add dmaengine PCM helper functions") Signed-off-by: Andreas Pape Signed-off-by: Eugeniu Rosca Link: https://lore.kernel.org/r/1664211493-11789-1-git-send-email-erosca@de.adit-jv.com Signed-off-by: Takashi Iwai --- sound/core/pcm_dmaengine.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c index 5b2ca028f5aa..494ec0c207fa 100644 --- a/sound/core/pcm_dmaengine.c +++ b/sound/core/pcm_dmaengine.c @@ -133,12 +133,14 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_set_config_from_dai_data); static void dmaengine_pcm_dma_complete(void *arg) { + unsigned int new_pos; struct snd_pcm_substream *substream = arg; struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); - prtd->pos += snd_pcm_lib_period_bytes(substream); - if (prtd->pos >= snd_pcm_lib_buffer_bytes(substream)) - prtd->pos = 0; + new_pos = prtd->pos + snd_pcm_lib_period_bytes(substream); + if (new_pos >= snd_pcm_lib_buffer_bytes(substream)) + new_pos = 0; + prtd->pos = new_pos; snd_pcm_period_elapsed(substream); } -- cgit v1.2.3 From b264ef796959cb65cdbc811da5ab950e33df4162 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 26 Sep 2022 16:40:55 -0500 Subject: ASoC: SOF: control.h: Replace zero-length array with DECLARE_FLEX_ARRAY() helper Zero-length arrays are deprecated and we are moving towards adopting C99 flexible-array members, instead. So, replace zero-length arrays declarations in anonymous union with the new DECLARE_FLEX_ARRAY() helper macro. This helper allows for flexible-array members in unions. Link: https://github.com/KSPP/linux/issues/193 Link: https://github.com/KSPP/linux/issues/211 Link: https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html Signed-off-by: Gustavo A. R. Silva Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/YzIcZ11k8RiQtS2T@work Signed-off-by: Mark Brown --- include/sound/sof/control.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/sound/sof/control.h b/include/sound/sof/control.h index 7379a33d7247..983d374fe511 100644 --- a/include/sound/sof/control.h +++ b/include/sound/sof/control.h @@ -117,11 +117,11 @@ struct sof_ipc_ctrl_data { /* control data - add new types if needed */ union { /* channel values can be used by volume type controls */ - struct sof_ipc_ctrl_value_chan chanv[0]; + DECLARE_FLEX_ARRAY(struct sof_ipc_ctrl_value_chan, chanv); /* component values used by routing controls like mux, mixer */ - struct sof_ipc_ctrl_value_comp compv[0]; + DECLARE_FLEX_ARRAY(struct sof_ipc_ctrl_value_comp, compv); /* data can be used by binary controls */ - struct sof_abi_hdr data[0]; + DECLARE_FLEX_ARRAY(struct sof_abi_hdr, data); }; } __packed; -- cgit v1.2.3 From b3eec3e6670d4da653e742bae16e5a6ff3f03825 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 27 Sep 2022 02:20:04 +0200 Subject: ASoC: st,stm32-sai: Document audio OF graph port It is expected that the SAI subnodes would contain audio OF graph port with endpoint to link it with the other side of audio link. Document the port: property. Signed-off-by: Marek Vasut Reviewed-by: Olivier Moysan Link: https://lore.kernel.org/r/20220927002004.685108-1-marex@denx.de Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/st,stm32-sai.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.yaml b/Documentation/devicetree/bindings/sound/st,stm32-sai.yaml index 1a3abc949505..56d206f97a96 100644 --- a/Documentation/devicetree/bindings/sound/st,stm32-sai.yaml +++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.yaml @@ -122,6 +122,10 @@ patternProperties: description: Configure the SAI device as master clock provider. const: 0 + port: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + required: - compatible - "#sound-dai-cells" -- cgit v1.2.3 From 6fed3265c3c811c79819860051375f6d7efc1d7e Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 26 Sep 2022 17:58:17 -0500 Subject: ASoC: Intel: Skylake: Replace zero-length arrays with DECLARE_FLEX_ARRAY() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Zero-length arrays are deprecated and we are moving towards adopting C99 flexible-array members, instead. So, replace zero-length arrays declarations in anonymous union with the new DECLARE_FLEX_ARRAY() helper macro. This helper allows for flexible-array members in unions. Link: https://github.com/KSPP/linux/issues/193 Link: https://github.com/KSPP/linux/issues/226 Link: https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html Signed-off-by: Gustavo A. R. Silva Reviewed-by: Kees Cook Reviewed-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/YzIuiUul2CwPlkKh@work Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index a5bccf2fcd88..017ac0ef324d 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -233,8 +233,8 @@ struct skl_uuid_inst_map { struct skl_kpb_params { u32 num_modules; union { - struct skl_mod_inst_map map[0]; - struct skl_uuid_inst_map map_uuid[0]; + DECLARE_FLEX_ARRAY(struct skl_mod_inst_map, map); + DECLARE_FLEX_ARRAY(struct skl_uuid_inst_map, map_uuid); } u; }; -- cgit v1.2.3 From d584e73e7310971cc226ef0e2a1bc0526da0d582 Mon Sep 17 00:00:00 2001 From: Martin Povišer Date: Tue, 27 Sep 2022 13:34:24 +0200 Subject: ASoC: apple: mca: Trigger, not deassert, the peripheral reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the deassertion of the peripheral's shared reset with the triggering of a pulse on it. This is what we should have been using all along as the platform's custom is not leaving the reset asserted on unused peripherals. Fixes: 3df5d0d97289 ("ASoC: apple: mca: Start new platform driver") Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220927113426.49724-1-povik+lin@cutebit.org Signed-off-by: Mark Brown --- sound/soc/apple/mca.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c index 69643524796e..75925bfcf754 100644 --- a/sound/soc/apple/mca.c +++ b/sound/soc/apple/mca.c @@ -995,7 +995,7 @@ static void apple_mca_release(struct mca_data *mca) if (!IS_ERR_OR_NULL(mca->pd_dev)) dev_pm_domain_detach(mca->pd_dev, true); - reset_control_assert(mca->rstc); + reset_control_rearm(mca->rstc); } static int apple_mca_probe(struct platform_device *pdev) @@ -1049,12 +1049,12 @@ static int apple_mca_probe(struct platform_device *pdev) DL_FLAG_RPM_ACTIVE); if (!mca->pd_link) { ret = -EINVAL; - /* Prevent an unbalanced reset assert */ + /* Prevent an unbalanced reset rearm */ mca->rstc = NULL; goto err_release; } - reset_control_deassert(mca->rstc); + reset_control_reset(mca->rstc); for (i = 0; i < nclusters; i++) { struct mca_cluster *cl = &clusters[i]; -- cgit v1.2.3 From e92e50e4263f5cf9c731ef5593c31f94dc3b7b8c Mon Sep 17 00:00:00 2001 From: Martin Povišer Date: Tue, 27 Sep 2022 13:34:25 +0200 Subject: ASoC: apple: mca: Remove stale release of DMA channels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The commit 4ec8179c212f ("ASoC: apple: mca: Postpone requesting of DMA channels") shuffled around with the requesting and releasing of DMA channels. It left behind stale release calls from within apple_mca_release, remove those now. Fixes: 4ec8179c212f ("ASoC: apple: mca: Postpone requesting of DMA channels") Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220927113426.49724-2-povik+lin@cutebit.org Signed-off-by: Mark Brown --- sound/soc/apple/mca.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c index 75925bfcf754..7ca653987b78 100644 --- a/sound/soc/apple/mca.c +++ b/sound/soc/apple/mca.c @@ -970,18 +970,11 @@ static const struct snd_soc_component_driver mca_component = { static void apple_mca_release(struct mca_data *mca) { - int i, stream; + int i; for (i = 0; i < mca->nclusters; i++) { struct mca_cluster *cl = &mca->clusters[i]; - for_each_pcm_streams(stream) { - if (IS_ERR_OR_NULL(cl->dma_chans[stream])) - continue; - - dma_release_channel(cl->dma_chans[stream]); - } - if (!IS_ERR_OR_NULL(cl->clk_parent)) clk_put(cl->clk_parent); -- cgit v1.2.3 From db6ae79a7e4f729457ec42db5d6d0fbe0e35784c Mon Sep 17 00:00:00 2001 From: Martin Povišer Date: Tue, 27 Sep 2022 13:34:26 +0200 Subject: ASoC: apple: mca: Adjust timing of component unregister MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On removal of the driver, the ASoC component should be unregistered first, before we start releasing any of the other resources. Fixes: 3df5d0d97289 ("ASoC: apple: mca: Start new platform driver") Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220927113426.49724-3-povik+lin@cutebit.org Signed-off-by: Mark Brown --- sound/soc/apple/mca.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c index 7ca653987b78..24381c42eb54 100644 --- a/sound/soc/apple/mca.c +++ b/sound/soc/apple/mca.c @@ -1129,8 +1129,8 @@ static int apple_mca_probe(struct platform_device *pdev) } } - ret = devm_snd_soc_register_component(&pdev->dev, &mca_component, - dai_drivers, nclusters * 2); + ret = snd_soc_register_component(&pdev->dev, &mca_component, + dai_drivers, nclusters * 2); if (ret) { dev_err(&pdev->dev, "unable to register ASoC component: %d\n", ret); @@ -1148,6 +1148,7 @@ static int apple_mca_remove(struct platform_device *pdev) { struct mca_data *mca = platform_get_drvdata(pdev); + snd_soc_unregister_component(&pdev->dev); apple_mca_release(mca); return 0; } -- cgit v1.2.3 From 45560891506fae31be66f2a73693c5c8bd7dbedb Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Tue, 27 Sep 2022 13:14:40 +0100 Subject: ASoC: cs42l42: Fallback to headphones for type detect After tip sense detects a jack insertion, if automatic type detection, and manual type detection fails, then fall back to assume the jack connected belongs to headphones. Signed-off-by: Stefan Binding Link: https://lore.kernel.org/r/20220927121440.2506632-1-sbinding@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index bdc7e6bed6ac..2fefbcf7bd13 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -1199,14 +1199,11 @@ static void cs42l42_manual_hs_type_detect(struct cs42l42_private *cs42l42) cs42l42->hs_type = CS42L42_PLUG_OMTP; hs_det_sw = CS42L42_HSDET_SW_TYPE2; break; - case CS42L42_HSDET_COMP_TYPE3: + /* Detect Type 3 and Type 4 Headsets as Headphones */ + default: cs42l42->hs_type = CS42L42_PLUG_HEADPHONE; hs_det_sw = CS42L42_HSDET_SW_TYPE3; break; - default: - cs42l42->hs_type = CS42L42_PLUG_INVALID; - hs_det_sw = CS42L42_HSDET_SW_TYPE4; - break; } } -- cgit v1.2.3 From b9a0da5b2edcae2a901b85c8cc42efc5bec4bd7b Mon Sep 17 00:00:00 2001 From: Zhang Qilong Date: Tue, 27 Sep 2022 22:26:00 +0800 Subject: ASoC: stm32: dfsdm: Fix PM disable depth imbalance in stm32_adfsdm_probe The pm_runtime_enable will increase power disable depth. Thus a pairing decrement is needed on the error handling path to keep it balanced according to context. We fix it by moving pm_runtime_enable to the endding of stm32_adfsdm_probe. Fixes:98e500a12f934 ("ASoC: stm32: dfsdm: add pm_runtime support for audio") Signed-off-by: Zhang Qilong Reviewed-by: Olivier Moysan Link: https://lore.kernel.org/r/20220927142601.64266-2-zhangqilong3@huawei.com Signed-off-by: Mark Brown --- sound/soc/stm/stm32_adfsdm.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c index 04f2912e1418..643fc8a17018 100644 --- a/sound/soc/stm/stm32_adfsdm.c +++ b/sound/soc/stm/stm32_adfsdm.c @@ -335,8 +335,6 @@ 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); @@ -366,9 +364,13 @@ static int stm32_adfsdm_probe(struct platform_device *pdev) #endif ret = snd_soc_add_component(component, NULL, 0); - if (ret < 0) + if (ret < 0) { dev_err(&pdev->dev, "%s: Failed to register PCM platform\n", __func__); + return ret; + } + + pm_runtime_enable(&pdev->dev); return ret; } -- cgit v1.2.3 From 0325cc0ac7980e1c7b744aab8df59afab6daeb43 Mon Sep 17 00:00:00 2001 From: Zhang Qilong Date: Tue, 27 Sep 2022 22:26:01 +0800 Subject: ASoC: stm32: spdifrx: Fix PM disable depth imbalance in stm32_spdifrx_probe The pm_runtime_enable will increase power disable depth. Thus a pairing decrement is needed on the error handling path to keep it balanced according to context. We fix it by moving pm_runtime_enable to the endding of stm32_spdifrx_probe. Fixes:ac5e3efd55868 ("ASoC: stm32: spdifrx: add pm_runtime support") Signed-off-by: Zhang Qilong Reviewed-by: Olivier Moysan Link: https://lore.kernel.org/r/20220927142601.64266-3-zhangqilong3@huawei.com Signed-off-by: Mark Brown --- sound/soc/stm/stm32_spdifrx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c index 0f7146756717..d399c906bb92 100644 --- a/sound/soc/stm/stm32_spdifrx.c +++ b/sound/soc/stm/stm32_spdifrx.c @@ -1002,8 +1002,6 @@ 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) @@ -1036,6 +1034,8 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) FIELD_GET(SPDIFRX_VERR_MIN_MASK, ver)); } + pm_runtime_enable(&pdev->dev); + return ret; error: -- cgit v1.2.3 From 93618e5e05a3ce4aa6750268c5025bdb4cb7dc6e Mon Sep 17 00:00:00 2001 From: Zhang Qilong Date: Tue, 27 Sep 2022 22:26:40 +0800 Subject: ASoC: stm: Fix PM disable depth imbalance in stm32_i2s_probe The pm_runtime_enable will increase power disable depth. Thus a pairing decrement is needed on the error handling path to keep it balanced according to context. We fix it by moving pm_runtime_enable to the endding of stm32_i2s_probe. Fixes:32a956a1fadf ("ASoC: stm32: i2s: add pm_runtime support") Signed-off-by: Zhang Qilong Reviewed-by: Olivier Moysan Link: https://lore.kernel.org/r/20220927142640.64647-1-zhangqilong3@huawei.com Signed-off-by: Mark Brown --- sound/soc/stm/stm32_i2s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index 6aafe793eec4..ce7f6942308f 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -1136,8 +1136,6 @@ static int stm32_i2s_probe(struct platform_device *pdev) 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) return dev_err_probe(&pdev->dev, ret, "PCM DMA register error\n"); @@ -1180,6 +1178,8 @@ static int stm32_i2s_probe(struct platform_device *pdev) FIELD_GET(I2S_VERR_MIN_MASK, val)); } + pm_runtime_enable(&pdev->dev); + return ret; error: -- cgit v1.2.3 From 7ba6546b547c75b0196029c7e0aaaab2eb6694a4 Mon Sep 17 00:00:00 2001 From: Trevor Wu Date: Tue, 27 Sep 2022 23:11:41 +0800 Subject: ASoC: mediatek: mt8195: update audio tuner settings Audio tuner is used to handle clock drift between 26M and APLL domain. It's expected when abs(chg_cnt) equals to upper bound, tuner updates pcw setting automatically, and then abs(chg_cnt) decreases. In the stress test, we found abs(chg_cnt) possibly equals to 2 at the unexpected timing. This results in wrong pcw updating. Finally, abs(chg_cnt) will always be larger than upper bound, As a result, we update the upper bound to 3 to handle the corner case. Signed-off-by: Trevor Wu Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220927151141.11846-1-trevor.wu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8195/mt8195-afe-clk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/mediatek/mt8195/mt8195-afe-clk.c b/sound/soc/mediatek/mt8195/mt8195-afe-clk.c index 2ee3872c83c3..9ca2cb8c8a9c 100644 --- a/sound/soc/mediatek/mt8195/mt8195-afe-clk.c +++ b/sound/soc/mediatek/mt8195/mt8195-afe-clk.c @@ -117,7 +117,7 @@ static struct mt8195_afe_tuner_cfg mt8195_afe_tuner_cfgs[MT8195_AUD_PLL_NUM] = { .upper_bound_reg = AFE_APLL_TUNER_CFG, .upper_bound_shift = 8, .upper_bound_maskbit = 0xff, - .upper_bound_default = 0x2, + .upper_bound_default = 0x3, }, [MT8195_AUD_PLL2] = { .id = MT8195_AUD_PLL2, @@ -135,7 +135,7 @@ static struct mt8195_afe_tuner_cfg mt8195_afe_tuner_cfgs[MT8195_AUD_PLL_NUM] = { .upper_bound_reg = AFE_APLL_TUNER_CFG1, .upper_bound_shift = 8, .upper_bound_maskbit = 0xff, - .upper_bound_default = 0x2, + .upper_bound_default = 0x3, }, [MT8195_AUD_PLL3] = { .id = MT8195_AUD_PLL3, -- cgit v1.2.3 From eefe77fdc0de86480f5dbb6bc721396d82d095d3 Mon Sep 17 00:00:00 2001 From: Shang XiaoJing Date: Tue, 27 Sep 2022 22:11:10 +0800 Subject: ALSA: sb: Use DIV_ROUND_UP() instead of open-coding it Use DIV_ROUND_UP() instead of open-coding it, which intents and makes it more clear what is going on for the casual reviewer. The Coccinelle references Commit e4d8aef21403 ("ALSA: usb: Use DIV_ROUND_UP() instead of open-coding it"). Signed-off-by: Shang XiaoJing Link: https://lore.kernel.org/r/20220927141110.18033-1-shangxiaojing@huawei.com Signed-off-by: Takashi Iwai --- sound/isa/sb/emu8000_pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/isa/sb/emu8000_pcm.c b/sound/isa/sb/emu8000_pcm.c index f8d90a1e989b..c8afc4347c54 100644 --- a/sound/isa/sb/emu8000_pcm.c +++ b/sound/isa/sb/emu8000_pcm.c @@ -236,7 +236,7 @@ static int emu8k_pcm_open(struct snd_pcm_substream *subs) /* use timer to update periods.. (specified in msec) */ snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, - (1000000 + HZ - 1) / HZ, UINT_MAX); + DIV_ROUND_UP(1000000, HZ), UINT_MAX); return 0; } -- cgit v1.2.3 From 2d6bd853cabc40f9fa7bf48edaa728e19f335e48 Mon Sep 17 00:00:00 2001 From: Yuan Can Date: Wed, 28 Sep 2022 08:48:33 +0000 Subject: ALSA: asihpi - Remove unused struct hpi_subsys_response After commit 3285ea10e9b0("ALSA: asihpi - Interrelated HPI tidy up."), struct hpi_subsys_response is not used any more and can be removed as well. Signed-off-by: Yuan Can Link: https://lore.kernel.org/r/20220928084833.61131-1-yuancan@huawei.com Signed-off-by: Takashi Iwai --- sound/pci/asihpi/hpimsgx.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/pci/asihpi/hpimsgx.c b/sound/pci/asihpi/hpimsgx.c index f7427f8eb630..d0caef299481 100644 --- a/sound/pci/asihpi/hpimsgx.c +++ b/sound/pci/asihpi/hpimsgx.c @@ -93,11 +93,6 @@ static void HPIMSGX__cleanup(u16 adapter_index, void *h_owner); #pragma pack(push, 1) #endif -struct hpi_subsys_response { - struct hpi_response_header h; - struct hpi_subsys_res s; -}; - struct hpi_adapter_response { struct hpi_response_header h; struct hpi_adapter_res a; -- cgit v1.2.3 From 225f6e1bc151978041595c7d2acaded3aac41f54 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 29 Sep 2022 08:14:55 +0200 Subject: ALSA: hda/realtek: Add quirk for HP Zbook Firefly 14 G9 model HP Zbook Firefly 14 G9 model (103c:8abb) requires yet another binding with CS35L41 codec, but with a slightly different configuration. It's over spi1 instead of spi0. Create a new fixup entry for that. Cc: Link: https://lore.kernel.org/r/20220929061455.13355-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index f9d46ae4c7b7..3dc19174670e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6741,6 +6741,11 @@ static void cs35l41_fixup_spi_two(struct hda_codec *codec, const struct hda_fixu cs35l41_generic_fixup(codec, action, "spi0", "CSC3551", 2); } +static void cs35l41_fixup_spi1_two(struct hda_codec *codec, const struct hda_fixup *fix, int action) +{ + cs35l41_generic_fixup(codec, action, "spi1", "CSC3551", 2); +} + static void cs35l41_fixup_spi_four(struct hda_codec *codec, const struct hda_fixup *fix, int action) { cs35l41_generic_fixup(codec, action, "spi0", "CSC3551", 4); @@ -7132,6 +7137,8 @@ enum { ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED, ALC245_FIXUP_CS35L41_SPI_2, ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED, + ALC245_FIXUP_CS35L41_SPI1_2, + ALC245_FIXUP_CS35L41_SPI1_2_HP_GPIO_LED, ALC245_FIXUP_CS35L41_SPI_4, ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED, ALC285_FIXUP_HP_SPEAKERS_MICMUTE_LED, @@ -8979,6 +8986,16 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC285_FIXUP_HP_GPIO_LED, }, + [ALC245_FIXUP_CS35L41_SPI1_2] = { + .type = HDA_FIXUP_FUNC, + .v.func = cs35l41_fixup_spi1_two, + }, + [ALC245_FIXUP_CS35L41_SPI1_2_HP_GPIO_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = cs35l41_fixup_spi1_two, + .chained = true, + .chain_id = ALC285_FIXUP_HP_GPIO_LED, + }, [ALC245_FIXUP_CS35L41_SPI_4] = { .type = HDA_FIXUP_FUNC, .v.func = cs35l41_fixup_spi_four, @@ -9341,6 +9358,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8aa3, "HP ProBook 450 G9 (MB 8AA1)", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8aa8, "HP EliteBook 640 G9 (MB 8AA6)", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8aab, "HP EliteBook 650 G9 (MB 8AA9)", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8abb, "HP ZBook Firefly 14 G9", ALC245_FIXUP_CS35L41_SPI1_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8ad1, "HP EliteBook 840 14 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8ad2, "HP EliteBook 860 16 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC), -- cgit v1.2.3 From 65c94e4d15830406a31a55085887e97bacd25434 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 28 Sep 2022 23:04:17 +0100 Subject: ASoC: mediatek: mt8186: Fix spelling mistake "slect" -> "select" There are some spelling mistakes in dev_err messages. Fix them. Signed-off-by: Colin Ian King Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220928220417.66799-1-colin.i.king@gmail.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8186/mt8186-afe-gpio.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-gpio.c b/sound/soc/mediatek/mt8186/mt8186-afe-gpio.c index 274c0c8ec2f2..eda913fa147a 100644 --- a/sound/soc/mediatek/mt8186/mt8186-afe-gpio.c +++ b/sound/soc/mediatek/mt8186/mt8186-afe-gpio.c @@ -170,25 +170,25 @@ static int mt8186_afe_gpio_adda_ul(struct device *dev, bool enable) if (enable) { ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MISO_ON); if (ret) { - dev_err(dev, "%s(), MISO CLK ON slect fail!\n", __func__); + dev_err(dev, "%s(), MISO CLK ON select fail!\n", __func__); return ret; } ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MISO_ON); if (ret) { - dev_err(dev, "%s(), MISO DAT ON slect fail!\n", __func__); + dev_err(dev, "%s(), MISO DAT ON select fail!\n", __func__); return ret; } } else { ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MISO_OFF); if (ret) { - dev_err(dev, "%s(), MISO DAT OFF slect fail!\n", __func__); + dev_err(dev, "%s(), MISO DAT OFF select fail!\n", __func__); return ret; } ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MISO_OFF); if (ret) { - dev_err(dev, "%s(), MISO CLK OFF slect fail!\n", __func__); + dev_err(dev, "%s(), MISO CLK OFF select fail!\n", __func__); return ret; } } -- cgit v1.2.3 From e18f6bcf8e864ea0e9690691d0d749c662b6a2c7 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 29 Sep 2022 15:15:28 +0200 Subject: ASoC: wcd-mbhc-v2: Revert "ASoC: wcd-mbhc-v2: use pm_runtime_resume_and_get()" This reverts commit ddea4bbf287b6028eaa15a185d0693856956ecf2 ("ASoC: wcd-mbhc-v2: use pm_runtime_resume_and_get()"), because it introduced double runtime PM put if pm_runtime_get_sync() returns -EACCES: wcd934x-codec wcd934x-codec.3.auto: WCD934X Minor:0x1 Version:0x401 wcd934x-codec wcd934x-codec.3.auto: Runtime PM usage count underflow! The commit claimed no changes in functionality except dropping the reference on -EACCESS. This is exactly the change introducing bug because function calls unconditionally pm_runtime_put_autosuspend() at the end. Fixes: ddea4bbf287b ("ASoC: wcd-mbhc-v2: use pm_runtime_resume_and_get()") Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220929131528.217502-1-krzysztof.kozlowski@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/wcd-mbhc-v2.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c index 98baef594bf3..31009283e7d4 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.c +++ b/sound/soc/codecs/wcd-mbhc-v2.c @@ -714,11 +714,12 @@ static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc) struct snd_soc_component *component = mbhc->component; int ret; - ret = pm_runtime_resume_and_get(component->dev); + ret = pm_runtime_get_sync(component->dev); if (ret < 0 && ret != -EACCES) { dev_err_ratelimited(component->dev, - "pm_runtime_resume_and_get failed in %s, ret %d\n", + "pm_runtime_get_sync failed in %s, ret %d\n", __func__, ret); + pm_runtime_put_noidle(component->dev); return ret; } @@ -1096,11 +1097,12 @@ static void wcd_correct_swch_plug(struct work_struct *work) mbhc = container_of(work, struct wcd_mbhc, correct_plug_swch); component = mbhc->component; - ret = pm_runtime_resume_and_get(component->dev); + ret = pm_runtime_get_sync(component->dev); if (ret < 0 && ret != -EACCES) { dev_err_ratelimited(component->dev, - "pm_runtime_resume_and_get failed in %s, ret %d\n", + "pm_runtime_get_sync failed in %s, ret %d\n", __func__, ret); + pm_runtime_put_noidle(component->dev); return; } micbias_mv = wcd_mbhc_get_micbias(mbhc); -- cgit v1.2.3 From 41a736ac20602f64773e80f0f5b32cde1830a44a Mon Sep 17 00:00:00 2001 From: Zhang Qilong Date: Thu, 29 Sep 2022 00:01:13 +0800 Subject: ASoC: wm8997: Fix PM disable depth imbalance in wm8997_probe The pm_runtime_enable will increase power disable depth. Thus a pairing decrement is needed on the error handling path to keep it balanced according to context. We fix it by moving pm_runtime_enable to the endding of wm8997_probe Fixes:40843aea5a9bd ("ASoC: wm8997: Initial CODEC driver") Signed-off-by: Zhang Qilong Link: https://lore.kernel.org/r/20220928160116.125020-2-zhangqilong3@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8997.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index 210ad662fc26..77136a521605 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -1161,9 +1161,6 @@ static int wm8997_probe(struct platform_device *pdev) regmap_update_bits(arizona->regmap, wm8997_digital_vu[i], WM8997_DIG_VU, WM8997_DIG_VU); - pm_runtime_enable(&pdev->dev); - pm_runtime_idle(&pdev->dev); - arizona_init_common(arizona); ret = arizona_init_vol_limit(arizona); @@ -1182,6 +1179,9 @@ static int wm8997_probe(struct platform_device *pdev) goto err_spk_irqs; } + pm_runtime_enable(&pdev->dev); + pm_runtime_idle(&pdev->dev); + return ret; err_spk_irqs: -- cgit v1.2.3 From 86b46bf1feb83898d89a2b4a8d08d21e9ea277a7 Mon Sep 17 00:00:00 2001 From: Zhang Qilong Date: Thu, 29 Sep 2022 00:01:14 +0800 Subject: ASoC: wm5110: Fix PM disable depth imbalance in wm5110_probe The pm_runtime_enable will increase power disable depth. Thus a pairing decrement is needed on the error handling path to keep it balanced according to context. We fix it by moving pm_runtime_enable to the endding of wm5110_probe. Fixes:5c6af635fd772 ("ASoC: wm5110: Add audio CODEC driver") Signed-off-by: Zhang Qilong Link: https://lore.kernel.org/r/20220928160116.125020-3-zhangqilong3@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm5110.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index f3f4a10bf0f7..fc634c995834 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -2457,9 +2457,6 @@ static int wm5110_probe(struct platform_device *pdev) regmap_update_bits(arizona->regmap, wm5110_digital_vu[i], WM5110_DIG_VU, WM5110_DIG_VU); - pm_runtime_enable(&pdev->dev); - pm_runtime_idle(&pdev->dev); - ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, "ADSP2 Compressed IRQ", wm5110_adsp2_irq, wm5110); @@ -2492,6 +2489,9 @@ static int wm5110_probe(struct platform_device *pdev) goto err_spk_irqs; } + pm_runtime_enable(&pdev->dev); + pm_runtime_idle(&pdev->dev); + return ret; err_spk_irqs: -- cgit v1.2.3 From fcbb60820cd3008bb44334a0395e5e57ccb77329 Mon Sep 17 00:00:00 2001 From: Zhang Qilong Date: Thu, 29 Sep 2022 00:01:15 +0800 Subject: ASoC: wm5102: Fix PM disable depth imbalance in wm5102_probe The pm_runtime_enable will increase power disable depth. Thus a pairing decrement is needed on the error handling path to keep it balanced according to context. We fix it by moving pm_runtime_enable to the endding of wm5102_probe. Fixes:93e8791dd34ca ("ASoC: wm5102: Initial driver") Signed-off-by: Zhang Qilong Link: https://lore.kernel.org/r/20220928160116.125020-4-zhangqilong3@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm5102.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index af7d324e3352..c09c9ac51b3e 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -2099,9 +2099,6 @@ static int wm5102_probe(struct platform_device *pdev) regmap_update_bits(arizona->regmap, wm5102_digital_vu[i], WM5102_DIG_VU, WM5102_DIG_VU); - pm_runtime_enable(&pdev->dev); - pm_runtime_idle(&pdev->dev); - ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, "ADSP2 Compressed IRQ", wm5102_adsp2_irq, wm5102); @@ -2134,6 +2131,9 @@ static int wm5102_probe(struct platform_device *pdev) goto err_spk_irqs; } + pm_runtime_enable(&pdev->dev); + pm_runtime_idle(&pdev->dev); + return ret; err_spk_irqs: -- cgit v1.2.3 From b73f11e895e140537e7f8c7251211ccd3ce0782b Mon Sep 17 00:00:00 2001 From: Zhang Qilong Date: Thu, 29 Sep 2022 00:01:16 +0800 Subject: ASoC: mt6660: Fix PM disable depth imbalance in mt6660_i2c_probe The pm_runtime_enable will increase power disable depth. Thus a pairing decrement is needed on the error handling path to keep it balanced according to context. We fix it by moving pm_runtime_enable to the endding of mt6660_i2c_probe. Fixes:f289e55c6eeb4 ("ASoC: Add MediaTek MT6660 Speaker Amp Driver") Signed-off-by: Zhang Qilong Link: https://lore.kernel.org/r/20220928160116.125020-5-zhangqilong3@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/mt6660.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/mt6660.c b/sound/soc/codecs/mt6660.c index ba11555796ad..45e0df13afb9 100644 --- a/sound/soc/codecs/mt6660.c +++ b/sound/soc/codecs/mt6660.c @@ -503,13 +503,17 @@ static int mt6660_i2c_probe(struct i2c_client *client) dev_err(chip->dev, "read chip revision fail\n"); goto probe_fail; } - pm_runtime_set_active(chip->dev); - pm_runtime_enable(chip->dev); ret = devm_snd_soc_register_component(chip->dev, &mt6660_component_driver, &mt6660_codec_dai, 1); + if (!ret) { + pm_runtime_set_active(chip->dev); + pm_runtime_enable(chip->dev); + } + return ret; + probe_fail: _mt6660_chip_power_on(chip, 0); mutex_destroy(&chip->io_lock); -- cgit v1.2.3 From c8d18e44022518ab026338ae86bf14cdf2e71887 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 29 Sep 2022 16:37:54 +0200 Subject: ASoC: core: clarify the driver name initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver field in the struct snd_ctl_card_info is a valid user space identifier. Actually, many ASoC drivers do not care and let to initialize this field using a standard wrapping method. Unfortunately, in this way, this field becomes unusable and unreadable for the drivers with longer card names. Also, there is a possibility to have clashes (driver field has only limit of 15 characters). This change will print an error when the wrapping is used. The developers of the affected drivers should fix the problem. Signed-off-by: Jaroslav Kysela Reviewed-by: Nícolas F. R. A. Prado Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index a812487b7b5f..12a82f5a3ff6 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1836,21 +1836,22 @@ match: } } -#define soc_setup_card_name(name, name1, name2, norm) \ - __soc_setup_card_name(name, sizeof(name), name1, name2, norm) -static void __soc_setup_card_name(char *name, int len, - const char *name1, const char *name2, - int normalization) +#define soc_setup_card_name(card, name, name1, name2) \ + __soc_setup_card_name(card, name, sizeof(name), name1, name2) +static void __soc_setup_card_name(struct snd_soc_card *card, + char *name, int len, + const char *name1, const char *name2) { + const char *src = name1 ? name1 : name2; int i; - snprintf(name, len, "%s", name1 ? name1 : name2); + snprintf(name, len, "%s", src); - if (!normalization) + if (name != card->snd_card->driver) return; /* - * Name normalization + * Name normalization (driver field) * * The driver name is somewhat special, as it's used as a key for * searches in the user-space. @@ -1870,6 +1871,14 @@ static void __soc_setup_card_name(char *name, int len, break; } } + + /* + * The driver field should contain a valid string from the user view. + * The wrapping usually does not work so well here. Set a smaller string + * in the specific ASoC driver. + */ + if (strlen(src) > len - 1) + dev_err(card->dev, "ASoC: driver name too long '%s' -> '%s'\n", src, name); } static void soc_cleanup_card_resources(struct snd_soc_card *card) @@ -2037,12 +2046,12 @@ static int snd_soc_bind_card(struct snd_soc_card *card) /* try to set some sane longname if DMI is available */ snd_soc_set_dmi_name(card, NULL); - soc_setup_card_name(card->snd_card->shortname, - card->name, NULL, 0); - soc_setup_card_name(card->snd_card->longname, - card->long_name, card->name, 0); - soc_setup_card_name(card->snd_card->driver, - card->driver_name, card->name, 1); + soc_setup_card_name(card, card->snd_card->shortname, + card->name, NULL); + soc_setup_card_name(card, card->snd_card->longname, + card->long_name, card->name); + soc_setup_card_name(card, card->snd_card->driver, + card->driver_name, card->name); if (card->components) { /* the current implementation of snd_component_add() accepts */ -- cgit v1.2.3 From dacdef1bd2fc6e1ab528fa16d70756965cd2877b Mon Sep 17 00:00:00 2001 From: David Lin Date: Fri, 30 Sep 2022 15:28:05 +0800 Subject: ASoC: nau8825: Add TDM support Support TDM format for NAU88L25. Signed-off-by: David Lin Link: https://lore.kernel.org/r/20220930072804.2524352-1-CTLIN0@nuvoton.com Signed-off-by: Mark Brown --- sound/soc/codecs/nau8825.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/nau8825.h | 14 +++++++ 2 files changed, 111 insertions(+) diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index b3cdbe884c05..6a2c2e373efd 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -1425,10 +1425,107 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return 0; } +/** + * nau8825_set_tdm_slot - configure DAI TDM. + * @dai: DAI + * @tx_mask: bitmask representing active TX slots. + * @rx_mask: bitmask representing active RX slots. + * @slots: Number of slots in use. + * @slot_width: Width in bits for each slot. + * + * Configures a DAI for TDM operation. Support TDM 4/8 slots. + * The limitation is DAC and ADC need shift 4 slots at 8 slots mode. + */ +static int nau8825_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct snd_soc_component *component = dai->component; + struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component); + unsigned int ctrl_val = 0, ctrl_offset = 0, value = 0, dac_s, adc_s; + + if (slots != 4 && slots != 8) { + dev_err(nau8825->dev, "Only support 4 or 8 slots!\n"); + return -EINVAL; + } + + /* The driver is limited to 1-channel for ADC, and 2-channel for DAC on TDM mode */ + if (hweight_long((unsigned long) tx_mask) != 1 || + hweight_long((unsigned long) rx_mask) != 2) { + dev_err(nau8825->dev, + "The limitation is 1-channel for ADC, and 2-channel for DAC on TDM mode.\n"); + return -EINVAL; + } + + if (((tx_mask & 0xf) && (tx_mask & 0xf0)) || + ((rx_mask & 0xf) && (rx_mask & 0xf0)) || + ((tx_mask & 0xf) && (rx_mask & 0xf0)) || + ((rx_mask & 0xf) && (tx_mask & 0xf0))) { + dev_err(nau8825->dev, + "Slot assignment of DAC and ADC need to set same interval.\n"); + return -EINVAL; + } + + /* The offset of fixed 4 slots for 8 slots support */ + if (rx_mask & 0xf0) { + regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2, + NAU8825_I2S_PCM_TS_EN_MASK, NAU8825_I2S_PCM_TS_EN); + regmap_read(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL1, &value); + ctrl_val |= NAU8825_TDM_OFFSET_EN; + ctrl_offset = 4 * slot_width; + if (!(value & NAU8825_I2S_PCMB_MASK)) + ctrl_offset += 1; + dac_s = (rx_mask & 0xf0) >> 4; + adc_s = fls((tx_mask & 0xf0) >> 4); + } else { + dac_s = rx_mask & 0xf; + adc_s = fls(tx_mask & 0xf); + } + + ctrl_val |= NAU8825_TDM_MODE; + + switch (dac_s) { + case 0x3: + ctrl_val |= 1 << NAU8825_TDM_DACR_RX_SFT; + break; + case 0x5: + ctrl_val |= 2 << NAU8825_TDM_DACR_RX_SFT; + break; + case 0x6: + ctrl_val |= 1 << NAU8825_TDM_DACL_RX_SFT; + ctrl_val |= 2 << NAU8825_TDM_DACR_RX_SFT; + break; + case 0x9: + ctrl_val |= 3 << NAU8825_TDM_DACR_RX_SFT; + break; + case 0xa: + ctrl_val |= 1 << NAU8825_TDM_DACL_RX_SFT; + ctrl_val |= 3 << NAU8825_TDM_DACR_RX_SFT; + break; + case 0xc: + ctrl_val |= 2 << NAU8825_TDM_DACL_RX_SFT; + ctrl_val |= 3 << NAU8825_TDM_DACR_RX_SFT; + break; + default: + return -EINVAL; + } + + ctrl_val |= adc_s - 1; + + regmap_update_bits(nau8825->regmap, NAU8825_REG_TDM_CTRL, + NAU8825_TDM_MODE | NAU8825_TDM_OFFSET_EN | + NAU8825_TDM_DACL_RX_MASK | NAU8825_TDM_DACR_RX_MASK | + NAU8825_TDM_TX_MASK, ctrl_val); + regmap_update_bits(nau8825->regmap, NAU8825_REG_LEFT_TIME_SLOT, + NAU8825_TSLOT_L0_MASK, ctrl_offset); + + return 0; +} + static const struct snd_soc_dai_ops nau8825_dai_ops = { .startup = nau8825_dai_startup, .hw_params = nau8825_hw_params, .set_fmt = nau8825_set_dai_fmt, + .set_tdm_slot = nau8825_set_tdm_slot, }; #define NAU8825_RATES SNDRV_PCM_RATE_8000_192000 diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h index 6d112b6145df..d84191a7beb2 100644 --- a/sound/soc/codecs/nau8825.h +++ b/sound/soc/codecs/nau8825.h @@ -225,6 +225,15 @@ #define NAU8825_JKDET_PULL_EN (1 << 9) /* 0 - enable pull, 1 - disable */ #define NAU8825_JKDET_OUTPUT_EN (1 << 8) /* 0 - enable input, 1 - enable output */ +/* TDM_CTRL (0x1b) */ +#define NAU8825_TDM_MODE (0x1 << 15) +#define NAU8825_TDM_OFFSET_EN (0x1 << 14) +#define NAU8825_TDM_DACL_RX_SFT 6 +#define NAU8825_TDM_DACL_RX_MASK (0x3 << NAU8825_TDM_DACL_RX_SFT) +#define NAU8825_TDM_DACR_RX_SFT 4 +#define NAU8825_TDM_DACR_RX_MASK (0x3 << NAU8825_TDM_DACR_RX_SFT) +#define NAU8825_TDM_TX_MASK 0x3 + /* I2S_PCM_CTRL1 (0x1c) */ #define NAU8825_I2S_BP_SFT 7 #define NAU8825_I2S_BP_MASK (1 << NAU8825_I2S_BP_SFT) @@ -249,6 +258,9 @@ #define NAU8825_I2S_TRISTATE (1 << 15) /* 0 - normal mode, 1 - Hi-Z output */ #define NAU8825_I2S_LRC_DIV_SFT 12 #define NAU8825_I2S_LRC_DIV_MASK (0x3 << NAU8825_I2S_LRC_DIV_SFT) +#define NAU8825_I2S_PCM_TS_EN_SFT 10 +#define NAU8825_I2S_PCM_TS_EN_MASK (1 << NAU8825_I2S_PCM_TS_EN_SFT) +#define NAU8825_I2S_PCM_TS_EN (1 << NAU8825_I2S_PCM_TS_EN_SFT) #define NAU8825_I2S_MS_SFT 3 #define NAU8825_I2S_MS_MASK (1 << NAU8825_I2S_MS_SFT) #define NAU8825_I2S_MS_MASTER (1 << NAU8825_I2S_MS_SFT) @@ -259,6 +271,8 @@ #define NAU8825_FS_ERR_CMP_SEL_SFT 14 #define NAU8825_FS_ERR_CMP_SEL_MASK (0x3 << NAU8825_FS_ERR_CMP_SEL_SFT) #define NAU8825_DIS_FS_SHORT_DET (1 << 13) +#define NAU8825_TSLOT_L0_MASK 0x3ff +#define NAU8825_TSLOT_R0_MASK 0x3ff /* BIQ_CTRL (0x20) */ #define NAU8825_BIQ_WRT_SFT 4 -- cgit v1.2.3 From 4157155df7d34bd91879c06a787944529f0d9a0d Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Tue, 13 Sep 2022 15:49:06 +0800 Subject: ASoC: Intel: sof_rt5682: remove SOF_RT1015_SPEAKER_AMP_100FS flag This flag could be removed since we now have API to query bclk fequency setting in the topology. The dai link structure itself also provides DAI format information instead of figuring it out with fs number. Signed-off-by: Brent Lu Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220913074906.926774-1-brent.lu@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_realtek_common.c | 86 +++++++++++++++-------------- sound/soc/intel/boards/sof_realtek_common.h | 2 +- sound/soc/intel/boards/sof_rt5682.c | 6 +- 3 files changed, 47 insertions(+), 47 deletions(-) diff --git a/sound/soc/intel/boards/sof_realtek_common.c b/sound/soc/intel/boards/sof_realtek_common.c index b9643ca2e2f2..ff2851fc8930 100644 --- a/sound/soc/intel/boards/sof_realtek_common.c +++ b/sound/soc/intel/boards/sof_realtek_common.c @@ -253,63 +253,70 @@ EXPORT_SYMBOL_NS(sof_rt1015p_codec_conf, SND_SOC_INTEL_SOF_REALTEK_COMMON); * RT1015 audio amplifier */ +static const struct { + unsigned int tx; + unsigned int rx; +} rt1015_tdm_mask[] = { + {.tx = 0x0, .rx = 0x1}, + {.tx = 0x0, .rx = 0x2}, +}; + 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_link *dai_link = rtd->dai_link; struct snd_soc_dai *codec_dai; - int i, fs = 64, ret; + int i, clk_freq, 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; + clk_freq = sof_dai_get_bclk(rtd); - ret = snd_soc_dai_set_sysclk(codec_dai, RT1015_SCLK_S_PLL, - params_rate(params) * 256, - SND_SOC_CLOCK_IN); - if (ret) - return ret; + if (clk_freq <= 0) { + dev_err(rtd->dev, "fail to get bclk freq, ret %d\n", clk_freq); + return -EINVAL; } - 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, + clk_freq, params_rate(params) * 256); - if (ret) + if (ret) { + dev_err(codec_dai->dev, "fail to set pll, ret %d\n", + 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) + if (ret) { + dev_err(codec_dai->dev, "fail to set sysclk, ret %d\n", + 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; + switch (dai_link->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + /* 4-slot TDM */ + ret = snd_soc_dai_set_tdm_slot(codec_dai, + rt1015_tdm_mask[i].tx, + rt1015_tdm_mask[i].rx, + 4, + params_width(params)); + if (ret < 0) { + dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n", + ret); + return ret; + } + break; + default: + dev_dbg(codec_dai->dev, "codec is in I2S mode\n"); + break; + } + } - return 0; + return ret; } static struct snd_soc_ops rt1015_ops = { @@ -351,15 +358,12 @@ void sof_rt1015_codec_conf(struct snd_soc_card *card) } EXPORT_SYMBOL_NS(sof_rt1015_codec_conf, SND_SOC_INTEL_SOF_REALTEK_COMMON); -void sof_rt1015_dai_link(struct snd_soc_dai_link *link, unsigned int fs) +void sof_rt1015_dai_link(struct snd_soc_dai_link *link) { 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; } EXPORT_SYMBOL_NS(sof_rt1015_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON); diff --git a/sound/soc/intel/boards/sof_realtek_common.h b/sound/soc/intel/boards/sof_realtek_common.h index 778443421090..3ae99d8239e0 100644 --- a/sound/soc/intel/boards/sof_realtek_common.h +++ b/sound/soc/intel/boards/sof_realtek_common.h @@ -32,7 +32,7 @@ void sof_rt1015p_codec_conf(struct snd_soc_card *card); #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_dai_link(struct snd_soc_dai_link *link); void sof_rt1015_codec_conf(struct snd_soc_card *card); #define RT1308_CODEC_DAI "rt1308-aif" diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 1bf9455eaf93..2d0986824b3d 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -46,7 +46,6 @@ ((quirk << SOF_RT5682_NUM_HDMIDEV_SHIFT) & SOF_RT5682_NUM_HDMIDEV_MASK) #define SOF_RT1011_SPEAKER_AMP_PRESENT BIT(13) #define SOF_RT1015_SPEAKER_AMP_PRESENT BIT(14) -#define SOF_RT1015_SPEAKER_AMP_100FS BIT(15) #define SOF_RT1015P_SPEAKER_AMP_PRESENT BIT(16) #define SOF_MAX98373_SPEAKER_AMP_PRESENT BIT(17) #define SOF_MAX98360A_SPEAKER_AMP_PRESENT BIT(18) @@ -132,7 +131,6 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { SOF_RT5682_SSP_CODEC(0) | SOF_SPEAKER_AMP_PRESENT | SOF_RT1015_SPEAKER_AMP_PRESENT | - SOF_RT1015_SPEAKER_AMP_100FS | SOF_RT5682_SSP_AMP(1)), }, { @@ -740,8 +738,7 @@ 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) { - sof_rt1015_dai_link(&links[id], (sof_rt5682_quirk & - SOF_RT1015_SPEAKER_AMP_100FS) ? 100 : 64); + sof_rt1015_dai_link(&links[id]); } else if (sof_rt5682_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT) { sof_rt1015p_dai_link(&links[id]); } else if (sof_rt5682_quirk & SOF_RT1019_SPEAKER_AMP_PRESENT) { @@ -1011,7 +1008,6 @@ static const struct platform_device_id board_ids[] = { SOF_RT5682_SSP_CODEC(0) | SOF_SPEAKER_AMP_PRESENT | SOF_RT1015_SPEAKER_AMP_PRESENT | - SOF_RT1015_SPEAKER_AMP_100FS | SOF_RT5682_SSP_AMP(1)), }, { -- cgit v1.2.3 From 35a1744423743247026668e2323d1b932583fc2a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 30 Sep 2022 10:48:10 +0200 Subject: ALSA: hda/realtek: More robust component matching for CS35L41 As the previous commit implies, a system may have a different SPI bus number that is embedded in the device string. And, assuming the fixed bus number is rather fragile; it may be assigned differently depending on the configuration or on the boot environment. Once when a bus number change happens, the binding fails, resulting in the silence. This patch tries to make the matching a bit more relaxed, allowing to bind with a different bus number (or without it). So the previous fix, the introduction of ALC245_FIXUP_CS35L41_SPI1_2 fixup became superfluous, and this is unified to ALC245_FIXUP_CS35L41_SPI_2. Fixes: 225f6e1bc151 ("ALSA: hda/realtek: Add quirk for HP Zbook Firefly 14 G9 model") Link: https://lore.kernel.org/r/20220930084810.10435-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 62 ++++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 3dc19174670e..bce82b834cec 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -6704,23 +6705,51 @@ static void comp_generic_playback_hook(struct hda_pcm_stream *hinfo, struct hda_ } } +struct cs35l41_dev_name { + const char *bus; + const char *hid; + int index; +}; + +/* match the device name in a slightly relaxed manner */ +static int comp_match_cs35l41_dev_name(struct device *dev, void *data) +{ + struct cs35l41_dev_name *p = data; + const char *d = dev_name(dev); + int n = strlen(p->bus); + char tmp[32]; + + /* check the bus name */ + if (strncmp(d, p->bus, n)) + return 0; + /* skip the bus number */ + if (isdigit(d[n])) + n++; + /* the rest must be exact matching */ + snprintf(tmp, sizeof(tmp), "-%s:00-cs35l41-hda.%d", p->hid, p->index); + return !strcmp(d + n, tmp); +} + static void cs35l41_generic_fixup(struct hda_codec *cdc, int action, const char *bus, const char *hid, int count) { struct device *dev = hda_codec_dev(cdc); struct alc_spec *spec = cdc->spec; - char *name; + struct cs35l41_dev_name *rec; int ret, i; switch (action) { case HDA_FIXUP_ACT_PRE_PROBE: for (i = 0; i < count; i++) { - name = devm_kasprintf(dev, GFP_KERNEL, - "%s-%s:00-cs35l41-hda.%d", bus, hid, i); - if (!name) + rec = devm_kmalloc(dev, sizeof(*rec), GFP_KERNEL); + if (!rec) return; + rec->bus = bus; + rec->hid = hid; + rec->index = i; spec->comps[i].codec = cdc; - component_match_add(dev, &spec->match, component_compare_dev_name, name); + component_match_add(dev, &spec->match, + comp_match_cs35l41_dev_name, rec); } ret = component_master_add_with_match(dev, &comp_master_ops, spec->match); if (ret) @@ -6738,17 +6767,12 @@ static void cs35l41_fixup_i2c_two(struct hda_codec *cdc, const struct hda_fixup static void cs35l41_fixup_spi_two(struct hda_codec *codec, const struct hda_fixup *fix, int action) { - cs35l41_generic_fixup(codec, action, "spi0", "CSC3551", 2); -} - -static void cs35l41_fixup_spi1_two(struct hda_codec *codec, const struct hda_fixup *fix, int action) -{ - cs35l41_generic_fixup(codec, action, "spi1", "CSC3551", 2); + cs35l41_generic_fixup(codec, action, "spi", "CSC3551", 2); } static void cs35l41_fixup_spi_four(struct hda_codec *codec, const struct hda_fixup *fix, int action) { - cs35l41_generic_fixup(codec, action, "spi0", "CSC3551", 4); + cs35l41_generic_fixup(codec, action, "spi", "CSC3551", 4); } static void alc287_fixup_legion_16achg6_speakers(struct hda_codec *cdc, const struct hda_fixup *fix, @@ -7137,8 +7161,6 @@ enum { ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED, ALC245_FIXUP_CS35L41_SPI_2, ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED, - ALC245_FIXUP_CS35L41_SPI1_2, - ALC245_FIXUP_CS35L41_SPI1_2_HP_GPIO_LED, ALC245_FIXUP_CS35L41_SPI_4, ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED, ALC285_FIXUP_HP_SPEAKERS_MICMUTE_LED, @@ -8986,16 +9008,6 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC285_FIXUP_HP_GPIO_LED, }, - [ALC245_FIXUP_CS35L41_SPI1_2] = { - .type = HDA_FIXUP_FUNC, - .v.func = cs35l41_fixup_spi1_two, - }, - [ALC245_FIXUP_CS35L41_SPI1_2_HP_GPIO_LED] = { - .type = HDA_FIXUP_FUNC, - .v.func = cs35l41_fixup_spi1_two, - .chained = true, - .chain_id = ALC285_FIXUP_HP_GPIO_LED, - }, [ALC245_FIXUP_CS35L41_SPI_4] = { .type = HDA_FIXUP_FUNC, .v.func = cs35l41_fixup_spi_four, @@ -9358,7 +9370,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8aa3, "HP ProBook 450 G9 (MB 8AA1)", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8aa8, "HP EliteBook 640 G9 (MB 8AA6)", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8aab, "HP EliteBook 650 G9 (MB 8AA9)", ALC236_FIXUP_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x8abb, "HP ZBook Firefly 14 G9", ALC245_FIXUP_CS35L41_SPI1_2_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8abb, "HP ZBook Firefly 14 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8ad1, "HP EliteBook 840 14 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8ad2, "HP EliteBook 860 16 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC), -- cgit v1.2.3 From 4674284aa74cfc6db0c54c16f9557ed8c3552409 Mon Sep 17 00:00:00 2001 From: "Nícolas F. R. A. Prado" Date: Thu, 29 Sep 2022 16:54:53 -0400 Subject: ASoC: mediatek: mt8192-mt6359: Set the driver name for the card MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ASoC core automatically populates the driver name field in the card from the card name if left unset. However, since the driver name can be at most 16 characters long, wrapping will happen if the card name is longer, which is the case for the mt8192-mt6359 driver. Explicitly set the driver name for the card in order to avoid said wrapping and have a readable driver name exposed to userspace. Signed-off-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220929205453.1144142-1-nfraprado@collabora.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 ff40ccd36f7e..b93c3237ef2d 100644 --- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c +++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c @@ -24,6 +24,8 @@ #include "mt8192-afe-clk.h" #include "mt8192-afe-gpio.h" +#define DRIVER_NAME "mt8192_mt6359" + #define RT1015_CODEC_DAI "rt1015-aif" #define RT1015_DEV0_NAME "rt1015.1-0028" #define RT1015_DEV1_NAME "rt1015.1-0029" @@ -1070,6 +1072,7 @@ static struct snd_soc_codec_conf rt1015_amp_conf[] = { static struct snd_soc_card mt8192_mt6359_rt1015_rt5682_card = { .name = RT1015_RT5682_CARD_NAME, + .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = mt8192_mt6359_dai_links, .num_links = ARRAY_SIZE(mt8192_mt6359_dai_links), @@ -1105,6 +1108,7 @@ static const struct snd_kcontrol_new mt8192_mt6359_rt1015p_rt5682x_controls[] = }; static struct snd_soc_card mt8192_mt6359_rt1015p_rt5682x_card = { + .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = mt8192_mt6359_dai_links, .num_links = ARRAY_SIZE(mt8192_mt6359_dai_links), @@ -1266,7 +1270,7 @@ static const struct dev_pm_ops mt8192_mt6359_pm_ops = { static struct platform_driver mt8192_mt6359_driver = { .driver = { - .name = "mt8192_mt6359", + .name = DRIVER_NAME, #ifdef CONFIG_OF .of_match_table = mt8192_mt6359_dt_match, #endif -- cgit v1.2.3 From 568be8aaf8a535f79c4db76cabe17b035aa2584d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 30 Sep 2022 12:01:29 +0200 Subject: ALSA: usb-audio: Fix NULL dererence at error path At an error path to release URB buffers and contexts, the driver might hit a NULL dererence for u->urb pointer, when u->buffer_size has been already set but the actual URB allocation failed. Fix it by adding the NULL check of urb. Also, make sure that buffer_size is cleared after the error path or the close. Cc: Reported-by: Sabri N. Ferreiro Link: https://lore.kernel.org/r/CAKG+3NRjTey+fFfUEGwuxL-pi_=T4cUskYG9OzpzHytF+tzYng@mail.gmail.com Link: https://lore.kernel.org/r/20220930100129.19445-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/endpoint.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index b2d0b42b581f..36f753a28341 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -95,12 +95,13 @@ static inline unsigned get_usb_high_speed_rate(unsigned int rate) */ static void release_urb_ctx(struct snd_urb_ctx *u) { - if (u->buffer_size) + if (u->urb && u->buffer_size) usb_free_coherent(u->ep->chip->dev, u->buffer_size, u->urb->transfer_buffer, u->urb->transfer_dma); usb_free_urb(u->urb); u->urb = NULL; + u->buffer_size = 0; } static const char *usb_error_string(int err) -- cgit v1.2.3 From 6382da0828995af87aa8b8bef28cc61aceb4aff3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 30 Sep 2022 12:01:51 +0200 Subject: ALSA: usb-audio: Fix potential memory leaks When the driver hits -ENOMEM at allocating a URB or a buffer, it aborts and goes to the error path that releases the all previously allocated resources. However, when -ENOMEM hits at the middle of the sync EP URB allocation loop, the partially allocated URBs might be left without released, because ep->nurbs is still zero at that point. Fix it by setting ep->nurbs at first, so that the error handler loops over the full URB list. Cc: Link: https://lore.kernel.org/r/20220930100151.19461-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/endpoint.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 36f753a28341..48a3843a08f1 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -1268,6 +1268,7 @@ static int sync_ep_set_params(struct snd_usb_endpoint *ep) if (!ep->syncbuf) return -ENOMEM; + ep->nurbs = SYNC_URBS; for (i = 0; i < SYNC_URBS; i++) { struct snd_urb_ctx *u = &ep->urb[i]; u->index = i; @@ -1287,8 +1288,6 @@ static int sync_ep_set_params(struct snd_usb_endpoint *ep) u->urb->complete = snd_complete_urb; } - ep->nurbs = SYNC_URBS; - return 0; out_of_memory: -- cgit v1.2.3 From 7bc08355a4917f2bbd38e7af5207f339f47e5d36 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Fri, 30 Sep 2022 11:53:47 +0100 Subject: ASoC: qcom: fix unmet direct dependencies for SND_SOC_QDSP6 SND_SOC_QDSP6 already has COMPILE_TEST so remove that from SND_SOC_SC8280XP and also add QCOM_APR dependencies to SND_SOC_SC8280XP like other Qualcomm machine drivers. This should also fix below warning: on x86_64, when QCOM_APR is not set and COMPILE_TEST=y: WARNING: unmet direct dependencies detected for SND_SOC_QDSP6 Depends on [n]: SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && SND_SOC_QCOM [=y] && QCOM_APR [=n] && COMMON_CLK [=y] Selected by [y]: - SND_SOC_SC8280XP [=y] && SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && SND_SOC_QCOM [=y] && (QCOM_APR [=n] || COMPILE_TEST [=y]) && SOUNDWIRE [=y] && COMMON_CLK [=y] Fixes: 295aeea6646a ("ASoC: qcom: add machine driver for sc8280xp") Reported-by: Randy Dunlap Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220930105347.41127-1-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 1b0252ec4665..d0e59e07b1fc 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -175,8 +175,7 @@ config SND_SOC_SM8250 config SND_SOC_SC8280XP tristate "SoC Machine driver for SC8280XP boards" - depends on QCOM_APR || COMPILE_TEST - depends on SOUNDWIRE + depends on QCOM_APR && SOUNDWIRE depends on COMMON_CLK select SND_SOC_QDSP6 select SND_SOC_QCOM_COMMON -- cgit v1.2.3 From 853110992cfefec433ca58cf7d69df4f639abe18 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 27 Sep 2022 20:53:59 +0200 Subject: ASoC: dt-bindings: Document audio OF graph dai-tdm-slot-num dai-tdm-slot-width props Document dai-tdm-slot-num and dai-tdm-slot-width props as those are parsed by simple graph card and may therefore appear in audio OF graph node. Signed-off-by: Marek Vasut Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20220927185359.294322-1-marex@denx.de Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/audio-graph-port.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/audio-graph-port.yaml b/Documentation/devicetree/bindings/sound/audio-graph-port.yaml index bc46a95ed840..64654ceef208 100644 --- a/Documentation/devicetree/bindings/sound/audio-graph-port.yaml +++ b/Documentation/devicetree/bindings/sound/audio-graph-port.yaml @@ -74,6 +74,12 @@ patternProperties: convert-sample-format: $ref: "/schemas/sound/dai-params.yaml#/$defs/dai-sample-format" + dai-tdm-slot-num: + description: Number of slots in use. + $ref: /schemas/types.yaml#/definitions/uint32 + dai-tdm-slot-width: + description: Width in bits for each slot. + $ref: /schemas/types.yaml#/definitions/uint32 dai-tdm-slot-width-map: description: Mapping of sample widths to slot widths. For hardware that cannot support a fixed slot width or a slot width always -- cgit v1.2.3 From f0c8d7468af0001b80b0c86802ee28063f800987 Mon Sep 17 00:00:00 2001 From: Judy Hsiao Date: Fri, 30 Sep 2022 15:15:46 +0000 Subject: ASoC: rockchip: i2s: use regmap_read_poll_timeout_atomic to poll I2S_CLR 1. Uses regmap_read_poll_timeout_atomic to poll I2S_CLR as it is called within a spin lock. 2. Fixes the typo of break condition in regmap_read_poll_timeout_atomic. Fixes: fbb0ec656ee5 ("ASoC: rockchip: i2s: use regmap_read_poll_timeout to poll I2S_CLR") Signed-off-by: Judy Hsiao Link: https://lore.kernel.org/r/20220930151546.2017667-1-judyhsiao@chromium.org Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_i2s.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 28c86f5e435e..a8758ad68442 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -162,12 +162,12 @@ static int rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on) I2S_CLR_TXC | I2S_CLR_RXC); if (ret < 0) goto end; - ret = regmap_read_poll_timeout(i2s->regmap, - I2S_CLR, - val, - val != 0, - 20, - 200); + ret = regmap_read_poll_timeout_atomic(i2s->regmap, + I2S_CLR, + val, + val == 0, + 20, + 200); if (ret < 0) dev_warn(i2s->dev, "fail to clear: %d\n", ret); } @@ -220,12 +220,12 @@ static int rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on) I2S_CLR_TXC | I2S_CLR_RXC); if (ret < 0) goto end; - ret = regmap_read_poll_timeout(i2s->regmap, - I2S_CLR, - val, - val != 0, - 20, - 200); + ret = regmap_read_poll_timeout_atomic(i2s->regmap, + I2S_CLR, + val, + val == 0, + 20, + 200); if (ret < 0) dev_warn(i2s->dev, "fail to clear: %d\n", ret); } -- cgit v1.2.3 From 5226c7b9784eee215e3914f440b3c2e1764f67a8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 1 Oct 2022 09:48:10 +0200 Subject: ALSA: hda/hdmi: Don't skip notification handling during PM operation The HDMI driver skips the notification handling from the graphics driver when the codec driver is being in the PM operation. This behavior was introduced by the commit eb399d3c99d8 ("ALSA: hda - Skip ELD notification during PM process"). This skip may cause a problem, as we may miss the ELD update when the connection/disconnection happens right at the runtime-PM operation of the audio codec. Although this workaround was valid at that time, it's no longer true; the fix was required just because the ELD update procedure needed to wake up the audio codec, which had lead to a runtime-resume during a runtime-suspend. Meanwhile, the ELD update procedure doesn't need a codec wake up any longer since the commit 788d441a164c ("ALSA: hda - Use component ops for i915 HDMI/DP audio jack handling"); i.e. there is no much reason for skipping the notification. Let's drop those checks for addressing the missing notification. Fixes: 788d441a164c ("ALSA: hda - Use component ops for i915 HDMI/DP audio jack handling") Reported-by: Brent Lu Link: https://lore.kernel.org/r/20220927135807.4097052-1-brent.lu@intel.com Link: https://lore.kernel.org/r/20221001074809.7461-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index c172640c8a41..21edf7a619f0 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2666,9 +2666,6 @@ static void generic_acomp_pin_eld_notify(void *audio_ptr, int port, int dev_id) */ if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND) return; - /* ditto during suspend/resume process itself */ - if (snd_hdac_is_in_pm(&codec->core)) - return; check_presence_and_report(codec, pin_nid, dev_id); } @@ -2852,9 +2849,6 @@ static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe) */ if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND) return; - /* ditto during suspend/resume process itself */ - if (snd_hdac_is_in_pm(&codec->core)) - return; snd_hdac_i915_set_bclk(&codec->bus->core); check_presence_and_report(codec, pin_nid, dev_id); -- cgit v1.2.3 From 56e696c0f0c71b77fff921fc94b58a02f0445b2c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 1 Oct 2022 16:21:24 +0200 Subject: ALSA: hda: Fix position reporting on Poulsbo Hans reported that his Sony VAIO VPX11S1E showed the broken sound behavior at the start of the stream for a couple of seconds, and it turned out that the position_fix=1 option fixes the issue. It implies that the position reporting is inaccurate, and very likely hitting on all Poulsbo devices. The patch applies the workaround for Poulsbo generically to switch to LPIB mode instead of the default position buffer. Reported-and-tested-by: Hans de Goede Cc: Link: https://lore.kernel.org/r/3e8697e1-87c6-7a7b-d2e8-b21f1d2f181b@redhat.com Link: https://lore.kernel.org/r/20221001142124.7241-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 2a93bc64c2d8..6ff19dd0d10c 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2547,7 +2547,8 @@ static const struct pci_device_id azx_ids[] = { .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM }, /* Poulsbo */ { PCI_DEVICE(0x8086, 0x811b), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE }, + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE | + AZX_DCAPS_POSFIX_LPIB }, /* Oaktrail */ { PCI_DEVICE(0x8086, 0x080a), .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE }, -- cgit v1.2.3