ASoC: SOF: Intel: override mclk_id for ES8336 support
Merge series from Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>:
This patchset solves a known issue with ES8336 platforms wrt MCLK
selection. Most of the devices use the MCLK0 signal, but some devices
do use the MCLK1 signal.
The MCLK is defined in the topology, it would be a nightmare to
generate more topology files just for one MCLK difference. With a
minor extension to the intel-nhlt library, the MCLK information can be
found by parsing the NHLT table, and we can override the mclk_id at
boot time.
The only known issues for this platform remain the detection of GPIO
and microphone connections, currently only possible with manual
quirks.
Thanks to Eugene J. Markow for testing this patchset.
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 0000000..2f12cab
--- /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 <fengzheng923@gmail.com>
+
+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 <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ #include <dt-bindings/clock/sun50i-h6-ccu.h>
+ #include <dt-bindings/reset/sun50i-h6-ccu.h>
+
+ dmic: dmic@5095000 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun50i-h6-dmic";
+ reg = <0x05095000 0x400>;
+ interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_DMIC>, <&ccu CLK_DMIC>;
+ clock-names = "bus", "mod";
+ dmas = <&dma 7>;
+ dma-names = "rx";
+ resets = <&ccu RST_BUS_DMIC>;
+ };
+
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 5e3f515..bda993e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -820,6 +820,13 @@
S: Maintained
F: drivers/staging/media/sunxi/cedrus/
+ALLWINNER DMIC DRIVERS
+M: Ban Tao <fengzheng923@gmail.com>
+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 <richard.henderson@linaro.org>
M: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
diff --git a/include/trace/events/sof.h b/include/trace/events/sof.h
new file mode 100644
index 0000000..21c2a1e
--- /dev/null
+++ b/include/trace/events/sof.h
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2022 Intel Corporation. All rights reserved.
+ *
+ * Author: Noah Klayman <noah.klayman@intel.com>
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM sof
+
+#if !defined(_TRACE_SOF_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_SOF_H
+#include <linux/tracepoint.h>
+#include <linux/types.h>
+#include <sound/sof/stream.h>
+#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)
+);
+
+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))
+);
+
+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 */
+#include <trace/define_trace.h>
diff --git a/include/trace/events/sof_intel.h b/include/trace/events/sof_intel.h
new file mode 100644
index 0000000..2a77f9d
--- /dev/null
+++ b/include/trace/events/sof_intel.h
@@ -0,0 +1,148 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2022 Intel Corporation. All rights reserved.
+ *
+ * Author: Noah Klayman <noah.klayman@intel.com>
+ */
+
+#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 <linux/tracepoint.h>
+#include <sound/hdaudio.h>
+#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))
+);
+
+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 */
+#include <trace/define_trace.h>
diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c
index d84ffdf..1997ffc1 100644
--- a/sound/hda/intel-dsp-config.c
+++ b/sound/hda/intel-dsp-config.c
@@ -428,6 +428,11 @@ static const struct config_entry config_table[] = {
},
/* Alderlake-PS */
{
+ .flags = FLAG_SOF,
+ .device = 0x51c9,
+ .codec_hid = &essx_83x6,
+ },
+ {
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
.device = 0x51c9,
},
diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c
index f0c4912..4c69cb6 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;
diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c
index ef2ce08..a0c84cd 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;
diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c
index eb47e7c..2831f2f 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"))
+ if (!rt5682s->wclk_enabled) {
snd_soc_component_update_bits(component,
- RT5682S_PWR_ANLG_1, RT5682S_PWR_MB, 0);
- if (!snd_soc_dapm_get_pin_status(&component->dapm, "Vref2"))
- 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);
@@ -1154,30 +1155,53 @@ 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;
+ int on = 0;
+
+ if (rt5682s->wclk_enabled)
+ return 0;
+
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ on = 1;
+
+ rt5682s_set_pllb_power(rt5682s, on);
+
+ 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};
- 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];
-
idx = rt5682s_div_sel(rt5682s, ref, div_f, ARRAY_SIZE(div_f));
- if (w->shift == RT5682S_PWR_ADC_S1F_BIT)
- reg = RT5682S_PLL_TRACK_3;
- else
- reg = RT5682S_PLL_TRACK_2;
-
snd_soc_component_update_bits(component, reg,
RT5682S_FILTER_CLK_DIV_MASK, idx << RT5682S_FILTER_CLK_DIV_SFT);
@@ -1190,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;
}
@@ -1218,13 +1265,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;
}
@@ -1232,41 +1275,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,
+static void rt5682s_set_i2s(struct rt5682s_priv *rt5682s, int id, int on)
+{
+ 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 {
+ 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 (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;
+ }
+
+ 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);
+ }
+
+ 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 pre_div, id;
- unsigned int reg, mask, sft;
+ int on = 0;
- if (event != SND_SOC_DAPM_PRE_PMU)
- return 0;
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ on = 1;
- 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;
- } else {
- id = RT5682S_AIF1;
- reg = RT5682S_ADDA_CLK_1;
- mask = RT5682S_I2S_M_D_MASK;
- sft = RT5682S_I2S_M_D_SFT;
- }
-
- if (!rt5682s->master[id])
- return 0;
-
- 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, reg, mask, pre_div << sft);
+ 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;
}
@@ -1615,26 +1675,18 @@ 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,
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,
@@ -1720,10 +1772,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),
@@ -1801,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},
@@ -2431,12 +2480,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;
@@ -2464,30 +2516,34 @@ 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;
- snd_soc_dapm_mutex_lock(dapm);
+ mutex_lock(&rt5682s->wclk_mutex);
- 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);
-
- 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);
- 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);
+ /* 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);
- snd_soc_dapm_mutex_unlock(dapm);
+ /* 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);
return 0;
}
@@ -2497,24 +2553,27 @@ 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;
- 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);
- snd_soc_dapm_disable_pin_unlocked(dapm, "I2S1");
- snd_soc_dapm_disable_pin_unlocked(dapm, "PLLB");
- snd_soc_dapm_sync_unlocked(dapm);
+ /* 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);
- snd_soc_dapm_mutex_unlock(dapm);
+ /* Power down PLLB */
+ rt5682s_set_pllb_power(rt5682s, 0);
+
+ rt5682s->wclk_enabled = 0;
+
+ mutex_unlock(&rt5682s->wclk_mutex);
}
static unsigned long rt5682s_wclk_recalc_rate(struct clk_hw *hw,
@@ -2805,7 +2864,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 +2872,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 +3168,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 7353831..824dc65 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,
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index 7fc1c96..275aba8 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);
diff --git a/sound/soc/intel/avs/boards/hdaudio.c b/sound/soc/intel/avs/boards/hdaudio.c
index d2fc41d..073663b 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/intel/boards/sof_cs42l42.c b/sound/soc/intel/boards/sof_cs42l42.c
index 85ffd06..e38bd28 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;
diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c
index 606cc32..fbb42e54 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;
}
diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c
index 8d7e5ba..5585c21 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;
}
diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c
index 0459653..1bf9455 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;
}
diff --git a/sound/soc/intel/boards/sof_ssp_amp.c b/sound/soc/intel/boards/sof_ssp_amp.c
index 4a762e0..94d25ae 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;
}
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index e020ab4..df2bd80 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 b101db8..c3be24b 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)
diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c
index c99b5e6..3e6141d 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 <trace/events/sof.h>
+
/* 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/intel/cnl.c b/sound/soc/sof/intel/cnl.c
index 0bb91df..180001d 100644
--- a/sound/soc/sof/intel/cnl.c
+++ b/sound/soc/sof/intel/cnl.c
@@ -17,6 +17,7 @@
#include <sound/sof/ext_manifest4.h>
#include <sound/sof/ipc4/header.h>
+#include <trace/events/sof_intel.h>
#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 671c3e0..1319c8e 100644
--- a/sound/soc/sof/intel/hda-dsp.c
+++ b/sound/soc/sof/intel/hda-dsp.c
@@ -18,6 +18,7 @@
#include <linux/module.h>
#include <sound/hdaudio_ext.h>
#include <sound/hda_register.h>
+#include <trace/events/sof_intel.h>
#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 65e688f..c597ef4 100644
--- a/sound/soc/sof/intel/hda-ipc.c
+++ b/sound/soc/sof/intel/hda-ipc.c
@@ -16,6 +16,7 @@
*/
#include <sound/sof/ipc4/header.h>
+#include <trace/events/sof_intel.h>
#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 6888e0a..0a9c802 100644
--- a/sound/soc/sof/intel/hda-pcm.c
+++ b/sound/soc/sof/intel/hda-pcm.c
@@ -18,6 +18,7 @@
#include <linux/moduleparam.h>
#include <sound/hda_register.h>
#include <sound/pcm_params.h>
+#include <trace/events/sof_intel.h>
#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 b58662f..be60e778 100644
--- a/sound/soc/sof/intel/hda-stream.c
+++ b/sound/soc/sof/intel/hda-stream.c
@@ -19,6 +19,7 @@
#include <sound/hdaudio_ext.h>
#include <sound/hda_register.h>
#include <sound/sof.h>
+#include <trace/events/sof_intel.h>
#include "../ops.h"
#include "../sof-audio.h"
#include "hda.h"
@@ -93,9 +94,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;
@@ -700,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)
@@ -739,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/hda.c b/sound/soc/sof/intel/hda.c
index dfb3b42..eec54c8 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 <trace/events/sof_intel.h>
+
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
#include <sound/soc-acpi-intel-match.h>
#endif
@@ -954,17 +957,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);
diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c
index efc91fe..5408c34 100644
--- a/sound/soc/sof/intel/mtl.c
+++ b/sound/soc/sof/intel/mtl.c
@@ -11,6 +11,7 @@
#include <linux/firmware.h>
#include <sound/sof/ipc4/header.h>
+#include <trace/events/sof_intel.h>
#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;
diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c
index 82fa320..b28af3a 100644
--- a/sound/soc/sof/ipc3.c
+++ b/sound/soc/sof/ipc3.c
@@ -9,6 +9,7 @@
#include <sound/sof/stream.h>
#include <sound/sof/control.h>
+#include <trace/events/sof.h>
#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/ipc4-loader.c b/sound/soc/sof/ipc4-loader.c
index c678f05..e635ae5 100644
--- a/sound/soc/sof/ipc4-loader.c
+++ b/sound/soc/sof/ipc4-loader.c
@@ -8,6 +8,7 @@
#include <linux/firmware.h>
#include <sound/sof/ext_manifest4.h>
#include <sound/sof/ipc4/header.h>
+#include <trace/events/sof.h>
#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:
diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c
index a1be5d7..9ec89fc 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 */
diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c
index 356497f..3537805 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;
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c
index 49f7cb0..14571b8 100644
--- a/sound/soc/sof/pcm.c
+++ b/sound/soc/sof/pcm.c
@@ -13,6 +13,7 @@
#include <linux/pm_runtime.h>
#include <sound/pcm_params.h>
#include <sound/sof.h>
+#include <trace/events/sof.h>
#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;
}
diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c
index ea9663d..a3d3dd7 100644
--- a/sound/soc/sof/sof-audio.c
+++ b/sound/soc/sof/sof-audio.c
@@ -9,6 +9,7 @@
//
#include <linux/bitfield.h>
+#include <trace/events/sof.h>
#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;
diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c
index d627092..643fd10 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"),
}
},
{},
diff --git a/sound/soc/sof/sof-utils.c b/sound/soc/sof/sof-utils.c
index a3300ec..b6345a7 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 9273a70..6087483 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 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index,
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 */
diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig
index ddcaaa9..1f18f01 100644
--- a/sound/soc/sunxi/Kconfig
+++ b/sound/soc/sunxi/Kconfig
@@ -56,6 +56,13 @@
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 a86be34..4483fe9 100644
--- a/sound/soc/sunxi/Makefile
+++ b/sound/soc/sunxi/Makefile
@@ -6,3 +6,4 @@
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/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 3a7075d..835dc34 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
diff --git a/sound/soc/sunxi/sun50i-dmic.c b/sound/soc/sunxi/sun50i-dmic.c
new file mode 100644
index 0000000..cd3c07f
--- /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 <fengzheng923@gmail.com>
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#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 <fengzheng923@gmail.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:sun50i-dmic");