ASoC: Merge fixes
Required for more changes for the ops.
diff --git a/Documentation/devicetree/bindings/sound/atmel-sam9x5-wm8731-audio.txt b/Documentation/devicetree/bindings/sound/atmel-sam9x5-wm8731-audio.txt
index 0720857..8facbce 100644
--- a/Documentation/devicetree/bindings/sound/atmel-sam9x5-wm8731-audio.txt
+++ b/Documentation/devicetree/bindings/sound/atmel-sam9x5-wm8731-audio.txt
@@ -16,7 +16,7 @@
* Line In Jack
wm8731 pins:
-cf Documentation/devicetree/bindings/sound/wm8731.txt
+cf Documentation/devicetree/bindings/sound/wlf,wm8731.yaml
Example:
sound {
diff --git a/Documentation/devicetree/bindings/sound/fsl,mqs.txt b/Documentation/devicetree/bindings/sound/fsl,mqs.txt
index 40353fc..d66284b 100644
--- a/Documentation/devicetree/bindings/sound/fsl,mqs.txt
+++ b/Documentation/devicetree/bindings/sound/fsl,mqs.txt
@@ -2,7 +2,7 @@
Required properties:
- compatible : Must contain one of "fsl,imx6sx-mqs", "fsl,codec-mqs"
- "fsl,imx8qm-mqs", "fsl,imx8qxp-mqs".
+ "fsl,imx8qm-mqs", "fsl,imx8qxp-mqs", "fsl,imx93-mqs".
- clocks : A list of phandles + clock-specifiers, one for each entry in
clock-names
- clock-names : "mclk" - must required.
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
index 6df6f85..47b6e71 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
@@ -110,6 +110,10 @@
type: object
$ref: nvidia,tegra186-asrc.yaml#
+ '^processing-engine@[0-9a-f]+$':
+ type: object
+ $ref: nvidia,tegra210-ope.yaml#
+
required:
- compatible
- reg
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
new file mode 100644
index 0000000..5b91986
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra210-mbdrc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra210 MBDRC
+
+description:
+ The Multi Band Dynamic Range Compressor (MBDRC) is part of Output
+ Processing Engine (OPE) which interfaces with Audio Hub (AHUB) via
+ Audio Client Interface (ACIF). MBDRC can be used as a traditional
+ single full band or a dual band or a multi band dynamic processor.
+
+maintainers:
+ - Jon Hunter <jonathanh@nvidia.com>
+ - Mohan Kumar <mkumard@nvidia.com>
+ - Sameer Pujar <spujar@nvidia.com>
+
+properties:
+ compatible:
+ oneOf:
+ - const: nvidia,tegra210-mbdrc
+ - items:
+ - enum:
+ - nvidia,tegra234-mbdrc
+ - nvidia,tegra194-mbdrc
+ - nvidia,tegra186-mbdrc
+ - const: nvidia,tegra210-mbdrc
+
+ reg:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ dynamic-range-compressor@702d8200 {
+ compatible = "nvidia,tegra210-mbdrc";
+ reg = <0x702d8200 0x200>;
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
new file mode 100644
index 0000000..9dc9ba5
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
@@ -0,0 +1,87 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra210-ope.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra210 OPE
+
+description:
+ The Output Processing Engine (OPE) is one of the AHUB client. It has
+ PEQ (Parametric Equalizer) and MBDRC (Multi Band Dynamic Range Compressor)
+ sub blocks for data processing.
+
+maintainers:
+ - Jon Hunter <jonathanh@nvidia.com>
+ - Mohan Kumar <mkumard@nvidia.com>
+ - Sameer Pujar <spujar@nvidia.com>
+
+allOf:
+ - $ref: name-prefix.yaml#
+
+properties:
+ compatible:
+ oneOf:
+ - const: nvidia,tegra210-ope
+ - items:
+ - enum:
+ - nvidia,tegra234-ope
+ - nvidia,tegra194-ope
+ - nvidia,tegra186-ope
+ - const: nvidia,tegra210-ope
+
+ reg:
+ maxItems: 1
+
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 1
+
+ ranges: true
+
+ sound-name-prefix:
+ pattern: "^OPE[1-9]$"
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+ properties:
+ port@0:
+ $ref: audio-graph-port.yaml#
+ unevaluatedProperties: false
+ description:
+ OPE ACIF (Audio Client Interface) input port. This is connected
+ to corresponding ACIF output port on AHUB (Audio Hub).
+
+ port@1:
+ $ref: audio-graph-port.yaml#
+ unevaluatedProperties: false
+ description:
+ OPE ACIF output port. This is connected to corresponding ACIF
+ input port on AHUB.
+
+patternProperties:
+ '^equalizer@[0-9a-f]+$':
+ type: object
+ $ref: nvidia,tegra210-peq.yaml#
+
+ '^dynamic-range-compressor@[0-9a-f]+$':
+ type: object
+ $ref: nvidia,tegra210-mbdrc.yaml#
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ processing-engine@702d8000 {
+ compatible = "nvidia,tegra210-ope";
+ reg = <0x702d8000 0x100>;
+ sound-name-prefix = "OPE1";
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml
new file mode 100644
index 0000000..1e373c4
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra210-peq.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra210 PEQ
+
+description:
+ The Parametric Equalizer (PEQ) is a cascade of biquad filters with
+ each filter tuned based on certain parameters. It can be used to
+ equalize the irregularities in the speaker frequency response.
+ PEQ sits inside Output Processing Engine (OPE) which interfaces
+ with Audio Hub (AHUB) via Audio Client Interface (ACIF).
+
+maintainers:
+ - Jon Hunter <jonathanh@nvidia.com>
+ - Mohan Kumar <mkumard@nvidia.com>
+ - Sameer Pujar <spujar@nvidia.com>
+
+properties:
+ compatible:
+ oneOf:
+ - const: nvidia,tegra210-peq
+ - items:
+ - enum:
+ - nvidia,tegra234-peq
+ - nvidia,tegra194-peq
+ - nvidia,tegra186-peq
+ - const: nvidia,tegra210-peq
+
+ reg:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ equalizer@702d8100 {
+ compatible = "nvidia,tegra210-peq";
+ reg = <0x702d8100 0x100>;
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml b/Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml
index b9b1dba..7f2e68f 100644
--- a/Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml
+++ b/Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml
@@ -15,6 +15,7 @@
properties:
compatible:
enum:
+ - nxp,tfa9890
- nxp,tfa9895
- nxp,tfa9897
diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c
index 65549fb..be9736f 100644
--- a/drivers/gpu/drm/bridge/sii902x.c
+++ b/drivers/gpu/drm/bridge/sii902x.c
@@ -549,8 +549,9 @@ static int sii902x_audio_hw_params(struct device *dev, void *data,
unsigned long mclk_rate;
int i, ret;
- if (daifmt->bit_clk_master || daifmt->frame_clk_master) {
- dev_dbg(dev, "%s: I2S master mode not supported\n", __func__);
+ if (daifmt->bit_clk_provider || daifmt->frame_clk_provider) {
+ dev_dbg(dev, "%s: I2S clock provider mode not supported\n",
+ __func__);
return -EINVAL;
}
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c
index f50b47a..a2f0860 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c
@@ -45,7 +45,7 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data,
u8 inputclkfs = 0;
/* it cares I2S only */
- if (fmt->bit_clk_master | fmt->frame_clk_master) {
+ if (fmt->bit_clk_provider | fmt->frame_clk_provider) {
dev_err(dev, "unsupported clock settings\n");
return -EINVAL;
}
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 7655142..10b0036 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -1594,12 +1594,12 @@ static int hdmi_audio_hw_params(struct device *dev, void *data,
struct hdmi_context *hdata = dev_get_drvdata(dev);
if (daifmt->fmt != HDMI_I2S || daifmt->bit_clk_inv ||
- daifmt->frame_clk_inv || daifmt->bit_clk_master ||
- daifmt->frame_clk_master) {
+ daifmt->frame_clk_inv || daifmt->bit_clk_provider ||
+ daifmt->frame_clk_provider) {
dev_err(dev, "%s: Bad flags %d %d %d %d\n", __func__,
daifmt->bit_clk_inv, daifmt->frame_clk_inv,
- daifmt->bit_clk_master,
- daifmt->frame_clk_master);
+ daifmt->bit_clk_provider,
+ daifmt->frame_clk_provider);
return -EINVAL;
}
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
index b7ec6c3..c4fadae 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -1095,11 +1095,11 @@ static int tda998x_audio_hw_params(struct device *dev, void *data,
if (!spdif &&
(daifmt->bit_clk_inv || daifmt->frame_clk_inv ||
- daifmt->bit_clk_master || daifmt->frame_clk_master)) {
+ daifmt->bit_clk_provider || daifmt->frame_clk_provider)) {
dev_err(dev, "%s: Bad flags %d %d %d %d\n", __func__,
daifmt->bit_clk_inv, daifmt->frame_clk_inv,
- daifmt->bit_clk_master,
- daifmt->frame_clk_master);
+ daifmt->bit_clk_provider,
+ daifmt->frame_clk_provider);
return -EINVAL;
}
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
index b3fbee7..65c7607 100644
--- a/drivers/gpu/drm/sti/sti_hdmi.c
+++ b/drivers/gpu/drm/sti/sti_hdmi.c
@@ -1175,12 +1175,12 @@ static int hdmi_audio_hw_params(struct device *dev,
DRM_DEBUG_DRIVER("\n");
if ((daifmt->fmt != HDMI_I2S) || daifmt->bit_clk_inv ||
- daifmt->frame_clk_inv || daifmt->bit_clk_master ||
- daifmt->frame_clk_master) {
+ daifmt->frame_clk_inv || daifmt->bit_clk_provider ||
+ daifmt->frame_clk_provider) {
dev_err(dev, "%s: Bad flags %d %d %d %d\n", __func__,
daifmt->bit_clk_inv, daifmt->frame_clk_inv,
- daifmt->bit_clk_master,
- daifmt->frame_clk_master);
+ daifmt->bit_clk_provider,
+ daifmt->frame_clk_provider);
return -EINVAL;
}
diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index 22b7063..a3fccf0 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -13,6 +13,7 @@
#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
+#include <linux/reset.h>
#include <linux/slab.h>
#include <linux/pm_wakeirq.h>
#include <linux/slimbus.h>
@@ -142,6 +143,7 @@ struct qcom_swrm_ctrl {
struct device *dev;
struct regmap *regmap;
void __iomem *mmio;
+ struct reset_control *audio_cgcr;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs;
#endif
@@ -656,6 +658,8 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
val = FIELD_PREP(SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK, ctrl->rows_index);
val |= FIELD_PREP(SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK, ctrl->cols_index);
+ reset_control_reset(ctrl->audio_cgcr);
+
ctrl->reg_write(ctrl, SWRM_MCP_FRAME_CTRL_BANK_ADDR(0), val);
/* Enable Auto enumeration */
@@ -1332,6 +1336,10 @@ static int qcom_swrm_probe(struct platform_device *pdev)
ctrl->bus.compute_params = &qcom_swrm_compute_params;
ctrl->bus.clk_stop_timeout = 300;
+ ctrl->audio_cgcr = devm_reset_control_get_exclusive(dev, "swr_audio_cgcr");
+ if (IS_ERR(ctrl->audio_cgcr))
+ dev_err(dev, "Failed to get audio_cgcr reset required for soundwire-v1.6.0\n");
+
ret = qcom_swrm_get_port_config(ctrl);
if (ret)
goto err_clk;
@@ -1485,6 +1493,8 @@ static int __maybe_unused swrm_runtime_resume(struct device *dev)
qcom_swrm_get_device_status(ctrl);
sdw_handle_slave_status(&ctrl->bus, ctrl->status);
} else {
+ reset_control_reset(ctrl->audio_cgcr);
+
ctrl->reg_write(ctrl, SWRM_MCP_BUS_CTRL, SWRM_MCP_BUS_CLK_START);
ctrl->reg_write(ctrl, SWRM_INTERRUPT_CLEAR,
SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET);
diff --git a/include/sound/cs35l41.h b/include/sound/cs35l41.h
index 8972fa6..a66ef37 100644
--- a/include/sound/cs35l41.h
+++ b/include/sound/cs35l41.h
@@ -881,6 +881,9 @@ void cs35l41_configure_cs_dsp(struct device *dev, struct regmap *reg, struct cs_
int cs35l41_set_cspl_mbox_cmd(struct device *dev, struct regmap *regmap,
enum cs35l41_cspl_mbox_cmd cmd);
int cs35l41_write_fs_errata(struct device *dev, struct regmap *regmap);
+int cs35l41_enter_hibernate(struct device *dev, struct regmap *regmap,
+ enum cs35l41_boost_type b_type);
+int cs35l41_exit_hibernate(struct device *dev, struct regmap *regmap);
int cs35l41_init_boost(struct device *dev, struct regmap *regmap,
struct cs35l41_hw_cfg *hw_cfg);
bool cs35l41_safe_reset(struct regmap *regmap, enum cs35l41_boost_type b_type);
diff --git a/include/sound/hdmi-codec.h b/include/sound/hdmi-codec.h
index 4fc733c..48ad33a 100644
--- a/include/sound/hdmi-codec.h
+++ b/include/sound/hdmi-codec.h
@@ -32,8 +32,8 @@ struct hdmi_codec_daifmt {
} fmt;
unsigned int bit_clk_inv:1;
unsigned int frame_clk_inv:1;
- unsigned int bit_clk_master:1;
- unsigned int frame_clk_master:1;
+ unsigned int bit_clk_provider:1;
+ unsigned int frame_clk_provider:1;
/* bit_fmt could be standard PCM format or
* IEC958 encoded format. ALSA IEC958 plugin will pass
* IEC958_SUBFRAME format to the underneath driver.
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 6b99310..26523cf 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -1393,6 +1393,20 @@ static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max)
const char *snd_pcm_format_name(snd_pcm_format_t format);
/**
+ * snd_pcm_direction_name - Get a string naming the direction of a stream
+ * @direction: Stream's direction, one of SNDRV_PCM_STREAM_XXX
+ *
+ * Returns a string naming the direction of the stream.
+ */
+static inline const char *snd_pcm_direction_name(int direction)
+{
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+ return "Playback";
+ else
+ return "Capture";
+}
+
+/**
* snd_pcm_stream_str - Get a string naming the direction of a stream
* @substream: the pcm substream instance
*
@@ -1400,10 +1414,7 @@ const char *snd_pcm_format_name(snd_pcm_format_t format);
*/
static inline const char *snd_pcm_stream_str(struct snd_pcm_substream *substream)
{
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- return "Playback";
- else
- return "Capture";
+ return snd_pcm_direction_name(substream->stream);
}
/*
diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h
index 8faa649..fe2337f 100644
--- a/include/sound/simple_card_utils.h
+++ b/include/sound/simple_card_utils.h
@@ -173,7 +173,7 @@ void asoc_simple_canonicalize_platform(struct snd_soc_dai_link_component *platfo
void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link_component *cpus,
int is_single_links);
-int asoc_simple_clean_reference(struct snd_soc_card *card);
+void asoc_simple_clean_reference(struct snd_soc_card *card);
void asoc_simple_convert_fixup(struct asoc_simple_data *data,
struct snd_pcm_hw_params *params);
diff --git a/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h
index 59551b1..bc7fd46 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_mtl_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cfl_sdw_machines[];
@@ -37,6 +38,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_mtl_sdw_machines[];
/*
* generic table used for HDA codec-based platforms, possibly with
diff --git a/include/sound/soc-card.h b/include/sound/soc-card.h
index df08573..9d31a5c 100644
--- a/include/sound/soc-card.h
+++ b/include/sound/soc-card.h
@@ -29,6 +29,7 @@ int snd_soc_card_resume_post(struct snd_soc_card *card);
int snd_soc_card_probe(struct snd_soc_card *card);
int snd_soc_card_late_probe(struct snd_soc_card *card);
+void snd_soc_card_fixup_controls(struct snd_soc_card *card);
int snd_soc_card_remove(struct snd_soc_card *card);
int snd_soc_card_set_bias_level(struct snd_soc_card *card,
diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h
index 5a764c3..5c4cfa7 100644
--- a/include/sound/soc-component.h
+++ b/include/sound/soc-component.h
@@ -348,11 +348,6 @@ static inline int snd_soc_component_cache_sync(
return regcache_sync(component->regmap);
}
-static inline int snd_soc_component_is_codec(struct snd_soc_component *component)
-{
- return component->driver->non_legacy_dai_naming;
-}
-
void snd_soc_component_set_aux(struct snd_soc_component *component,
struct snd_soc_aux_dev *aux);
int snd_soc_component_init(struct snd_soc_component *component);
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index bbd821d..ea75096 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -124,6 +124,12 @@ struct snd_compr_stream;
#define SND_SOC_DAIFMT_CBM_CFS SND_SOC_DAIFMT_CBP_CFC
#define SND_SOC_DAIFMT_CBS_CFS SND_SOC_DAIFMT_CBC_CFC
+/* when passed to set_fmt directly indicate if the device is provider or consumer */
+#define SND_SOC_DAIFMT_BP_FP SND_SOC_DAIFMT_CBP_CFP
+#define SND_SOC_DAIFMT_BC_FP SND_SOC_DAIFMT_CBC_CFP
+#define SND_SOC_DAIFMT_BP_FC SND_SOC_DAIFMT_CBP_CFC
+#define SND_SOC_DAIFMT_BC_FC SND_SOC_DAIFMT_CBC_CFC
+
/* Describes the possible PCM format */
#define SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT 48
#define SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_MASK (0xFFFFULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT)
diff --git a/include/sound/soc.h b/include/sound/soc.h
index b276dcb..8909cc7 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -914,6 +914,7 @@ struct snd_soc_card {
int (*probe)(struct snd_soc_card *card);
int (*late_probe)(struct snd_soc_card *card);
+ void (*fixup_controls)(struct snd_soc_card *card);
int (*remove)(struct snd_soc_card *card);
/* the pre and post PM functions are used to do any PM work before and
diff --git a/include/sound/sof.h b/include/sound/sof.h
index 1a82a0d..367dccf 100644
--- a/include/sound/sof.h
+++ b/include/sound/sof.h
@@ -138,6 +138,7 @@ struct sof_dev_desc {
struct snd_sof_dsp_ops *ops;
int (*ops_init)(struct snd_sof_dev *sdev);
+ void (*ops_free)(struct snd_sof_dev *sdev);
};
int sof_dai_get_mclk(struct snd_soc_pcm_runtime *rtd);
diff --git a/include/sound/sof/dai-amd.h b/include/sound/sof/dai-amd.h
index 90d09db..92f45c1 100644
--- a/include/sound/sof/dai-amd.h
+++ b/include/sound/sof/dai-amd.h
@@ -18,4 +18,11 @@ struct sof_ipc_dai_acp_params {
uint32_t fsync_rate; /* FSYNC frequency in Hz */
uint32_t tdm_slots;
} __packed;
+
+/* ACPDMIC Configuration Request - SOF_IPC_DAI_AMD_CONFIG */
+struct sof_ipc_dai_acpdmic_params {
+ uint32_t pdm_rate;
+ uint32_t pdm_ch;
+} __packed;
+
#endif
diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h
index a818a0f..21d98f3 100644
--- a/include/sound/sof/dai.h
+++ b/include/sound/sof/dai.h
@@ -111,7 +111,7 @@ struct sof_ipc_dai_config {
struct sof_ipc_dai_sai_params sai;
struct sof_ipc_dai_acp_params acpbt;
struct sof_ipc_dai_acp_params acpsp;
- struct sof_ipc_dai_acp_params acpdmic;
+ struct sof_ipc_dai_acpdmic_params acpdmic;
struct sof_ipc_dai_mtk_afe_params afe;
};
} __packed;
diff --git a/include/sound/sof/ipc4/header.h b/include/sound/sof/ipc4/header.h
index b8b8e5b..a795dea 100644
--- a/include/sound/sof/ipc4/header.h
+++ b/include/sound/sof/ipc4/header.h
@@ -385,6 +385,14 @@ struct sof_ipc4_fw_version {
uint16_t build;
} __packed;
+/* Payload data for SOF_IPC4_MOD_SET_DX */
+struct sof_ipc4_dx_state_info {
+ /* core(s) to apply the change */
+ uint32_t core_mask;
+ /* core state: 0: put core_id to D3; 1: put core_id to D0 */
+ uint32_t dx_mask;
+} __packed __aligned(4);
+
/* Reply messages */
/*
diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h
index 0e7dccd..c88f467 100644
--- a/include/uapi/sound/sof/abi.h
+++ b/include/uapi/sound/sof/abi.h
@@ -24,6 +24,8 @@
#ifndef __INCLUDE_UAPI_SOUND_SOF_ABI_H__
#define __INCLUDE_UAPI_SOUND_SOF_ABI_H__
+#include <linux/types.h>
+
/* SOF ABI version major, minor and patch numbers */
#define SOF_ABI_MAJOR 3
#define SOF_ABI_MINOR 21
diff --git a/include/uapi/sound/sof/header.h b/include/uapi/sound/sof/header.h
index 5f4518e..f125f77 100644
--- a/include/uapi/sound/sof/header.h
+++ b/include/uapi/sound/sof/header.h
@@ -26,4 +26,34 @@ struct sof_abi_hdr {
__u32 data[0]; /**< Component data - opaque to core */
} __packed;
+#define SOF_MANIFEST_DATA_TYPE_NHLT 1
+
+/**
+ * struct sof_manifest_tlv - SOF manifest TLV data
+ * @type: type of data
+ * @size: data size (not including the size of this struct)
+ * @data: payload data
+ */
+struct sof_manifest_tlv {
+ __le32 type;
+ __le32 size;
+ __u8 data[];
+};
+
+/**
+ * struct sof_manifest - SOF topology manifest
+ * @abi_major: Major ABI version
+ * @abi_minor: Minor ABI version
+ * @abi_patch: ABI patch
+ * @count: count of tlv items
+ * @items: consecutive variable size tlv items
+ */
+struct sof_manifest {
+ __le16 abi_major;
+ __le16 abi_minor;
+ __le16 abi_patch;
+ __le16 count;
+ struct sof_manifest_tlv items[];
+};
+
#endif
diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h
index b72fa38..5caf75c 100644
--- a/include/uapi/sound/sof/tokens.h
+++ b/include/uapi/sound/sof/tokens.h
@@ -52,11 +52,17 @@
#define SOF_TKN_SCHED_FRAMES 204
#define SOF_TKN_SCHED_TIME_DOMAIN 205
#define SOF_TKN_SCHED_DYNAMIC_PIPELINE 206
+#define SOF_TKN_SCHED_LP_MODE 207
+#define SOF_TKN_SCHED_MEM_USAGE 208
/* volume */
#define SOF_TKN_VOLUME_RAMP_STEP_TYPE 250
#define SOF_TKN_VOLUME_RAMP_STEP_MS 251
+#define SOF_TKN_GAIN_RAMP_TYPE 260
+#define SOF_TKN_GAIN_RAMP_DURATION 261
+#define SOF_TKN_GAIN_VAL 262
+
/* SRC */
#define SOF_TKN_SRC_RATE_IN 300
#define SOF_TKN_SRC_RATE_OUT 301
@@ -79,6 +85,9 @@
*/
#define SOF_TKN_COMP_CORE_ID 404
#define SOF_TKN_COMP_UUID 405
+#define SOF_TKN_COMP_CPC 406
+#define SOF_TKN_COMP_IS_PAGES 409
+#define SOF_TKN_COMP_NUM_AUDIO_FORMATS 410
/* SSP */
#define SOF_TKN_INTEL_SSP_CLKS_CONTROL 500
@@ -145,4 +154,39 @@
#define SOF_TKN_MEDIATEK_AFE_CH 1601
#define SOF_TKN_MEDIATEK_AFE_FORMAT 1602
+/* MIXER */
+#define SOF_TKN_MIXER_TYPE 1700
+
+/* ACPDMIC */
+#define SOF_TKN_AMD_ACPDMIC_RATE 1800
+#define SOF_TKN_AMD_ACPDMIC_CH 1801
+
+/* CAVS AUDIO FORMAT */
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_RATE 1900
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_BIT_DEPTH 1901
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_VALID_BIT 1902
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_CHANNELS 1903
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_MAP 1904
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_CFG 1905
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_INTERLEAVING_STYLE 1906
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_FMT_CFG 1907
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_SAMPLE_TYPE 1908
+/* intentional token numbering discontinuity, reserved for future use */
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_RATE 1930
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_BIT_DEPTH 1931
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_VALID_BIT 1932
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CHANNELS 1933
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_MAP 1934
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_CFG 1935
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_INTERLEAVING_STYLE 1936
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_FMT_CFG 1937
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_SAMPLE_TYPE 1938
+/* intentional token numbering discontinuity, reserved for future use */
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IBS 1970
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OBS 1971
+#define SOF_TKN_CAVS_AUDIO_FORMAT_DMA_BUFFER_SIZE 1972
+
+/* COPIER */
+#define SOF_TKN_INTEL_COPIER_NODE_TYPE 1980
+
#endif
diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c
index 5cbc82e..0932473 100644
--- a/sound/soc/amd/acp-config.c
+++ b/sound/soc/amd/acp-config.c
@@ -130,4 +130,34 @@ struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[] = {
};
EXPORT_SYMBOL(snd_soc_acpi_amd_sof_machines);
+struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_sof_machines[] = {
+ {
+ .id = "AMDI1019",
+ .drv_name = "rmb-dsp",
+ .pdata = &acp_quirk_data,
+ .fw_filename = "sof-rmb.ri",
+ .sof_tplg_filename = "sof-acp-rmb.tplg",
+ },
+ {
+ .id = "10508825",
+ .drv_name = "nau8825-max",
+ .pdata = &acp_quirk_data,
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &_max,
+ .fw_filename = "sof-rmb.ri",
+ .sof_tplg_filename = "sof-rmb-nau8825-max98360.tplg",
+ },
+ {
+ .id = "RTL5682",
+ .drv_name = "rt5682s-hs-rt1019",
+ .pdata = &acp_quirk_data,
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &_rt1019,
+ .fw_filename = "sof-rmb.ri",
+ .sof_tplg_filename = "sof-rmb-rt5682s-rt1019.tplg",
+ },
+ {},
+};
+EXPORT_SYMBOL(snd_soc_acpi_amd_rmb_sof_machines);
+
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/amd/acp/Kconfig b/sound/soc/amd/acp/Kconfig
index 9dae271..7e56d26 100644
--- a/sound/soc/amd/acp/Kconfig
+++ b/sound/soc/amd/acp/Kconfig
@@ -49,6 +49,7 @@
select SND_SOC_RT1019
select SND_SOC_MAX98357A
select SND_SOC_RT5682S
+ select SND_SOC_NAU8825
help
This option enables common Machine driver module for ACP.
diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c
index 6ae454b..7530cab 100644
--- a/sound/soc/amd/acp/acp-mach-common.c
+++ b/sound/soc/amd/acp/acp-mach-common.c
@@ -24,6 +24,7 @@
#include "../../codecs/rt5682.h"
#include "../../codecs/rt1019.h"
#include "../../codecs/rt5682s.h"
+#include "../../codecs/nau8825.h"
#include "acp-mach.h"
#define PCO_PLAT_CLK 48000000
@@ -148,9 +149,14 @@ static int acp_card_hs_startup(struct snd_pcm_substream *substream)
struct acp_card_drvdata *drvdata = card->drvdata;
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
int ret;
+ unsigned int fmt;
- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBP_CFP);
+ if (drvdata->soc_mclk)
+ fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
+ else
+ fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP;
+
+ ret = snd_soc_dai_set_fmt(codec_dai, fmt);
if (ret < 0) {
dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret);
return ret;
@@ -161,10 +167,13 @@ static int acp_card_hs_startup(struct snd_pcm_substream *substream)
&constraints_channels);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_rates);
-
- ret = acp_clk_enable(drvdata);
- if (ret < 0)
- dev_err(rtd->card->dev, "Failed to enable HS clk: %d\n", ret);
+ if (!drvdata->soc_mclk) {
+ ret = acp_clk_enable(drvdata);
+ if (ret < 0) {
+ dev_err(rtd->card->dev, "Failed to enable HS clk: %d\n", ret);
+ return ret;
+ }
+ }
return ret;
}
@@ -175,7 +184,8 @@ static void acp_card_shutdown(struct snd_pcm_substream *substream)
struct snd_soc_card *card = rtd->card;
struct acp_card_drvdata *drvdata = card->drvdata;
- clk_disable_unprepare(drvdata->wclk);
+ if (!drvdata->soc_mclk)
+ clk_disable_unprepare(drvdata->wclk);
}
static const struct snd_soc_ops acp_card_rt5682_ops = {
@@ -199,6 +209,7 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
struct acp_card_drvdata *drvdata = card->drvdata;
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
struct snd_soc_component *component = codec_dai->component;
+ unsigned int fmt;
int ret;
dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name);
@@ -206,8 +217,12 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
if (drvdata->hs_codec_id != RT5682S)
return -EINVAL;
- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBP_CFP);
+ if (drvdata->soc_mclk)
+ fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
+ else
+ fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP;
+
+ ret = snd_soc_dai_set_fmt(codec_dai, fmt);
if (ret < 0) {
dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret);
return ret;
@@ -234,8 +249,10 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
- drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk");
- drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk");
+ if (!drvdata->soc_mclk) {
+ drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk");
+ drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk");
+ }
ret = snd_soc_card_jack_new(card, "Headset Jack",
SND_JACK_HEADSET | SND_JACK_LINEOUT |
@@ -296,6 +313,9 @@ static const struct snd_soc_ops acp_card_dmic_ops = {
SND_SOC_DAILINK_DEF(rt1019,
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC1019:00", "rt1019-aif"),
COMP_CODEC("i2c-10EC1019:01", "rt1019-aif")));
+SND_SOC_DAILINK_DEF(rt1019_1,
+ DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC1019:02", "rt1019-aif"),
+ COMP_CODEC("i2c-10EC1019:01", "rt1019-aif")));
static const struct snd_soc_dapm_route rt1019_map_lr[] = {
{ "Left Spk", NULL, "Left SPO" },
@@ -313,6 +333,17 @@ static struct snd_soc_codec_conf rt1019_conf[] = {
},
};
+static struct snd_soc_codec_conf rt1019_1_conf[] = {
+ {
+ .dlc = COMP_CODEC_CONF("i2c-10EC1019:02"),
+ .name_prefix = "Left",
+ },
+ {
+ .dlc = COMP_CODEC_CONF("i2c-10EC1019:01"),
+ .name_prefix = "Right",
+ },
+};
+
static int acp_card_rt1019_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
@@ -363,7 +394,7 @@ static int acp_card_amp_startup(struct snd_pcm_substream *substream)
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct acp_card_drvdata *drvdata = card->drvdata;
- int ret;
+ int ret = 0;
runtime->hw.channels_max = DUAL_CHANNEL;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
@@ -371,10 +402,13 @@ static int acp_card_amp_startup(struct snd_pcm_substream *substream)
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_rates);
- ret = acp_clk_enable(drvdata);
- if (ret < 0)
- dev_err(rtd->card->dev, "Failed to enable AMP clk: %d\n", ret);
-
+ if (!drvdata->soc_mclk) {
+ ret = acp_clk_enable(drvdata);
+ if (ret < 0) {
+ dev_err(rtd->card->dev, "Failed to enable AMP clk: %d\n", ret);
+ return ret;
+ }
+ }
return ret;
}
@@ -409,6 +443,104 @@ static const struct snd_soc_ops acp_card_maxim_ops = {
.shutdown = acp_card_shutdown,
};
+/* Declare nau8825 codec components */
+SND_SOC_DAILINK_DEF(nau8825,
+ DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10508825:00", "nau8825-hifi")));
+
+static const struct snd_soc_dapm_route nau8825_map[] = {
+ { "Headphone Jack", NULL, "HPOL" },
+ { "Headphone Jack", NULL, "HPOR" },
+};
+
+static int acp_card_nau8825_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct acp_card_drvdata *drvdata = card->drvdata;
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_component *component = codec_dai->component;
+ unsigned int fmt;
+ int ret;
+
+ dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name);
+
+ if (drvdata->hs_codec_id != NAU8825)
+ return -EINVAL;
+
+ if (drvdata->soc_mclk)
+ fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
+ else
+ fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP;
+
+ ret = snd_soc_dai_set_fmt(codec_dai, fmt);
+ if (ret < 0) {
+ dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret);
+ return ret;
+ }
+ ret = snd_soc_card_jack_new(card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_LINEOUT |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &pco_jack);
+ if (ret) {
+ dev_err(card->dev, "HP jack creation failed %d\n", ret);
+ return ret;
+ }
+
+ snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+ snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+ snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+
+ ret = snd_soc_component_set_jack(component, &pco_jack, NULL);
+ if (ret) {
+ dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
+ return ret;
+ }
+
+ return snd_soc_dapm_add_routes(&rtd->card->dapm, nau8825_map, ARRAY_SIZE(nau8825_map));
+}
+
+static int acp_nau8825_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ int ret;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_FS,
+ (48000 * 256), SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
+
+ ret = snd_soc_dai_set_pll(codec_dai, 0, 0, params_rate(params),
+ params_rate(params) * 256);
+ if (ret < 0) {
+ dev_err(rtd->dev, "can't set FLL: %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int acp_nau8825_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ runtime->hw.channels_max = 2;
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ &constraints_channels);
+
+ runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
+ snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+ return 0;
+}
+
+static const struct snd_soc_ops acp_card_nau8825_ops = {
+ .startup = acp_nau8825_startup,
+ .hw_params = acp_nau8825_hw_params,
+};
+
/* Declare DMIC codec components */
SND_SOC_DAILINK_DEF(dmic_codec,
DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
@@ -437,6 +569,8 @@ SND_SOC_DAILINK_DEF(i2s_sp,
DAILINK_COMP_ARRAY(COMP_CPU("acp-i2s-sp")));
SND_SOC_DAILINK_DEF(sof_sp,
DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-sp")));
+SND_SOC_DAILINK_DEF(sof_hs,
+ DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-hs")));
SND_SOC_DAILINK_DEF(sof_dmic,
DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-dmic")));
SND_SOC_DAILINK_DEF(pdm_dmic,
@@ -491,6 +625,37 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
i++;
}
+ if (drv_data->hs_cpu_id == I2S_HS) {
+ links[i].name = "acp-headset-codec";
+ links[i].id = HEADSET_BE_ID;
+ links[i].cpus = sof_hs;
+ links[i].num_cpus = ARRAY_SIZE(sof_hs);
+ links[i].platforms = sof_component;
+ links[i].num_platforms = ARRAY_SIZE(sof_component);
+ links[i].dpcm_playback = 1;
+ links[i].dpcm_capture = 1;
+ links[i].nonatomic = true;
+ links[i].no_pcm = 1;
+ if (!drv_data->hs_codec_id) {
+ /* Use dummy codec if codec id not specified */
+ links[i].codecs = dummy_codec;
+ links[i].num_codecs = ARRAY_SIZE(dummy_codec);
+ }
+ if (drv_data->hs_codec_id == NAU8825) {
+ links[i].codecs = nau8825;
+ links[i].num_codecs = ARRAY_SIZE(nau8825);
+ links[i].init = acp_card_nau8825_init;
+ links[i].ops = &acp_card_nau8825_ops;
+ }
+ if (drv_data->hs_codec_id == RT5682S) {
+ links[i].codecs = rt5682s;
+ links[i].num_codecs = ARRAY_SIZE(rt5682s);
+ links[i].init = acp_card_rt5682s_init;
+ links[i].ops = &acp_card_rt5682s_ops;
+ }
+ i++;
+ }
+
if (drv_data->amp_cpu_id == I2S_SP) {
links[i].name = "acp-amp-codec";
links[i].id = AMP_BE_ID;
@@ -523,6 +688,42 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
i++;
}
+ if (drv_data->amp_cpu_id == I2S_HS) {
+ links[i].name = "acp-amp-codec";
+ links[i].id = AMP_BE_ID;
+ links[i].cpus = sof_hs;
+ links[i].num_cpus = ARRAY_SIZE(sof_hs);
+ links[i].platforms = sof_component;
+ links[i].num_platforms = ARRAY_SIZE(sof_component);
+ links[i].dpcm_playback = 1;
+ links[i].nonatomic = true;
+ links[i].no_pcm = 1;
+ if (!drv_data->amp_codec_id) {
+ /* Use dummy codec if codec id not specified */
+ links[i].codecs = dummy_codec;
+ links[i].num_codecs = ARRAY_SIZE(dummy_codec);
+ }
+ if (drv_data->amp_codec_id == MAX98360A) {
+ links[i].codecs = max98360a;
+ links[i].num_codecs = ARRAY_SIZE(max98360a);
+ links[i].ops = &acp_card_maxim_ops;
+ links[i].init = acp_card_maxim_init;
+ }
+ if (drv_data->amp_codec_id == RT1019) {
+ links[i].codecs = rt1019;
+ links[i].num_codecs = ARRAY_SIZE(rt1019);
+ links[i].ops = &acp_card_rt1019_ops;
+ links[i].init = acp_card_rt1019_init;
+ card->codec_conf = rt1019_conf;
+ card->num_configs = ARRAY_SIZE(rt1019_conf);
+ links[i].codecs = rt1019_1;
+ links[i].num_codecs = ARRAY_SIZE(rt1019_1);
+ card->codec_conf = rt1019_1_conf;
+ card->num_configs = ARRAY_SIZE(rt1019_1_conf);
+ }
+ i++;
+ }
+
if (drv_data->dmic_cpu_id == DMIC) {
links[i].name = "acp-dmic-codec";
links[i].id = DMIC_BE_ID;
diff --git a/sound/soc/amd/acp/acp-mach.h b/sound/soc/amd/acp/acp-mach.h
index 5dc47cfb..c95ee1c 100644
--- a/sound/soc/amd/acp/acp-mach.h
+++ b/sound/soc/amd/acp/acp-mach.h
@@ -26,6 +26,7 @@ enum be_id {
enum cpu_endpoints {
NONE = 0,
+ I2S_HS,
I2S_SP,
I2S_BT,
DMIC,
@@ -37,6 +38,7 @@ enum codec_endpoints {
RT1019,
MAX98360A,
RT5682S,
+ NAU8825,
};
struct acp_card_drvdata {
@@ -49,6 +51,7 @@ struct acp_card_drvdata {
unsigned int dai_fmt;
struct clk *wclk;
struct clk *bclk;
+ bool soc_mclk;
};
int acp_sofdsp_dai_links_create(struct snd_soc_card *card);
diff --git a/sound/soc/amd/acp/acp-pdm.c b/sound/soc/amd/acp/acp-pdm.c
index 424c6e0..7a0b26a 100644
--- a/sound/soc/amd/acp/acp-pdm.c
+++ b/sound/soc/amd/acp/acp-pdm.c
@@ -174,7 +174,7 @@ static void acp_dmic_dai_shutdown(struct snd_pcm_substream *substream,
struct acp_dev_data *adata = dev_get_drvdata(dev);
u32 ext_int_ctrl;
- /* Disable DMIC interrrupts */
+ /* Disable DMIC interrupts */
ext_int_ctrl = readl(adata->acp_base + ACP_EXTERNAL_INTR_CNTL);
ext_int_ctrl |= ~PDM_DMA_INTR_MASK;
writel(ext_int_ctrl, adata->acp_base + ACP_EXTERNAL_INTR_CNTL);
diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c
index d1531cd..f19f064 100644
--- a/sound/soc/amd/acp/acp-sof-mach.c
+++ b/sound/soc/amd/acp/acp-sof-mach.c
@@ -56,6 +56,26 @@ static struct acp_card_drvdata sof_rt5682s_max_data = {
.dmic_codec_id = DMIC,
};
+static struct acp_card_drvdata sof_nau8825_data = {
+ .hs_cpu_id = I2S_HS,
+ .amp_cpu_id = I2S_HS,
+ .dmic_cpu_id = DMIC,
+ .hs_codec_id = NAU8825,
+ .amp_codec_id = MAX98360A,
+ .dmic_codec_id = DMIC,
+ .soc_mclk = true,
+};
+
+static struct acp_card_drvdata sof_rt5682s_hs_rt1019_data = {
+ .hs_cpu_id = I2S_HS,
+ .amp_cpu_id = I2S_HS,
+ .dmic_cpu_id = DMIC,
+ .hs_codec_id = RT5682S,
+ .amp_codec_id = RT1019,
+ .dmic_codec_id = DMIC,
+ .soc_mclk = true,
+};
+
static const struct snd_kcontrol_new acp_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
@@ -124,6 +144,14 @@ static const struct platform_device_id board_ids[] = {
.name = "rt5682s-rt1019",
.driver_data = (kernel_ulong_t)&sof_rt5682s_rt1019_data
},
+ {
+ .name = "nau8825-max",
+ .driver_data = (kernel_ulong_t)&sof_nau8825_data
+ },
+ {
+ .name = "rt5682s-hs-rt1019",
+ .driver_data = (kernel_ulong_t)&sof_rt5682s_hs_rt1019_data
+ },
{ }
};
static struct platform_driver acp_asoc_audio = {
@@ -143,4 +171,6 @@ MODULE_ALIAS("platform:rt5682-rt1019");
MODULE_ALIAS("platform:rt5682-max");
MODULE_ALIAS("platform:rt5682s-max");
MODULE_ALIAS("platform:rt5682s-rt1019");
+MODULE_ALIAS("platform:nau8825-max");
+MODULE_ALIAS("platform:rt5682s-hs-rt1019");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/amd/mach-config.h b/sound/soc/amd/mach-config.h
index 0a54567..7b4c625 100644
--- a/sound/soc/amd/mach-config.h
+++ b/sound/soc/amd/mach-config.h
@@ -19,6 +19,7 @@
#define ACP_PCI_DEV_ID 0x15E2
extern struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[];
+extern struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_sof_machines[];
struct config_entry {
u32 flags;
diff --git a/sound/soc/amd/vangogh/acp5x-i2s.c b/sound/soc/amd/vangogh/acp5x-i2s.c
index 59a98f8..72c8c68 100644
--- a/sound/soc/amd/vangogh/acp5x-i2s.c
+++ b/sound/soc/amd/vangogh/acp5x-i2s.c
@@ -37,10 +37,10 @@ static int acp5x_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
}
mode = fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK;
switch (mode) {
- case SND_SOC_DAIFMT_CBC_CFC:
+ case SND_SOC_DAIFMT_BP_FP:
adata->master_mode = I2S_MASTER_MODE_ENABLE;
break;
- case SND_SOC_DAIFMT_CBP_CFP:
+ case SND_SOC_DAIFMT_BC_FC:
adata->master_mode = I2S_MASTER_MODE_DISABLE;
break;
}
diff --git a/sound/soc/atmel/atmel-i2s.c b/sound/soc/atmel/atmel-i2s.c
index 1934767..ba56d6a 100644
--- a/sound/soc/atmel/atmel-i2s.c
+++ b/sound/soc/atmel/atmel-i2s.c
@@ -343,7 +343,7 @@ static int atmel_i2s_hw_params(struct snd_pcm_substream *substream,
}
switch (dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
- case SND_SOC_DAIFMT_CBC_CFC:
+ case SND_SOC_DAIFMT_BP_FP:
/* codec is slave, so cpu is master */
mr |= ATMEL_I2SC_MR_MODE_MASTER;
ret = atmel_i2s_get_gck_param(dev, params_rate(params));
@@ -351,7 +351,7 @@ static int atmel_i2s_hw_params(struct snd_pcm_substream *substream,
return ret;
break;
- case SND_SOC_DAIFMT_CBP_CFP:
+ case SND_SOC_DAIFMT_BC_FC:
/* codec is master, so cpu is slave */
mr |= ATMEL_I2SC_MR_MODE_SLAVE;
dev->gck_param = NULL;
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index c1dea8d..c92905e 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -210,7 +210,7 @@ static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params,
return frame_size;
switch (ssc_p->daifmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
- case SND_SOC_DAIFMT_CBP_CFC:
+ case SND_SOC_DAIFMT_BC_FP:
if ((ssc_p->dir_mask & SSC_DIR_MASK_CAPTURE)
&& ssc->clk_from_rk_pin)
/* Receiver Frame Synchro (i.e. capture)
@@ -220,7 +220,7 @@ static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params,
mck_div = 3;
break;
- case SND_SOC_DAIFMT_CBP_CFP:
+ case SND_SOC_DAIFMT_BC_FC:
if ((ssc_p->dir_mask & SSC_DIR_MASK_PLAYBACK)
&& !ssc->clk_from_rk_pin)
/* Transmit Frame Synchro (i.e. playback)
@@ -233,7 +233,7 @@ static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params,
}
switch (ssc_p->daifmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
- case SND_SOC_DAIFMT_CBC_CFC:
+ case SND_SOC_DAIFMT_BP_FP:
r.num = ssc_p->mck_rate / mck_div / frame_size;
ret = snd_interval_ratnum(i, 1, &r, &num, &den);
@@ -243,8 +243,8 @@ static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params,
}
break;
- case SND_SOC_DAIFMT_CBP_CFC:
- case SND_SOC_DAIFMT_CBP_CFP:
+ case SND_SOC_DAIFMT_BC_FP:
+ case SND_SOC_DAIFMT_BC_FC:
t.min = 8000;
t.max = ssc_p->mck_rate / mck_div / frame_size;
t.openmin = t.openmax = 0;
@@ -433,8 +433,8 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
static int atmel_ssc_cfs(struct atmel_ssc_info *ssc_p)
{
switch (ssc_p->daifmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
- case SND_SOC_DAIFMT_CBP_CFC:
- case SND_SOC_DAIFMT_CBC_CFC:
+ case SND_SOC_DAIFMT_BC_FP:
+ case SND_SOC_DAIFMT_BP_FP:
return 1;
}
return 0;
@@ -444,8 +444,8 @@ static int atmel_ssc_cfs(struct atmel_ssc_info *ssc_p)
static int atmel_ssc_cbs(struct atmel_ssc_info *ssc_p)
{
switch (ssc_p->daifmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
- case SND_SOC_DAIFMT_CBC_CFP:
- case SND_SOC_DAIFMT_CBC_CFC:
+ case SND_SOC_DAIFMT_BP_FC:
+ case SND_SOC_DAIFMT_BP_FP:
return 1;
}
return 0;
diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c
index 6d1227a..269eab5 100644
--- a/sound/soc/atmel/mchp-i2s-mcc.c
+++ b/sound/soc/atmel/mchp-i2s-mcc.c
@@ -350,7 +350,7 @@ static int mchp_i2s_mcc_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return -EINVAL;
/* We can't generate only FSYNC */
- if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == SND_SOC_DAIFMT_CBP_CFC)
+ if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == SND_SOC_DAIFMT_BC_FP)
return -EINVAL;
/* We can only reconfigure the IP when it's stopped */
@@ -547,19 +547,19 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
}
switch (dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
- case SND_SOC_DAIFMT_CBC_CFC:
+ case SND_SOC_DAIFMT_BP_FP:
/* cpu is BCLK and LRC master */
mra |= MCHP_I2SMCC_MRA_MODE_MASTER;
if (dev->sysclk)
mra |= MCHP_I2SMCC_MRA_IMCKMODE_GEN;
set_divs = 1;
break;
- case SND_SOC_DAIFMT_CBC_CFP:
+ case SND_SOC_DAIFMT_BP_FC:
/* cpu is BCLK master */
mrb |= MCHP_I2SMCC_MRB_CLKSEL_INT;
set_divs = 1;
fallthrough;
- case SND_SOC_DAIFMT_CBP_CFP:
+ case SND_SOC_DAIFMT_BC_FC:
/* cpu is slave */
mra |= MCHP_I2SMCC_MRA_MODE_SLAVE;
if (dev->sysclk)
diff --git a/sound/soc/atmel/mchp-pdmc.c b/sound/soc/atmel/mchp-pdmc.c
index a3856c7..b9f6370 100644
--- a/sound/soc/atmel/mchp-pdmc.c
+++ b/sound/soc/atmel/mchp-pdmc.c
@@ -492,8 +492,8 @@ static int mchp_pdmc_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
unsigned int fmt_format = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
/* IP needs to be bitclock master */
- if (fmt_master != SND_SOC_DAIFMT_CBS_CFS &&
- fmt_master != SND_SOC_DAIFMT_CBS_CFM)
+ if (fmt_master != SND_SOC_DAIFMT_BP_FP &&
+ fmt_master != SND_SOC_DAIFMT_BP_FC)
return -EINVAL;
/* IP supports only PDM interface */
diff --git a/sound/soc/au1x/i2sc.c b/sound/soc/au1x/i2sc.c
index 740d4e0..45bb785 100644
--- a/sound/soc/au1x/i2sc.c
+++ b/sound/soc/au1x/i2sc.c
@@ -121,7 +121,7 @@ static int au1xi2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
/* I2S controller only supports provider */
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
- case SND_SOC_DAIFMT_CBC_CFC: /* CODEC consumer */
+ case SND_SOC_DAIFMT_BP_FP: /* CODEC consumer */
break;
default:
goto out;
diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c
index b2b8896..530a072 100644
--- a/sound/soc/au1x/psc-i2s.c
+++ b/sound/soc/au1x/psc-i2s.c
@@ -91,10 +91,10 @@ static int au1xpsc_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
}
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
- case SND_SOC_DAIFMT_CBP_CFP: /* CODEC provider */
+ case SND_SOC_DAIFMT_BC_FC: /* CODEC provider */
ct |= PSC_I2SCFG_MS; /* PSC I2S consumer mode */
break;
- case SND_SOC_DAIFMT_CBC_CFC: /* CODEC consumer */
+ case SND_SOC_DAIFMT_BP_FP: /* CODEC consumer */
ct &= ~PSC_I2SCFG_MS; /* PSC I2S provider mode */
break;
default:
diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c
index e3fc4be..e39c8d9 100644
--- a/sound/soc/bcm/bcm2835-i2s.c
+++ b/sound/soc/bcm/bcm2835-i2s.c
@@ -133,8 +133,8 @@ static void bcm2835_i2s_start_clock(struct bcm2835_i2s_dev *dev)
return;
switch (provider) {
- case SND_SOC_DAIFMT_CBC_CFC:
- case SND_SOC_DAIFMT_CBC_CFP:
+ case SND_SOC_DAIFMT_BP_FP:
+ case SND_SOC_DAIFMT_BP_FC:
clk_prepare_enable(dev->clk);
dev->clk_prepared = true;
break;
@@ -385,12 +385,12 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream,
/* Check if CPU is bit clock provider */
switch (dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
- case SND_SOC_DAIFMT_CBC_CFC:
- case SND_SOC_DAIFMT_CBC_CFP:
+ case SND_SOC_DAIFMT_BP_FP:
+ case SND_SOC_DAIFMT_BP_FC:
bit_clock_provider = true;
break;
- case SND_SOC_DAIFMT_CBP_CFC:
- case SND_SOC_DAIFMT_CBP_CFP:
+ case SND_SOC_DAIFMT_BC_FP:
+ case SND_SOC_DAIFMT_BC_FC:
bit_clock_provider = false;
break;
default:
@@ -399,12 +399,12 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream,
/* Check if CPU is frame sync provider */
switch (dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
- case SND_SOC_DAIFMT_CBC_CFC:
- case SND_SOC_DAIFMT_CBP_CFC:
+ case SND_SOC_DAIFMT_BP_FP:
+ case SND_SOC_DAIFMT_BC_FP:
frame_sync_provider = true;
break;
- case SND_SOC_DAIFMT_CBC_CFP:
- case SND_SOC_DAIFMT_CBP_CFP:
+ case SND_SOC_DAIFMT_BP_FC:
+ case SND_SOC_DAIFMT_BC_FC:
frame_sync_provider = false;
break;
default:
diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index 9698f453..4bfa2d7 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -849,11 +849,11 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
ssp_newcfg = 0;
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
- case SND_SOC_DAIFMT_CBP_CFP:
+ case SND_SOC_DAIFMT_BC_FC:
ssp_newcfg |= BIT(I2S_OUT_CFGX_SLAVE_MODE);
aio->is_slave = 1;
break;
- case SND_SOC_DAIFMT_CBC_CFC:
+ case SND_SOC_DAIFMT_BP_FP:
ssp_newcfg &= ~BIT(I2S_OUT_CFGX_SLAVE_MODE);
aio->is_slave = 0;
break;
diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c
index 2c8cd84..4795979 100644
--- a/sound/soc/cirrus/ep93xx-i2s.c
+++ b/sound/soc/cirrus/ep93xx-i2s.c
@@ -246,12 +246,12 @@ static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
}
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
- case SND_SOC_DAIFMT_CBC_CFC:
+ case SND_SOC_DAIFMT_BP_FP:
/* CPU is provider */
clk_cfg |= EP93XX_I2S_CLKCFG_MASTER;
break;
- case SND_SOC_DAIFMT_CBP_CFP:
+ case SND_SOC_DAIFMT_BC_FC:
/* Codec is provider */
clk_cfg &= ~EP93XX_I2S_CLKCFG_MASTER;
break;
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 6165db9..5a60633 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -937,6 +937,16 @@
tristate
select SND_HDA
+config SND_SOC_HDA
+ tristate "HD-Audio codec driver"
+ select SND_HDA_EXT_CORE
+ select SND_HDA
+ help
+ This enables HD-Audio codec support in ASoC subsystem. Compared
+ to SND_SOC_HDAC_HDA, driver's behavior is identical to HD-Audio
+ legacy solution - including the dynamic resource allocation
+ based on actual codec capabilities.
+
config SND_SOC_ICS43432
tristate "ICS43423 and compatible i2s microphones"
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 28dc4ed..d32026a 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -106,6 +106,7 @@
snd-soc-gtm601-objs := gtm601.o
snd-soc-hdac-hdmi-objs := hdac_hdmi.o
snd-soc-hdac-hda-objs := hdac_hda.o
+snd-soc-hda-codec-objs := hda.o hda-dai.o
snd-soc-ics43432-objs := ics43432.o
snd-soc-inno-rk3036-objs := inno_rk3036.o
snd-soc-isabelle-objs := isabelle.o
@@ -458,6 +459,7 @@
obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o
obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o
obj-$(CONFIG_SND_SOC_HDAC_HDA) += snd-soc-hdac-hda.o
+obj-$(CONFIG_SND_SOC_HDA) += snd-soc-hda-codec.o
obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o
obj-$(CONFIG_SND_SOC_INNO_RK3036) += snd-soc-inno-rk3036.o
obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
index aefafb0..cbd4a92 100644
--- a/sound/soc/codecs/ab8500-codec.c
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -12,8 +12,6 @@
* Mikko Sarmanne <mikko.sarmanne@symbio.com>,
* Jarmo K. Kuronen <jarmo.kuronen@symbio.com>,
* for ST-Ericsson.
- *
- * License terms:
*/
#include <linux/kernel.h>
diff --git a/sound/soc/codecs/ab8500-codec.h b/sound/soc/codecs/ab8500-codec.h
index 0ac87d0..2a6f640 100644
--- a/sound/soc/codecs/ab8500-codec.h
+++ b/sound/soc/codecs/ab8500-codec.h
@@ -11,8 +11,6 @@
* Mikko J. Lehto <mikko.lehto@symbio.com>,
* Mikko Sarmanne <mikko.sarmanne@symbio.com>,
* for ST-Ericsson.
- *
- * License terms:
*/
#ifndef AB8500_CODEC_REGISTERS_H
diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c
index 93606e5..d29d5e0 100644
--- a/sound/soc/codecs/ak4613.c
+++ b/sound/soc/codecs/ak4613.c
@@ -921,18 +921,12 @@ static int ak4613_i2c_probe(struct i2c_client *i2c)
&ak4613_dai, 1);
}
-static int ak4613_i2c_remove(struct i2c_client *client)
-{
- return 0;
-}
-
static struct i2c_driver ak4613_i2c_driver = {
.driver = {
.name = "ak4613-codec",
.of_match_table = ak4613_of_match,
},
.probe_new = ak4613_i2c_probe,
- .remove = ak4613_i2c_remove,
.id_table = ak4613_i2c_id,
};
diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c
index 8b0a9c7..11e7b3f 100644
--- a/sound/soc/codecs/cros_ec_codec.c
+++ b/sound/soc/codecs/cros_ec_codec.c
@@ -995,6 +995,7 @@ static int cros_ec_codec_platform_probe(struct platform_device *pdev)
dev_dbg(dev, "ap_shm_phys_addr=%#llx len=%#x\n",
priv->ap_shm_phys_addr, priv->ap_shm_len);
}
+ of_node_put(node);
}
#endif
diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c
index 6d3070e..0c7d1c7 100644
--- a/sound/soc/codecs/cs35l41-lib.c
+++ b/sound/soc/codecs/cs35l41-lib.c
@@ -1302,7 +1302,8 @@ int cs35l41_set_cspl_mbox_cmd(struct device *dev, struct regmap *regmap,
return 0;
}
- dev_err(dev, "Failed to set mailbox cmd %u (status %u)\n", cmd, sts);
+ if (cmd != CSPL_MBOX_CMD_OUT_OF_HIBERNATE)
+ dev_err(dev, "Failed to set mailbox cmd %u (status %u)\n", cmd, sts);
return -ENOMSG;
}
@@ -1321,6 +1322,85 @@ int cs35l41_write_fs_errata(struct device *dev, struct regmap *regmap)
}
EXPORT_SYMBOL_GPL(cs35l41_write_fs_errata);
+int cs35l41_enter_hibernate(struct device *dev, struct regmap *regmap,
+ enum cs35l41_boost_type b_type)
+{
+ if (!cs35l41_safe_reset(regmap, b_type)) {
+ dev_dbg(dev, "System does not support Suspend\n");
+ return -EINVAL;
+ }
+
+ dev_dbg(dev, "Enter hibernate\n");
+ regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0088);
+ regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0188);
+
+ // Don't wait for ACK since bus activity would wake the device
+ regmap_write(regmap, CS35L41_DSP_VIRT1_MBOX_1, CSPL_MBOX_CMD_HIBERNATE);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cs35l41_enter_hibernate);
+
+static void cs35l41_wait_for_pwrmgt_sts(struct device *dev, struct regmap *regmap)
+{
+ const int pwrmgt_retries = 10;
+ unsigned int sts;
+ int i, ret;
+
+ for (i = 0; i < pwrmgt_retries; i++) {
+ ret = regmap_read(regmap, CS35L41_PWRMGT_STS, &sts);
+ if (ret)
+ dev_err(dev, "Failed to read PWRMGT_STS: %d\n", ret);
+ else if (!(sts & CS35L41_WR_PEND_STS_MASK))
+ return;
+
+ udelay(20);
+ }
+
+ dev_err(dev, "Timed out reading PWRMGT_STS\n");
+}
+
+int cs35l41_exit_hibernate(struct device *dev, struct regmap *regmap)
+{
+ const int wake_retries = 20;
+ const int sleep_retries = 5;
+ int ret, i, j;
+
+ for (i = 0; i < sleep_retries; i++) {
+ dev_dbg(dev, "Exit hibernate\n");
+
+ for (j = 0; j < wake_retries; j++) {
+ ret = cs35l41_set_cspl_mbox_cmd(dev, regmap,
+ CSPL_MBOX_CMD_OUT_OF_HIBERNATE);
+ if (!ret)
+ break;
+
+ usleep_range(100, 200);
+ }
+
+ if (j < wake_retries) {
+ dev_dbg(dev, "Wake success at cycle: %d\n", j);
+ return 0;
+ }
+
+ dev_err(dev, "Wake failed, re-enter hibernate: %d\n", ret);
+
+ cs35l41_wait_for_pwrmgt_sts(dev, regmap);
+ regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0088);
+
+ cs35l41_wait_for_pwrmgt_sts(dev, regmap);
+ regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0188);
+
+ cs35l41_wait_for_pwrmgt_sts(dev, regmap);
+ regmap_write(regmap, CS35L41_PWRMGT_CTL, 0x3);
+ }
+
+ dev_err(dev, "Timed out waking device\n");
+
+ return -ETIMEDOUT;
+}
+EXPORT_SYMBOL_GPL(cs35l41_exit_hibernate);
+
MODULE_DESCRIPTION("CS35L41 library");
MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, <david.rhodes@cirrus.com>");
MODULE_AUTHOR("Lucas Tanure, Cirrus Logic Inc, <tanureal@opensource.cirrus.com>");
diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c
index 3e68a07..a115ea3 100644
--- a/sound/soc/codecs/cs35l41.c
+++ b/sound/soc/codecs/cs35l41.c
@@ -1335,15 +1335,7 @@ static int __maybe_unused cs35l41_runtime_suspend(struct device *dev)
if (!cs35l41->dsp.preloaded || !cs35l41->dsp.cs_dsp.running)
return 0;
- dev_dbg(cs35l41->dev, "Enter hibernate\n");
-
- cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type);
- regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0088);
- regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0188);
-
- // Don't wait for ACK since bus activity would wake the device
- regmap_write(cs35l41->regmap, CS35L41_DSP_VIRT1_MBOX_1,
- CSPL_MBOX_CMD_HIBERNATE);
+ cs35l41_enter_hibernate(dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type);
regcache_cache_only(cs35l41->regmap, true);
regcache_mark_dirty(cs35l41->regmap);
@@ -1351,65 +1343,6 @@ static int __maybe_unused cs35l41_runtime_suspend(struct device *dev)
return 0;
}
-static void cs35l41_wait_for_pwrmgt_sts(struct cs35l41_private *cs35l41)
-{
- const int pwrmgt_retries = 10;
- unsigned int sts;
- int i, ret;
-
- for (i = 0; i < pwrmgt_retries; i++) {
- ret = regmap_read(cs35l41->regmap, CS35L41_PWRMGT_STS, &sts);
- if (ret)
- dev_err(cs35l41->dev, "Failed to read PWRMGT_STS: %d\n", ret);
- else if (!(sts & CS35L41_WR_PEND_STS_MASK))
- return;
-
- udelay(20);
- }
-
- dev_err(cs35l41->dev, "Timed out reading PWRMGT_STS\n");
-}
-
-static int cs35l41_exit_hibernate(struct cs35l41_private *cs35l41)
-{
- const int wake_retries = 20;
- const int sleep_retries = 5;
- int ret, i, j;
-
- for (i = 0; i < sleep_retries; i++) {
- dev_dbg(cs35l41->dev, "Exit hibernate\n");
-
- for (j = 0; j < wake_retries; j++) {
- ret = cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap,
- CSPL_MBOX_CMD_OUT_OF_HIBERNATE);
- if (!ret)
- break;
-
- usleep_range(100, 200);
- }
-
- if (j < wake_retries) {
- dev_dbg(cs35l41->dev, "Wake success at cycle: %d\n", j);
- return 0;
- }
-
- dev_err(cs35l41->dev, "Wake failed, re-enter hibernate: %d\n", ret);
-
- cs35l41_wait_for_pwrmgt_sts(cs35l41);
- regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0088);
-
- cs35l41_wait_for_pwrmgt_sts(cs35l41);
- regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0188);
-
- cs35l41_wait_for_pwrmgt_sts(cs35l41);
- regmap_write(cs35l41->regmap, CS35L41_PWRMGT_CTL, 0x3);
- }
-
- dev_err(cs35l41->dev, "Timed out waking device\n");
-
- return -ETIMEDOUT;
-}
-
static int __maybe_unused cs35l41_runtime_resume(struct device *dev)
{
struct cs35l41_private *cs35l41 = dev_get_drvdata(dev);
@@ -1422,7 +1355,7 @@ static int __maybe_unused cs35l41_runtime_resume(struct device *dev)
regcache_cache_only(cs35l41->regmap, false);
- ret = cs35l41_exit_hibernate(cs35l41);
+ ret = cs35l41_exit_hibernate(cs35l41->dev, cs35l41->regmap);
if (ret)
return ret;
diff --git a/sound/soc/codecs/cs35l45-i2c.c b/sound/soc/codecs/cs35l45-i2c.c
index 38a4dbc..06c2ddf 100644
--- a/sound/soc/codecs/cs35l45-i2c.c
+++ b/sound/soc/codecs/cs35l45-i2c.c
@@ -40,7 +40,9 @@ static int cs35l45_i2c_remove(struct i2c_client *client)
{
struct cs35l45_private *cs35l45 = i2c_get_clientdata(client);
- return cs35l45_remove(cs35l45);
+ cs35l45_remove(cs35l45);
+
+ return 0;
}
static const struct of_device_id cs35l45_of_match[] = {
diff --git a/sound/soc/codecs/cs35l45.c b/sound/soc/codecs/cs35l45.c
index 2367c1a..c94edfc 100644
--- a/sound/soc/codecs/cs35l45.c
+++ b/sound/soc/codecs/cs35l45.c
@@ -665,7 +665,7 @@ int cs35l45_probe(struct cs35l45_private *cs35l45)
}
EXPORT_SYMBOL_NS_GPL(cs35l45_probe, SND_SOC_CS35L45);
-int cs35l45_remove(struct cs35l45_private *cs35l45)
+void cs35l45_remove(struct cs35l45_private *cs35l45)
{
pm_runtime_disable(cs35l45->dev);
@@ -673,8 +673,6 @@ int cs35l45_remove(struct cs35l45_private *cs35l45)
regulator_disable(cs35l45->vdd_a);
/* VDD_BATT must be the last to power-off */
regulator_disable(cs35l45->vdd_batt);
-
- return 0;
}
EXPORT_SYMBOL_NS_GPL(cs35l45_remove, SND_SOC_CS35L45);
diff --git a/sound/soc/codecs/cs35l45.h b/sound/soc/codecs/cs35l45.h
index 4e266d1..53fe9d2 100644
--- a/sound/soc/codecs/cs35l45.h
+++ b/sound/soc/codecs/cs35l45.h
@@ -209,9 +209,9 @@ struct cs35l45_private {
extern const struct dev_pm_ops cs35l45_pm_ops;
extern const struct regmap_config cs35l45_i2c_regmap;
extern const struct regmap_config cs35l45_spi_regmap;
-int cs35l45_apply_patch(struct cs35l45_private *cs43l45);
+int cs35l45_apply_patch(struct cs35l45_private *cs35l45);
unsigned int cs35l45_get_clk_freq_id(unsigned int freq);
int cs35l45_probe(struct cs35l45_private *cs35l45);
-int cs35l45_remove(struct cs35l45_private *cs35l45);
+void cs35l45_remove(struct cs35l45_private *cs35l45);
#endif /* CS35L45_H */
diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c
index 4fade23..6ca74c0 100644
--- a/sound/soc/codecs/cs42l42.c
+++ b/sound/soc/codecs/cs42l42.c
@@ -1701,8 +1701,7 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data)
break;
default:
- if (cs42l42->plug_state != CS42L42_TS_TRANS)
- cs42l42->plug_state = CS42L42_TS_TRANS;
+ cs42l42->plug_state = CS42L42_TS_TRANS;
}
}
diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c
index b35debb..b6667e8 100644
--- a/sound/soc/codecs/cx2072x.c
+++ b/sound/soc/codecs/cx2072x.c
@@ -710,22 +710,19 @@ static int cx2072x_config_i2spcm(struct cx2072x_priv *cx2072x)
regdbt2.ulval = 0xac;
- /* set master/slave */
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBP_CFP:
reg2.r.tx_master = 1;
reg3.r.rx_master = 1;
- dev_dbg(dev, "Sets Master mode\n");
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
reg2.r.tx_master = 0;
reg3.r.rx_master = 0;
- dev_dbg(dev, "Sets Slave mode\n");
break;
default:
- dev_err(dev, "Unsupported DAI master mode\n");
+ dev_err(dev, "Unsupported DAI clocking mode\n");
return -EINVAL;
}
@@ -1009,9 +1006,9 @@ static int cx2072x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
dev_dbg(dev, "set_dai_fmt- %08x\n", fmt);
/* set master/slave */
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBP_CFP:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index 3fa3042..76a2197 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -1335,6 +1335,8 @@ static int __init da7210_modinit(void)
int ret = 0;
#if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&da7210_i2c_driver);
+ if (ret)
+ return ret;
#endif
#if defined(CONFIG_SPI_MASTER)
ret = spi_register_driver(&da7210_spi_driver);
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
index 7fdef38..c18f76f 100644
--- a/sound/soc/codecs/da7219.c
+++ b/sound/soc/codecs/da7219.c
@@ -2693,11 +2693,6 @@ static int da7219_i2c_probe(struct i2c_client *i2c)
return ret;
}
-static int da7219_i2c_remove(struct i2c_client *client)
-{
- return 0;
-}
-
static const struct i2c_device_id da7219_i2c_id[] = {
{ "da7219", },
{ }
@@ -2711,7 +2706,6 @@ static struct i2c_driver da7219_i2c_driver = {
.acpi_match_table = ACPI_PTR(da7219_acpi_match),
},
.probe_new = da7219_i2c_probe,
- .remove = da7219_i2c_remove,
.id_table = da7219_i2c_id,
};
diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c
index f14cddf..3f1cfee 100644
--- a/sound/soc/codecs/da732x.c
+++ b/sound/soc/codecs/da732x.c
@@ -1546,11 +1546,6 @@ static int da732x_i2c_probe(struct i2c_client *i2c)
return ret;
}
-static int da732x_i2c_remove(struct i2c_client *client)
-{
- return 0;
-}
-
static const struct i2c_device_id da732x_i2c_id[] = {
{ "da7320", 0},
{ }
@@ -1562,7 +1557,6 @@ static struct i2c_driver da732x_i2c_driver = {
.name = "da7320",
},
.probe_new = da732x_i2c_probe,
- .remove = da732x_i2c_remove,
.id_table = da732x_i2c_id,
};
diff --git a/sound/soc/codecs/hda-dai.c b/sound/soc/codecs/hda-dai.c
new file mode 100644
index 0000000..5371ff0
--- /dev/null
+++ b/sound/soc/codecs/hda-dai.c
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Author: Cezary Rojewski <cezary.rojewski@intel.com>
+//
+
+#include <sound/soc.h>
+#include <sound/hda_codec.h>
+#include "hda.h"
+
+static int hda_codec_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ struct hda_pcm_stream *stream_info;
+ struct hda_codec *codec;
+ struct hda_pcm *pcm;
+ int ret;
+
+ codec = dev_to_hda_codec(dai->dev);
+ stream_info = snd_soc_dai_get_dma_data(dai, substream);
+ pcm = container_of(stream_info, struct hda_pcm, stream[substream->stream]);
+
+ dev_dbg(dai->dev, "open stream codec: %08x, info: %p, pcm: %p %s substream: %p\n",
+ codec->core.vendor_id, stream_info, pcm, pcm->name, substream);
+
+ snd_hda_codec_pcm_get(pcm);
+
+ ret = stream_info->ops.open(stream_info, codec, substream);
+ if (ret < 0) {
+ dev_err(dai->dev, "codec open failed: %d\n", ret);
+ snd_hda_codec_pcm_put(pcm);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void hda_codec_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ struct hda_pcm_stream *stream_info;
+ struct hda_codec *codec;
+ struct hda_pcm *pcm;
+ int ret;
+
+ codec = dev_to_hda_codec(dai->dev);
+ stream_info = snd_soc_dai_get_dma_data(dai, substream);
+ pcm = container_of(stream_info, struct hda_pcm, stream[substream->stream]);
+
+ dev_dbg(dai->dev, "close stream codec: %08x, info: %p, pcm: %p %s substream: %p\n",
+ codec->core.vendor_id, stream_info, pcm, pcm->name, substream);
+
+ ret = stream_info->ops.close(stream_info, codec, substream);
+ if (ret < 0)
+ dev_err(dai->dev, "codec close failed: %d\n", ret);
+
+ snd_hda_codec_pcm_put(pcm);
+}
+
+static int hda_codec_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ struct hda_pcm_stream *stream_info;
+ struct hda_codec *codec;
+
+ codec = dev_to_hda_codec(dai->dev);
+ stream_info = snd_soc_dai_get_dma_data(dai, substream);
+
+ snd_hda_codec_cleanup(codec, stream_info, substream);
+
+ return 0;
+}
+
+static int hda_codec_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct hda_pcm_stream *stream_info;
+ struct hdac_stream *stream;
+ struct hda_codec *codec;
+ unsigned int format;
+ int ret;
+
+ codec = dev_to_hda_codec(dai->dev);
+ stream = substream->runtime->private_data;
+ stream_info = snd_soc_dai_get_dma_data(dai, substream);
+ format = snd_hdac_calc_stream_format(runtime->rate, runtime->channels, runtime->format,
+ runtime->sample_bits, 0);
+
+ ret = snd_hda_codec_prepare(codec, stream_info, stream->stream_tag, format, substream);
+ if (ret < 0) {
+ dev_err(dai->dev, "codec prepare failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+const struct snd_soc_dai_ops snd_soc_hda_codec_dai_ops = {
+ .startup = hda_codec_dai_startup,
+ .shutdown = hda_codec_dai_shutdown,
+ .hw_free = hda_codec_dai_hw_free,
+ .prepare = hda_codec_dai_prepare,
+};
+EXPORT_SYMBOL_GPL(snd_soc_hda_codec_dai_ops);
diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c
new file mode 100644
index 0000000..edcb8bc
--- /dev/null
+++ b/sound/soc/codecs/hda.c
@@ -0,0 +1,395 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Author: Cezary Rojewski <cezary.rojewski@intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <sound/soc.h>
+#include <sound/hdaudio_ext.h>
+#include <sound/hda_i915.h>
+#include <sound/hda_codec.h>
+#include "hda.h"
+
+static int hda_codec_create_dais(struct hda_codec *codec, int pcm_count,
+ struct snd_soc_dai_driver **drivers)
+{
+ struct device *dev = &codec->core.dev;
+ struct snd_soc_dai_driver *drvs;
+ struct hda_pcm *pcm;
+ int i;
+
+ drvs = devm_kcalloc(dev, pcm_count, sizeof(*drvs), GFP_KERNEL);
+ if (!drvs)
+ return -ENOMEM;
+
+ pcm = list_first_entry(&codec->pcm_list_head, struct hda_pcm, list);
+
+ for (i = 0; i < pcm_count; i++, pcm = list_next_entry(pcm, list)) {
+ struct snd_soc_pcm_stream *stream;
+ int dir;
+
+ dev_info(dev, "creating for %s %d\n", pcm->name, i);
+ drvs[i].id = i;
+ drvs[i].name = pcm->name;
+ drvs[i].ops = &snd_soc_hda_codec_dai_ops;
+
+ dir = SNDRV_PCM_STREAM_PLAYBACK;
+ stream = &drvs[i].playback;
+ if (!pcm->stream[dir].substreams) {
+ dev_info(dev, "skipping playback dai for %s\n", pcm->name);
+ goto capture_dais;
+ }
+
+ stream->stream_name =
+ devm_kasprintf(dev, GFP_KERNEL, "%s %s", pcm->name,
+ snd_pcm_direction_name(dir));
+ if (!stream->stream_name)
+ return -ENOMEM;
+ stream->channels_min = pcm->stream[dir].channels_min;
+ stream->channels_max = pcm->stream[dir].channels_max;
+ stream->rates = pcm->stream[dir].rates;
+ stream->formats = pcm->stream[dir].formats;
+ stream->sig_bits = pcm->stream[dir].maxbps;
+
+capture_dais:
+ dir = SNDRV_PCM_STREAM_CAPTURE;
+ stream = &drvs[i].capture;
+ if (!pcm->stream[dir].substreams) {
+ dev_info(dev, "skipping capture dai for %s\n", pcm->name);
+ continue;
+ }
+
+ stream->stream_name =
+ devm_kasprintf(dev, GFP_KERNEL, "%s %s", pcm->name,
+ snd_pcm_direction_name(dir));
+ if (!stream->stream_name)
+ return -ENOMEM;
+ stream->channels_min = pcm->stream[dir].channels_min;
+ stream->channels_max = pcm->stream[dir].channels_max;
+ stream->rates = pcm->stream[dir].rates;
+ stream->formats = pcm->stream[dir].formats;
+ stream->sig_bits = pcm->stream[dir].maxbps;
+ }
+
+ *drivers = drvs;
+ return 0;
+}
+
+static int hda_codec_register_dais(struct hda_codec *codec, struct snd_soc_component *component)
+{
+ struct snd_soc_dai_driver *drvs = NULL;
+ struct snd_soc_dapm_context *dapm;
+ struct hda_pcm *pcm;
+ int ret, pcm_count = 0;
+
+ if (list_empty(&codec->pcm_list_head))
+ return -EINVAL;
+ list_for_each_entry(pcm, &codec->pcm_list_head, list)
+ pcm_count++;
+
+ ret = hda_codec_create_dais(codec, pcm_count, &drvs);
+ if (ret < 0)
+ return ret;
+
+ dapm = snd_soc_component_get_dapm(component);
+
+ list_for_each_entry(pcm, &codec->pcm_list_head, list) {
+ struct snd_soc_dai *dai;
+
+ dai = snd_soc_register_dai(component, drvs, false);
+ if (!dai) {
+ dev_err(component->dev, "register dai for %s failed\n", pcm->name);
+ return -EINVAL;
+ }
+
+ ret = snd_soc_dapm_new_dai_widgets(dapm, dai);
+ if (ret < 0) {
+ dev_err(component->dev, "create widgets failed: %d\n", ret);
+ snd_soc_unregister_dai(dai);
+ return ret;
+ }
+
+ snd_soc_dai_init_dma_data(dai, &pcm->stream[0], &pcm->stream[1]);
+ drvs++;
+ }
+
+ return 0;
+}
+
+static void hda_codec_unregister_dais(struct hda_codec *codec,
+ struct snd_soc_component *component)
+{
+ struct snd_soc_dai *dai, *save;
+ struct hda_pcm *pcm;
+
+ for_each_component_dais_safe(component, dai, save) {
+ list_for_each_entry(pcm, &codec->pcm_list_head, list) {
+ if (strcmp(dai->driver->name, pcm->name))
+ continue;
+
+ if (dai->playback_widget)
+ snd_soc_dapm_free_widget(dai->playback_widget);
+ if (dai->capture_widget)
+ snd_soc_dapm_free_widget(dai->capture_widget);
+ snd_soc_unregister_dai(dai);
+ break;
+ }
+ }
+}
+
+int hda_codec_probe_complete(struct hda_codec *codec)
+{
+ struct hdac_device *hdev = &codec->core;
+ struct hdac_bus *bus = hdev->bus;
+ int ret;
+
+ ret = snd_hda_codec_build_controls(codec);
+ if (ret < 0) {
+ dev_err(&hdev->dev, "unable to create controls %d\n", ret);
+ goto out;
+ }
+
+ /* Bus suspended codecs as it does not manage their pm */
+ pm_runtime_set_active(&hdev->dev);
+ /* rpm was forbidden in snd_hda_codec_device_new() */
+ snd_hda_codec_set_power_save(codec, 2000);
+ snd_hda_codec_register(codec);
+out:
+ /* Complement pm_runtime_get_sync(bus) in probe */
+ pm_runtime_mark_last_busy(bus->dev);
+ pm_runtime_put_autosuspend(bus->dev);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(hda_codec_probe_complete);
+
+/* Expects codec with usage_count=1 and status=suspended */
+static int hda_codec_probe(struct snd_soc_component *component)
+{
+ struct hda_codec *codec = dev_to_hda_codec(component->dev);
+ struct hdac_device *hdev = &codec->core;
+ struct hdac_bus *bus = hdev->bus;
+ struct hdac_ext_link *hlink;
+ hda_codec_patch_t patch;
+ int ret;
+
+#ifdef CONFIG_PM
+ WARN_ON(atomic_read(&hdev->dev.power.usage_count) != 1 ||
+ !pm_runtime_status_suspended(&hdev->dev));
+#endif
+
+ hlink = snd_hdac_ext_bus_link_at(bus, hdev->addr);
+ if (!hlink) {
+ dev_err(&hdev->dev, "hdac link not found\n");
+ return -EIO;
+ }
+
+ pm_runtime_get_sync(bus->dev);
+ if (hda_codec_is_display(codec))
+ snd_hdac_display_power(bus, hdev->addr, true);
+ snd_hdac_ext_bus_link_get(bus, hlink);
+
+ ret = snd_hda_codec_device_new(codec->bus, component->card->snd_card, hdev->addr, codec,
+ false);
+ if (ret < 0) {
+ dev_err(&hdev->dev, "create hda codec failed: %d\n", ret);
+ goto device_new_err;
+ }
+
+ ret = snd_hda_codec_set_name(codec, codec->preset->name);
+ if (ret < 0) {
+ dev_err(&hdev->dev, "name failed %s\n", codec->preset->name);
+ goto err;
+ }
+
+ ret = snd_hdac_regmap_init(&codec->core);
+ if (ret < 0) {
+ dev_err(&hdev->dev, "regmap init failed\n");
+ goto err;
+ }
+
+ patch = (hda_codec_patch_t)codec->preset->driver_data;
+ if (!patch) {
+ dev_err(&hdev->dev, "no patch specified?\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = patch(codec);
+ if (ret < 0) {
+ dev_err(&hdev->dev, "patch failed %d\n", ret);
+ 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);
+ goto parse_pcms_err;
+ }
+
+ ret = hda_codec_register_dais(codec, component);
+ if (ret < 0) {
+ dev_err(&hdev->dev, "update dais failed: %d\n", ret);
+ goto parse_pcms_err;
+ }
+
+ if (!hda_codec_is_display(codec)) {
+ ret = hda_codec_probe_complete(codec);
+ if (ret < 0)
+ goto complete_err;
+ }
+
+ codec->core.lazy_cache = true;
+
+ return 0;
+
+complete_err:
+ hda_codec_unregister_dais(codec, component);
+parse_pcms_err:
+ if (codec->patch_ops.free)
+ codec->patch_ops.free(codec);
+err:
+ snd_hda_codec_cleanup_for_unbind(codec);
+device_new_err:
+ if (hda_codec_is_display(codec))
+ snd_hdac_display_power(bus, hdev->addr, false);
+
+ snd_hdac_ext_bus_link_put(bus, hlink);
+
+ pm_runtime_mark_last_busy(bus->dev);
+ pm_runtime_put_autosuspend(bus->dev);
+ return ret;
+}
+
+/* Leaves codec with usage_count=1 and status=suspended */
+static void hda_codec_remove(struct snd_soc_component *component)
+{
+ struct hda_codec *codec = dev_to_hda_codec(component->dev);
+ struct hdac_device *hdev = &codec->core;
+ struct hdac_bus *bus = hdev->bus;
+ struct hdac_ext_link *hlink;
+ bool was_registered = codec->registered;
+
+ /* Don't allow any more runtime suspends */
+ pm_runtime_forbid(&hdev->dev);
+
+ hda_codec_unregister_dais(codec, component);
+
+ if (codec->patch_ops.free)
+ codec->patch_ops.free(codec);
+
+ snd_hda_codec_cleanup_for_unbind(codec);
+ pm_runtime_put_noidle(&hdev->dev);
+ /* snd_hdac_device_exit() is only called on bus remove */
+ pm_runtime_set_suspended(&hdev->dev);
+
+ if (hda_codec_is_display(codec))
+ snd_hdac_display_power(bus, hdev->addr, false);
+
+ hlink = snd_hdac_ext_bus_link_at(bus, hdev->addr);
+ if (hlink)
+ snd_hdac_ext_bus_link_put(bus, hlink);
+ /*
+ * HDMI card's hda_codec_probe_complete() (see late_probe()) may
+ * not be called due to early error, leaving bus uc unbalanced
+ */
+ if (!was_registered) {
+ pm_runtime_mark_last_busy(bus->dev);
+ pm_runtime_put_autosuspend(bus->dev);
+ }
+
+#ifdef CONFIG_PM
+ WARN_ON(atomic_read(&hdev->dev.power.usage_count) != 1 ||
+ !pm_runtime_status_suspended(&hdev->dev));
+#endif
+}
+
+static const struct snd_soc_dapm_route hda_dapm_routes[] = {
+ {"AIF1TX", NULL, "Codec Input Pin1"},
+ {"AIF2TX", NULL, "Codec Input Pin2"},
+ {"AIF3TX", NULL, "Codec Input Pin3"},
+
+ {"Codec Output Pin1", NULL, "AIF1RX"},
+ {"Codec Output Pin2", NULL, "AIF2RX"},
+ {"Codec Output Pin3", NULL, "AIF3RX"},
+};
+
+static const struct snd_soc_dapm_widget hda_dapm_widgets[] = {
+ /* Audio Interface */
+ SND_SOC_DAPM_AIF_IN("AIF1RX", "Analog Codec Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("AIF2RX", "Digital Codec Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("AIF3RX", "Alt Analog Codec Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF1TX", "Analog Codec Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF2TX", "Digital Codec Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF3TX", "Alt Analog Codec Capture", 0, SND_SOC_NOPM, 0, 0),
+
+ /* Input Pins */
+ SND_SOC_DAPM_INPUT("Codec Input Pin1"),
+ SND_SOC_DAPM_INPUT("Codec Input Pin2"),
+ SND_SOC_DAPM_INPUT("Codec Input Pin3"),
+
+ /* Output Pins */
+ SND_SOC_DAPM_OUTPUT("Codec Output Pin1"),
+ SND_SOC_DAPM_OUTPUT("Codec Output Pin2"),
+ SND_SOC_DAPM_OUTPUT("Codec Output Pin3"),
+};
+
+static struct snd_soc_dai_driver card_binder_dai = {
+ .id = -1,
+ .name = "codec-probing-DAI",
+};
+
+static int hda_hdev_attach(struct hdac_device *hdev)
+{
+ struct hda_codec *codec = dev_to_hda_codec(&hdev->dev);
+ struct snd_soc_component_driver *comp_drv;
+
+ comp_drv = devm_kzalloc(&hdev->dev, sizeof(*comp_drv), GFP_KERNEL);
+ if (!comp_drv)
+ return -ENOMEM;
+
+ /*
+ * It's save to rely on dev_name() rather than a copy as component
+ * driver's lifetime is directly tied to hda codec one
+ */
+ comp_drv->name = dev_name(&hdev->dev);
+ comp_drv->probe = hda_codec_probe;
+ comp_drv->remove = hda_codec_remove;
+ comp_drv->idle_bias_on = false;
+ if (!hda_codec_is_display(codec)) {
+ comp_drv->dapm_widgets = hda_dapm_widgets;
+ comp_drv->num_dapm_widgets = ARRAY_SIZE(hda_dapm_widgets);
+ comp_drv->dapm_routes = hda_dapm_routes;
+ comp_drv->num_dapm_routes = ARRAY_SIZE(hda_dapm_routes);
+ }
+
+ return snd_soc_register_component(&hdev->dev, comp_drv, &card_binder_dai, 1);
+}
+
+static int hda_hdev_detach(struct hdac_device *hdev)
+{
+ struct hda_codec *codec = dev_to_hda_codec(&hdev->dev);
+
+ if (codec->registered)
+ cancel_delayed_work_sync(&codec->jackpoll_work);
+
+ snd_soc_unregister_component(&hdev->dev);
+
+ return 0;
+}
+
+const struct hdac_ext_bus_ops soc_hda_ext_bus_ops = {
+ .hdev_attach = hda_hdev_attach,
+ .hdev_detach = hda_hdev_detach,
+};
+EXPORT_SYMBOL_GPL(soc_hda_ext_bus_ops);
+
+MODULE_DESCRIPTION("HD-Audio codec driver");
+MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/hda.h b/sound/soc/codecs/hda.h
new file mode 100644
index 0000000..78a2be4
--- /dev/null
+++ b/sound/soc/codecs/hda.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+ *
+ * Author: Cezary Rojewski <cezary.rojewski@intel.com>
+ */
+
+#ifndef SND_SOC_CODECS_HDA_H
+#define SND_SOC_CODECS_HDA_H
+
+#define hda_codec_is_display(codec) \
+ ((((codec)->core.vendor_id >> 16) & 0xFFFF) == 0x8086)
+
+extern const struct snd_soc_dai_ops snd_soc_hda_codec_dai_ops;
+
+extern const struct hdac_ext_bus_ops soc_hda_ext_bus_ops;
+int hda_codec_probe_complete(struct hda_codec *codec);
+
+#endif
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index b773466..7d1e351 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -606,18 +606,18 @@ static int hdmi_codec_i2s_set_fmt(struct snd_soc_dai *dai,
/* Reset daifmt */
memset(cf, 0, sizeof(*cf));
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
- cf->bit_clk_master = 1;
- cf->frame_clk_master = 1;
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBP_CFP:
+ cf->bit_clk_provider = 1;
+ cf->frame_clk_provider = 1;
break;
- case SND_SOC_DAIFMT_CBS_CFM:
- cf->frame_clk_master = 1;
+ case SND_SOC_DAIFMT_CBC_CFP:
+ cf->frame_clk_provider = 1;
break;
- case SND_SOC_DAIFMT_CBM_CFS:
- cf->bit_clk_master = 1;
+ case SND_SOC_DAIFMT_CBP_CFC:
+ cf->bit_clk_provider = 1;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c
index bd0078e..c4900ad 100644
--- a/sound/soc/codecs/lm49453.c
+++ b/sound/soc/codecs/lm49453.c
@@ -1442,11 +1442,6 @@ static int lm49453_i2c_probe(struct i2c_client *i2c)
return ret;
}
-static int lm49453_i2c_remove(struct i2c_client *client)
-{
- return 0;
-}
-
static const struct i2c_device_id lm49453_i2c_id[] = {
{ "lm49453", 0 },
{ }
@@ -1458,7 +1453,6 @@ static struct i2c_driver lm49453_i2c_driver = {
.name = "lm49453",
},
.probe_new = lm49453_i2c_probe,
- .remove = lm49453_i2c_remove,
.id_table = lm49453_i2c_id,
};
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index 576277a..72471cd 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -1591,9 +1591,9 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
cdata->fmt = fmt;
regval = 0;
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
- /* Set to slave mode PLL - MAS mode off */
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBC_CFC:
+ /* Set to consumer mode PLL - MAS mode off */
snd_soc_component_write(component,
M98090_REG_CLOCK_RATIO_NI_MSB, 0x00);
snd_soc_component_write(component,
@@ -1602,8 +1602,8 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
M98090_USE_M1_MASK, 0);
max98090->master = false;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
- /* Set to master mode */
+ case SND_SOC_DAIFMT_CBP_CFP:
+ /* Set to provider mode */
if (max98090->tdm_slots == 4) {
/* TDM */
regval |= M98090_MAS_MASK |
@@ -1619,8 +1619,6 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
}
max98090->master = true;
break;
- case SND_SOC_DAIFMT_CBS_CFM:
- case SND_SOC_DAIFMT_CBM_CFS:
default:
dev_err(component->dev, "DAI clock mode unsupported");
return -EINVAL;
diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c
index 2a6b164..d83f81d 100644
--- a/sound/soc/codecs/max98390.c
+++ b/sound/soc/codecs/max98390.c
@@ -10,7 +10,7 @@
#include <linux/cdev.h>
#include <linux/dmi.h>
#include <linux/firmware.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
diff --git a/sound/soc/codecs/max9860.c b/sound/soc/codecs/max9860.c
index 82f20a8..a1d0179 100644
--- a/sound/soc/codecs/max9860.c
+++ b/sound/soc/codecs/max9860.c
@@ -448,9 +448,9 @@ static int max9860_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
struct snd_soc_component *component = dai->component;
struct max9860_priv *max9860 = snd_soc_component_get_drvdata(component);
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBP_CFP:
+ case SND_SOC_DAIFMT_CBC_CFC:
max9860->fmt = fmt;
return 0;
diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c
index 20a07c9..098a589 100644
--- a/sound/soc/codecs/msm8916-wcd-digital.c
+++ b/sound/soc/codecs/msm8916-wcd-digital.c
@@ -328,8 +328,8 @@ static const struct snd_kcontrol_new rx1_mix2_inp1_mux = SOC_DAPM_ENUM(
static const struct snd_kcontrol_new rx2_mix2_inp1_mux = SOC_DAPM_ENUM(
"RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
-/* Digital Gain control -38.4 dB to +38.4 dB in 0.3 dB steps */
-static const DECLARE_TLV_DB_SCALE(digital_gain, -3840, 30, 0);
+/* Digital Gain control -84 dB to +40 dB in 1 dB steps */
+static const DECLARE_TLV_DB_SCALE(digital_gain, -8400, 100, -8400);
/* Cutoff Freq for High Pass Filter at -3dB */
static const char * const hpf_cutoff_text[] = {
@@ -510,15 +510,15 @@ static int wcd_iir_filter_info(struct snd_kcontrol *kcontrol,
static const struct snd_kcontrol_new msm8916_wcd_digital_snd_controls[] = {
SOC_SINGLE_S8_TLV("RX1 Digital Volume", LPASS_CDC_RX1_VOL_CTL_B2_CTL,
- -128, 127, digital_gain),
+ -84, 40, digital_gain),
SOC_SINGLE_S8_TLV("RX2 Digital Volume", LPASS_CDC_RX2_VOL_CTL_B2_CTL,
- -128, 127, digital_gain),
+ -84, 40, digital_gain),
SOC_SINGLE_S8_TLV("RX3 Digital Volume", LPASS_CDC_RX3_VOL_CTL_B2_CTL,
- -128, 127, digital_gain),
+ -84, 40, digital_gain),
SOC_SINGLE_S8_TLV("TX1 Digital Volume", LPASS_CDC_TX1_VOL_CTL_GAIN,
- -128, 127, digital_gain),
+ -84, 40, digital_gain),
SOC_SINGLE_S8_TLV("TX2 Digital Volume", LPASS_CDC_TX2_VOL_CTL_GAIN,
- -128, 127, digital_gain),
+ -84, 40, digital_gain),
SOC_ENUM("TX1 HPF Cutoff", tx1_hpf_cutoff_enum),
SOC_ENUM("TX2 HPF Cutoff", tx2_hpf_cutoff_enum),
SOC_SINGLE("TX1 HPF Switch", LPASS_CDC_TX1_MUX_CTL, 3, 1, 0),
@@ -553,22 +553,22 @@ static const struct snd_kcontrol_new msm8916_wcd_digital_snd_controls[] = {
WCD_IIR_FILTER_CTL("IIR2 Band3", IIR2, BAND3),
WCD_IIR_FILTER_CTL("IIR2 Band4", IIR2, BAND4),
WCD_IIR_FILTER_CTL("IIR2 Band5", IIR2, BAND5),
- SOC_SINGLE_SX_TLV("IIR1 INP1 Volume", LPASS_CDC_IIR1_GAIN_B1_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("IIR1 INP2 Volume", LPASS_CDC_IIR1_GAIN_B2_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("IIR1 INP3 Volume", LPASS_CDC_IIR1_GAIN_B3_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("IIR1 INP4 Volume", LPASS_CDC_IIR1_GAIN_B4_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("IIR2 INP1 Volume", LPASS_CDC_IIR2_GAIN_B1_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("IIR2 INP2 Volume", LPASS_CDC_IIR2_GAIN_B2_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("IIR2 INP3 Volume", LPASS_CDC_IIR2_GAIN_B3_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("IIR2 INP4 Volume", LPASS_CDC_IIR2_GAIN_B4_CTL,
- 0, -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", LPASS_CDC_IIR1_GAIN_B1_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", LPASS_CDC_IIR1_GAIN_B2_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", LPASS_CDC_IIR1_GAIN_B3_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", LPASS_CDC_IIR1_GAIN_B4_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("IIR2 INP1 Volume", LPASS_CDC_IIR2_GAIN_B1_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("IIR2 INP2 Volume", LPASS_CDC_IIR2_GAIN_B2_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("IIR2 INP3 Volume", LPASS_CDC_IIR2_GAIN_B3_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("IIR2 INP4 Volume", LPASS_CDC_IIR2_GAIN_B4_CTL,
+ -84, 40, digital_gain),
};
diff --git a/sound/soc/codecs/mt6358.c b/sound/soc/codecs/mt6358.c
index 60b209e..93f35e8 100644
--- a/sound/soc/codecs/mt6358.c
+++ b/sound/soc/codecs/mt6358.c
@@ -2479,6 +2479,7 @@ static int mt6358_platform_driver_probe(struct platform_device *pdev)
static const struct of_device_id mt6358_of_match[] = {
{.compatible = "mediatek,mt6358-sound",},
+ {.compatible = "mediatek,mt6366-sound",},
{}
};
MODULE_DEVICE_TABLE(of, mt6358_of_match);
diff --git a/sound/soc/codecs/nau8822.c b/sound/soc/codecs/nau8822.c
index 08f6c56..3907d1d 100644
--- a/sound/soc/codecs/nau8822.c
+++ b/sound/soc/codecs/nau8822.c
@@ -726,6 +726,17 @@ static int nau8822_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
struct nau8822_pll *pll_param = &nau8822->pll;
int ret, fs;
+ if (freq_in == pll_param->freq_in &&
+ freq_out == pll_param->freq_out)
+ return 0;
+
+ if (freq_out == 0) {
+ dev_dbg(component->dev, "PLL disabled\n");
+ snd_soc_component_update_bits(component,
+ NAU8822_REG_POWER_MANAGEMENT_1, NAU8822_PLL_EN_MASK, NAU8822_PLL_OFF);
+ return 0;
+ }
+
fs = freq_out / 256;
ret = nau8822_calc_pll(freq_in, fs, pll_param);
@@ -762,6 +773,9 @@ static int nau8822_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
snd_soc_component_update_bits(component,
NAU8822_REG_POWER_MANAGEMENT_1, NAU8822_PLL_EN_MASK, NAU8822_PLL_ON);
+ pll_param->freq_in = freq_in;
+ pll_param->freq_out = freq_out;
+
return 0;
}
diff --git a/sound/soc/codecs/nau8822.h b/sound/soc/codecs/nau8822.h
index b45d42c..547ec05 100644
--- a/sound/soc/codecs/nau8822.h
+++ b/sound/soc/codecs/nau8822.h
@@ -198,6 +198,8 @@ struct nau8822_pll {
int mclk_scaler;
int pll_frac;
int pll_int;
+ int freq_in;
+ int freq_out;
};
/* Codec Private Data */
diff --git a/sound/soc/codecs/rk3328_codec.c b/sound/soc/codecs/rk3328_codec.c
index 86b679c..1d523bf 100644
--- a/sound/soc/codecs/rk3328_codec.c
+++ b/sound/soc/codecs/rk3328_codec.c
@@ -69,11 +69,11 @@ static int rk3328_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
snd_soc_component_get_drvdata(dai->component);
unsigned int val;
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBC_CFC:
val = PIN_DIRECTION_IN | DAC_I2S_MODE_SLAVE;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
val = PIN_DIRECTION_OUT | DAC_I2S_MODE_MASTER;
break;
default:
diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c
index ab093bd..a5615e9 100644
--- a/sound/soc/codecs/rt274.c
+++ b/sound/soc/codecs/rt274.c
@@ -980,14 +980,11 @@ static int rt274_probe(struct snd_soc_component *component)
struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
rt274->component = component;
+ INIT_DELAYED_WORK(&rt274->jack_detect_work, rt274_jack_detect_work);
- if (rt274->i2c->irq) {
- INIT_DELAYED_WORK(&rt274->jack_detect_work,
- rt274_jack_detect_work);
+ if (rt274->i2c->irq)
schedule_delayed_work(&rt274->jack_detect_work,
- msecs_to_jiffies(1250));
- }
-
+ msecs_to_jiffies(1250));
return 0;
}
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index ad8ea1f..0534a07 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -311,7 +311,8 @@ static void rt286_jack_detect_work(struct work_struct *work)
SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
}
-int rt286_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack)
+static int rt286_mic_detect(struct snd_soc_component *component,
+ struct snd_soc_jack *jack, void *data)
{
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component);
@@ -335,7 +336,6 @@ int rt286_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *j
return 0;
}
-EXPORT_SYMBOL_GPL(rt286_mic_detect);
static int is_mclk_mode(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink)
@@ -947,17 +947,11 @@ static int rt286_probe(struct snd_soc_component *component)
struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component);
rt286->component = component;
+ INIT_DELAYED_WORK(&rt286->jack_detect_work, rt286_jack_detect_work);
- if (rt286->i2c->irq) {
- regmap_update_bits(rt286->regmap,
- RT286_IRQ_CTRL, 0x2, 0x2);
-
- INIT_DELAYED_WORK(&rt286->jack_detect_work,
- rt286_jack_detect_work);
+ if (rt286->i2c->irq)
schedule_delayed_work(&rt286->jack_detect_work,
- msecs_to_jiffies(1250));
- }
-
+ msecs_to_jiffies(50));
return 0;
}
@@ -1055,6 +1049,7 @@ static const struct snd_soc_component_driver soc_component_dev_rt286 = {
.suspend = rt286_suspend,
.resume = rt286_resume,
.set_bias_level = rt286_set_bias_level,
+ .set_jack = rt286_mic_detect,
.controls = rt286_snd_controls,
.num_controls = ARRAY_SIZE(rt286_snd_controls),
.dapm_widgets = rt286_dapm_widgets,
diff --git a/sound/soc/codecs/rt286.h b/sound/soc/codecs/rt286.h
index f27a4e7..4b7a3bd 100644
--- a/sound/soc/codecs/rt286.h
+++ b/sound/soc/codecs/rt286.h
@@ -196,7 +196,5 @@ enum {
RT286_AIFS,
};
-int rt286_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack);
-
#endif /* __RT286_H__ */
diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c
index c291786..1a27e5e6 100644
--- a/sound/soc/codecs/rt298.c
+++ b/sound/soc/codecs/rt298.c
@@ -326,7 +326,8 @@ static void rt298_jack_detect_work(struct work_struct *work)
SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
}
-int rt298_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack)
+static int rt298_mic_detect(struct snd_soc_component *component,
+ struct snd_soc_jack *jack, void *data)
{
struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component);
struct snd_soc_dapm_context *dapm;
@@ -358,7 +359,6 @@ int rt298_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *j
return 0;
}
-EXPORT_SYMBOL_GPL(rt298_mic_detect);
static int is_mclk_mode(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink)
@@ -1011,17 +1011,11 @@ static int rt298_probe(struct snd_soc_component *component)
struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component);
rt298->component = component;
+ INIT_DELAYED_WORK(&rt298->jack_detect_work, rt298_jack_detect_work);
- if (rt298->i2c->irq) {
- regmap_update_bits(rt298->regmap,
- RT298_IRQ_CTRL, 0x2, 0x2);
-
- INIT_DELAYED_WORK(&rt298->jack_detect_work,
- rt298_jack_detect_work);
+ if (rt298->i2c->irq)
schedule_delayed_work(&rt298->jack_detect_work,
- msecs_to_jiffies(1250));
- }
-
+ msecs_to_jiffies(1250));
return 0;
}
@@ -1120,6 +1114,7 @@ static const struct snd_soc_component_driver soc_component_dev_rt298 = {
.suspend = rt298_suspend,
.resume = rt298_resume,
.set_bias_level = rt298_set_bias_level,
+ .set_jack = rt298_mic_detect,
.controls = rt298_snd_controls,
.num_controls = ARRAY_SIZE(rt298_snd_controls),
.dapm_widgets = rt298_dapm_widgets,
diff --git a/sound/soc/codecs/rt298.h b/sound/soc/codecs/rt298.h
index ed2b8fd..f1be9c1 100644
--- a/sound/soc/codecs/rt298.h
+++ b/sound/soc/codecs/rt298.h
@@ -207,7 +207,5 @@ enum {
RT298_AIFS,
};
-int rt298_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack);
-
#endif /* __RT298_H__ */
diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c
index 83acbdb..012f209 100644
--- a/sound/soc/codecs/ssm2518.c
+++ b/sound/soc/codecs/ssm2518.c
@@ -409,8 +409,8 @@ static int ssm2518_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
bool invert_fclk;
int ret;
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index 7964e92..1821854 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -411,11 +411,11 @@ static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int iface = 0;
/* set master/slave audio interface */
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBP_CFP:
iface |= 0x0040;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c
index 08ced09..b47321c 100644
--- a/sound/soc/codecs/ssm4567.c
+++ b/sound/soc/codecs/ssm4567.c
@@ -278,8 +278,8 @@ static int ssm4567_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
unsigned int ctrl1 = 0;
bool invert_fclk;
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
index 8585cbe..17e5077 100644
--- a/sound/soc/codecs/sta32x.c
+++ b/sound/soc/codecs/sta32x.c
@@ -601,8 +601,8 @@ static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai,
struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
u8 confb = 0;
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c
index 9189fb3..b2d15d2 100644
--- a/sound/soc/codecs/sta350.c
+++ b/sound/soc/codecs/sta350.c
@@ -630,8 +630,8 @@ static int sta350_set_dai_fmt(struct snd_soc_dai *codec_dai,
struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component);
unsigned int confb = 0;
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c
index 3be4940..10a6a11 100644
--- a/sound/soc/codecs/sti-sas.c
+++ b/sound/soc/codecs/sti-sas.c
@@ -199,10 +199,10 @@ static int stih407_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream)
static int sti_sas_spdif_set_fmt(struct snd_soc_dai *dai,
unsigned int fmt)
{
- if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
+ if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) {
dev_err(dai->component->dev,
- "%s: ERROR: Unsupporter master mask 0x%x\n",
- __func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
+ "%s: ERROR: Unsupported clocking mask 0x%x\n",
+ __func__, fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK);
return -EINVAL;
}
diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c
index b5c9c61..c98a933 100644
--- a/sound/soc/codecs/tas2552.c
+++ b/sound/soc/codecs/tas2552.c
@@ -347,17 +347,17 @@ static int tas2552_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
struct tas2552_data *tas2552 = dev_get_drvdata(component->dev);
u8 serial_format;
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBC_CFC:
serial_format = 0x00;
break;
- case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBC_CFP:
serial_format = TAS2552_WCLKDIR;
break;
- case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_CBP_CFC:
serial_format = TAS2552_BCLKDIR;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
serial_format = (TAS2552_BCLKDIR | TAS2552_WCLKDIR);
break;
default:
diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c
index c1dbd97..f6037a14 100644
--- a/sound/soc/codecs/tas2770.c
+++ b/sound/soc/codecs/tas2770.c
@@ -340,11 +340,11 @@ static int tas2770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0;
int ret;
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
- dev_err(tas2770->dev, "ASI format master is not found\n");
+ dev_err(tas2770->dev, "ASI invalid DAI clocking\n");
return -EINVAL;
}
diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c
index 5c0df3c..05b57bb 100644
--- a/sound/soc/codecs/tas5086.c
+++ b/sound/soc/codecs/tas5086.c
@@ -318,7 +318,7 @@ static int tas5086_set_dai_fmt(struct snd_soc_dai *codec_dai,
struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
/* The TAS5086 can only be slave to all clocks */
- if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
+ if ((format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) {
dev_err(component->dev, "Invalid clocking mode\n");
return -EINVAL;
}
diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c
index 17034ab..2ee06a9 100644
--- a/sound/soc/codecs/tas5720.c
+++ b/sound/soc/codecs/tas5720.c
@@ -89,8 +89,8 @@ static int tas5720_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
u8 serial_format;
int ret;
- if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
- dev_vdbg(component->dev, "DAI Format master is not found\n");
+ if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) {
+ dev_vdbg(component->dev, "DAI clocking invalid\n");
return -EINVAL;
}
diff --git a/sound/soc/codecs/tas6424.c b/sound/soc/codecs/tas6424.c
index 22b5385..9c9a6ec 100644
--- a/sound/soc/codecs/tas6424.c
+++ b/sound/soc/codecs/tas6424.c
@@ -160,11 +160,11 @@ static int tas6424_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
dev_dbg(component->dev, "%s() fmt=0x%0x\n", __func__, fmt);
/* clock masters */
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
- dev_err(component->dev, "Invalid DAI master/slave interface\n");
+ dev_err(component->dev, "Invalid DAI clocking\n");
return -EINVAL;
}
diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c
index 3d8e8c2..41a9b1b 100644
--- a/sound/soc/codecs/tfa9879.c
+++ b/sound/soc/codecs/tfa9879.c
@@ -111,8 +111,8 @@ static int tfa9879_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
int i2s_set;
int sck_pol;
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/tfa989x.c b/sound/soc/codecs/tfa989x.c
index dc86852..8ab2656 100644
--- a/sound/soc/codecs/tfa989x.c
+++ b/sound/soc/codecs/tfa989x.c
@@ -40,12 +40,14 @@
#define TFA989X_I2S_SEL_REG 0x0a
#define TFA989X_I2S_SEL_REG_SPKR_MSK GENMASK(10, 9) /* speaker impedance */
#define TFA989X_I2S_SEL_REG_DCFG_MSK GENMASK(14, 11) /* DCDC compensation */
+#define TFA989X_HIDE_UNHIDE_KEY 0x40
#define TFA989X_PWM_CONTROL 0x41
#define TFA989X_CURRENTSENSE1 0x46
#define TFA989X_CURRENTSENSE2 0x47
#define TFA989X_CURRENTSENSE3 0x48
#define TFA989X_CURRENTSENSE4 0x49
+#define TFA9890_REVISION 0x80
#define TFA9895_REVISION 0x12
#define TFA9897_REVISION 0x97
@@ -188,6 +190,33 @@ static struct snd_soc_dai_driver tfa989x_dai = {
.ops = &tfa989x_dai_ops,
};
+static int tfa9890_init(struct regmap *regmap)
+{
+ int ret;
+
+ /* unhide keys to allow updating them */
+ ret = regmap_write(regmap, TFA989X_HIDE_UNHIDE_KEY, 0x5a6b);
+ if (ret)
+ return ret;
+
+ /* update PLL registers */
+ ret = regmap_set_bits(regmap, 0x59, 0x3);
+ if (ret)
+ return ret;
+
+ /* hide keys again */
+ ret = regmap_write(regmap, TFA989X_HIDE_UNHIDE_KEY, 0x0000);
+ if (ret)
+ return ret;
+
+ return regmap_write(regmap, TFA989X_CURRENTSENSE2, 0x7BE1);
+}
+
+static const struct tfa989x_rev tfa9890_rev = {
+ .rev = TFA9890_REVISION,
+ .init = tfa9890_init,
+};
+
static const struct reg_sequence tfa9895_reg_init[] = {
/* some other registers must be set for optimal amplifier behaviour */
{ TFA989X_BAT_PROT, 0x13ab },
@@ -376,6 +405,7 @@ static int tfa989x_i2c_probe(struct i2c_client *i2c)
}
static const struct of_device_id tfa989x_of_match[] = {
+ { .compatible = "nxp,tfa9890", .data = &tfa9890_rev },
{ .compatible = "nxp,tfa9895", .data = &tfa9895_rev },
{ .compatible = "nxp,tfa9897", .data = &tfa9897_rev },
{ }
diff --git a/sound/soc/codecs/tlv320adc3xxx.c b/sound/soc/codecs/tlv320adc3xxx.c
index 82532ad..748998e 100644
--- a/sound/soc/codecs/tlv320adc3xxx.c
+++ b/sound/soc/codecs/tlv320adc3xxx.c
@@ -1252,8 +1252,7 @@ static int adc3xxx_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
int master = 0;
int ret;
- /* set master/slave audio interface */
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_CBP_CFP:
master = 1;
clkdir = ADC3XXX_BCLK_MASTER | ADC3XXX_WCLK_MASTER;
diff --git a/sound/soc/codecs/tlv320adcx140.c b/sound/soc/codecs/tlv320adcx140.c
index b55f0b8..de5b184 100644
--- a/sound/soc/codecs/tlv320adcx140.c
+++ b/sound/soc/codecs/tlv320adcx140.c
@@ -713,16 +713,14 @@ static int adcx140_set_dai_fmt(struct snd_soc_dai *codec_dai,
bool inverted_bclk = false;
/* set master/slave audio interface */
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBP_CFP:
iface_reg2 |= ADCX140_BCLK_FSYNC_MASTER;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
- case SND_SOC_DAIFMT_CBS_CFM:
- case SND_SOC_DAIFMT_CBM_CFS:
default:
- dev_err(component->dev, "Invalid DAI master/slave interface\n");
+ dev_err(component->dev, "Invalid DAI clock provider\n");
return -EINVAL;
}
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index 2400093..c86ca79 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -429,12 +429,11 @@ static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai,
iface_reg = snd_soc_component_read(component, TLV320AIC23_DIGT_FMT) & (~0x03);
- /* set master/slave audio interface */
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBP_CFP:
iface_reg |= TLV320AIC23_MS_MASTER;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
iface_reg &= ~TLV320AIC23_MS_MASTER;
break;
default:
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
index 077415a..f85f806 100644
--- a/sound/soc/codecs/tlv320aic26.c
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -32,7 +32,7 @@ struct aic26 {
struct spi_device *spi;
struct regmap *regmap;
struct snd_soc_component *component;
- int master;
+ int clock_provider;
int datfm;
int mclk;
@@ -117,8 +117,8 @@ static int aic26_hw_params(struct snd_pcm_substream *substream,
reg = dval << 2;
snd_soc_component_write(component, AIC26_REG_PLL_PROG2, reg);
- /* Audio Control 3 (master mode, fsref rate) */
- if (aic26->master)
+ /* Audio Control 3 (clock provider mode, fsref rate) */
+ if (aic26->clock_provider)
reg = 0x0800;
if (fsref == 48000)
reg = 0x2000;
@@ -178,10 +178,9 @@ static int aic26_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
dev_dbg(&aic26->spi->dev, "aic26_set_fmt(dai=%p, fmt==%i)\n",
codec_dai, fmt);
- /* set master/slave audio interface */
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM: aic26->master = 1; break;
- case SND_SOC_DAIFMT_CBS_CFS: aic26->master = 0; break;
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBP_CFP: aic26->clock_provider = 1; break;
+ case SND_SOC_DAIFMT_CBC_CFC: aic26->clock_provider = 0; break;
default:
dev_dbg(&aic26->spi->dev, "bad master\n"); return -EINVAL;
}
@@ -363,7 +362,7 @@ static int aic26_spi_probe(struct spi_device *spi)
/* Initialize the driver data */
aic26->spi = spi;
dev_set_drvdata(&spi->dev, aic26);
- aic26->master = 1;
+ aic26->clock_provider = 1;
ret = devm_snd_soc_register_component(&spi->dev,
&aic26_soc_component_dev, &aic26_dai, 1);
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index b2e5958..aacee23 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -1033,8 +1033,8 @@ static int aic31xx_clock_master_routes(struct snd_soc_component *component,
struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
int ret;
- fmt &= SND_SOC_DAIFMT_MASTER_MASK;
- if (fmt == SND_SOC_DAIFMT_CBS_CFS &&
+ fmt &= SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK;
+ if (fmt == SND_SOC_DAIFMT_CBC_CFC &&
aic31xx->master_dapm_route_applied) {
/*
* Remove the DAPM route(s) for codec clock master modes,
@@ -1051,7 +1051,7 @@ static int aic31xx_clock_master_routes(struct snd_soc_component *component,
return ret;
aic31xx->master_dapm_route_applied = false;
- } else if (fmt != SND_SOC_DAIFMT_CBS_CFS &&
+ } else if (fmt != SND_SOC_DAIFMT_CBC_CFC &&
!aic31xx->master_dapm_route_applied) {
/*
* Add the needed DAPM route(s) for codec clock master modes,
@@ -1083,21 +1083,20 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
dev_dbg(component->dev, "## %s: fmt = 0x%x\n", __func__, fmt);
- /* set master/slave audio interface */
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBP_CFP:
iface_reg1 |= AIC31XX_BCLK_MASTER | AIC31XX_WCLK_MASTER;
break;
- case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBC_CFP:
iface_reg1 |= AIC31XX_WCLK_MASTER;
break;
- case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_CBP_CFC:
iface_reg1 |= AIC31XX_BCLK_MASTER;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
- dev_err(component->dev, "Invalid DAI master/slave interface\n");
+ dev_err(component->dev, "Invalid DAI clock provider\n");
return -EINVAL;
}
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index 8f42fd7..a8e6adf 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -615,15 +615,14 @@ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
u8 iface_reg_2 = 0;
u8 iface_reg_3 = 0;
- /* set master/slave audio interface */
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBP_CFP:
iface_reg_1 |= AIC32X4_BCLKMASTER | AIC32X4_WCLKMASTER;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
- printk(KERN_ERR "aic32x4: invalid DAI master/slave interface\n");
+ printk(KERN_ERR "aic32x4: invalid clock provider\n");
return -EINVAL;
}
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index d53037b..610e41b 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -1253,22 +1253,21 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
iface_areg = snd_soc_component_read(component, AIC3X_ASD_INTF_CTRLA) & 0x3f;
iface_breg = snd_soc_component_read(component, AIC3X_ASD_INTF_CTRLB) & 0x3f;
- /* set master/slave audio interface */
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBP_CFP:
aic3x->master = 1;
iface_areg |= BIT_CLK_MASTER | WORD_CLK_MASTER;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
aic3x->master = 0;
iface_areg &= ~(BIT_CLK_MASTER | WORD_CLK_MASTER);
break;
- case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_CBP_CFC:
aic3x->master = 1;
iface_areg |= BIT_CLK_MASTER;
iface_areg &= ~WORD_CLK_MASTER;
break;
- case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBC_CFP:
aic3x->master = 1;
iface_areg |= WORD_CLK_MASTER;
iface_areg &= ~BIT_CLK_MASTER;
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 66f1d1c..371026e 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -1317,16 +1317,14 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai,
aictrl_a = dac33_read_reg_cache(component, DAC33_SER_AUDIOIF_CTRL_A);
aictrl_b = dac33_read_reg_cache(component, DAC33_SER_AUDIOIF_CTRL_B);
- /* set master/slave audio interface */
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
- /* Codec Master */
+
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBP_CFP:
aictrl_a |= (DAC33_MSBCLK | DAC33_MSWCLK);
break;
- case SND_SOC_DAIFMT_CBS_CFS:
- /* Codec Slave */
+ case SND_SOC_DAIFMT_CBC_CFC:
if (dac33->fifo_mode) {
- dev_err(component->dev, "FIFO mode requires master mode\n");
+ dev_err(component->dev, "FIFO mode requires provider mode\n");
return -EINVAL;
} else
aictrl_a &= ~(DAC33_MSBCLK | DAC33_MSWCLK);
diff --git a/sound/soc/codecs/uda1334.c b/sound/soc/codecs/uda1334.c
index 8670a2a..9d5ed34 100644
--- a/sound/soc/codecs/uda1334.c
+++ b/sound/soc/codecs/uda1334.c
@@ -169,7 +169,7 @@ static int uda1334_set_dai_sysclk(struct snd_soc_dai *codec_dai,
static int uda1334_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{
fmt &= (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK |
- SND_SOC_DAIFMT_MASTER_MASK);
+ SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK);
if (fmt != (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBC_CFC)) {
diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c
index c53c2ef..3100928 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.c
+++ b/sound/soc/codecs/wcd-mbhc-v2.c
@@ -1306,7 +1306,7 @@ static irqreturn_t wcd_mbhc_adc_hs_rem_irq(int irq, void *data)
static irqreturn_t wcd_mbhc_adc_hs_ins_irq(int irq, void *data)
{
struct wcd_mbhc *mbhc = data;
- u8 clamp_state = 0;
+ u8 clamp_state;
u8 clamp_retry = WCD_MBHC_FAKE_INS_RETRY;
/*
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index d9f1352..7d40a61 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -1813,11 +1813,11 @@ static int wcd9335_set_decimator_rate(struct snd_soc_dai *dai,
tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0;
shift = (tx_port << 1);
shift_val = 0x03;
- } else if ((tx_port >= 4) && (tx_port < 8)) {
+ } else if (tx_port < 8) {
tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1;
shift = ((tx_port - 4) << 1);
shift_val = 0x03;
- } else if ((tx_port >= 8) && (tx_port < 11)) {
+ } else if (tx_port < 11) {
tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2;
shift = ((tx_port - 8) << 1);
shift_val = 0x03;
@@ -2259,51 +2259,42 @@ static int wcd9335_rx_hph_mode_put(struct snd_kcontrol *kc,
static const struct snd_kcontrol_new wcd9335_snd_controls[] = {
/* -84dB min - 40dB max */
- SOC_SINGLE_SX_TLV("RX0 Digital Volume", WCD9335_CDC_RX0_RX_VOL_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("RX1 Digital Volume", WCD9335_CDC_RX1_RX_VOL_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("RX2 Digital Volume", WCD9335_CDC_RX2_RX_VOL_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("RX3 Digital Volume", WCD9335_CDC_RX3_RX_VOL_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("RX4 Digital Volume", WCD9335_CDC_RX4_RX_VOL_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("RX5 Digital Volume", WCD9335_CDC_RX5_RX_VOL_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("RX6 Digital Volume", WCD9335_CDC_RX6_RX_VOL_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("RX7 Digital Volume", WCD9335_CDC_RX7_RX_VOL_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("RX8 Digital Volume", WCD9335_CDC_RX8_RX_VOL_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("RX0 Mix Digital Volume",
- WCD9335_CDC_RX0_RX_VOL_MIX_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("RX1 Mix Digital Volume",
- WCD9335_CDC_RX1_RX_VOL_MIX_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("RX2 Mix Digital Volume",
- WCD9335_CDC_RX2_RX_VOL_MIX_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("RX3 Mix Digital Volume",
- WCD9335_CDC_RX3_RX_VOL_MIX_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("RX4 Mix Digital Volume",
- WCD9335_CDC_RX4_RX_VOL_MIX_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("RX5 Mix Digital Volume",
- WCD9335_CDC_RX5_RX_VOL_MIX_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("RX6 Mix Digital Volume",
- WCD9335_CDC_RX6_RX_VOL_MIX_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("RX7 Mix Digital Volume",
- WCD9335_CDC_RX7_RX_VOL_MIX_CTL,
- 0, -84, 40, digital_gain),
- SOC_SINGLE_SX_TLV("RX8 Mix Digital Volume",
- WCD9335_CDC_RX8_RX_VOL_MIX_CTL,
- 0, -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX0 Digital Volume", WCD9335_CDC_RX0_RX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX1 Digital Volume", WCD9335_CDC_RX1_RX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX2 Digital Volume", WCD9335_CDC_RX2_RX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX3 Digital Volume", WCD9335_CDC_RX3_RX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX4 Digital Volume", WCD9335_CDC_RX4_RX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX5 Digital Volume", WCD9335_CDC_RX5_RX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX6 Digital Volume", WCD9335_CDC_RX6_RX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX7 Digital Volume", WCD9335_CDC_RX7_RX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX8 Digital Volume", WCD9335_CDC_RX8_RX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX0 Mix Digital Volume", WCD9335_CDC_RX0_RX_VOL_MIX_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX1 Mix Digital Volume", WCD9335_CDC_RX1_RX_VOL_MIX_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX2 Mix Digital Volume", WCD9335_CDC_RX2_RX_VOL_MIX_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX3 Mix Digital Volume", WCD9335_CDC_RX3_RX_VOL_MIX_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX4 Mix Digital Volume", WCD9335_CDC_RX4_RX_VOL_MIX_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX5 Mix Digital Volume", WCD9335_CDC_RX5_RX_VOL_MIX_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX6 Mix Digital Volume", WCD9335_CDC_RX6_RX_VOL_MIX_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX7 Mix Digital Volume", WCD9335_CDC_RX7_RX_VOL_MIX_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX8 Mix Digital Volume", WCD9335_CDC_RX8_RX_VOL_MIX_CTL,
+ -84, 40, digital_gain),
SOC_ENUM("RX INT0_1 HPF cut off", cf_int0_1_enum),
SOC_ENUM("RX INT0_2 HPF cut off", cf_int0_2_enum),
SOC_ENUM("RX INT1_1 HPF cut off", cf_int1_1_enum),
diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c
index 1edac3e..e794e02 100644
--- a/sound/soc/dwc/dwc-i2s.c
+++ b/sound/soc/dwc/dwc-i2s.c
@@ -357,20 +357,20 @@ static int dw_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
int ret = 0;
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
- case SND_SOC_DAIFMT_CBP_CFP:
+ case SND_SOC_DAIFMT_BC_FC:
if (dev->capability & DW_I2S_SLAVE)
ret = 0;
else
ret = -EINVAL;
break;
- case SND_SOC_DAIFMT_CBC_CFC:
+ case SND_SOC_DAIFMT_BP_FP:
if (dev->capability & DW_I2S_MASTER)
ret = 0;
else
ret = -EINVAL;
break;
- case SND_SOC_DAIFMT_CBP_CFC:
- case SND_SOC_DAIFMT_CBC_CFP:
+ case SND_SOC_DAIFMT_BC_FP:
+ case SND_SOC_DAIFMT_BP_FC:
ret = -EINVAL;
break;
default:
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c
index 5038faf..aaf7993 100644
--- a/sound/soc/fsl/fsl_asrc_dma.c
+++ b/sound/soc/fsl/fsl_asrc_dma.c
@@ -129,6 +129,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
struct snd_pcm_hw_params *params)
{
enum dma_slave_buswidth buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ enum sdma_peripheral_type be_peripheral_type = IMX_DMATYPE_SSI;
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
struct snd_dmaengine_dai_dma_data *dma_params_fe = NULL;
@@ -139,6 +140,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
struct snd_soc_component *component_be = NULL;
struct fsl_asrc *asrc = pair->asrc;
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;
struct device_node *of_dma_node;
@@ -221,6 +223,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
/* Get DMA request of Back-End */
tmp_data = tmp_chan->private;
pair->dma_data.dma_request = tmp_data->dma_request;
+ be_peripheral_type = tmp_data->peripheral_type;
if (!be_chan)
dma_release_channel(tmp_chan);
@@ -268,6 +271,17 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
config_be.dst_addr_width = buswidth;
config_be.dst_maxburst = dma_params_be->maxburst;
+ memset(&audio_config, 0, sizeof(audio_config));
+ config_be.peripheral_config = &audio_config;
+ config_be.peripheral_size = sizeof(audio_config);
+
+ if (tx && (be_peripheral_type == IMX_DMATYPE_SSI_DUAL ||
+ be_peripheral_type == IMX_DMATYPE_SPDIF))
+ audio_config.n_fifos_dst = 2;
+ if (!tx && (be_peripheral_type == IMX_DMATYPE_SSI_DUAL ||
+ be_peripheral_type == IMX_DMATYPE_SPDIF))
+ audio_config.n_fifos_src = 2;
+
if (tx) {
config_be.src_addr = asrc->paddr + asrc->get_fifo_addr(OUT, index);
config_be.dst_addr = dma_params_be->addr;
diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c
index 6dbb8c9..43857b7 100644
--- a/sound/soc/fsl/fsl_audmix.c
+++ b/sound/soc/fsl/fsl_audmix.c
@@ -259,8 +259,8 @@ static int fsl_audmix_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
/* For playback the AUDMIX is consumer, and for record is provider */
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
- case SND_SOC_DAIFMT_CBP_CFP:
- case SND_SOC_DAIFMT_CBC_CFC:
+ case SND_SOC_DAIFMT_BC_FC:
+ case SND_SOC_DAIFMT_BP_FP:
break;
default:
return -EINVAL;
@@ -317,7 +317,7 @@ static int fsl_audmix_dai_trigger(struct snd_pcm_substream *substream, int cmd,
}
static const struct snd_soc_dai_ops fsl_audmix_dai_ops = {
- .set_fmt = fsl_audmix_dai_set_fmt,
+ .set_fmt = fsl_audmix_dai_set_fmt,
.trigger = fsl_audmix_dai_trigger,
};
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index 1a2bdf8..75f7807d 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -480,16 +480,16 @@ static int fsl_esai_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
/* DAI clock provider masks */
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
- case SND_SOC_DAIFMT_CBP_CFP:
+ case SND_SOC_DAIFMT_BC_FC:
esai_priv->consumer_mode = true;
break;
- case SND_SOC_DAIFMT_CBC_CFP:
+ case SND_SOC_DAIFMT_BP_FC:
xccr |= ESAI_xCCR_xCKD;
break;
- case SND_SOC_DAIFMT_CBP_CFC:
+ case SND_SOC_DAIFMT_BC_FP:
xccr |= ESAI_xCCR_xFSD;
break;
- case SND_SOC_DAIFMT_CBC_CFC:
+ case SND_SOC_DAIFMT_BP_FP:
xccr |= ESAI_xCCR_xFSD | ESAI_xCCR_xCKD;
break;
default:
diff --git a/sound/soc/fsl/fsl_mqs.c b/sound/soc/fsl/fsl_mqs.c
index ceaecbe..bb25c58e 100644
--- a/sound/soc/fsl/fsl_mqs.c
+++ b/sound/soc/fsl/fsl_mqs.c
@@ -10,6 +10,7 @@
#include <linux/moduleparam.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/pm.h>
@@ -29,15 +30,41 @@
#define MQS_CLK_DIV_MASK (0xFF << 0)
#define MQS_CLK_DIV_SHIFT (0)
+/**
+ * struct fsl_mqs_soc_data - soc specific data
+ *
+ * @use_gpr: control register is in General Purpose Register group
+ * @ctrl_off: control register offset
+ * @en_mask: enable bit mask
+ * @en_shift: enable bit shift
+ * @rst_mask: reset bit mask
+ * @rst_shift: reset bit shift
+ * @osr_mask: oversample bit mask
+ * @osr_shift: oversample bit shift
+ * @div_mask: clock divider mask
+ * @div_shift: clock divider bit shift
+ */
+struct fsl_mqs_soc_data {
+ bool use_gpr;
+ int ctrl_off;
+ int en_mask;
+ int en_shift;
+ int rst_mask;
+ int rst_shift;
+ int osr_mask;
+ int osr_shift;
+ int div_mask;
+ int div_shift;
+};
+
/* codec private data */
struct fsl_mqs {
struct regmap *regmap;
struct clk *mclk;
struct clk *ipg;
+ const struct fsl_mqs_soc_data *soc;
- unsigned int reg_iomuxc_gpr2;
unsigned int reg_mqs_ctrl;
- bool use_gpr;
};
#define FSL_MQS_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
@@ -65,19 +92,11 @@ static int fsl_mqs_hw_params(struct snd_pcm_substream *substream,
res = mclk_rate % (32 * lrclk * 2 * 8);
if (res == 0 && div > 0 && div <= 256) {
- if (mqs_priv->use_gpr) {
- regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2,
- IMX6SX_GPR2_MQS_CLK_DIV_MASK,
- (div - 1) << IMX6SX_GPR2_MQS_CLK_DIV_SHIFT);
- regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2,
- IMX6SX_GPR2_MQS_OVERSAMPLE_MASK, 0);
- } else {
- regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL,
- MQS_CLK_DIV_MASK,
- (div - 1) << MQS_CLK_DIV_SHIFT);
- regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL,
- MQS_OVERSAMPLE_MASK, 0);
- }
+ regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off,
+ mqs_priv->soc->div_mask,
+ (div - 1) << mqs_priv->soc->div_shift);
+ regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off,
+ mqs_priv->soc->osr_mask, 0);
} else {
dev_err(component->dev, "can't get proper divider\n");
}
@@ -103,7 +122,7 @@ static int fsl_mqs_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
}
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
- case SND_SOC_DAIFMT_CBC_CFC:
+ case SND_SOC_DAIFMT_BP_FP:
break;
default:
return -EINVAL;
@@ -118,14 +137,9 @@ static int fsl_mqs_startup(struct snd_pcm_substream *substream,
struct snd_soc_component *component = dai->component;
struct fsl_mqs *mqs_priv = snd_soc_component_get_drvdata(component);
- if (mqs_priv->use_gpr)
- regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2,
- IMX6SX_GPR2_MQS_EN_MASK,
- 1 << IMX6SX_GPR2_MQS_EN_SHIFT);
- else
- regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL,
- MQS_EN_MASK,
- 1 << MQS_EN_SHIFT);
+ regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off,
+ mqs_priv->soc->en_mask,
+ 1 << mqs_priv->soc->en_shift);
return 0;
}
@@ -135,12 +149,8 @@ static void fsl_mqs_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_component *component = dai->component;
struct fsl_mqs *mqs_priv = snd_soc_component_get_drvdata(component);
- if (mqs_priv->use_gpr)
- regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2,
- IMX6SX_GPR2_MQS_EN_MASK, 0);
- else
- regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL,
- MQS_EN_MASK, 0);
+ regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off,
+ mqs_priv->soc->en_mask, 0);
}
static const struct snd_soc_component_driver soc_codec_fsl_mqs = {
@@ -191,12 +201,9 @@ static int fsl_mqs_probe(struct platform_device *pdev)
* But in i.MX8QM/i.MX8QXP the control register is moved
* to its own domain.
*/
- if (of_device_is_compatible(np, "fsl,imx8qm-mqs"))
- mqs_priv->use_gpr = false;
- else
- mqs_priv->use_gpr = true;
+ mqs_priv->soc = of_device_get_match_data(&pdev->dev);
- if (mqs_priv->use_gpr) {
+ if (mqs_priv->soc->use_gpr) {
gpr_np = of_parse_phandle(np, "gpr", 0);
if (!gpr_np) {
dev_err(&pdev->dev, "failed to get gpr node by phandle\n");
@@ -280,12 +287,7 @@ static int fsl_mqs_runtime_resume(struct device *dev)
return ret;
}
- if (mqs_priv->use_gpr)
- regmap_write(mqs_priv->regmap, IOMUXC_GPR2,
- mqs_priv->reg_iomuxc_gpr2);
- else
- regmap_write(mqs_priv->regmap, REG_MQS_CTRL,
- mqs_priv->reg_mqs_ctrl);
+ regmap_write(mqs_priv->regmap, mqs_priv->soc->ctrl_off, mqs_priv->reg_mqs_ctrl);
return 0;
}
@@ -293,12 +295,7 @@ static int fsl_mqs_runtime_suspend(struct device *dev)
{
struct fsl_mqs *mqs_priv = dev_get_drvdata(dev);
- if (mqs_priv->use_gpr)
- regmap_read(mqs_priv->regmap, IOMUXC_GPR2,
- &mqs_priv->reg_iomuxc_gpr2);
- else
- regmap_read(mqs_priv->regmap, REG_MQS_CTRL,
- &mqs_priv->reg_mqs_ctrl);
+ regmap_read(mqs_priv->regmap, mqs_priv->soc->ctrl_off, &mqs_priv->reg_mqs_ctrl);
clk_disable_unprepare(mqs_priv->mclk);
clk_disable_unprepare(mqs_priv->ipg);
@@ -315,9 +312,49 @@ static const struct dev_pm_ops fsl_mqs_pm_ops = {
pm_runtime_force_resume)
};
+static const struct fsl_mqs_soc_data fsl_mqs_imx8qm_data = {
+ .use_gpr = false,
+ .ctrl_off = REG_MQS_CTRL,
+ .en_mask = MQS_EN_MASK,
+ .en_shift = MQS_EN_SHIFT,
+ .rst_mask = MQS_SW_RST_MASK,
+ .rst_shift = MQS_SW_RST_SHIFT,
+ .osr_mask = MQS_OVERSAMPLE_MASK,
+ .osr_shift = MQS_OVERSAMPLE_SHIFT,
+ .div_mask = MQS_CLK_DIV_MASK,
+ .div_shift = MQS_CLK_DIV_SHIFT,
+};
+
+static const struct fsl_mqs_soc_data fsl_mqs_imx6sx_data = {
+ .use_gpr = true,
+ .ctrl_off = IOMUXC_GPR2,
+ .en_mask = IMX6SX_GPR2_MQS_EN_MASK,
+ .en_shift = IMX6SX_GPR2_MQS_EN_SHIFT,
+ .rst_mask = IMX6SX_GPR2_MQS_SW_RST_MASK,
+ .rst_shift = IMX6SX_GPR2_MQS_SW_RST_SHIFT,
+ .osr_mask = IMX6SX_GPR2_MQS_OVERSAMPLE_MASK,
+ .osr_shift = IMX6SX_GPR2_MQS_OVERSAMPLE_SHIFT,
+ .div_mask = IMX6SX_GPR2_MQS_CLK_DIV_MASK,
+ .div_shift = IMX6SX_GPR2_MQS_CLK_DIV_SHIFT,
+};
+
+static const struct fsl_mqs_soc_data fsl_mqs_imx93_data = {
+ .use_gpr = true,
+ .ctrl_off = 0x20,
+ .en_mask = BIT(1),
+ .en_shift = 1,
+ .rst_mask = BIT(2),
+ .rst_shift = 2,
+ .osr_mask = BIT(3),
+ .osr_shift = 3,
+ .div_mask = GENMASK(15, 8),
+ .div_shift = 8,
+};
+
static const struct of_device_id fsl_mqs_dt_ids[] = {
- { .compatible = "fsl,imx8qm-mqs", },
- { .compatible = "fsl,imx6sx-mqs", },
+ { .compatible = "fsl,imx8qm-mqs", .data = &fsl_mqs_imx8qm_data },
+ { .compatible = "fsl,imx6sx-mqs", .data = &fsl_mqs_imx6sx_data },
+ { .compatible = "fsl,imx93-mqs", .data = &fsl_mqs_imx93_data },
{}
};
MODULE_DEVICE_TABLE(of, fsl_mqs_dt_ids);
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index e765da9..4f5bd95 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -292,19 +292,19 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
/* DAI clock provider masks */
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
- case SND_SOC_DAIFMT_CBC_CFC:
+ case SND_SOC_DAIFMT_BP_FP:
val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
sai->is_consumer_mode = false;
break;
- case SND_SOC_DAIFMT_CBP_CFP:
+ case SND_SOC_DAIFMT_BC_FC:
sai->is_consumer_mode = true;
break;
- case SND_SOC_DAIFMT_CBC_CFP:
+ case SND_SOC_DAIFMT_BP_FC:
val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
sai->is_consumer_mode = false;
break;
- case SND_SOC_DAIFMT_CBP_CFC:
+ case SND_SOC_DAIFMT_BC_FP:
val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
sai->is_consumer_mode = true;
break;
@@ -437,6 +437,12 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
FSL_SAI_CR2_DIV_MASK | FSL_SAI_CR2_BYP,
savediv / 2 - 1);
+ if (sai->soc_data->max_register >= FSL_SAI_MCTL) {
+ /* SAI is in master mode at this point, so enable MCLK */
+ regmap_update_bits(sai->regmap, FSL_SAI_MCTL,
+ FSL_SAI_MCTL_MCLK_EN, FSL_SAI_MCTL_MCLK_EN);
+ }
+
return 0;
}
@@ -1004,6 +1010,7 @@ static int fsl_sai_runtime_resume(struct device *dev);
static int fsl_sai_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
struct fsl_sai *sai;
struct regmap *gpr;
struct resource *res;
@@ -1012,12 +1019,12 @@ static int fsl_sai_probe(struct platform_device *pdev)
int irq, ret, i;
int index;
- sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
+ sai = devm_kzalloc(dev, sizeof(*sai), GFP_KERNEL);
if (!sai)
return -ENOMEM;
sai->pdev = pdev;
- sai->soc_data = of_device_get_match_data(&pdev->dev);
+ sai->soc_data = of_device_get_match_data(dev);
sai->is_lsb_first = of_property_read_bool(np, "lsb-first");
@@ -1032,18 +1039,18 @@ static int fsl_sai_probe(struct platform_device *pdev)
ARRAY_SIZE(fsl_sai_reg_defaults_ofs8);
}
- sai->regmap = devm_regmap_init_mmio(&pdev->dev, base, &fsl_sai_regmap_config);
+ sai->regmap = devm_regmap_init_mmio(dev, base, &fsl_sai_regmap_config);
if (IS_ERR(sai->regmap)) {
- dev_err(&pdev->dev, "regmap init failed\n");
+ dev_err(dev, "regmap init failed\n");
return PTR_ERR(sai->regmap);
}
- sai->bus_clk = devm_clk_get(&pdev->dev, "bus");
+ sai->bus_clk = devm_clk_get(dev, "bus");
/* Compatible with old DTB cases */
if (IS_ERR(sai->bus_clk) && PTR_ERR(sai->bus_clk) != -EPROBE_DEFER)
- sai->bus_clk = devm_clk_get(&pdev->dev, "sai");
+ sai->bus_clk = devm_clk_get(dev, "sai");
if (IS_ERR(sai->bus_clk)) {
- dev_err(&pdev->dev, "failed to get bus clock: %ld\n",
+ dev_err(dev, "failed to get bus clock: %ld\n",
PTR_ERR(sai->bus_clk));
/* -EPROBE_DEFER */
return PTR_ERR(sai->bus_clk);
@@ -1051,9 +1058,9 @@ static int fsl_sai_probe(struct platform_device *pdev)
for (i = 1; i < FSL_SAI_MCLK_MAX; i++) {
sprintf(tmp, "mclk%d", i);
- sai->mclk_clk[i] = devm_clk_get(&pdev->dev, tmp);
+ sai->mclk_clk[i] = devm_clk_get(dev, tmp);
if (IS_ERR(sai->mclk_clk[i])) {
- dev_err(&pdev->dev, "failed to get mclk%d clock: %ld\n",
+ dev_err(dev, "failed to get mclk%d clock: %ld\n",
i + 1, PTR_ERR(sai->mclk_clk[i]));
sai->mclk_clk[i] = NULL;
}
@@ -1068,10 +1075,10 @@ static int fsl_sai_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- ret = devm_request_irq(&pdev->dev, irq, fsl_sai_isr, IRQF_SHARED,
+ ret = devm_request_irq(dev, irq, fsl_sai_isr, IRQF_SHARED,
np->name, sai);
if (ret) {
- dev_err(&pdev->dev, "failed to claim irq %u\n", irq);
+ dev_err(dev, "failed to claim irq %u\n", irq);
return ret;
}
@@ -1088,7 +1095,7 @@ static int fsl_sai_probe(struct platform_device *pdev)
if (of_find_property(np, "fsl,sai-synchronous-rx", NULL) &&
of_find_property(np, "fsl,sai-asynchronous", NULL)) {
/* error out if both synchronous and asynchronous are present */
- dev_err(&pdev->dev, "invalid binding for synchronous mode\n");
+ dev_err(dev, "invalid binding for synchronous mode\n");
return -EINVAL;
}
@@ -1109,7 +1116,7 @@ static int fsl_sai_probe(struct platform_device *pdev)
of_device_is_compatible(np, "fsl,imx6ul-sai")) {
gpr = syscon_regmap_lookup_by_compatible("fsl,imx6ul-iomuxc-gpr");
if (IS_ERR(gpr)) {
- dev_err(&pdev->dev, "cannot find iomuxc registers\n");
+ dev_err(dev, "cannot find iomuxc registers\n");
return PTR_ERR(gpr);
}
@@ -1127,23 +1134,23 @@ static int fsl_sai_probe(struct platform_device *pdev)
sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;
platform_set_drvdata(pdev, sai);
- pm_runtime_enable(&pdev->dev);
- if (!pm_runtime_enabled(&pdev->dev)) {
- ret = fsl_sai_runtime_resume(&pdev->dev);
+ pm_runtime_enable(dev);
+ if (!pm_runtime_enabled(dev)) {
+ ret = fsl_sai_runtime_resume(dev);
if (ret)
goto err_pm_disable;
}
- ret = pm_runtime_get_sync(&pdev->dev);
+ ret = pm_runtime_get_sync(dev);
if (ret < 0) {
- pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_put_noidle(dev);
goto err_pm_get_sync;
}
/* Get sai version */
- ret = fsl_sai_check_version(&pdev->dev);
+ ret = fsl_sai_check_version(dev);
if (ret < 0)
- dev_warn(&pdev->dev, "Error reading SAI version: %d\n", ret);
+ dev_warn(dev, "Error reading SAI version: %d\n", ret);
/* Select MCLK direction */
if (of_find_property(np, "fsl,sai-mclk-direction-output", NULL) &&
@@ -1152,7 +1159,7 @@ static int fsl_sai_probe(struct platform_device *pdev)
FSL_SAI_MCTL_MCLK_EN, FSL_SAI_MCTL_MCLK_EN);
}
- ret = pm_runtime_put_sync(&pdev->dev);
+ ret = pm_runtime_put_sync(dev);
if (ret < 0)
goto err_pm_get_sync;
@@ -1162,15 +1169,18 @@ static int fsl_sai_probe(struct platform_device *pdev)
*/
if (sai->soc_data->use_imx_pcm) {
ret = imx_pcm_dma_init(pdev);
- if (ret)
+ if (ret) {
+ if (!IS_ENABLED(CONFIG_SND_SOC_IMX_PCM_DMA))
+ dev_err(dev, "Error: You must enable the imx-pcm-dma support!\n");
goto err_pm_get_sync;
+ }
} else {
- ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+ ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0);
if (ret)
goto err_pm_get_sync;
}
- ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component,
+ ret = devm_snd_soc_register_component(dev, &fsl_component,
&sai->cpu_dai_drv, 1);
if (ret)
goto err_pm_get_sync;
@@ -1178,10 +1188,10 @@ static int fsl_sai_probe(struct platform_device *pdev)
return ret;
err_pm_get_sync:
- if (!pm_runtime_status_suspended(&pdev->dev))
- fsl_sai_runtime_suspend(&pdev->dev);
+ if (!pm_runtime_status_suspended(dev))
+ fsl_sai_runtime_suspend(dev);
err_pm_disable:
- pm_runtime_disable(&pdev->dev);
+ pm_runtime_disable(dev);
return ret;
}
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 84cb36d..7dd0c48 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -93,7 +93,7 @@
*/
#define FSLSSI_AC97_DAIFMT \
(SND_SOC_DAIFMT_AC97 | \
- SND_SOC_DAIFMT_CBM_CFS | \
+ SND_SOC_DAIFMT_BC_FP | \
SND_SOC_DAIFMT_NB_NF)
#define FSLSSI_SIER_DBG_RX_FLAGS \
@@ -358,13 +358,13 @@ static bool fsl_ssi_is_ac97(struct fsl_ssi *ssi)
static bool fsl_ssi_is_i2s_clock_provider(struct fsl_ssi *ssi)
{
return (ssi->dai_fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) ==
- SND_SOC_DAIFMT_CBC_CFC;
+ SND_SOC_DAIFMT_BP_FP;
}
-static bool fsl_ssi_is_i2s_cbp_cfc(struct fsl_ssi *ssi)
+static bool fsl_ssi_is_i2s_bc_fp(struct fsl_ssi *ssi)
{
return (ssi->dai_fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) ==
- SND_SOC_DAIFMT_CBP_CFC;
+ SND_SOC_DAIFMT_BC_FP;
}
/**
@@ -847,7 +847,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
u8 i2s_net = ssi->i2s_net;
/* Normal + Network mode to send 16-bit data in 32-bit frames */
- if (fsl_ssi_is_i2s_cbp_cfc(ssi) && sample_size == 16)
+ if (fsl_ssi_is_i2s_bc_fp(ssi) && sample_size == 16)
i2s_net = SSI_SCR_I2S_MODE_NORMAL | SSI_SCR_NET;
/* Use Normal mode to send mono data at 1st slot of 2 slots */
@@ -920,17 +920,17 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi *ssi, unsigned int fmt)
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
- case SND_SOC_DAIFMT_CBC_CFC:
+ case SND_SOC_DAIFMT_BP_FP:
if (IS_ERR(ssi->baudclk)) {
dev_err(ssi->dev,
"missing baudclk for master mode\n");
return -EINVAL;
}
fallthrough;
- case SND_SOC_DAIFMT_CBP_CFC:
+ case SND_SOC_DAIFMT_BC_FP:
ssi->i2s_net |= SSI_SCR_I2S_MODE_MASTER;
break;
- case SND_SOC_DAIFMT_CBP_CFP:
+ case SND_SOC_DAIFMT_BC_FC:
ssi->i2s_net |= SSI_SCR_I2S_MODE_SLAVE;
break;
default:
@@ -992,15 +992,15 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi *ssi, unsigned int fmt)
/* DAI clock provider masks */
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
- case SND_SOC_DAIFMT_CBC_CFC:
+ case SND_SOC_DAIFMT_BP_FP:
/* Output bit and frame sync clocks */
strcr |= SSI_STCR_TFDIR | SSI_STCR_TXDIR;
scr |= SSI_SCR_SYS_CLK_EN;
break;
- case SND_SOC_DAIFMT_CBP_CFP:
+ case SND_SOC_DAIFMT_BC_FC:
/* Input bit or frame sync clocks */
break;
- case SND_SOC_DAIFMT_CBP_CFC:
+ case SND_SOC_DAIFMT_BC_FP:
/* Input bit clock but output frame sync clock */
strcr |= SSI_STCR_TFDIR;
break;
diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c
index d0556c7..55e640c 100644
--- a/sound/soc/fsl/fsl_xcvr.c
+++ b/sound/soc/fsl/fsl_xcvr.c
@@ -1228,6 +1228,7 @@ static int fsl_xcvr_probe(struct platform_device *pdev)
*/
ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0);
if (ret) {
+ pm_runtime_disable(dev);
dev_err(dev, "failed to pcm register\n");
return ret;
}
@@ -1235,6 +1236,7 @@ static int fsl_xcvr_probe(struct platform_device *pdev)
ret = devm_snd_soc_register_component(dev, &fsl_xcvr_comp,
&fsl_xcvr_dai, 1);
if (ret) {
+ pm_runtime_disable(dev);
dev_err(dev, "failed to register component %s\n",
fsl_xcvr_comp.name);
}
@@ -1242,6 +1244,12 @@ static int fsl_xcvr_probe(struct platform_device *pdev)
return ret;
}
+static int fsl_xcvr_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+ return 0;
+}
+
static __maybe_unused int fsl_xcvr_runtime_suspend(struct device *dev)
{
struct fsl_xcvr *xcvr = dev_get_drvdata(dev);
@@ -1370,6 +1378,7 @@ static struct platform_driver fsl_xcvr_driver = {
.pm = &fsl_xcvr_pm_ops,
.of_match_table = fsl_xcvr_dt_ids,
},
+ .remove = fsl_xcvr_remove,
};
module_platform_driver(fsl_xcvr_driver);
diff --git a/sound/soc/fsl/imx-audmix.c b/sound/soc/fsl/imx-audmix.c
index 502fe1b..1292a84 100644
--- a/sound/soc/fsl/imx-audmix.c
+++ b/sound/soc/fsl/imx-audmix.c
@@ -81,7 +81,7 @@ static int imx_audmix_fe_hw_params(struct snd_pcm_substream *substream,
int ret, dir;
/* For playback the AUDMIX is consumer, and for record is provider */
- fmt |= tx ? SND_SOC_DAIFMT_CBC_CFC : SND_SOC_DAIFMT_CBP_CFP;
+ fmt |= tx ? SND_SOC_DAIFMT_BP_FP : SND_SOC_DAIFMT_BC_FC;
dir = tx ? SND_SOC_CLOCK_OUT : SND_SOC_CLOCK_IN;
/* set DAI configuration */
@@ -122,7 +122,7 @@ static int imx_audmix_be_hw_params(struct snd_pcm_substream *substream,
return 0;
/* For playback the AUDMIX is consumer */
- fmt |= SND_SOC_DAIFMT_CBP_CFP;
+ fmt |= SND_SOC_DAIFMT_BC_FC;
/* set AUDMIX DAI configuration */
ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), fmt);
diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c
index dfa05d4..50b71e5 100644
--- a/sound/soc/fsl/imx-audmux.c
+++ b/sound/soc/fsl/imx-audmux.c
@@ -62,17 +62,14 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf,
uintptr_t port = (uintptr_t)file->private_data;
u32 pdcr, ptcr;
- if (audmux_clk) {
- ret = clk_prepare_enable(audmux_clk);
- if (ret)
- return ret;
- }
+ ret = clk_prepare_enable(audmux_clk);
+ if (ret)
+ return ret;
ptcr = readl(audmux_base + IMX_AUDMUX_V2_PTCR(port));
pdcr = readl(audmux_base + IMX_AUDMUX_V2_PDCR(port));
- if (audmux_clk)
- clk_disable_unprepare(audmux_clk);
+ clk_disable_unprepare(audmux_clk);
buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!buf)
@@ -209,17 +206,14 @@ int imx_audmux_v2_configure_port(unsigned int port, unsigned int ptcr,
if (!audmux_base)
return -ENOSYS;
- if (audmux_clk) {
- ret = clk_prepare_enable(audmux_clk);
- if (ret)
- return ret;
- }
+ ret = clk_prepare_enable(audmux_clk);
+ if (ret)
+ return ret;
writel(ptcr, audmux_base + IMX_AUDMUX_V2_PTCR(port));
writel(pdcr, audmux_base + IMX_AUDMUX_V2_PDCR(port));
- if (audmux_clk)
- clk_disable_unprepare(audmux_clk);
+ clk_disable_unprepare(audmux_clk);
return 0;
}
@@ -298,7 +292,7 @@ static int imx_audmux_probe(struct platform_device *pdev)
audmux_clk = NULL;
}
- audmux_type = (enum imx_audmux_type)of_device_get_match_data(&pdev->dev);
+ audmux_type = (uintptr_t)of_device_get_match_data(&pdev->dev);
switch (audmux_type) {
case IMX31_AUDMUX:
diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c
index 6f8efd8..1797d77 100644
--- a/sound/soc/fsl/imx-card.c
+++ b/sound/soc/fsl/imx-card.c
@@ -317,7 +317,7 @@ static int imx_aif_hw_params(struct snd_pcm_substream *substream,
}
}
- ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+ ret = snd_soc_dai_set_fmt(cpu_dai, snd_soc_daifmt_clock_provider_flipped(fmt));
if (ret && ret != -ENOTSUPP) {
dev_err(dev, "failed to set cpu dai fmt: %d\n", ret);
return ret;
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index 539d7f0..7be84c7 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -513,7 +513,12 @@ static int asoc_simple_init_dai(struct snd_soc_dai *dai,
return 0;
}
-static int asoc_simple_init_dai_link_params(struct snd_soc_pcm_runtime *rtd,
+static inline int asoc_simple_component_is_codec(struct snd_soc_component *component)
+{
+ return component->driver->endianness;
+}
+
+static int asoc_simple_init_for_codec2codec(struct snd_soc_pcm_runtime *rtd,
struct simple_dai_props *dai_props)
{
struct snd_soc_dai_link *dai_link = rtd->dai_link;
@@ -524,7 +529,7 @@ static int asoc_simple_init_dai_link_params(struct snd_soc_pcm_runtime *rtd,
/* Only Codecs */
for_each_rtd_components(rtd, i, component) {
- if (!snd_soc_component_is_codec(component))
+ if (!asoc_simple_component_is_codec(component))
return 0;
}
@@ -575,7 +580,7 @@ int asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
- ret = asoc_simple_init_dai_link_params(rtd, props);
+ ret = asoc_simple_init_for_codec2codec(rtd, props);
if (ret < 0)
return ret;
@@ -609,7 +614,7 @@ void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link_component *cpus,
}
EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_cpu);
-int asoc_simple_clean_reference(struct snd_soc_card *card)
+void asoc_simple_clean_reference(struct snd_soc_card *card)
{
struct snd_soc_dai_link *dai_link;
struct snd_soc_dai_link_component *cpu;
@@ -622,7 +627,6 @@ int asoc_simple_clean_reference(struct snd_soc_card *card)
for_each_link_codecs(dai_link, j, codec)
of_node_put(codec->of_node);
}
- return 0;
}
EXPORT_SYMBOL_GPL(asoc_simple_clean_reference);
@@ -877,7 +881,9 @@ int asoc_simple_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
- return asoc_simple_clean_reference(card);
+ asoc_simple_clean_reference(card);
+
+ return 0;
}
EXPORT_SYMBOL_GPL(asoc_simple_remove);
diff --git a/sound/soc/generic/test-component.c b/sound/soc/generic/test-component.c
index 5da4725..d28712f 100644
--- a/sound/soc/generic/test-component.c
+++ b/sound/soc/generic/test-component.c
@@ -66,7 +66,7 @@ static int test_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
unsigned int format = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
unsigned int clock = fmt & SND_SOC_DAIFMT_CLOCK_MASK;
unsigned int inv = fmt & SND_SOC_DAIFMT_INV_MASK;
- unsigned int master = fmt & SND_SOC_DAIFMT_MASTER_MASK;
+ unsigned int master = fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK;
char *str;
dev_info(dai->dev, "name : %s", dai->name);
@@ -105,16 +105,16 @@ static int test_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
str = "unknown";
switch (master) {
- case SND_SOC_DAIFMT_CBP_CFP:
+ case SND_SOC_DAIFMT_BP_FP:
str = "clk provider, frame provider";
break;
- case SND_SOC_DAIFMT_CBC_CFP:
+ case SND_SOC_DAIFMT_BC_FP:
str = "clk consumer, frame provider";
break;
- case SND_SOC_DAIFMT_CBP_CFC:
+ case SND_SOC_DAIFMT_BP_FC:
str = "clk provider, frame consumer";
break;
- case SND_SOC_DAIFMT_CBC_CFC:
+ case SND_SOC_DAIFMT_BC_FC:
str = "clk consumer, frame consumer";
break;
}
@@ -192,10 +192,10 @@ static int test_dai_bespoke_trigger(struct snd_pcm_substream *substream,
static u64 test_dai_formats =
/*
* Select below from Sound Card, not auto
- * SND_SOC_POSSIBLE_DAIFMT_CBP_CFP
- * SND_SOC_POSSIBLE_DAIFMT_CBC_CFP
- * SND_SOC_POSSIBLE_DAIFMT_CBP_CFC
- * SND_SOC_POSSIBLE_DAIFMT_CBC_CFC
+ * SND_SOC_POSSIBLE_DAIFMT_BP_FP
+ * SND_SOC_POSSIBLE_DAIFMT_BC_FP
+ * SND_SOC_POSSIBLE_DAIFMT_BP_FC
+ * SND_SOC_POSSIBLE_DAIFMT_BC_FC
*/
SND_SOC_POSSIBLE_DAIFMT_I2S |
SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
diff --git a/sound/soc/hisilicon/hi6210-i2s.c b/sound/soc/hisilicon/hi6210-i2s.c
index a297d4a..689ae13 100644
--- a/sound/soc/hisilicon/hi6210-i2s.c
+++ b/sound/soc/hisilicon/hi6210-i2s.c
@@ -227,9 +227,9 @@ static int hi6210_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
* We don't actually set the hardware until the hw_params
* call, but we need to validate the user input here.
*/
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BC_FC:
+ case SND_SOC_DAIFMT_BP_FP:
break;
default:
return -EINVAL;
@@ -245,8 +245,8 @@ static int hi6210_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
}
i2s->format = fmt;
- i2s->master = (i2s->format & SND_SOC_DAIFMT_MASTER_MASK) ==
- SND_SOC_DAIFMT_CBS_CFS;
+ i2s->master = (i2s->format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) ==
+ SND_SOC_DAIFMT_BP_FP;
return 0;
}
@@ -375,21 +375,21 @@ static int hi6210_i2s_hw_params(struct snd_pcm_substream *substream,
hi6210_write_reg(i2s, HII2S_MUX_TOP_MODULE_CFG, val);
- switch (i2s->format & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ switch (i2s->format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BC_FC:
i2s->master = false;
val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
val |= HII2S_I2S_CFG__S2_MST_SLV;
hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_BP_FP:
i2s->master = true;
val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
val &= ~HII2S_I2S_CFG__S2_MST_SLV;
hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
break;
default:
- WARN_ONCE(1, "Invalid i2s->fmt MASTER_MASK. This shouldn't happen\n");
+ WARN_ONCE(1, "Invalid i2s->fmt CLOCK_PROVIDER_MASK. This shouldn't happen\n");
return -EINVAL;
}
diff --git a/sound/soc/img/img-i2s-in.c b/sound/soc/img/img-i2s-in.c
index 09d23b1..97cab6d 100644
--- a/sound/soc/img/img-i2s-in.c
+++ b/sound/soc/img/img-i2s-in.c
@@ -333,8 +333,8 @@ static int img_i2s_in_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return -EINVAL;
}
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BC_FC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/img/img-i2s-out.c b/sound/soc/img/img-i2s-out.c
index 28f48ca..9ec6fc5 100644
--- a/sound/soc/img/img-i2s-out.c
+++ b/sound/soc/img/img-i2s-out.c
@@ -302,10 +302,10 @@ static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
if (force_clk_active)
control_set |= IMG_I2S_OUT_CTL_CLK_EN_MASK;
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BC_FC:
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_BP_FP:
control_set |= IMG_I2S_OUT_CTL_MASTER_MASK;
break;
default:
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index 7c85d1b..e5107a3 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -226,5 +226,8 @@
capabilities. This includes Skylake, Kabylake, Amberlake and
Apollolake.
+# Machine board drivers
+source "sound/soc/intel/avs/boards/Kconfig"
+
# ASoC codec drivers
source "sound/soc/intel/boards/Kconfig"
diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c
index 335c327..fd59b35 100644
--- a/sound/soc/intel/atom/sst-atom-controls.c
+++ b/sound/soc/intel/atom/sst-atom-controls.c
@@ -831,9 +831,9 @@ static int sst_get_ssp_mode(struct snd_soc_dai *dai, unsigned int fmt)
dev_dbg(dai->dev, "Enter:%s, format=%x\n", __func__, format);
switch (format) {
- case SND_SOC_DAIFMT_CBC_CFC:
+ case SND_SOC_DAIFMT_BP_FP:
return SSP_MODE_PROVIDER;
- case SND_SOC_DAIFMT_CBP_CFP:
+ case SND_SOC_DAIFMT_BC_FC:
return SSP_MODE_CONSUMER;
default:
dev_err(dai->dev, "Invalid ssp protocol: %d\n", format);
@@ -1328,7 +1328,7 @@ int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute)
{
struct sst_data *drv = snd_soc_dai_get_drvdata(dai);
struct snd_soc_dapm_widget *w;
- struct snd_soc_dapm_path *p = NULL;
+ struct snd_soc_dapm_path *p;
dev_dbg(dai->dev, "enter, dai-name=%s dir=%d\n", dai->name, stream);
@@ -1392,7 +1392,7 @@ int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute)
static int sst_fill_module_list(struct snd_kcontrol *kctl,
struct snd_soc_dapm_widget *w, int type)
{
- struct sst_module *module = NULL;
+ struct sst_module *module;
struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
struct sst_ids *ids = w->priv;
int ret = 0;
diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c
index 3a42d68..160b50f 100644
--- a/sound/soc/intel/atom/sst/sst.c
+++ b/sound/soc/intel/atom/sst/sst.c
@@ -114,7 +114,7 @@ static irqreturn_t intel_sst_interrupt_mrfld(int irq, void *context)
static irqreturn_t intel_sst_irq_thread_mrfld(int irq, void *context)
{
struct intel_sst_drv *drv = (struct intel_sst_drv *) context;
- struct ipc_post *__msg, *msg = NULL;
+ struct ipc_post *__msg, *msg;
unsigned long irq_flags;
spin_lock_irqsave(&drv->rx_msg_lock, irq_flags);
diff --git a/sound/soc/intel/atom/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c
index 4e83820..4e039c7 100644
--- a/sound/soc/intel/atom/sst/sst_ipc.c
+++ b/sound/soc/intel/atom/sst/sst_ipc.c
@@ -28,7 +28,7 @@
struct sst_block *sst_create_block(struct intel_sst_drv *ctx,
u32 msg_id, u32 drv_id)
{
- struct sst_block *msg = NULL;
+ struct sst_block *msg;
dev_dbg(ctx->dev, "Enter\n");
msg = kzalloc(sizeof(*msg), GFP_KERNEL);
@@ -63,7 +63,7 @@ struct sst_block *sst_create_block(struct intel_sst_drv *ctx,
int sst_wake_up_block(struct intel_sst_drv *ctx, int result,
u32 drv_id, u32 ipc, void *data, u32 size)
{
- struct sst_block *block = NULL;
+ struct sst_block *block;
dev_dbg(ctx->dev, "Enter\n");
@@ -91,7 +91,7 @@ int sst_wake_up_block(struct intel_sst_drv *ctx, int result,
int sst_free_block(struct intel_sst_drv *ctx, struct sst_block *freed)
{
- struct sst_block *block = NULL, *__block;
+ struct sst_block *block, *__block;
dev_dbg(ctx->dev, "Enter\n");
spin_lock_bh(&ctx->block_lock);
@@ -341,7 +341,7 @@ void sst_process_reply_mrfld(struct intel_sst_drv *sst_drv_ctx,
}
/* FW sent short error response for an IPC */
- if (msg_high.part.result && drv_id && !msg_high.part.large) {
+ if (msg_high.part.result && !msg_high.part.large) {
/* 32-bit FW error code in msg_low */
dev_err(sst_drv_ctx->dev, "FW sent error response 0x%x", msg_low);
sst_wake_up_block(sst_drv_ctx, msg_high.part.result,
diff --git a/sound/soc/intel/avs/Makefile b/sound/soc/intel/avs/Makefile
index b6b93ae..9192128 100644
--- a/sound/soc/intel/avs/Makefile
+++ b/sound/soc/intel/avs/Makefile
@@ -10,3 +10,6 @@
CFLAGS_trace.o := -I$(src)
obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o
+
+# Machine support
+obj-$(CONFIG_SND_SOC) += boards/
diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig
new file mode 100644
index 0000000..4d68e3e
--- /dev/null
+++ b/sound/soc/intel/avs/boards/Kconfig
@@ -0,0 +1,121 @@
+# SPDX-License-Identifier: GPL-2.0-only
+menu "Intel AVS Machine drivers"
+ depends on SND_SOC_INTEL_AVS
+
+comment "Available DSP configurations"
+
+config SND_SOC_INTEL_AVS_MACH_DA7219
+ tristate "da7219 I2S board"
+ depends on I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_DA7219
+ help
+ This adds support for AVS with DA7219 I2S codec configuration.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_DMIC
+ tristate "DMIC generic board"
+ select SND_SOC_DMIC
+ help
+ This adds support for AVS with Digital Mic array configuration.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_HDAUDIO
+ tristate "HD-Audio generic board"
+ select SND_SOC_HDA
+ help
+ This adds support for AVS with HDAudio codec configuration.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_I2S_TEST
+ tristate "I2S test board"
+ help
+ This adds support for I2S test-board which can be used to verify
+ transfer over I2S interface with SSP loopback scenarios.
+
+config SND_SOC_INTEL_AVS_MACH_MAX98357A
+ tristate "max98357A I2S board"
+ depends on I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_MAX98357A
+ help
+ This adds support for AVS with MAX98357A I2S codec configuration.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_MAX98373
+ tristate "max98373 I2S board"
+ depends on I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_MAX98373
+ help
+ This adds support for AVS with MAX98373 I2S codec configuration.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_NAU8825
+ tristate "nau8825 I2S board"
+ depends on I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_NAU8825
+ help
+ This adds support for ASoC machine driver with NAU8825 I2S audio codec.
+ It is meant to be used with AVS driver.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_RT274
+ tristate "rt274 in I2S mode"
+ depends on I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_RT274
+ help
+ This adds support for ASoC machine driver with RT274 I2S audio codec.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_RT286
+ tristate "rt286 in I2S mode"
+ depends on I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_RT286
+ help
+ This adds support for ASoC machine driver with RT286 I2S audio codec.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_RT298
+ tristate "rt298 in I2S mode"
+ depends on I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_RT298
+ help
+ This adds support for ASoC machine driver with RT298 I2S audio codec.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_RT5682
+ tristate "rt5682 in I2S mode"
+ depends on I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_RT5682_I2C
+ help
+ This adds support for ASoC machine driver with RT5682 I2S audio codec.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_SSM4567
+ tristate "ssm4567 I2S board"
+ depends on I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_SSM4567
+ help
+ This adds support for ASoC machine driver with SSM4567 I2S audio codec.
+ It is meant to be used with AVS driver.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
+endmenu
diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile
new file mode 100644
index 0000000..25e8c4b
--- /dev/null
+++ b/sound/soc/intel/avs/boards/Makefile
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+snd-soc-avs-da7219-objs := da7219.o
+snd-soc-avs-dmic-objs := dmic.o
+snd-soc-avs-hdaudio-objs := hdaudio.o
+snd-soc-avs-i2s-test-objs := i2s_test.o
+snd-soc-avs-max98357a-objs := max98357a.o
+snd-soc-avs-max98373-objs := max98373.o
+snd-soc-avs-nau8825-objs := nau8825.o
+snd-soc-avs-rt274-objs := rt274.o
+snd-soc-avs-rt286-objs := rt286.o
+snd-soc-avs-rt298-objs := rt298.o
+snd-soc-avs-rt5682-objs := rt5682.o
+snd-soc-avs-ssm4567-objs := ssm4567.o
+
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DA7219) += snd-soc-avs-da7219.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DMIC) += snd-soc-avs-dmic.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_HDAUDIO) += snd-soc-avs-hdaudio.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_i2s_TEST) += snd-soc-avs-i2s-test.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98357A) += snd-soc-avs-max98357a.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98373) += snd-soc-avs-max98373.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_NAU8825) += snd-soc-avs-nau8825.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT274) += snd-soc-avs-rt274.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT286) += snd-soc-avs-rt286.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT298) += snd-soc-avs-rt298.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT5682) += snd-soc-avs-rt5682.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_SSM4567) += snd-soc-avs-ssm4567.o
diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c
new file mode 100644
index 0000000..02ae542
--- /dev/null
+++ b/sound/soc/intel/avs/boards/da7219.c
@@ -0,0 +1,282 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Author: Cezary Rojewski <cezary.rojewski@intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+#include <uapi/linux/input-event-codes.h>
+#include "../../../codecs/da7219.h"
+#include "../../../codecs/da7219-aad.h"
+
+#define DA7219_DAI_NAME "da7219-hifi"
+
+static const struct snd_kcontrol_new card_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static int platform_clock_control(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_dapm_context *dapm = w->dapm;
+ struct snd_soc_card *card = dapm->card;
+ struct snd_soc_dai *codec_dai;
+ int ret = 0;
+
+ codec_dai = snd_soc_card_get_codec_dai(card, DA7219_DAI_NAME);
+ if (!codec_dai) {
+ dev_err(card->dev, "Codec dai not found. Unable to set/unset codec pll\n");
+ return -EIO;
+ }
+
+ if (SND_SOC_DAPM_EVENT_OFF(event)) {
+ ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0);
+ if (ret)
+ dev_err(card->dev, "failed to stop PLL: %d\n", ret);
+ } else if (SND_SOC_DAPM_EVENT_ON(event)) {
+ ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL_SRM,
+ 0, DA7219_PLL_FREQ_OUT_98304);
+ if (ret)
+ dev_err(card->dev, "failed to start PLL: %d\n", ret);
+ }
+
+ return ret;
+}
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control,
+ SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+ /* HP jack connectors - unknown if we have jack detection */
+ {"Headphone Jack", NULL, "HPL"},
+ {"Headphone Jack", NULL, "HPR"},
+
+ {"MIC", NULL, "Headset Mic"},
+
+ { "Headphone Jack", NULL, "Platform Clock" },
+ { "Headset Mic", NULL, "Platform Clock" },
+};
+
+static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+ struct snd_soc_card *card = runtime->card;
+ struct snd_soc_jack *jack;
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+ int clk_freq;
+ int ret;
+
+ jack = snd_soc_card_get_drvdata(card);
+ clk_freq = 19200000;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, clk_freq, SND_SOC_CLOCK_IN);
+ if (ret) {
+ dev_err(card->dev, "can't set codec sysclk configuration\n");
+ return ret;
+ }
+
+ /*
+ * Headset buttons map to the google Reference headset.
+ * These can be configured by userspace.
+ */
+ ret = snd_soc_card_jack_new(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);
+ if (ret) {
+ dev_err(card->dev, "Headset Jack creation failed: %d\n", ret);
+ return ret;
+ }
+
+ 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);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
+
+ da7219_aad_jack_det(component, jack);
+
+ return 0;
+}
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = platform_name;
+
+ dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+ dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-DLGS7219:00");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, DA7219_DAI_NAME);
+ if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+ return -ENOMEM;
+
+ dl->num_cpus = 1;
+ dl->num_codecs = 1;
+ dl->platforms = platform;
+ dl->num_platforms = 1;
+ dl->id = 0;
+ dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->init = avs_da7219_codec_init;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+ dl->dpcm_capture = 1;
+ dl->dpcm_playback = 1;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+ struct snd_soc_dapm_route **routes, int *num_routes)
+{
+ struct snd_soc_dapm_route *dr;
+ const int num_base = ARRAY_SIZE(card_base_routes);
+ const int num_dr = num_base + 2;
+ int idx;
+
+ dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+ idx = num_base;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Playback");
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ idx++;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "Capture");
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ *routes = dr;
+ *num_routes = num_dr;
+
+ return 0;
+}
+
+static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
+{
+ struct snd_soc_component *component;
+
+ for_each_card_components(card, component)
+ snd_soc_component_set_jack(component, jack, NULL);
+ return 0;
+}
+
+static int avs_card_remove(struct snd_soc_card *card)
+{
+ return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+ return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+ struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+ return avs_card_set_jack(card, jack);
+}
+
+static int avs_da7219_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dapm_route *routes;
+ struct snd_soc_dai_link *dai_link;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct snd_soc_jack *jack;
+ struct device *dev = &pdev->dev;
+ const char *pname;
+ int num_routes, ssp_port, ret;
+
+ mach = dev_get_platdata(dev);
+ pname = mach->mach_params.platform;
+ ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+ ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d", ret);
+ return ret;
+ }
+
+ ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+ if (ret) {
+ dev_err(dev, "Failed to create dapm routes: %d", ret);
+ return ret;
+ }
+
+ jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL);
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!jack || !card)
+ return -ENOMEM;
+
+ card->name = "avs_da7219";
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->remove = avs_card_remove;
+ card->suspend_pre = avs_card_suspend_pre;
+ card->resume_post = avs_card_resume_post;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->controls = card_controls;
+ card->num_controls = ARRAY_SIZE(card_controls);
+ card->dapm_widgets = card_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+ card->dapm_routes = routes;
+ card->num_dapm_routes = num_routes;
+ card->fully_routed = true;
+ snd_soc_card_set_drvdata(card, jack);
+
+ ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_da7219_driver = {
+ .probe = avs_da7219_probe,
+ .driver = {
+ .name = "avs_da7219",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_da7219_driver);
+
+MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_da7219");
diff --git a/sound/soc/intel/avs/boards/dmic.c b/sound/soc/intel/avs/boards/dmic.c
new file mode 100644
index 0000000..90a9216
--- /dev/null
+++ b/sound/soc/intel/avs/boards/dmic.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+
+SND_SOC_DAILINK_DEF(dmic_pin, DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin")));
+SND_SOC_DAILINK_DEF(dmic_wov_pin, DAILINK_COMP_ARRAY(COMP_CPU("DMIC WoV Pin")));
+SND_SOC_DAILINK_DEF(dmic_codec, DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
+/* Name overridden on probe */
+SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("")));
+
+static struct snd_soc_dai_link card_dai_links[] = {
+ /* Back ends */
+ {
+ .name = "DMIC",
+ .id = 0,
+ .dpcm_capture = 1,
+ .nonatomic = 1,
+ .no_pcm = 1,
+ SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform),
+ },
+ {
+ .name = "DMIC WoV",
+ .id = 1,
+ .dpcm_capture = 1,
+ .nonatomic = 1,
+ .no_pcm = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(dmic_wov_pin, dmic_codec, platform),
+ },
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_MIC("SoC DMIC", NULL),
+};
+
+static const struct snd_soc_dapm_route card_routes[] = {
+ {"DMic", NULL, "SoC DMIC"},
+ {"DMIC Rx", NULL, "Capture"},
+ {"DMIC WoV Rx", NULL, "Capture"},
+};
+
+static int avs_dmic_probe(struct platform_device *pdev)
+{
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ mach = dev_get_platdata(dev);
+
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return -ENOMEM;
+
+ card->name = "avs_dmic";
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->dai_link = card_dai_links;
+ card->num_links = ARRAY_SIZE(card_dai_links);
+ card->dapm_widgets = card_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+ card->dapm_routes = card_routes;
+ card->num_dapm_routes = ARRAY_SIZE(card_routes);
+ card->fully_routed = true;
+
+ ret = snd_soc_fixup_dai_links_platform_name(card, mach->mach_params.platform);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_dmic_driver = {
+ .probe = avs_dmic_probe,
+ .driver = {
+ .name = "avs_dmic",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_dmic_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_dmic");
diff --git a/sound/soc/intel/avs/boards/hdaudio.c b/sound/soc/intel/avs/boards/hdaudio.c
new file mode 100644
index 0000000..d2fc41d
--- /dev/null
+++ b/sound/soc/intel/avs/boards/hdaudio.c
@@ -0,0 +1,294 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/platform_device.h>
+#include <sound/hda_codec.h>
+#include <sound/hda_i915.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/hda.h"
+
+static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int pcm_count,
+ const char *platform_name, struct snd_soc_dai_link **links)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+ struct hda_pcm *pcm;
+ const char *cname = dev_name(&codec->core.dev);
+ int i;
+
+ dl = devm_kcalloc(dev, pcm_count, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = platform_name;
+ pcm = list_first_entry(&codec->pcm_list_head, struct hda_pcm, list);
+
+ for (i = 0; i < pcm_count; i++, pcm = list_next_entry(pcm, list)) {
+ dl[i].name = devm_kasprintf(dev, GFP_KERNEL, "%s link%d", cname, i);
+ if (!dl[i].name)
+ return -ENOMEM;
+
+ dl[i].id = i;
+ dl[i].nonatomic = 1;
+ dl[i].no_pcm = 1;
+ dl[i].dpcm_playback = 1;
+ dl[i].dpcm_capture = 1;
+ dl[i].platforms = platform;
+ dl[i].num_platforms = 1;
+
+ dl[i].codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+ dl[i].cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+ if (!dl[i].codecs || !dl[i].cpus)
+ return -ENOMEM;
+
+ dl[i].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "%s-cpu%d", cname, i);
+ if (!dl[i].cpus->dai_name)
+ return -ENOMEM;
+
+ dl[i].codecs->name = devm_kstrdup(dev, cname, GFP_KERNEL);
+ dl[i].codecs->dai_name = pcm->name;
+ dl[i].num_codecs = 1;
+ dl[i].num_cpus = 1;
+ }
+
+ *links = dl;
+ return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, struct hda_codec *codec, int pcm_count,
+ struct snd_soc_dapm_route **routes, int *num_routes)
+{
+ struct snd_soc_dapm_route *dr;
+ struct hda_pcm *pcm;
+ const char *cname = dev_name(&codec->core.dev);
+ int i, n = 0;
+
+ /* at max twice the number of pcms */
+ dr = devm_kcalloc(dev, pcm_count * 2, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ pcm = list_first_entry(&codec->pcm_list_head, struct hda_pcm, list);
+
+ for (i = 0; i < pcm_count; i++, pcm = list_next_entry(pcm, list)) {
+ struct hda_pcm_stream *stream;
+ int dir;
+
+ dir = SNDRV_PCM_STREAM_PLAYBACK;
+ stream = &pcm->stream[dir];
+ if (!stream->substreams)
+ goto capture_routes;
+
+ dr[n].sink = devm_kasprintf(dev, GFP_KERNEL, "%s %s", pcm->name,
+ snd_pcm_direction_name(dir));
+ dr[n].source = devm_kasprintf(dev, GFP_KERNEL, "%s-cpu%d Tx", cname, i);
+ if (!dr[n].sink || !dr[n].source)
+ return -ENOMEM;
+ n++;
+
+capture_routes:
+ dir = SNDRV_PCM_STREAM_CAPTURE;
+ stream = &pcm->stream[dir];
+ if (!stream->substreams)
+ continue;
+
+ dr[n].sink = devm_kasprintf(dev, GFP_KERNEL, "%s-cpu%d Rx", cname, i);
+ dr[n].source = devm_kasprintf(dev, GFP_KERNEL, "%s %s", pcm->name,
+ snd_pcm_direction_name(dir));
+ if (!dr[n].sink || !dr[n].source)
+ return -ENOMEM;
+ n++;
+ }
+
+ *routes = dr;
+ *num_routes = n;
+ return 0;
+}
+
+/* Should be aligned with SectionPCM's name from topology */
+#define FEDAI_NAME_PREFIX "HDMI"
+
+static struct snd_pcm *
+avs_card_hdmi_pcm_at(struct snd_soc_card *card, int hdmi_idx)
+{
+ struct snd_soc_pcm_runtime *rtd;
+ int dir = SNDRV_PCM_STREAM_PLAYBACK;
+
+ for_each_card_rtds(card, rtd) {
+ struct snd_pcm *spcm;
+ int ret, n;
+
+ spcm = rtd->pcm ? rtd->pcm->streams[dir].pcm : NULL;
+ if (!spcm || !strstr(spcm->id, FEDAI_NAME_PREFIX))
+ continue;
+
+ ret = sscanf(spcm->id, FEDAI_NAME_PREFIX "%d", &n);
+ if (ret != 1)
+ continue;
+ if (n == hdmi_idx)
+ return rtd->pcm;
+ }
+
+ return NULL;
+}
+
+static int avs_card_late_probe(struct snd_soc_card *card)
+{
+ struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);
+ struct hda_codec *codec = mach->pdata;
+ struct hda_pcm *hpcm;
+ /* Topology pcm indexing is 1-based */
+ int i = 1;
+
+ list_for_each_entry(hpcm, &codec->pcm_list_head, list) {
+ struct snd_pcm *spcm;
+
+ spcm = avs_card_hdmi_pcm_at(card, i);
+ if (spcm) {
+ hpcm->pcm = spcm;
+ hpcm->device = spcm->device;
+ dev_info(card->dev, "%s: mapping HDMI converter %d to PCM %d (%p)\n",
+ __func__, i, hpcm->device, spcm);
+ } else {
+ hpcm->pcm = NULL;
+ hpcm->device = SNDRV_PCM_INVALID_DEVICE;
+ dev_warn(card->dev, "%s: no PCM in topology for HDMI converter %d\n",
+ __func__, i);
+ }
+ i++;
+ }
+
+ return hda_codec_probe_complete(codec);
+}
+
+static int avs_probing_link_init(struct snd_soc_pcm_runtime *rtm)
+{
+ struct snd_soc_dapm_route *routes;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_dai_link *links = NULL;
+ struct snd_soc_card *card = rtm->card;
+ struct hda_codec *codec;
+ struct hda_pcm *pcm;
+ int ret, n, pcm_count = 0;
+
+ mach = dev_get_platdata(card->dev);
+ codec = mach->pdata;
+
+ if (list_empty(&codec->pcm_list_head))
+ return -EINVAL;
+ list_for_each_entry(pcm, &codec->pcm_list_head, list)
+ pcm_count++;
+
+ ret = avs_create_dai_links(card->dev, codec, pcm_count, mach->mach_params.platform, &links);
+ if (ret < 0) {
+ dev_err(card->dev, "create links failed: %d\n", ret);
+ return ret;
+ }
+
+ for (n = 0; n < pcm_count; n++) {
+ ret = snd_soc_add_pcm_runtime(card, &links[n]);
+ if (ret < 0) {
+ dev_err(card->dev, "add links failed: %d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = avs_create_dapm_routes(card->dev, codec, pcm_count, &routes, &n);
+ if (ret < 0) {
+ dev_err(card->dev, "create routes failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dapm_add_routes(&card->dapm, routes, n);
+ if (ret < 0) {
+ dev_err(card->dev, "add routes failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY()));
+
+static struct snd_soc_dai_link probing_link = {
+ .name = "probing-LINK",
+ .id = -1,
+ .nonatomic = 1,
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .cpus = dummy,
+ .num_cpus = ARRAY_SIZE(dummy),
+ .init = avs_probing_link_init,
+};
+
+static int avs_hdaudio_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dai_link *binder;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct device *dev = &pdev->dev;
+ struct hda_codec *codec;
+
+ mach = dev_get_platdata(dev);
+ codec = mach->pdata;
+
+ /* codec may be unloaded before card's probe() fires */
+ if (!device_is_registered(&codec->core.dev))
+ return -ENODEV;
+
+ binder = devm_kmemdup(dev, &probing_link, sizeof(probing_link), GFP_KERNEL);
+ if (!binder)
+ return -ENOMEM;
+
+ binder->platforms = devm_kzalloc(dev, sizeof(*binder->platforms), GFP_KERNEL);
+ binder->codecs = devm_kzalloc(dev, sizeof(*binder->codecs), GFP_KERNEL);
+ if (!binder->platforms || !binder->codecs)
+ return -ENOMEM;
+
+ binder->codecs->name = devm_kstrdup(dev, dev_name(&codec->core.dev), GFP_KERNEL);
+ if (!binder->codecs->name)
+ return -ENOMEM;
+
+ binder->platforms->name = mach->mach_params.platform;
+ binder->num_platforms = 1;
+ binder->codecs->dai_name = "codec-probing-DAI";
+ binder->num_codecs = 1;
+
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return -ENOMEM;
+
+ card->name = binder->codecs->name;
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->dai_link = binder;
+ card->num_links = 1;
+ card->fully_routed = true;
+ if (hda_codec_is_display(codec))
+ card->late_probe = avs_card_late_probe;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_hdaudio_driver = {
+ .probe = avs_hdaudio_probe,
+ .driver = {
+ .name = "avs_hdaudio",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_hdaudio_driver)
+
+MODULE_DESCRIPTION("Intel HD-Audio machine driver");
+MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_hdaudio");
diff --git a/sound/soc/intel/avs/boards/i2s_test.c b/sound/soc/intel/avs/boards/i2s_test.c
new file mode 100644
index 0000000..461b651
--- /dev/null
+++ b/sound/soc/intel/avs/boards/i2s_test.c
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = platform_name;
+
+ dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+ dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "snd-soc-dummy");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "snd-soc-dummy-dai");
+ if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+ return -ENOMEM;
+
+ dl->num_cpus = 1;
+ dl->num_codecs = 1;
+ dl->platforms = platform;
+ dl->num_platforms = 1;
+ dl->id = 0;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+ dl->dpcm_capture = 1;
+ dl->dpcm_playback = 1;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+ struct snd_soc_dapm_route **routes, int *num_routes)
+{
+ struct snd_soc_dapm_route *dr;
+ const int num_dr = 2;
+
+ dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ dr[0].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%dpb", ssp_port);
+ dr[0].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[0].sink || !dr[0].source)
+ return -ENOMEM;
+
+ dr[1].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+ dr[1].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%dcp", ssp_port);
+ if (!dr[1].sink || !dr[1].source)
+ return -ENOMEM;
+
+ *routes = dr;
+ *num_routes = num_dr;
+
+ return 0;
+}
+
+static int avs_create_dapm_widgets(struct device *dev, int ssp_port,
+ struct snd_soc_dapm_widget **widgets, int *num_widgets)
+{
+ struct snd_soc_dapm_widget *dw;
+ const int num_dw = 2;
+
+ dw = devm_kcalloc(dev, num_dw, sizeof(*dw), GFP_KERNEL);
+ if (!dw)
+ return -ENOMEM;
+
+ dw[0].id = snd_soc_dapm_hp;
+ dw[0].reg = SND_SOC_NOPM;
+ dw[0].name = devm_kasprintf(dev, GFP_KERNEL, "ssp%dpb", ssp_port);
+ if (!dw[0].name)
+ return -ENOMEM;
+
+ dw[1].id = snd_soc_dapm_mic;
+ dw[1].reg = SND_SOC_NOPM;
+ dw[1].name = devm_kasprintf(dev, GFP_KERNEL, "ssp%dcp", ssp_port);
+ if (!dw[1].name)
+ return -ENOMEM;
+
+ *widgets = dw;
+ *num_widgets = num_dw;
+
+ return 0;
+}
+
+static int avs_i2s_test_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dapm_widget *widgets;
+ struct snd_soc_dapm_route *routes;
+ struct snd_soc_dai_link *dai_link;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct device *dev = &pdev->dev;
+ const char *pname;
+ int num_routes, num_widgets;
+ int ssp_port, ret;
+
+ mach = dev_get_platdata(dev);
+ pname = mach->mach_params.platform;
+ ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return -ENOMEM;
+
+ card->name = devm_kasprintf(dev, GFP_KERNEL, "ssp%ld-loopback", ssp_port);
+ if (!card->name)
+ return -ENOMEM;
+
+ ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d\n", ret);
+ return ret;
+ }
+
+ ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+ if (ret) {
+ dev_err(dev, "Failed to create dapm routes: %d\n", ret);
+ return ret;
+ }
+
+ ret = avs_create_dapm_widgets(dev, ssp_port, &widgets, &num_widgets);
+ if (ret) {
+ dev_err(dev, "Failed to create dapm widgets: %d\n", ret);
+ return ret;
+ }
+
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->dapm_routes = routes;
+ card->num_dapm_routes = num_routes;
+ card->dapm_widgets = widgets;
+ card->num_dapm_widgets = num_widgets;
+ card->fully_routed = true;
+
+ ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_i2s_test_driver = {
+ .probe = avs_i2s_test_probe,
+ .driver = {
+ .name = "avs_i2s_test",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_i2s_test_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_i2s_test");
diff --git a/sound/soc/intel/avs/boards/max98357a.c b/sound/soc/intel/avs/boards/max98357a.c
new file mode 100644
index 0000000..921f42c
--- /dev/null
+++ b/sound/soc/intel/avs/boards/max98357a.c
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+
+static const struct snd_kcontrol_new card_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Spk"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_SPK("Spk", NULL),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+ { "Spk", NULL, "Speaker" },
+};
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = platform_name;
+
+ dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+ dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "MX98357A:00");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "HiFi");
+ if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+ return -ENOMEM;
+
+ dl->num_cpus = 1;
+ dl->num_codecs = 1;
+ dl->platforms = platform;
+ dl->num_platforms = 1;
+ dl->id = 0;
+ dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+ dl->dpcm_playback = 1;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+ struct snd_soc_dapm_route **routes, int *num_routes)
+{
+ struct snd_soc_dapm_route *dr;
+ const int num_base = ARRAY_SIZE(card_base_routes);
+ const int num_dr = num_base + 1;
+ int idx;
+
+ dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+ idx = num_base;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "HiFi Playback");
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ *routes = dr;
+ *num_routes = num_dr;
+
+ return 0;
+}
+
+static int avs_max98357a_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dapm_route *routes;
+ struct snd_soc_dai_link *dai_link;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct device *dev = &pdev->dev;
+ const char *pname;
+ int num_routes, ssp_port, ret;
+
+ mach = dev_get_platdata(dev);
+ pname = mach->mach_params.platform;
+ ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+ ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d", ret);
+ return ret;
+ }
+
+ ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+ if (ret) {
+ dev_err(dev, "Failed to create dapm routes: %d", ret);
+ return ret;
+ }
+
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return -ENOMEM;
+
+ card->name = "avs_max98357a";
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->controls = card_controls;
+ card->num_controls = ARRAY_SIZE(card_controls);
+ card->dapm_widgets = card_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+ card->dapm_routes = routes;
+ card->num_dapm_routes = num_routes;
+ card->fully_routed = true;
+
+ ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_max98357a_driver = {
+ .probe = avs_max98357a_probe,
+ .driver = {
+ .name = "avs_max98357a",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_max98357a_driver)
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_max98357a");
diff --git a/sound/soc/intel/avs/boards/max98373.c b/sound/soc/intel/avs/boards/max98373.c
new file mode 100644
index 0000000..0fa8f56
--- /dev/null
+++ b/sound/soc/intel/avs/boards/max98373.c
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+
+#define MAX98373_DEV0_NAME "i2c-MX98373:00"
+#define MAX98373_DEV1_NAME "i2c-MX98373:01"
+#define MAX98373_CODEC_NAME "max98373-aif1"
+
+static struct snd_soc_codec_conf card_codec_conf[] = {
+ {
+ .dlc = COMP_CODEC_CONF(MAX98373_DEV0_NAME),
+ .name_prefix = "Right",
+ },
+ {
+ .dlc = COMP_CODEC_CONF(MAX98373_DEV1_NAME),
+ .name_prefix = "Left",
+ },
+};
+
+static const struct snd_kcontrol_new card_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Left Spk"),
+ SOC_DAPM_PIN_SWITCH("Right Spk"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_SPK("Left Spk", NULL),
+ SND_SOC_DAPM_SPK("Right Spk", NULL),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+ { "Left Spk", NULL, "Left BE_OUT" },
+ { "Right Spk", NULL, "Right BE_OUT" },
+};
+
+static int
+avs_max98373_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate, *channels;
+ struct snd_mask *fmt;
+
+ rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ /* The ADSP will covert the FE rate to 48k, stereo */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ /* set SSP0 to 16 bit */
+ snd_mask_none(fmt);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
+ return 0;
+}
+
+static int avs_max98373_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai;
+ int ret, i;
+
+ for_each_rtd_codec_dais(runtime, i, codec_dai) {
+ if (!strcmp(codec_dai->component->name, MAX98373_DEV0_NAME)) {
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16);
+ if (ret < 0) {
+ dev_err(runtime->dev, "DEV0 TDM slot err:%d\n", ret);
+ return ret;
+ }
+ }
+ if (!strcmp(codec_dai->component->name, MAX98373_DEV1_NAME)) {
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16);
+ if (ret < 0) {
+ dev_err(runtime->dev, "DEV1 TDM slot err:%d\n", ret);
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_ops avs_max98373_ops = {
+ .hw_params = avs_max98373_hw_params,
+};
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = platform_name;
+
+ dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+ dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs) * 2, GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->codecs[0].name = devm_kasprintf(dev, GFP_KERNEL, MAX98373_DEV0_NAME);
+ dl->codecs[0].dai_name = devm_kasprintf(dev, GFP_KERNEL, MAX98373_CODEC_NAME);
+ dl->codecs[1].name = devm_kasprintf(dev, GFP_KERNEL, MAX98373_DEV1_NAME);
+ dl->codecs[1].dai_name = devm_kasprintf(dev, GFP_KERNEL, MAX98373_CODEC_NAME);
+ if (!dl->cpus->dai_name || !dl->codecs[0].name || !dl->codecs[0].dai_name ||
+ !dl->codecs[1].name || !dl->codecs[1].dai_name)
+ return -ENOMEM;
+
+ dl->num_cpus = 1;
+ dl->num_codecs = 2;
+ dl->platforms = platform;
+ dl->num_platforms = 1;
+ dl->id = 0;
+ dl->dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
+ dl->be_hw_params_fixup = avs_max98373_be_fixup;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+ dl->dpcm_capture = 1;
+ dl->dpcm_playback = 1;
+ dl->ignore_pmdown_time = 1;
+ dl->ops = &avs_max98373_ops;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+ struct snd_soc_dapm_route **routes, int *num_routes)
+{
+ struct snd_soc_dapm_route *dr;
+ const int num_base = ARRAY_SIZE(card_base_routes);
+ const int num_dr = num_base + 2;
+ int idx;
+
+ dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+ idx = num_base;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Left HiFi Playback");
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ idx++;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Right HiFi Playback");
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ *routes = dr;
+ *num_routes = num_dr;
+
+ return 0;
+}
+
+static int avs_max98373_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dapm_route *routes;
+ struct snd_soc_dai_link *dai_link;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct device *dev = &pdev->dev;
+ const char *pname;
+ int num_routes, ssp_port, ret;
+
+ mach = dev_get_platdata(dev);
+ pname = mach->mach_params.platform;
+ ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+ ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d", ret);
+ return ret;
+ }
+
+ ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+ if (ret) {
+ dev_err(dev, "Failed to create dapm routes: %d", ret);
+ return ret;
+ }
+
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return -ENOMEM;
+
+ card->name = "avs_max98373";
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->codec_conf = card_codec_conf;
+ card->num_configs = ARRAY_SIZE(card_codec_conf);
+ card->controls = card_controls;
+ card->num_controls = ARRAY_SIZE(card_controls);
+ card->dapm_widgets = card_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+ card->dapm_routes = routes;
+ card->num_dapm_routes = num_routes;
+ card->fully_routed = true;
+
+ ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_max98373_driver = {
+ .probe = avs_max98373_probe,
+ .driver = {
+ .name = "avs_max98373",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_max98373_driver)
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_max98373");
diff --git a/sound/soc/intel/avs/boards/nau8825.c b/sound/soc/intel/avs/boards/nau8825.c
new file mode 100644
index 0000000..f76909e
--- /dev/null
+++ b/sound/soc/intel/avs/boards/nau8825.c
@@ -0,0 +1,353 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/nau8825.h"
+
+#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi"
+
+static int
+avs_nau8825_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *control, int event)
+{
+ struct snd_soc_dapm_context *dapm = w->dapm;
+ struct snd_soc_card *card = dapm->card;
+ struct snd_soc_dai *codec_dai;
+ int ret;
+
+ codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI);
+ if (!codec_dai) {
+ dev_err(card->dev, "Codec dai not found\n");
+ return -EINVAL;
+ }
+
+ if (!SND_SOC_DAPM_EVENT_ON(event)) {
+ ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(card->dev, "set sysclk err = %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new card_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, avs_nau8825_clock_control,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+ { "Headphone Jack", NULL, "HPOL" },
+ { "Headphone Jack", NULL, "HPOR" },
+
+ { "MIC", NULL, "Headset Mic" },
+
+ { "Headphone Jack", NULL, "Platform Clock" },
+ { "Headset Mic", NULL, "Platform Clock" },
+};
+
+static struct snd_soc_jack_pin card_headset_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static int avs_nau8825_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+ struct snd_soc_component *component = codec_dai->component;
+ struct snd_soc_jack_pin *pins;
+ struct snd_soc_jack *jack;
+ struct snd_soc_card *card = runtime->card;
+ int num_pins, ret;
+
+ jack = snd_soc_card_get_drvdata(card);
+ num_pins = ARRAY_SIZE(card_headset_pins);
+
+ pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
+
+ /*
+ * 4 buttons here map to the google Reference headset.
+ * The use of these buttons can be decided by the user space.
+ */
+ ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0 |
+ SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ jack, pins, num_pins);
+ if (ret)
+ return ret;
+
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+
+ //snd_soc_component_set_jack(component, jack, NULL);
+ // TODO: Fix nau8825 codec to use .set_jack, like everyone else
+ nau8825_enable_jack_detect(component, jack);
+
+ return 0;
+}
+
+static int
+avs_nau8825_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate, *channels;
+ struct snd_mask *fmt;
+
+ rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ /* The ADSP will convert the FE rate to 48k, stereo */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ /* set SSP to 24 bit */
+ snd_mask_none(fmt);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+ return 0;
+}
+
+static int avs_nau8825_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtm = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtm, 0);
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_FS, 0, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "can't set FS clock %d\n", ret);
+ break;
+ }
+
+ ret = snd_soc_dai_set_pll(codec_dai, 0, 0, runtime->rate, runtime->rate * 256);
+ if (ret < 0)
+ dev_err(codec_dai->dev, "can't set FLL: %d\n", ret);
+ break;
+
+ case SNDRV_PCM_TRIGGER_RESUME:
+ ret = snd_soc_dai_set_pll(codec_dai, 0, 0, runtime->rate, runtime->rate * 256);
+ if (ret < 0)
+ dev_err(codec_dai->dev, "can't set FLL: %d\n", ret);
+ break;
+ }
+
+ return ret;
+}
+
+
+static const struct snd_soc_ops avs_nau8825_ops = {
+ .trigger = avs_nau8825_trigger,
+};
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = platform_name;
+
+ dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+ dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-10508825:00");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, SKL_NUVOTON_CODEC_DAI);
+ if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+ return -ENOMEM;
+
+ dl->num_cpus = 1;
+ dl->num_codecs = 1;
+ dl->platforms = platform;
+ dl->num_platforms = 1;
+ dl->id = 0;
+ dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->init = avs_nau8825_codec_init;
+ dl->be_hw_params_fixup = avs_nau8825_be_fixup;
+ dl->ops = &avs_nau8825_ops;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+ dl->dpcm_capture = 1;
+ dl->dpcm_playback = 1;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+ struct snd_soc_dapm_route **routes, int *num_routes)
+{
+ struct snd_soc_dapm_route *dr;
+ const int num_base = ARRAY_SIZE(card_base_routes);
+ const int num_dr = num_base + 2;
+ int idx;
+
+ dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+ idx = num_base;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Playback");
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ idx++;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "Capture");
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ *routes = dr;
+ *num_routes = num_dr;
+
+ return 0;
+}
+
+static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
+{
+ struct snd_soc_component *component;
+
+ for_each_card_components(card, component)
+ snd_soc_component_set_jack(component, jack, NULL);
+ return 0;
+}
+
+static int avs_card_remove(struct snd_soc_card *card)
+{
+ return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+ return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI);
+ struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+ if (!codec_dai) {
+ dev_err(card->dev, "Codec dai not found\n");
+ return -EINVAL;
+ }
+
+ if (codec_dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK] &&
+ codec_dai->playback_widget->active)
+ snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_FS, 0, SND_SOC_CLOCK_IN);
+
+ return avs_card_set_jack(card, jack);
+}
+
+static int avs_nau8825_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dapm_route *routes;
+ struct snd_soc_dai_link *dai_link;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct snd_soc_jack *jack;
+ struct device *dev = &pdev->dev;
+ const char *pname;
+ int num_routes, ssp_port, ret;
+
+ mach = dev_get_platdata(dev);
+ pname = mach->mach_params.platform;
+ ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+ ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d", ret);
+ return ret;
+ }
+
+ ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+ if (ret) {
+ dev_err(dev, "Failed to create dapm routes: %d", ret);
+ return ret;
+ }
+
+ jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL);
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!jack || !card)
+ return -ENOMEM;
+
+ card->name = "avs_nau8825";
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->remove = avs_card_remove;
+ card->suspend_pre = avs_card_suspend_pre;
+ card->resume_post = avs_card_resume_post;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->controls = card_controls;
+ card->num_controls = ARRAY_SIZE(card_controls);
+ card->dapm_widgets = card_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+ card->dapm_routes = routes;
+ card->num_dapm_routes = num_routes;
+ card->fully_routed = true;
+ snd_soc_card_set_drvdata(card, jack);
+
+ ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_nau8825_driver = {
+ .probe = avs_nau8825_probe,
+ .driver = {
+ .name = "avs_nau8825",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_nau8825_driver)
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_nau8825");
diff --git a/sound/soc/intel/avs/boards/rt274.c b/sound/soc/intel/avs/boards/rt274.c
new file mode 100644
index 0000000..afef5a3
--- /dev/null
+++ b/sound/soc/intel/avs/boards/rt274.c
@@ -0,0 +1,310 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/rt274.h"
+
+#define AVS_RT274_FREQ_OUT 24000000
+#define AVS_RT274_BE_FIXUP_RATE 48000
+#define RT274_CODEC_DAI "rt274-aif1"
+
+static const struct snd_kcontrol_new card_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Mic Jack"),
+};
+
+static int
+avs_rt274_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *control, int event)
+{
+ struct snd_soc_dapm_context *dapm = w->dapm;
+ struct snd_soc_card *card = dapm->card;
+ struct snd_soc_dai *codec_dai;
+ int ret;
+
+ codec_dai = snd_soc_card_get_codec_dai(card, RT274_CODEC_DAI);
+ if (!codec_dai)
+ return -EINVAL;
+
+ /* Codec needs clock for Jack detection and button press */
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT274_SCLK_S_PLL2, AVS_RT274_FREQ_OUT,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "set codec sysclk failed: %d\n", ret);
+ return ret;
+ }
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ int ratio = 100;
+
+ snd_soc_dai_set_bclk_ratio(codec_dai, ratio);
+
+ ret = snd_soc_dai_set_pll(codec_dai, 0, RT274_PLL2_S_BCLK,
+ AVS_RT274_BE_FIXUP_RATE * ratio, AVS_RT274_FREQ_OUT);
+ if (ret) {
+ dev_err(codec_dai->dev, "failed to enable PLL2: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+ SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, avs_rt274_clock_control,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+ {"Headphone Jack", NULL, "HPO Pin"},
+ {"MIC", NULL, "Mic Jack"},
+
+ {"Headphone Jack", NULL, "Platform Clock"},
+ {"MIC", NULL, "Platform Clock"},
+};
+
+static struct snd_soc_jack_pin card_headset_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Mic Jack",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static int avs_rt274_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+ struct snd_soc_component *component = codec_dai->component;
+ struct snd_soc_jack_pin *pins;
+ struct snd_soc_jack *jack;
+ struct snd_soc_card *card = runtime->card;
+ int num_pins, ret;
+
+ jack = snd_soc_card_get_drvdata(card);
+ num_pins = ARRAY_SIZE(card_headset_pins);
+
+ pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
+
+ ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET, jack, pins, num_pins);
+ if (ret)
+ return ret;
+
+ snd_soc_component_set_jack(component, jack, NULL);
+
+ /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24);
+ if (ret < 0) {
+ dev_err(card->dev, "can't set codec pcm format %d\n", ret);
+ return ret;
+ }
+
+ card->dapm.idle_bias_off = true;
+
+ return 0;
+}
+
+static int avs_rt274_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate, *channels;
+ struct snd_mask *fmt;
+
+ rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ /* The ADSP will convert the FE rate to 48k, stereo */
+ rate->min = rate->max = AVS_RT274_BE_FIXUP_RATE;
+ channels->min = channels->max = 2;
+
+ /* set SSPN to 24 bit */
+ snd_mask_none(fmt);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+ return 0;
+}
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = platform_name;
+
+ dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+ dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT34C2:00");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "rt274-aif1");
+ if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+ return -ENOMEM;
+
+ dl->num_cpus = 1;
+ dl->num_codecs = 1;
+ dl->platforms = platform;
+ dl->num_platforms = 1;
+ dl->id = 0;
+ dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->init = avs_rt274_codec_init;
+ dl->be_hw_params_fixup = avs_rt274_be_fixup;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+ dl->dpcm_capture = 1;
+ dl->dpcm_playback = 1;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+ struct snd_soc_dapm_route **routes, int *num_routes)
+{
+ struct snd_soc_dapm_route *dr;
+ const int num_base = ARRAY_SIZE(card_base_routes);
+ const int num_dr = num_base + 2;
+ int idx;
+
+ dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+ idx = num_base;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Playback");
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ idx++;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Capture");
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ *routes = dr;
+ *num_routes = num_dr;
+
+ return 0;
+}
+
+static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
+{
+ struct snd_soc_component *component;
+
+ for_each_card_components(card, component)
+ snd_soc_component_set_jack(component, jack, NULL);
+ return 0;
+}
+
+static int avs_card_remove(struct snd_soc_card *card)
+{
+ return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+ return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+ struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+ return avs_card_set_jack(card, jack);
+}
+
+static int avs_rt274_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dapm_route *routes;
+ struct snd_soc_dai_link *dai_link;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct snd_soc_jack *jack;
+ struct device *dev = &pdev->dev;
+ const char *pname;
+ int num_routes, ssp_port, ret;
+
+ mach = dev_get_platdata(dev);
+ pname = mach->mach_params.platform;
+ ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+ ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d", ret);
+ return ret;
+ }
+
+ ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+ if (ret) {
+ dev_err(dev, "Failed to create dapm routes: %d", ret);
+ return ret;
+ }
+
+ jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL);
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!jack || !card)
+ return -ENOMEM;
+
+ card->name = "avs_rt274";
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->remove = avs_card_remove;
+ card->suspend_pre = avs_card_suspend_pre;
+ card->resume_post = avs_card_resume_post;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->controls = card_controls;
+ card->num_controls = ARRAY_SIZE(card_controls);
+ card->dapm_widgets = card_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+ card->dapm_routes = routes;
+ card->num_dapm_routes = num_routes;
+ card->fully_routed = true;
+ snd_soc_card_set_drvdata(card, jack);
+
+ ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_rt274_driver = {
+ .probe = avs_rt274_probe,
+ .driver = {
+ .name = "avs_rt274",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_rt274_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_rt274");
diff --git a/sound/soc/intel/avs/boards/rt286.c b/sound/soc/intel/avs/boards/rt286.c
new file mode 100644
index 0000000..e51d4e1
--- /dev/null
+++ b/sound/soc/intel/avs/boards/rt286.c
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/rt286.h"
+
+static const struct snd_kcontrol_new card_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Mic Jack"),
+ SOC_DAPM_PIN_SWITCH("Speaker"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+ /* HP jack connectors - unknown if we have jack detect */
+ {"Headphone Jack", NULL, "HPO Pin"},
+ {"MIC1", NULL, "Mic Jack"},
+
+ {"Speaker", NULL, "SPOR"},
+ {"Speaker", NULL, "SPOL"},
+};
+
+static struct snd_soc_jack_pin card_headset_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Mic Jack",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static int avs_rt286_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+ struct snd_soc_jack_pin *pins;
+ struct snd_soc_jack *jack;
+ struct snd_soc_card *card = runtime->card;
+ int num_pins, ret;
+
+ jack = snd_soc_card_get_drvdata(card);
+ num_pins = ARRAY_SIZE(card_headset_pins);
+
+ pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
+
+ ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0, jack,
+ pins, num_pins);
+ if (ret)
+ return ret;
+
+ snd_soc_component_set_jack(component, jack, NULL);
+
+ return 0;
+}
+
+static int avs_rt286_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate, *channels;
+ struct snd_mask *fmt;
+
+ rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ /* The ADSP will convert the FE rate to 48k, stereo */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ /* set SSP0 to 24 bit */
+ snd_mask_none(fmt);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+ return 0;
+}
+
+static int
+avs_rt286_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *runtime = substream->private_data;
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+ int ret;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ dev_err(runtime->dev, "Set codec sysclk failed: %d\n", ret);
+
+ return ret;
+}
+
+static const struct snd_soc_ops avs_rt286_ops = {
+ .hw_params = avs_rt286_hw_params,
+};
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = platform_name;
+
+ dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+ dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT343A:00");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "rt286-aif1");
+ if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+ return -ENOMEM;
+
+ dl->num_cpus = 1;
+ dl->num_codecs = 1;
+ dl->platforms = platform;
+ dl->num_platforms = 1;
+ dl->id = 0;
+ dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->init = avs_rt286_codec_init;
+ dl->be_hw_params_fixup = avs_rt286_be_fixup;
+ dl->ops = &avs_rt286_ops;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+ dl->dpcm_capture = 1;
+ dl->dpcm_playback = 1;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+ struct snd_soc_dapm_route **routes, int *num_routes)
+{
+ struct snd_soc_dapm_route *dr;
+ const int num_base = ARRAY_SIZE(card_base_routes);
+ const int num_dr = num_base + 2;
+ int idx;
+
+ dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+ idx = num_base;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Playback");
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ idx++;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Capture");
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ *routes = dr;
+ *num_routes = num_dr;
+
+ return 0;
+}
+
+static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
+{
+ struct snd_soc_component *component;
+
+ for_each_card_components(card, component)
+ snd_soc_component_set_jack(component, jack, NULL);
+ return 0;
+}
+
+static int avs_card_remove(struct snd_soc_card *card)
+{
+ return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+ return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+ struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+ return avs_card_set_jack(card, jack);
+}
+
+static int avs_rt286_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dapm_route *routes;
+ struct snd_soc_dai_link *dai_link;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct snd_soc_jack *jack;
+ struct device *dev = &pdev->dev;
+ const char *pname;
+ int num_routes, ssp_port, ret;
+
+ mach = dev_get_platdata(dev);
+ pname = mach->mach_params.platform;
+ ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+ ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d", ret);
+ return ret;
+ }
+
+ ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+ if (ret) {
+ dev_err(dev, "Failed to create dapm routes: %d", ret);
+ return ret;
+ }
+
+ jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL);
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!jack || !card)
+ return -ENOMEM;
+
+ card->name = "avs_rt286";
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->remove = avs_card_remove;
+ card->suspend_pre = avs_card_suspend_pre;
+ card->resume_post = avs_card_resume_post;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->controls = card_controls;
+ card->num_controls = ARRAY_SIZE(card_controls);
+ card->dapm_widgets = card_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+ card->dapm_routes = routes;
+ card->num_dapm_routes = num_routes;
+ card->fully_routed = true;
+ snd_soc_card_set_drvdata(card, jack);
+
+ ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_rt286_driver = {
+ .probe = avs_rt286_probe,
+ .driver = {
+ .name = "avs_rt286",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_rt286_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_rt286");
diff --git a/sound/soc/intel/avs/boards/rt298.c b/sound/soc/intel/avs/boards/rt298.c
new file mode 100644
index 0000000..b28d368
--- /dev/null
+++ b/sound/soc/intel/avs/boards/rt298.c
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/rt298.h"
+
+static const struct snd_kcontrol_new card_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Mic Jack"),
+ SOC_DAPM_PIN_SWITCH("Speaker"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+ /* HP jack connectors - unknown if we have jack detect */
+ {"Headphone Jack", NULL, "HPO Pin"},
+ {"MIC1", NULL, "Mic Jack"},
+
+ {"Speaker", NULL, "SPOR"},
+ {"Speaker", NULL, "SPOL"},
+};
+
+static struct snd_soc_jack_pin card_headset_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Mic Jack",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static int avs_rt298_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+ struct snd_soc_jack_pin *pins;
+ struct snd_soc_jack *jack;
+ struct snd_soc_card *card = runtime->card;
+ int num_pins, ret;
+
+ jack = snd_soc_card_get_drvdata(card);
+ num_pins = ARRAY_SIZE(card_headset_pins);
+
+ pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
+
+ ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0, jack,
+ pins, num_pins);
+ if (ret)
+ return ret;
+
+ snd_soc_component_set_jack(component, jack, NULL);
+
+ return 0;
+}
+
+static int avs_rt298_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate, *channels;
+ struct snd_mask *fmt;
+
+ rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ /* The ADSP will convert the FE rate to 48k, stereo */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ /* set SSP0 to 24 bit */
+ snd_mask_none(fmt);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+ return 0;
+}
+
+static int
+avs_rt298_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 = asoc_rtd_to_codec(rtd, 0);
+ int ret;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT298_SCLK_S_PLL, 19200000, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ dev_err(rtd->dev, "Set codec sysclk failed: %d\n", ret);
+
+ return ret;
+}
+
+static const struct snd_soc_ops avs_rt298_ops = {
+ .hw_params = avs_rt298_hw_params,
+};
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = platform_name;
+
+ dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+ dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT343A:00");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "rt298-aif1");
+ if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+ return -ENOMEM;
+
+ dl->num_cpus = 1;
+ dl->num_codecs = 1;
+ dl->platforms = platform;
+ dl->num_platforms = 1;
+ dl->id = 0;
+ dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->init = avs_rt298_codec_init;
+ dl->be_hw_params_fixup = avs_rt298_be_fixup;
+ dl->ops = &avs_rt298_ops;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+ dl->dpcm_capture = 1;
+ dl->dpcm_playback = 1;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+ struct snd_soc_dapm_route **routes, int *num_routes)
+{
+ struct snd_soc_dapm_route *dr;
+ const int num_base = ARRAY_SIZE(card_base_routes);
+ const int num_dr = num_base + 2;
+ int idx;
+
+ dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+ idx = num_base;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Playback");
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ idx++;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Capture");
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ *routes = dr;
+ *num_routes = num_dr;
+
+ return 0;
+}
+
+static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
+{
+ struct snd_soc_component *component;
+
+ for_each_card_components(card, component)
+ snd_soc_component_set_jack(component, jack, NULL);
+ return 0;
+}
+
+static int avs_card_remove(struct snd_soc_card *card)
+{
+ return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+ return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+ struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+ return avs_card_set_jack(card, jack);
+}
+
+static int avs_rt298_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dapm_route *routes;
+ struct snd_soc_dai_link *dai_link;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct snd_soc_jack *jack;
+ struct device *dev = &pdev->dev;
+ const char *pname;
+ int num_routes, ssp_port, ret;
+
+ mach = dev_get_platdata(dev);
+ pname = mach->mach_params.platform;
+ ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+ ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d", ret);
+ return ret;
+ }
+
+ ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+ if (ret) {
+ dev_err(dev, "Failed to create dapm routes: %d", ret);
+ return ret;
+ }
+
+ jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL);
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!jack || !card)
+ return -ENOMEM;
+
+ card->name = "avs_rt298";
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->remove = avs_card_remove;
+ card->suspend_pre = avs_card_suspend_pre;
+ card->resume_post = avs_card_resume_post;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->controls = card_controls;
+ card->num_controls = ARRAY_SIZE(card_controls);
+ card->dapm_widgets = card_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+ card->dapm_routes = routes;
+ card->num_dapm_routes = num_routes;
+ card->fully_routed = true;
+ snd_soc_card_set_drvdata(card, jack);
+
+ ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_rt298_driver = {
+ .probe = avs_rt298_probe,
+ .driver = {
+ .name = "avs_rt298",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_rt298_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_rt298");
diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c
new file mode 100644
index 0000000..01f9b9f
--- /dev/null
+++ b/sound/soc/intel/avs/boards/rt5682.c
@@ -0,0 +1,340 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/clk.h>
+#include <linux/dmi.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/rt5682.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../common/soc-intel-quirks.h"
+#include "../../../codecs/rt5682.h"
+
+#define AVS_RT5682_SSP_CODEC(quirk) ((quirk) & GENMASK(2, 0))
+#define AVS_RT5682_SSP_CODEC_MASK (GENMASK(2, 0))
+#define AVS_RT5682_MCLK_EN BIT(3)
+#define AVS_RT5682_MCLK_24MHZ BIT(4)
+
+/* Default: MCLK on, MCLK 19.2M, SSP0 */
+static unsigned long avs_rt5682_quirk = AVS_RT5682_MCLK_EN | AVS_RT5682_SSP_CODEC(0);
+
+static int avs_rt5682_quirk_cb(const struct dmi_system_id *id)
+{
+ avs_rt5682_quirk = (unsigned long)id->driver_data;
+ return 1;
+}
+
+static const struct dmi_system_id avs_rt5682_quirk_table[] = {
+ {
+ .callback = avs_rt5682_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "WhiskeyLake Client"),
+ },
+ .driver_data = (void *)(AVS_RT5682_MCLK_EN |
+ AVS_RT5682_MCLK_24MHZ |
+ AVS_RT5682_SSP_CODEC(1)),
+ },
+ {
+ .callback = avs_rt5682_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"),
+ },
+ .driver_data = (void *)(AVS_RT5682_MCLK_EN |
+ AVS_RT5682_SSP_CODEC(0)),
+ },
+ {}
+};
+
+static const struct snd_kcontrol_new card_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+ /* HP jack connectors - unknown if we have jack detect */
+ { "Headphone Jack", NULL, "HPOL" },
+ { "Headphone Jack", NULL, "HPOR" },
+
+ /* other jacks */
+ { "IN1P", NULL, "Headset Mic" },
+};
+
+static int avs_rt5682_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+ struct snd_soc_jack *jack;
+ struct snd_soc_card *card = runtime->card;
+ int ret;
+
+ jack = snd_soc_card_get_drvdata(card);
+
+ /* Need to enable ASRC function for 24MHz mclk rate */
+ if ((avs_rt5682_quirk & AVS_RT5682_MCLK_EN) &&
+ (avs_rt5682_quirk & AVS_RT5682_MCLK_24MHZ)) {
+ rt5682_sel_asrc_clk_src(component, RT5682_DA_STEREO1_FILTER |
+ RT5682_AD_STEREO1_FILTER, RT5682_CLK_SEL_I2S1_ASRC);
+ }
+
+ /*
+ * Headset buttons map to the google Reference headset.
+ * These can be configured by userspace.
+ */
+ ret = snd_soc_card_jack_new(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0 |
+ SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, jack);
+ if (ret) {
+ dev_err(card->dev, "Headset Jack creation failed: %d\n", ret);
+ return ret;
+ }
+
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+
+ ret = snd_soc_component_set_jack(component, jack, NULL);
+ if (ret) {
+ dev_err(card->dev, "Headset Jack call-back failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+};
+
+static int
+avs_rt5682_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+ int clk_id, clk_freq;
+ int pll_out, ret;
+
+ if (avs_rt5682_quirk & AVS_RT5682_MCLK_EN) {
+ clk_id = RT5682_PLL1_S_MCLK;
+ if (avs_rt5682_quirk & AVS_RT5682_MCLK_24MHZ)
+ clk_freq = 24000000;
+ else
+ clk_freq = 19200000;
+ } else {
+ clk_id = RT5682_PLL1_S_BCLK1;
+ clk_freq = params_rate(params) * 50;
+ }
+
+ pll_out = params_rate(params) * 512;
+
+ ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out);
+ if (ret < 0)
+ dev_err(runtime->dev, "snd_soc_dai_set_pll err = %d\n", ret);
+
+ /* Configure sysclk for codec */
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, pll_out, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ dev_err(runtime->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
+
+ /* slot_width should equal or large than data length, set them be the same */
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2, params_width(params));
+ if (ret < 0) {
+ dev_err(runtime->dev, "set TDM slot err:%d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_ops avs_rt5682_ops = {
+ .hw_params = avs_rt5682_hw_params,
+};
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = platform_name;
+
+ dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+ dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-10EC5682:00");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "rt5682-aif1");
+ if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+ return -ENOMEM;
+
+ dl->num_cpus = 1;
+ dl->num_codecs = 1;
+ dl->platforms = platform;
+ dl->num_platforms = 1;
+ dl->id = 0;
+ dl->init = avs_rt5682_codec_init;
+ dl->ops = &avs_rt5682_ops;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+ dl->dpcm_capture = 1;
+ dl->dpcm_playback = 1;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+ struct snd_soc_dapm_route **routes, int *num_routes)
+{
+ struct snd_soc_dapm_route *dr;
+ const int num_base = ARRAY_SIZE(card_base_routes);
+ const int num_dr = num_base + 2;
+ int idx;
+
+ dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+ idx = num_base;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Playback");
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ idx++;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Capture");
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ *routes = dr;
+ *num_routes = num_dr;
+
+ return 0;
+}
+
+static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
+{
+ struct snd_soc_component *component;
+
+ for_each_card_components(card, component)
+ snd_soc_component_set_jack(component, jack, NULL);
+ return 0;
+}
+
+static int avs_card_remove(struct snd_soc_card *card)
+{
+ return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+ return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+ struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+ return avs_card_set_jack(card, jack);
+}
+
+static int avs_rt5682_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dapm_route *routes;
+ struct snd_soc_dai_link *dai_link;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct snd_soc_jack *jack;
+ struct device *dev = &pdev->dev;
+ const char *pname;
+ int num_routes, ssp_port, ret;
+
+ if (pdev->id_entry && pdev->id_entry->driver_data)
+ avs_rt5682_quirk = (unsigned long)pdev->id_entry->driver_data;
+
+ dmi_check_system(avs_rt5682_quirk_table);
+ dev_dbg(dev, "avs_rt5682_quirk = %lx\n", avs_rt5682_quirk);
+
+ mach = dev_get_platdata(dev);
+ pname = mach->mach_params.platform;
+ ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+ ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d", ret);
+ return ret;
+ }
+
+ ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+ if (ret) {
+ dev_err(dev, "Failed to create dapm routes: %d", ret);
+ return ret;
+ }
+
+ jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL);
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!jack || !card)
+ return -ENOMEM;
+
+ card->name = "avs_rt5682";
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->remove = avs_card_remove;
+ card->suspend_pre = avs_card_suspend_pre;
+ card->resume_post = avs_card_resume_post;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->controls = card_controls;
+ card->num_controls = ARRAY_SIZE(card_controls);
+ card->dapm_widgets = card_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+ card->dapm_routes = routes;
+ card->num_dapm_routes = num_routes;
+ card->fully_routed = true;
+ snd_soc_card_set_drvdata(card, jack);
+
+ ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_rt5682_driver = {
+ .probe = avs_rt5682_probe,
+ .driver = {
+ .name = "avs_rt5682",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_rt5682_driver)
+
+MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_rt5682");
diff --git a/sound/soc/intel/avs/boards/ssm4567.c b/sound/soc/intel/avs/boards/ssm4567.c
new file mode 100644
index 0000000..9f84c8ab
--- /dev/null
+++ b/sound/soc/intel/avs/boards/ssm4567.c
@@ -0,0 +1,271 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/nau8825.h"
+
+#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi"
+#define SKL_SSM_CODEC_DAI "ssm4567-hifi"
+
+static struct snd_soc_codec_conf card_codec_conf[] = {
+ {
+ .dlc = COMP_CODEC_CONF("i2c-INT343B:00"),
+ .name_prefix = "Left",
+ },
+ {
+ .dlc = COMP_CODEC_CONF("i2c-INT343B:01"),
+ .name_prefix = "Right",
+ },
+};
+
+static const struct snd_kcontrol_new card_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Left Speaker"),
+ SOC_DAPM_PIN_SWITCH("Right Speaker"),
+};
+
+static int
+platform_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *control, int event)
+{
+ struct snd_soc_dapm_context *dapm = w->dapm;
+ struct snd_soc_card *card = dapm->card;
+ struct snd_soc_dai *codec_dai;
+ int ret;
+
+ codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI);
+ if (!codec_dai) {
+ dev_err(card->dev, "Codec dai not found\n");
+ return -EINVAL;
+ }
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_MCLK, 24000000,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ dev_err(card->dev, "set sysclk err = %d\n", ret);
+ } else {
+ ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ dev_err(card->dev, "set sysclk err = %d\n", ret);
+ }
+
+ return ret;
+}
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_SPK("Left Speaker", NULL),
+ SND_SOC_DAPM_SPK("Right Speaker", NULL),
+ SND_SOC_DAPM_SPK("DP1", NULL),
+ SND_SOC_DAPM_SPK("DP2", NULL),
+ SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+ {"Left Speaker", NULL, "Left OUT"},
+ {"Right Speaker", NULL, "Right OUT"},
+};
+
+static int avs_ssm4567_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+ int ret;
+
+ /* Slot 1 for left */
+ ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(runtime, 0), 0x01, 0x01, 2, 48);
+ if (ret < 0)
+ return ret;
+
+ /* Slot 2 for right */
+ ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(runtime, 1), 0x02, 0x02, 2, 48);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int
+avs_ssm4567_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate, *channels;
+ struct snd_mask *fmt;
+
+ rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ /* The ADSP will covert the FE rate to 48k, stereo */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ /* set SSP0 to 24 bit */
+ snd_mask_none(fmt);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+ return 0;
+}
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = platform_name;
+
+ dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+ dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs) * 2, GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->codecs[0].name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT343B:00");
+ dl->codecs[0].dai_name = devm_kasprintf(dev, GFP_KERNEL, "ssm4567-hifi");
+ dl->codecs[1].name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT343B:01");
+ dl->codecs[1].dai_name = devm_kasprintf(dev, GFP_KERNEL, "ssm4567-hifi");
+ if (!dl->cpus->dai_name || !dl->codecs[0].name || !dl->codecs[0].dai_name ||
+ !dl->codecs[1].name || !dl->codecs[1].dai_name)
+ return -ENOMEM;
+
+ dl->num_cpus = 1;
+ dl->num_codecs = 2;
+ dl->platforms = platform;
+ dl->num_platforms = 1;
+ dl->id = 0;
+ dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->init = avs_ssm4567_codec_init;
+ dl->be_hw_params_fixup = avs_ssm4567_be_fixup;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+ dl->dpcm_capture = 1;
+ dl->dpcm_playback = 1;
+ dl->ignore_pmdown_time = 1;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+ struct snd_soc_dapm_route **routes, int *num_routes)
+{
+ struct snd_soc_dapm_route *dr;
+ const int num_base = ARRAY_SIZE(card_base_routes);
+ const int num_dr = num_base + 4;
+ int idx;
+
+ dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+ idx = num_base;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Left Playback");
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ idx++;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Right Playback");
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ idx++;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "Left Capture Sense");
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ idx++;
+ dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+ dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "Right Capture Sense");
+ if (!dr[idx].sink || !dr[idx].source)
+ return -ENOMEM;
+
+ *routes = dr;
+ *num_routes = num_dr;
+
+ return 0;
+}
+
+static int avs_ssm4567_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dapm_route *routes;
+ struct snd_soc_dai_link *dai_link;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct device *dev = &pdev->dev;
+ const char *pname;
+ int num_routes, ssp_port, ret;
+
+ mach = dev_get_platdata(dev);
+ pname = mach->mach_params.platform;
+ ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+ ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d", ret);
+ return ret;
+ }
+
+ ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+ if (ret) {
+ dev_err(dev, "Failed to create dapm routes: %d", ret);
+ return ret;
+ }
+
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return -ENOMEM;
+
+ card->name = "avs_ssm4567-adi";
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->codec_conf = card_codec_conf;
+ card->num_configs = ARRAY_SIZE(card_codec_conf);
+ card->controls = card_controls;
+ card->num_controls = ARRAY_SIZE(card_controls);
+ card->dapm_widgets = card_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+ card->dapm_routes = routes;
+ card->num_dapm_routes = num_routes;
+ card->fully_routed = true;
+ card->disable_route_checks = true;
+
+ ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_ssm4567_driver = {
+ .probe = avs_ssm4567_probe,
+ .driver = {
+ .name = "avs_ssm4567",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_ssm4567_driver)
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_ssm4567");
diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
index f3873b5..4b4c1e1 100644
--- a/sound/soc/intel/boards/Kconfig
+++ b/sound/soc/intel/boards/Kconfig
@@ -660,7 +660,6 @@
depends on MFD_INTEL_LPSS || COMPILE_TEST
depends on SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES || COMPILE_TEST
depends on SOUNDWIRE
- depends on SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC
select SND_SOC_MAX98373_I2C
select SND_SOC_MAX98373_SDW
select SND_SOC_RT700_SDW
diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c
index c30a9dc..48bf324 100644
--- a/sound/soc/intel/boards/broadwell.c
+++ b/sound/soc/intel/boards/broadwell.c
@@ -75,7 +75,7 @@ static int broadwell_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
if (ret)
return ret;
- rt286_mic_detect(component, &broadwell_headset);
+ snd_soc_component_set_jack(component, &broadwell_headset, NULL);
return 0;
}
@@ -227,7 +227,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = {
},
};
-static int broadwell_disable_jack(struct snd_soc_card *card)
+static void broadwell_disable_jack(struct snd_soc_card *card)
{
struct snd_soc_component *component;
@@ -235,17 +235,17 @@ static int broadwell_disable_jack(struct snd_soc_card *card)
if (!strcmp(component->name, "i2c-INT343A:00")) {
dev_dbg(component->dev, "disabling jack detect before going to suspend.\n");
- rt286_mic_detect(component, NULL);
+ snd_soc_component_set_jack(component, NULL, NULL);
break;
}
}
-
- return 0;
}
static int broadwell_suspend(struct snd_soc_card *card)
{
- return broadwell_disable_jack(card);
+ broadwell_disable_jack(card);
+
+ return 0;
}
static int broadwell_resume(struct snd_soc_card *card){
@@ -255,7 +255,7 @@ static int broadwell_resume(struct snd_soc_card *card){
if (!strcmp(component->name, "i2c-INT343A:00")) {
dev_dbg(component->dev, "enabling jack detect for resume.\n");
- rt286_mic_detect(component, &broadwell_headset);
+ snd_soc_component_set_jack(component, &broadwell_headset, NULL);
break;
}
}
@@ -315,7 +315,9 @@ static int broadwell_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
- return broadwell_disable_jack(card);
+ broadwell_disable_jack(card);
+
+ return 0;
}
static struct platform_driver broadwell_audio = {
diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c
index 75995d1..4bd93c3 100644
--- a/sound/soc/intel/boards/bxt_rt298.c
+++ b/sound/soc/intel/boards/bxt_rt298.c
@@ -176,7 +176,7 @@ static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd)
if (ret)
return ret;
- rt298_mic_detect(component, &broxton_headset);
+ snd_soc_component_set_jack(component, &broxton_headset, NULL);
snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
diff --git a/sound/soc/intel/boards/bytcht_cx2072x.c b/sound/soc/intel/boards/bytcht_cx2072x.c
index 0eed68a..ae89986 100644
--- a/sound/soc/intel/boards/bytcht_cx2072x.c
+++ b/sound/soc/intel/boards/bytcht_cx2072x.c
@@ -126,7 +126,7 @@ static int byt_cht_cx2072x_fixup(struct snd_soc_pcm_runtime *rtd,
ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC);
+ SND_SOC_DAIFMT_BP_FP);
if (ret < 0) {
dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
return ret;
diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c
index eb19bf1..a0c8f1d 100644
--- a/sound/soc/intel/boards/bytcht_da7213.c
+++ b/sound/soc/intel/boards/bytcht_da7213.c
@@ -81,7 +81,7 @@ static int codec_fixup(struct snd_soc_pcm_runtime *rtd,
ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC);
+ SND_SOC_DAIFMT_BP_FP);
if (ret < 0) {
dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
return ret;
diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c
index a085077..6432b83f 100644
--- a/sound/soc/intel/boards/bytcht_es8316.c
+++ b/sound/soc/intel/boards/bytcht_es8316.c
@@ -265,7 +265,7 @@ static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd,
ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC
+ SND_SOC_DAIFMT_BP_FP
);
if (ret < 0) {
dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
diff --git a/sound/soc/intel/boards/bytcht_nocodec.c b/sound/soc/intel/boards/bytcht_nocodec.c
index 115c2bc..7fc03f2 100644
--- a/sound/soc/intel/boards/bytcht_nocodec.c
+++ b/sound/soc/intel/boards/bytcht_nocodec.c
@@ -61,7 +61,7 @@ static int codec_fixup(struct snd_soc_pcm_runtime *rtd,
ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC);
+ SND_SOC_DAIFMT_BP_FP);
if (ret < 0) {
dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index ed9fa17..fb9d9e2 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -1413,7 +1413,7 @@ static int byt_rt5640_codec_fixup(struct snd_soc_pcm_runtime *rtd,
ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC);
+ SND_SOC_DAIFMT_BP_FP);
if (ret < 0) {
dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
return ret;
@@ -1636,7 +1636,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
* with the codec driver/pdata are non-existent
*/
- struct acpi_chan_package chan_package;
+ struct acpi_chan_package chan_package = { 0 };
/* format specified: 2 64-bit integers */
struct acpi_buffer format = {sizeof("NN"), "NN"};
diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c
index d467fca..2beb686 100644
--- a/sound/soc/intel/boards/bytcr_rt5651.c
+++ b/sound/soc/intel/boards/bytcr_rt5651.c
@@ -706,7 +706,7 @@ static int byt_rt5651_codec_fixup(struct snd_soc_pcm_runtime *rtd,
ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC
+ SND_SOC_DAIFMT_BP_FP
);
if (ret < 0) {
@@ -952,7 +952,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
* with the codec driver/pdata are non-existent
*/
- struct acpi_chan_package chan_package;
+ struct acpi_chan_package chan_package = { 0 };
/* format specified: 2 64-bit integers */
struct acpi_buffer format = {sizeof("NN"), "NN"};
diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c
index 330c0ac..45a6805 100644
--- a/sound/soc/intel/boards/bytcr_wm5102.c
+++ b/sound/soc/intel/boards/bytcr_wm5102.c
@@ -265,7 +265,7 @@ static int byt_wm5102_codec_fixup(struct snd_soc_pcm_runtime *rtd,
ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC);
+ SND_SOC_DAIFMT_BP_FP);
if (ret) {
dev_err(rtd->dev, "Error setting format to I2S: %d\n", ret);
return ret;
diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
index a5160f2..64eb735 100644
--- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c
+++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
@@ -264,8 +264,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
return ret;
}
- fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBC_CFC;
+ fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_BP_FP;
ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), fmt);
if (ret < 0) {
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c
index 45c301ea5..96501ae 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5645.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5645.c
@@ -362,7 +362,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC
+ SND_SOC_DAIFMT_BP_FP
);
if (ret < 0) {
dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
@@ -372,7 +372,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
ret = snd_soc_dai_set_fmt(asoc_rtd_to_codec(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC
+ SND_SOC_DAIFMT_BC_FC
);
if (ret < 0) {
dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
@@ -396,7 +396,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
ret = snd_soc_dai_set_fmt(asoc_rtd_to_codec(rtd, 0),
SND_SOC_DAIFMT_DSP_B |
SND_SOC_DAIFMT_IB_NF |
- SND_SOC_DAIFMT_CBC_CFC);
+ SND_SOC_DAIFMT_BC_FC);
if (ret < 0) {
dev_err(rtd->dev, "can't set format to TDM %d\n", ret);
return ret;
@@ -603,7 +603,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
* with the codec driver/pdata are non-existent
*/
- struct acpi_chan_package chan_package;
+ struct acpi_chan_package chan_package = { 0 };
/* format specified: 2 64-bit integers */
struct acpi_buffer format = {sizeof("NN"), "NN"};
diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c
index c80324f..ca47f64 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5672.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5672.c
@@ -300,7 +300,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC);
+ SND_SOC_DAIFMT_BP_FP);
if (ret < 0) {
dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
return ret;
diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c
index e9f9520..4f3d655 100644
--- a/sound/soc/intel/boards/skl_rt286.c
+++ b/sound/soc/intel/boards/skl_rt286.c
@@ -133,7 +133,7 @@ static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
if (ret)
return ret;
- rt286_mic_detect(component, &skylake_headset);
+ snd_soc_component_set_jack(component, &skylake_headset, NULL);
snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
diff --git a/sound/soc/intel/boards/sof_pcm512x.c b/sound/soc/intel/boards/sof_pcm512x.c
index 6815204..d4c67d5 100644
--- a/sound/soc/intel/boards/sof_pcm512x.c
+++ b/sound/soc/intel/boards/sof_pcm512x.c
@@ -419,7 +419,7 @@ static int sof_audio_probe(struct platform_device *pdev)
static int sof_pcm512x_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
- struct snd_soc_component *component = NULL;
+ struct snd_soc_component *component;
for_each_card_components(card, component) {
if (!strcmp(component->name, pcm512x_component[0].name)) {
diff --git a/sound/soc/intel/boards/sof_realtek_common.c b/sound/soc/intel/boards/sof_realtek_common.c
index 2ab568c..b9643ca 100644
--- a/sound/soc/intel/boards/sof_realtek_common.c
+++ b/sound/soc/intel/boards/sof_realtek_common.c
@@ -463,26 +463,26 @@ EXPORT_SYMBOL_NS(sof_rt1308_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);
* 2-amp Configuration for RT1019
*/
-static const struct snd_soc_dapm_route rt1019_dapm_routes[] = {
+static const struct snd_soc_dapm_route rt1019p_dapm_routes[] = {
/* speaker */
{ "Left Spk", NULL, "Speaker" },
{ "Right Spk", NULL, "Speaker" },
};
-static struct snd_soc_dai_link_component rt1019_components[] = {
+static struct snd_soc_dai_link_component rt1019p_components[] = {
{
- .name = RT1019_DEV0_NAME,
- .dai_name = RT1019_CODEC_DAI,
+ .name = RT1019P_DEV0_NAME,
+ .dai_name = RT1019P_CODEC_DAI,
},
};
-static int rt1019_init(struct snd_soc_pcm_runtime *rtd)
+static int rt1019p_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
int ret;
- ret = snd_soc_dapm_add_routes(&card->dapm, rt1019_dapm_routes,
- ARRAY_SIZE(rt1019_dapm_routes));
+ ret = snd_soc_dapm_add_routes(&card->dapm, rt1019p_dapm_routes,
+ ARRAY_SIZE(rt1019p_dapm_routes));
if (ret) {
dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret);
return ret;
@@ -490,13 +490,13 @@ static int rt1019_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
-void sof_rt1019_dai_link(struct snd_soc_dai_link *link)
+void sof_rt1019p_dai_link(struct snd_soc_dai_link *link)
{
- link->codecs = rt1019_components;
- link->num_codecs = ARRAY_SIZE(rt1019_components);
- link->init = rt1019_init;
+ link->codecs = rt1019p_components;
+ link->num_codecs = ARRAY_SIZE(rt1019p_components);
+ link->init = rt1019p_init;
}
-EXPORT_SYMBOL_NS(sof_rt1019_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);
+EXPORT_SYMBOL_NS(sof_rt1019p_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);
MODULE_DESCRIPTION("ASoC Intel SOF Realtek helpers");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/intel/boards/sof_realtek_common.h b/sound/soc/intel/boards/sof_realtek_common.h
index ec3eea6..7784434 100644
--- a/sound/soc/intel/boards/sof_realtek_common.h
+++ b/sound/soc/intel/boards/sof_realtek_common.h
@@ -39,9 +39,9 @@ void sof_rt1015_codec_conf(struct snd_soc_card *card);
#define RT1308_DEV0_NAME "i2c-10EC1308:00"
void sof_rt1308_dai_link(struct snd_soc_dai_link *link);
-#define RT1019_CODEC_DAI "HiFi"
-#define RT1019_DEV0_NAME "RTL1019:00"
+#define RT1019P_CODEC_DAI "HiFi"
+#define RT1019P_DEV0_NAME "RTL1019:00"
-void sof_rt1019_dai_link(struct snd_soc_dai_link *link);
+void sof_rt1019p_dai_link(struct snd_soc_dai_link *link);
#endif /* __SOF_REALTEK_COMMON_H */
diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c
index 5d67a2c..f28dae6 100644
--- a/sound/soc/intel/boards/sof_rt5682.c
+++ b/sound/soc/intel/boards/sof_rt5682.c
@@ -735,7 +735,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
} 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) {
- sof_rt1019_dai_link(&links[id]);
+ sof_rt1019p_dai_link(&links[id]);
} else if (sof_rt5682_quirk &
SOF_MAX98373_SPEAKER_AMP_PRESENT) {
links[id].codecs = max_98373_components;
diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c
index ad826ad..d238465 100644
--- a/sound/soc/intel/boards/sof_sdw.c
+++ b/sound/soc/intel/boards/sof_sdw.c
@@ -315,6 +315,14 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
RT711_JD2 |
SOF_SDW_FOUR_SPK),
},
+ /* MeteorLake devices */
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_mtlrvp"),
+ },
+ .driver_data = (void *)(RT711_JD1 | SOF_SDW_TGL_HDMI),
+ },
{}
};
@@ -1127,10 +1135,14 @@ static int sof_card_dai_links_create(struct device *dev,
for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
codec_info_list[i].amp_num = 0;
- if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
- hdmi_num = SOF_TGL_HDMI_COUNT;
- else
- hdmi_num = SOF_PRE_TGL_HDMI_COUNT;
+ if (mach_params->codec_mask & IDISP_CODEC_MASK) {
+ ctx->idisp_codec = true;
+
+ if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
+ hdmi_num = SOF_TGL_HDMI_COUNT;
+ else
+ hdmi_num = SOF_PRE_TGL_HDMI_COUNT;
+ }
ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk);
/*
@@ -1150,9 +1162,6 @@ static int sof_card_dai_links_create(struct device *dev,
return ret;
}
- if (mach_params->codec_mask & IDISP_CODEC_MASK)
- ctx->idisp_codec = true;
-
/* enable dmic01 & dmic16k */
dmic_num = (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num) ? 2 : 0;
comp_num += dmic_num;
@@ -1375,7 +1384,9 @@ static int sof_card_dai_links_create(struct device *dev,
static int sof_sdw_card_late_probe(struct snd_soc_card *card)
{
- int i, ret;
+ struct mc_private *ctx = snd_soc_card_get_drvdata(card);
+ int ret = 0;
+ int i;
for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
if (!codec_info_list[i].late_probe)
@@ -1386,7 +1397,10 @@ static int sof_sdw_card_late_probe(struct snd_soc_card *card)
return ret;
}
- return sof_sdw_hdmi_card_late_probe(card);
+ if (ctx->idisp_codec)
+ ret = sof_sdw_hdmi_card_late_probe(card);
+
+ return ret;
}
/* SoC card */
diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile
index fef0b2d..8ca8f87 100644
--- a/sound/soc/intel/common/Makefile
+++ b/sound/soc/intel/common/Makefile
@@ -9,6 +9,7 @@
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-hda-match.o \
soc-acpi-intel-sdw-mockup-match.o
diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
new file mode 100644
index 0000000..74d3b82
--- /dev/null
+++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * soc-acpi-intel-mtl-match.c - tables and support for MTL ACPI enumeration.
+ *
+ * Copyright (c) 2022, Intel Corporation.
+ *
+ */
+
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+#include "soc-acpi-intel-sdw-mockup-match.h"
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[] = {
+ {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_mtl_machines);
+
+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_sdca_0_adr[] = {
+ {
+ .adr = 0x000030025D071101ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt711"
+ }
+};
+
+static const struct snd_soc_acpi_link_adr mtl_rvp[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt711_sdca_0_adr),
+ .adr_d = rt711_sdca_0_adr,
+ },
+ {}
+};
+
+/* this table is used when there is no I2S codec present */
+struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
+ /* mockup tests need to be first */
+ {
+ .link_mask = GENMASK(3, 0),
+ .links = sdw_mockup_headset_2amps_mic,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-mtl-rt711-rt1308-rt715.tplg",
+ },
+ {
+ .link_mask = BIT(0) | BIT(1) | BIT(3),
+ .links = sdw_mockup_headset_1amp_mic,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-mtl-rt711-rt1308-mono-rt715.tplg",
+ },
+ {
+ .link_mask = GENMASK(2, 0),
+ .links = sdw_mockup_mic_headset_1amp,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-mtl-rt715-rt711-rt1308-mono.tplg",
+ },
+ {
+ .link_mask = BIT(0),
+ .links = mtl_rvp,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-mtl-rt711.tplg",
+ },
+ {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_mtl_sdw_machines);
diff --git a/sound/soc/intel/keembay/kmb_platform.c b/sound/soc/intel/keembay/kmb_platform.c
index a6fb74b..d10881f 100644
--- a/sound/soc/intel/keembay/kmb_platform.c
+++ b/sound/soc/intel/keembay/kmb_platform.c
@@ -497,11 +497,11 @@ static int kmb_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
int ret;
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
- case SND_SOC_DAIFMT_CBP_CFP:
+ case SND_SOC_DAIFMT_BC_FC:
kmb_i2s->clock_provider = false;
ret = 0;
break;
- case SND_SOC_DAIFMT_CBC_CFC:
+ case SND_SOC_DAIFMT_BP_FP:
writel(CLOCK_PROVIDER_MODE, kmb_i2s->pss_base + I2S_GEN_CFG_0);
ret = clk_prepare_enable(kmb_i2s->clk_i2s);
diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c
index 7ad5d9a..446c5e0 100644
--- a/sound/soc/jz4740/jz4740-i2s.c
+++ b/sound/soc/jz4740/jz4740-i2s.c
@@ -206,18 +206,18 @@ static int jz4740_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
conf &= ~(JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER);
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BP_FP:
conf |= JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER;
format |= JZ_AIC_I2S_FMT_ENABLE_SYS_CLK;
break;
- case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_BC_FP:
conf |= JZ_AIC_CONF_SYNC_CLK_MASTER;
break;
- case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_BP_FC:
conf |= JZ_AIC_CONF_BIT_CLK_MASTER;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_BC_FC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/mediatek/mt6797/mt6797-mt6351.c b/sound/soc/mediatek/mt6797/mt6797-mt6351.c
index 496f32b..d2f6213 100644
--- a/sound/soc/mediatek/mt6797/mt6797-mt6351.c
+++ b/sound/soc/mediatek/mt6797/mt6797-mt6351.c
@@ -217,7 +217,8 @@ static int mt6797_mt6351_dev_probe(struct platform_device *pdev)
if (!codec_node) {
dev_err(&pdev->dev,
"Property 'audio-codec' missing or invalid\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto put_platform_node;
}
for_each_card_prelinks(card, i, dai_link) {
if (dai_link->codecs->name)
@@ -230,6 +231,9 @@ static int mt6797_mt6351_dev_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
__func__, ret);
+ of_node_put(codec_node);
+put_platform_node:
+ of_node_put(platform_node);
return ret;
}
diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
index 31494930..dcaeeeb 100644
--- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
+++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
@@ -286,10 +286,8 @@ static int mt8173_afe_dais_set_clks(struct mtk_base_afe *afe,
static void mt8173_afe_dais_disable_clks(struct mtk_base_afe *afe,
struct clk *m_ck, struct clk *b_ck)
{
- if (m_ck)
- clk_disable_unprepare(m_ck);
- if (b_ck)
- clk_disable_unprepare(b_ck);
+ clk_disable_unprepare(m_ck);
+ clk_disable_unprepare(b_ck);
}
static int mt8173_afe_i2s_startup(struct snd_pcm_substream *substream,
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
index 70bf312..8794720 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
@@ -256,14 +256,16 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev)
if (!mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node) {
dev_err(&pdev->dev,
"Property 'audio-codec' missing or invalid\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto put_node;
}
mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node =
of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 1);
if (!mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node) {
dev_err(&pdev->dev,
"Property 'audio-codec' missing or invalid\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto put_node;
}
mt8173_rt5650_rt5676_codec_conf[0].dlc.of_node =
mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node;
@@ -276,13 +278,15 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev)
if (!mt8173_rt5650_rt5676_dais[DAI_LINK_HDMI_I2S].codecs->of_node) {
dev_err(&pdev->dev,
"Property 'audio-codec' missing or invalid\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto put_node;
}
card->dev = &pdev->dev;
ret = devm_snd_soc_register_card(&pdev->dev, card);
+put_node:
of_node_put(platform_node);
return ret;
}
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
index d1c94ac..e05f2b0 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
@@ -280,7 +280,8 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev)
if (!mt8173_rt5650_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node) {
dev_err(&pdev->dev,
"Property 'audio-codec' missing or invalid\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto put_platform_node;
}
mt8173_rt5650_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node =
mt8173_rt5650_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node;
@@ -293,7 +294,7 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev)
dev_err(&pdev->dev,
"%s codec_capture_dai name fail %d\n",
__func__, ret);
- return ret;
+ goto put_platform_node;
}
mt8173_rt5650_dais[DAI_LINK_CODEC_I2S].codecs[1].dai_name =
codec_capture_dai;
@@ -315,12 +316,14 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev)
if (!mt8173_rt5650_dais[DAI_LINK_HDMI_I2S].codecs->of_node) {
dev_err(&pdev->dev,
"Property 'audio-codec' missing or invalid\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto put_platform_node;
}
card->dev = &pdev->dev;
ret = devm_snd_soc_register_card(&pdev->dev, card);
+put_platform_node:
of_node_put(platform_node);
return ret;
}
diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-clk.c b/sound/soc/mediatek/mt8186/mt8186-afe-clk.c
new file mode 100644
index 0000000..0275f66
--- /dev/null
+++ b/sound/soc/mediatek/mt8186/mt8186-afe-clk.c
@@ -0,0 +1,651 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mt8186-afe-clk.c -- Mediatek 8186 afe clock ctrl
+//
+// Copyright (c) 2022 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#include "mt8186-afe-common.h"
+#include "mt8186-afe-clk.h"
+#include "mt8186-audsys-clk.h"
+
+static DEFINE_MUTEX(mutex_request_dram);
+
+static const char *aud_clks[CLK_NUM] = {
+ [CLK_AFE] = "aud_afe_clk",
+ [CLK_DAC] = "aud_dac_clk",
+ [CLK_DAC_PREDIS] = "aud_dac_predis_clk",
+ [CLK_ADC] = "aud_adc_clk",
+ [CLK_TML] = "aud_tml_clk",
+ [CLK_APLL22M] = "aud_apll22m_clk",
+ [CLK_APLL24M] = "aud_apll24m_clk",
+ [CLK_APLL1_TUNER] = "aud_apll_tuner_clk",
+ [CLK_APLL2_TUNER] = "aud_apll2_tuner_clk",
+ [CLK_TDM] = "aud_tdm_clk",
+ [CLK_NLE] = "aud_nle_clk",
+ [CLK_DAC_HIRES] = "aud_dac_hires_clk",
+ [CLK_ADC_HIRES] = "aud_adc_hires_clk",
+ [CLK_I2S1_BCLK] = "aud_i2s1_bclk",
+ [CLK_I2S2_BCLK] = "aud_i2s2_bclk",
+ [CLK_I2S3_BCLK] = "aud_i2s3_bclk",
+ [CLK_I2S4_BCLK] = "aud_i2s4_bclk",
+ [CLK_CONNSYS_I2S_ASRC] = "aud_connsys_i2s_asrc",
+ [CLK_GENERAL1_ASRC] = "aud_general1_asrc",
+ [CLK_GENERAL2_ASRC] = "aud_general2_asrc",
+ [CLK_ADC_HIRES_TML] = "aud_adc_hires_tml",
+ [CLK_ADDA6_ADC] = "aud_adda6_adc",
+ [CLK_ADDA6_ADC_HIRES] = "aud_adda6_adc_hires",
+ [CLK_3RD_DAC] = "aud_3rd_dac",
+ [CLK_3RD_DAC_PREDIS] = "aud_3rd_dac_predis",
+ [CLK_3RD_DAC_TML] = "aud_3rd_dac_tml",
+ [CLK_3RD_DAC_HIRES] = "aud_3rd_dac_hires",
+ [CLK_ETDM_IN1_BCLK] = "aud_etdm_in1_bclk",
+ [CLK_ETDM_OUT1_BCLK] = "aud_etdm_out1_bclk",
+ [CLK_INFRA_SYS_AUDIO] = "aud_infra_clk",
+ [CLK_INFRA_AUDIO_26M] = "mtkaif_26m_clk",
+ [CLK_MUX_AUDIO] = "top_mux_audio",
+ [CLK_MUX_AUDIOINTBUS] = "top_mux_audio_int",
+ [CLK_TOP_MAINPLL_D2_D4] = "top_mainpll_d2_d4",
+ [CLK_TOP_MUX_AUD_1] = "top_mux_aud_1",
+ [CLK_TOP_APLL1_CK] = "top_apll1_ck",
+ [CLK_TOP_MUX_AUD_2] = "top_mux_aud_2",
+ [CLK_TOP_APLL2_CK] = "top_apll2_ck",
+ [CLK_TOP_MUX_AUD_ENG1] = "top_mux_aud_eng1",
+ [CLK_TOP_APLL1_D8] = "top_apll1_d8",
+ [CLK_TOP_MUX_AUD_ENG2] = "top_mux_aud_eng2",
+ [CLK_TOP_APLL2_D8] = "top_apll2_d8",
+ [CLK_TOP_MUX_AUDIO_H] = "top_mux_audio_h",
+ [CLK_TOP_I2S0_M_SEL] = "top_i2s0_m_sel",
+ [CLK_TOP_I2S1_M_SEL] = "top_i2s1_m_sel",
+ [CLK_TOP_I2S2_M_SEL] = "top_i2s2_m_sel",
+ [CLK_TOP_I2S4_M_SEL] = "top_i2s4_m_sel",
+ [CLK_TOP_TDM_M_SEL] = "top_tdm_m_sel",
+ [CLK_TOP_APLL12_DIV0] = "top_apll12_div0",
+ [CLK_TOP_APLL12_DIV1] = "top_apll12_div1",
+ [CLK_TOP_APLL12_DIV2] = "top_apll12_div2",
+ [CLK_TOP_APLL12_DIV4] = "top_apll12_div4",
+ [CLK_TOP_APLL12_DIV_TDM] = "top_apll12_div_tdm",
+ [CLK_CLK26M] = "top_clk26m_clk",
+};
+
+int mt8186_set_audio_int_bus_parent(struct mtk_base_afe *afe,
+ int clk_id)
+{
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ ret = clk_set_parent(afe_priv->clk[CLK_MUX_AUDIOINTBUS],
+ afe_priv->clk[clk_id]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_MUX_AUDIOINTBUS],
+ aud_clks[clk_id], ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable)
+{
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ if (enable) {
+ ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_1]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_TOP_MUX_AUD_1], ret);
+ return ret;
+ }
+ ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_1],
+ afe_priv->clk[CLK_TOP_APLL1_CK]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_TOP_MUX_AUD_1],
+ aud_clks[CLK_TOP_APLL1_CK], ret);
+ return ret;
+ }
+
+ /* 180.6336 / 8 = 22.5792MHz */
+ ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1], ret);
+ return ret;
+ }
+ ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1],
+ afe_priv->clk[CLK_TOP_APLL1_D8]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1],
+ aud_clks[CLK_TOP_APLL1_D8], ret);
+ return ret;
+ }
+ } else {
+ ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1],
+ afe_priv->clk[CLK_CLK26M]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1],
+ aud_clks[CLK_CLK26M], ret);
+ return ret;
+ }
+ clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1]);
+
+ ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_1],
+ afe_priv->clk[CLK_CLK26M]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_TOP_MUX_AUD_1],
+ aud_clks[CLK_CLK26M], ret);
+ return ret;
+ }
+ clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_1]);
+ }
+
+ return 0;
+}
+
+static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable)
+{
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ if (enable) {
+ ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_2]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_TOP_MUX_AUD_2], ret);
+ return ret;
+ }
+ ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_2],
+ afe_priv->clk[CLK_TOP_APLL2_CK]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_TOP_MUX_AUD_2],
+ aud_clks[CLK_TOP_APLL2_CK], ret);
+ return ret;
+ }
+
+ /* 196.608 / 8 = 24.576MHz */
+ ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2], ret);
+ return ret;
+ }
+ ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2],
+ afe_priv->clk[CLK_TOP_APLL2_D8]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2],
+ aud_clks[CLK_TOP_APLL2_D8], ret);
+ return ret;
+ }
+ } else {
+ ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2],
+ afe_priv->clk[CLK_CLK26M]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2],
+ aud_clks[CLK_CLK26M], ret);
+ return ret;
+ }
+ clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2]);
+
+ ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_2],
+ afe_priv->clk[CLK_CLK26M]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_TOP_MUX_AUD_2],
+ aud_clks[CLK_CLK26M], ret);
+ return ret;
+ }
+ clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_2]);
+ }
+
+ return 0;
+}
+
+int mt8186_afe_enable_cgs(struct mtk_base_afe *afe)
+{
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int ret = 0;
+ int i;
+
+ for (i = CLK_I2S1_BCLK; i <= CLK_ETDM_OUT1_BCLK; i++) {
+ ret = clk_prepare_enable(afe_priv->clk[i]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[i], ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+void mt8186_afe_disable_cgs(struct mtk_base_afe *afe)
+{
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int i;
+
+ for (i = CLK_I2S1_BCLK; i <= CLK_ETDM_OUT1_BCLK; i++)
+ clk_disable_unprepare(afe_priv->clk[i]);
+}
+
+int mt8186_afe_enable_clock(struct mtk_base_afe *afe)
+{
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int ret = 0;
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_INFRA_SYS_AUDIO]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_INFRA_SYS_AUDIO], ret);
+ goto clk_infra_sys_audio_err;
+ }
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_INFRA_AUDIO_26M]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_INFRA_AUDIO_26M], ret);
+ goto clk_infra_audio_26m_err;
+ }
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIO]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_MUX_AUDIO], ret);
+ goto clk_mux_audio_err;
+ }
+ ret = clk_set_parent(afe_priv->clk[CLK_MUX_AUDIO],
+ afe_priv->clk[CLK_CLK26M]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_MUX_AUDIO],
+ aud_clks[CLK_CLK26M], ret);
+ goto clk_mux_audio_err;
+ }
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_MUX_AUDIOINTBUS], ret);
+ goto clk_mux_audio_intbus_err;
+ }
+ ret = mt8186_set_audio_int_bus_parent(afe,
+ CLK_TOP_MAINPLL_D2_D4);
+ if (ret)
+ goto clk_mux_audio_intbus_parent_err;
+
+ ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUDIO_H],
+ afe_priv->clk[CLK_TOP_APLL2_CK]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[CLK_TOP_MUX_AUDIO_H],
+ aud_clks[CLK_TOP_APLL2_CK], ret);
+ goto clk_mux_audio_h_parent_err;
+ }
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_AFE]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_AFE], ret);
+ goto clk_afe_err;
+ }
+
+ return 0;
+
+clk_afe_err:
+ clk_disable_unprepare(afe_priv->clk[CLK_AFE]);
+clk_mux_audio_h_parent_err:
+clk_mux_audio_intbus_parent_err:
+ mt8186_set_audio_int_bus_parent(afe, CLK_CLK26M);
+clk_mux_audio_intbus_err:
+ clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
+clk_mux_audio_err:
+ clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIO]);
+clk_infra_sys_audio_err:
+ clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUDIO]);
+clk_infra_audio_26m_err:
+ clk_disable_unprepare(afe_priv->clk[CLK_INFRA_AUDIO_26M]);
+
+ return ret;
+}
+
+void mt8186_afe_disable_clock(struct mtk_base_afe *afe)
+{
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+
+ clk_disable_unprepare(afe_priv->clk[CLK_AFE]);
+ mt8186_set_audio_int_bus_parent(afe, CLK_CLK26M);
+ clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
+ clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIO]);
+ clk_disable_unprepare(afe_priv->clk[CLK_INFRA_AUDIO_26M]);
+ clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUDIO]);
+}
+
+int mt8186_afe_suspend_clock(struct mtk_base_afe *afe)
+{
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ /* set audio int bus to 26M */
+ ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
+ if (ret) {
+ dev_info(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_MUX_AUDIOINTBUS], ret);
+ goto clk_mux_audio_intbus_err;
+ }
+ ret = mt8186_set_audio_int_bus_parent(afe, CLK_CLK26M);
+ if (ret)
+ goto clk_mux_audio_intbus_parent_err;
+
+ clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
+
+ return 0;
+
+clk_mux_audio_intbus_parent_err:
+ mt8186_set_audio_int_bus_parent(afe, CLK_TOP_MAINPLL_D2_D4);
+clk_mux_audio_intbus_err:
+ clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
+ return ret;
+}
+
+int mt8186_afe_resume_clock(struct mtk_base_afe *afe)
+{
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ /* set audio int bus to normal working clock */
+ ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
+ if (ret) {
+ dev_info(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_MUX_AUDIOINTBUS], ret);
+ goto clk_mux_audio_intbus_err;
+ }
+ ret = mt8186_set_audio_int_bus_parent(afe,
+ CLK_TOP_MAINPLL_D2_D4);
+ if (ret)
+ goto clk_mux_audio_intbus_parent_err;
+
+ clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
+
+ return 0;
+
+clk_mux_audio_intbus_parent_err:
+ mt8186_set_audio_int_bus_parent(afe, CLK_CLK26M);
+clk_mux_audio_intbus_err:
+ clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
+ return ret;
+}
+
+int mt8186_apll1_enable(struct mtk_base_afe *afe)
+{
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ /* setting for APLL */
+ apll1_mux_setting(afe, true);
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_APLL22M]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_APLL22M], ret);
+ goto err_clk_apll22m;
+ }
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_APLL1_TUNER]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_APLL1_TUNER], ret);
+ goto err_clk_apll1_tuner;
+ }
+
+ regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0xfff7, 0x832);
+ regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0x1, 0x1);
+
+ regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
+ AFE_22M_ON_MASK_SFT, BIT(AFE_22M_ON_SFT));
+
+ return 0;
+
+err_clk_apll1_tuner:
+ clk_disable_unprepare(afe_priv->clk[CLK_APLL1_TUNER]);
+err_clk_apll22m:
+ clk_disable_unprepare(afe_priv->clk[CLK_APLL22M]);
+
+ return ret;
+}
+
+void mt8186_apll1_disable(struct mtk_base_afe *afe)
+{
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+
+ regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
+ AFE_22M_ON_MASK_SFT, 0);
+
+ regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0x1, 0);
+
+ clk_disable_unprepare(afe_priv->clk[CLK_APLL1_TUNER]);
+ clk_disable_unprepare(afe_priv->clk[CLK_APLL22M]);
+
+ apll1_mux_setting(afe, false);
+}
+
+int mt8186_apll2_enable(struct mtk_base_afe *afe)
+{
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ /* setting for APLL */
+ apll2_mux_setting(afe, true);
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_APLL24M]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_APLL24M], ret);
+ goto err_clk_apll24m;
+ }
+
+ ret = clk_prepare_enable(afe_priv->clk[CLK_APLL2_TUNER]);
+ if (ret) {
+ dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[CLK_APLL2_TUNER], ret);
+ goto err_clk_apll2_tuner;
+ }
+
+ regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0xfff7, 0x634);
+ regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0x1, 0x1);
+
+ regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
+ AFE_24M_ON_MASK_SFT, BIT(AFE_24M_ON_SFT));
+
+ return 0;
+
+err_clk_apll2_tuner:
+ clk_disable_unprepare(afe_priv->clk[CLK_APLL2_TUNER]);
+err_clk_apll24m:
+ clk_disable_unprepare(afe_priv->clk[CLK_APLL24M]);
+
+ return ret;
+}
+
+void mt8186_apll2_disable(struct mtk_base_afe *afe)
+{
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+
+ regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
+ AFE_24M_ON_MASK_SFT, 0);
+
+ regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0x1, 0);
+
+ clk_disable_unprepare(afe_priv->clk[CLK_APLL2_TUNER]);
+ clk_disable_unprepare(afe_priv->clk[CLK_APLL24M]);
+
+ apll2_mux_setting(afe, false);
+}
+
+int mt8186_get_apll_rate(struct mtk_base_afe *afe, int apll)
+{
+ return (apll == MT8186_APLL1) ? 180633600 : 196608000;
+}
+
+int mt8186_get_apll_by_rate(struct mtk_base_afe *afe, int rate)
+{
+ return ((rate % 8000) == 0) ? MT8186_APLL2 : MT8186_APLL1;
+}
+
+int mt8186_get_apll_by_name(struct mtk_base_afe *afe, const char *name)
+{
+ if (strcmp(name, APLL1_W_NAME) == 0)
+ return MT8186_APLL1;
+
+ return MT8186_APLL2;
+}
+
+/* mck */
+struct mt8186_mck_div {
+ u32 m_sel_id;
+ u32 div_clk_id;
+};
+
+static const struct mt8186_mck_div mck_div[MT8186_MCK_NUM] = {
+ [MT8186_I2S0_MCK] = {
+ .m_sel_id = CLK_TOP_I2S0_M_SEL,
+ .div_clk_id = CLK_TOP_APLL12_DIV0,
+ },
+ [MT8186_I2S1_MCK] = {
+ .m_sel_id = CLK_TOP_I2S1_M_SEL,
+ .div_clk_id = CLK_TOP_APLL12_DIV1,
+ },
+ [MT8186_I2S2_MCK] = {
+ .m_sel_id = CLK_TOP_I2S2_M_SEL,
+ .div_clk_id = CLK_TOP_APLL12_DIV2,
+ },
+ [MT8186_I2S4_MCK] = {
+ .m_sel_id = CLK_TOP_I2S4_M_SEL,
+ .div_clk_id = CLK_TOP_APLL12_DIV4,
+ },
+ [MT8186_TDM_MCK] = {
+ .m_sel_id = CLK_TOP_TDM_M_SEL,
+ .div_clk_id = CLK_TOP_APLL12_DIV_TDM,
+ },
+};
+
+int mt8186_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate)
+{
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int apll = mt8186_get_apll_by_rate(afe, rate);
+ int apll_clk_id = apll == MT8186_APLL1 ?
+ CLK_TOP_MUX_AUD_1 : CLK_TOP_MUX_AUD_2;
+ int m_sel_id = mck_div[mck_id].m_sel_id;
+ int div_clk_id = mck_div[mck_id].div_clk_id;
+ int ret;
+
+ /* select apll */
+ if (m_sel_id >= 0) {
+ ret = clk_prepare_enable(afe_priv->clk[m_sel_id]);
+ if (ret) {
+ dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[m_sel_id], ret);
+ return ret;
+ }
+ ret = clk_set_parent(afe_priv->clk[m_sel_id],
+ afe_priv->clk[apll_clk_id]);
+ if (ret) {
+ dev_err(afe->dev, "%s(), clk_set_parent %s-%s fail %d\n",
+ __func__, aud_clks[m_sel_id],
+ aud_clks[apll_clk_id], ret);
+ return ret;
+ }
+ }
+
+ /* enable div, set rate */
+ ret = clk_prepare_enable(afe_priv->clk[div_clk_id]);
+ if (ret) {
+ dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
+ __func__, aud_clks[div_clk_id], ret);
+ return ret;
+ }
+ ret = clk_set_rate(afe_priv->clk[div_clk_id], rate);
+ if (ret) {
+ dev_err(afe->dev, "%s(), clk_set_rate %s, rate %d, fail %d\n",
+ __func__, aud_clks[div_clk_id], rate, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+void mt8186_mck_disable(struct mtk_base_afe *afe, int mck_id)
+{
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int m_sel_id = mck_div[mck_id].m_sel_id;
+ int div_clk_id = mck_div[mck_id].div_clk_id;
+
+ clk_disable_unprepare(afe_priv->clk[div_clk_id]);
+ if (m_sel_id >= 0)
+ clk_disable_unprepare(afe_priv->clk[m_sel_id]);
+}
+
+int mt8186_init_clock(struct mtk_base_afe *afe)
+{
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ struct device_node *of_node = afe->dev->of_node;
+ int i = 0;
+
+ mt8186_audsys_clk_register(afe);
+
+ afe_priv->clk = devm_kcalloc(afe->dev, CLK_NUM, sizeof(*afe_priv->clk),
+ GFP_KERNEL);
+ if (!afe_priv->clk)
+ return -ENOMEM;
+
+ for (i = 0; i < CLK_NUM; i++) {
+ afe_priv->clk[i] = devm_clk_get(afe->dev, aud_clks[i]);
+ if (IS_ERR(afe_priv->clk[i])) {
+ dev_err(afe->dev, "%s devm_clk_get %s fail, ret %ld\n",
+ __func__,
+ aud_clks[i], PTR_ERR(afe_priv->clk[i]));
+ afe_priv->clk[i] = NULL;
+ }
+ }
+
+ afe_priv->apmixedsys = syscon_regmap_lookup_by_phandle(of_node,
+ "mediatek,apmixedsys");
+ if (IS_ERR(afe_priv->apmixedsys)) {
+ dev_err(afe->dev, "%s() Cannot find apmixedsys controller: %ld\n",
+ __func__, PTR_ERR(afe_priv->apmixedsys));
+ return PTR_ERR(afe_priv->apmixedsys);
+ }
+
+ afe_priv->topckgen = syscon_regmap_lookup_by_phandle(of_node,
+ "mediatek,topckgen");
+ if (IS_ERR(afe_priv->topckgen)) {
+ dev_err(afe->dev, "%s() Cannot find topckgen controller: %ld\n",
+ __func__, PTR_ERR(afe_priv->topckgen));
+ return PTR_ERR(afe_priv->topckgen);
+ }
+
+ afe_priv->infracfg = syscon_regmap_lookup_by_phandle(of_node,
+ "mediatek,infracfg");
+ if (IS_ERR(afe_priv->infracfg)) {
+ dev_err(afe->dev, "%s() Cannot find infracfg: %ld\n",
+ __func__, PTR_ERR(afe_priv->infracfg));
+ return PTR_ERR(afe_priv->infracfg);
+ }
+
+ return 0;
+}
+
+void mt8186_deinit_clock(struct mtk_base_afe *afe)
+{
+ mt8186_audsys_clk_unregister(afe);
+}
diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-clk.h b/sound/soc/mediatek/mt8186/mt8186-afe-clk.h
new file mode 100644
index 0000000..c539557
--- /dev/null
+++ b/sound/soc/mediatek/mt8186/mt8186-afe-clk.h
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * mt8186-afe-clk.h -- Mediatek 8186 afe clock ctrl definition
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+ */
+
+#ifndef _MT8186_AFE_CLOCK_CTRL_H_
+#define _MT8186_AFE_CLOCK_CTRL_H_
+
+#define PERI_BUS_DCM_CTRL 0x74
+
+/* APLL */
+#define APLL1_W_NAME "APLL1"
+#define APLL2_W_NAME "APLL2"
+enum {
+ MT8186_APLL1 = 0,
+ MT8186_APLL2,
+};
+
+enum {
+ CLK_AFE = 0,
+ CLK_DAC,
+ CLK_DAC_PREDIS,
+ CLK_ADC,
+ CLK_TML,
+ CLK_APLL22M,
+ CLK_APLL24M,
+ CLK_APLL1_TUNER,
+ CLK_APLL2_TUNER,
+ CLK_TDM,
+ CLK_NLE,
+ CLK_DAC_HIRES,
+ CLK_ADC_HIRES,
+ CLK_I2S1_BCLK,
+ CLK_I2S2_BCLK,
+ CLK_I2S3_BCLK,
+ CLK_I2S4_BCLK,
+ CLK_CONNSYS_I2S_ASRC,
+ CLK_GENERAL1_ASRC,
+ CLK_GENERAL2_ASRC,
+ CLK_ADC_HIRES_TML,
+ CLK_ADDA6_ADC,
+ CLK_ADDA6_ADC_HIRES,
+ CLK_3RD_DAC,
+ CLK_3RD_DAC_PREDIS,
+ CLK_3RD_DAC_TML,
+ CLK_3RD_DAC_HIRES,
+ CLK_ETDM_IN1_BCLK,
+ CLK_ETDM_OUT1_BCLK,
+ CLK_INFRA_SYS_AUDIO,
+ CLK_INFRA_AUDIO_26M,
+ CLK_MUX_AUDIO,
+ CLK_MUX_AUDIOINTBUS,
+ CLK_TOP_MAINPLL_D2_D4,
+ /* apll related mux */
+ CLK_TOP_MUX_AUD_1,
+ CLK_TOP_APLL1_CK,
+ CLK_TOP_MUX_AUD_2,
+ CLK_TOP_APLL2_CK,
+ CLK_TOP_MUX_AUD_ENG1,
+ CLK_TOP_APLL1_D8,
+ CLK_TOP_MUX_AUD_ENG2,
+ CLK_TOP_APLL2_D8,
+ CLK_TOP_MUX_AUDIO_H,
+ CLK_TOP_I2S0_M_SEL,
+ CLK_TOP_I2S1_M_SEL,
+ CLK_TOP_I2S2_M_SEL,
+ CLK_TOP_I2S4_M_SEL,
+ CLK_TOP_TDM_M_SEL,
+ CLK_TOP_APLL12_DIV0,
+ CLK_TOP_APLL12_DIV1,
+ CLK_TOP_APLL12_DIV2,
+ CLK_TOP_APLL12_DIV4,
+ CLK_TOP_APLL12_DIV_TDM,
+ CLK_CLK26M,
+ CLK_NUM
+};
+
+struct mtk_base_afe;
+int mt8186_set_audio_int_bus_parent(struct mtk_base_afe *afe, int clk_id);
+int mt8186_init_clock(struct mtk_base_afe *afe);
+void mt8186_deinit_clock(struct mtk_base_afe *afe);
+int mt8186_afe_enable_cgs(struct mtk_base_afe *afe);
+void mt8186_afe_disable_cgs(struct mtk_base_afe *afe);
+int mt8186_afe_enable_clock(struct mtk_base_afe *afe);
+void mt8186_afe_disable_clock(struct mtk_base_afe *afe);
+int mt8186_afe_suspend_clock(struct mtk_base_afe *afe);
+int mt8186_afe_resume_clock(struct mtk_base_afe *afe);
+
+int mt8186_apll1_enable(struct mtk_base_afe *afe);
+void mt8186_apll1_disable(struct mtk_base_afe *afe);
+
+int mt8186_apll2_enable(struct mtk_base_afe *afe);
+void mt8186_apll2_disable(struct mtk_base_afe *afe);
+
+int mt8186_get_apll_rate(struct mtk_base_afe *afe, int apll);
+int mt8186_get_apll_by_rate(struct mtk_base_afe *afe, int rate);
+int mt8186_get_apll_by_name(struct mtk_base_afe *afe, const char *name);
+
+/* these will be replaced by using CCF */
+int mt8186_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate);
+void mt8186_mck_disable(struct mtk_base_afe *afe, int mck_id);
+
+#endif
diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-gpio.c b/sound/soc/mediatek/mt8186/mt8186-afe-gpio.c
new file mode 100644
index 0000000..255ffba
--- /dev/null
+++ b/sound/soc/mediatek/mt8186/mt8186-afe-gpio.c
@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mt8186-afe-gpio.c -- Mediatek 8186 afe gpio ctrl
+//
+// Copyright (c) 2022 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+
+#include <linux/gpio.h>
+#include <linux/pinctrl/consumer.h>
+
+#include "mt8186-afe-common.h"
+#include "mt8186-afe-gpio.h"
+
+struct pinctrl *aud_pinctrl;
+
+enum mt8186_afe_gpio {
+ MT8186_AFE_GPIO_CLK_MOSI_OFF,
+ MT8186_AFE_GPIO_CLK_MOSI_ON,
+ MT8186_AFE_GPIO_CLK_MISO_OFF,
+ MT8186_AFE_GPIO_CLK_MISO_ON,
+ MT8186_AFE_GPIO_DAT_MISO_OFF,
+ MT8186_AFE_GPIO_DAT_MISO_ON,
+ MT8186_AFE_GPIO_DAT_MOSI_OFF,
+ MT8186_AFE_GPIO_DAT_MOSI_ON,
+ MT8186_AFE_GPIO_I2S0_OFF,
+ MT8186_AFE_GPIO_I2S0_ON,
+ MT8186_AFE_GPIO_I2S1_OFF,
+ MT8186_AFE_GPIO_I2S1_ON,
+ MT8186_AFE_GPIO_I2S2_OFF,
+ MT8186_AFE_GPIO_I2S2_ON,
+ MT8186_AFE_GPIO_I2S3_OFF,
+ MT8186_AFE_GPIO_I2S3_ON,
+ MT8186_AFE_GPIO_TDM_OFF,
+ MT8186_AFE_GPIO_TDM_ON,
+ MT8186_AFE_GPIO_PCM_OFF,
+ MT8186_AFE_GPIO_PCM_ON,
+ MT8186_AFE_GPIO_GPIO_NUM
+};
+
+struct audio_gpio_attr {
+ const char *name;
+ bool gpio_prepare;
+ struct pinctrl_state *gpioctrl;
+};
+
+static struct audio_gpio_attr aud_gpios[MT8186_AFE_GPIO_GPIO_NUM] = {
+ [MT8186_AFE_GPIO_CLK_MOSI_OFF] = {"aud_clk_mosi_off", false, NULL},
+ [MT8186_AFE_GPIO_CLK_MOSI_ON] = {"aud_clk_mosi_on", false, NULL},
+ [MT8186_AFE_GPIO_CLK_MISO_OFF] = {"aud_clk_miso_off", false, NULL},
+ [MT8186_AFE_GPIO_CLK_MISO_ON] = {"aud_clk_miso_on", false, NULL},
+ [MT8186_AFE_GPIO_DAT_MISO_OFF] = {"aud_dat_miso_off", false, NULL},
+ [MT8186_AFE_GPIO_DAT_MISO_ON] = {"aud_dat_miso_on", false, NULL},
+ [MT8186_AFE_GPIO_DAT_MOSI_OFF] = {"aud_dat_mosi_off", false, NULL},
+ [MT8186_AFE_GPIO_DAT_MOSI_ON] = {"aud_dat_mosi_on", false, NULL},
+ [MT8186_AFE_GPIO_I2S0_OFF] = {"aud_gpio_i2s0_off", false, NULL},
+ [MT8186_AFE_GPIO_I2S0_ON] = {"aud_gpio_i2s0_on", false, NULL},
+ [MT8186_AFE_GPIO_I2S1_OFF] = {"aud_gpio_i2s1_off", false, NULL},
+ [MT8186_AFE_GPIO_I2S1_ON] = {"aud_gpio_i2s1_on", false, NULL},
+ [MT8186_AFE_GPIO_I2S2_OFF] = {"aud_gpio_i2s2_off", false, NULL},
+ [MT8186_AFE_GPIO_I2S2_ON] = {"aud_gpio_i2s2_on", false, NULL},
+ [MT8186_AFE_GPIO_I2S3_OFF] = {"aud_gpio_i2s3_off", false, NULL},
+ [MT8186_AFE_GPIO_I2S3_ON] = {"aud_gpio_i2s3_on", false, NULL},
+ [MT8186_AFE_GPIO_TDM_OFF] = {"aud_gpio_tdm_off", false, NULL},
+ [MT8186_AFE_GPIO_TDM_ON] = {"aud_gpio_tdm_on", false, NULL},
+ [MT8186_AFE_GPIO_PCM_OFF] = {"aud_gpio_pcm_off", false, NULL},
+ [MT8186_AFE_GPIO_PCM_ON] = {"aud_gpio_pcm_on", false, NULL},
+};
+
+static DEFINE_MUTEX(gpio_request_mutex);
+
+int mt8186_afe_gpio_init(struct device *dev)
+{
+ int i, j, ret;
+
+ aud_pinctrl = devm_pinctrl_get(dev);
+ if (IS_ERR(aud_pinctrl)) {
+ ret = PTR_ERR(aud_pinctrl);
+ dev_err(dev, "%s(), ret %d, cannot get aud_pinctrl!\n",
+ __func__, ret);
+ return ret;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(aud_gpios); i++) {
+ aud_gpios[i].gpioctrl = pinctrl_lookup_state(aud_pinctrl,
+ aud_gpios[i].name);
+ if (IS_ERR(aud_gpios[i].gpioctrl)) {
+ ret = PTR_ERR(aud_gpios[i].gpioctrl);
+ dev_info(dev, "%s(), pinctrl_lookup_state %s fail, ret %d\n",
+ __func__, aud_gpios[i].name, ret);
+ } else {
+ aud_gpios[i].gpio_prepare = true;
+ }
+ }
+
+ /* gpio status init */
+ for (i = MT8186_DAI_ADDA; i <= MT8186_DAI_TDM_IN; i++) {
+ for (j = 0; j <= 1; j++)
+ mt8186_afe_gpio_request(dev, false, i, j);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt8186_afe_gpio_init);
+
+static int mt8186_afe_gpio_select(struct device *dev,
+ enum mt8186_afe_gpio type)
+{
+ int ret = 0;
+
+ if (type < 0 || type >= MT8186_AFE_GPIO_GPIO_NUM) {
+ dev_err(dev, "%s(), error, invalid gpio type %d\n",
+ __func__, type);
+ return -EINVAL;
+ }
+
+ if (!aud_gpios[type].gpio_prepare) {
+ dev_err(dev, "%s(), error, gpio type %d not prepared\n",
+ __func__, type);
+ return -EIO;
+ }
+
+ ret = pinctrl_select_state(aud_pinctrl,
+ aud_gpios[type].gpioctrl);
+ if (ret) {
+ dev_err(dev, "%s(), error, can not set gpio type %d\n",
+ __func__, type);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mt8186_afe_gpio_adda_dl(struct device *dev, bool enable)
+{
+ int ret;
+
+ if (enable) {
+ ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MOSI_ON);
+ if (ret) {
+ dev_err(dev, "%s(), MOSI CLK ON select fail!\n", __func__);
+ return ret;
+ }
+
+ ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MOSI_ON);
+ if (ret) {
+ dev_err(dev, "%s(), MOSI DAT ON select fail!\n", __func__);
+ return ret;
+ }
+ } else {
+ ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MOSI_OFF);
+ if (ret) {
+ dev_err(dev, "%s(), MOSI DAT OFF select fail!\n", __func__);
+ return ret;
+ }
+
+ ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MOSI_OFF);
+ if (ret) {
+ dev_err(dev, "%s(), MOSI CLK ON select fail!\n", __func__);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int mt8186_afe_gpio_adda_ul(struct device *dev, bool enable)
+{
+ int ret;
+
+ 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__);
+ 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__);
+ 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__);
+ 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__);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int mt8186_afe_gpio_request(struct device *dev, bool enable,
+ int dai, int uplink)
+{
+ enum mt8186_afe_gpio sel;
+ int ret = -EINVAL;
+
+ mutex_lock(&gpio_request_mutex);
+
+ switch (dai) {
+ case MT8186_DAI_ADDA:
+ if (uplink)
+ ret = mt8186_afe_gpio_adda_ul(dev, enable);
+ else
+ ret = mt8186_afe_gpio_adda_dl(dev, enable);
+ goto unlock;
+ case MT8186_DAI_I2S_0:
+ sel = enable ? MT8186_AFE_GPIO_I2S0_ON : MT8186_AFE_GPIO_I2S0_OFF;
+ break;
+ case MT8186_DAI_I2S_1:
+ sel = enable ? MT8186_AFE_GPIO_I2S1_ON : MT8186_AFE_GPIO_I2S1_OFF;
+ break;
+ case MT8186_DAI_I2S_2:
+ sel = enable ? MT8186_AFE_GPIO_I2S2_ON : MT8186_AFE_GPIO_I2S2_OFF;
+ break;
+ case MT8186_DAI_I2S_3:
+ sel = enable ? MT8186_AFE_GPIO_I2S3_ON : MT8186_AFE_GPIO_I2S3_OFF;
+ break;
+ case MT8186_DAI_TDM_IN:
+ sel = enable ? MT8186_AFE_GPIO_TDM_ON : MT8186_AFE_GPIO_TDM_OFF;
+ break;
+ case MT8186_DAI_PCM:
+ sel = enable ? MT8186_AFE_GPIO_PCM_ON : MT8186_AFE_GPIO_PCM_OFF;
+ break;
+ default:
+ mutex_unlock(&gpio_request_mutex);
+ dev_err(dev, "%s(), invalid dai %d\n", __func__, dai);
+ goto unlock;
+ }
+
+ ret = mt8186_afe_gpio_select(dev, sel);
+
+unlock:
+ mutex_unlock(&gpio_request_mutex);
+
+ return ret;
+}
diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-gpio.h b/sound/soc/mediatek/mt8186/mt8186-afe-gpio.h
new file mode 100644
index 0000000..1ddc278
--- /dev/null
+++ b/sound/soc/mediatek/mt8186/mt8186-afe-gpio.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * mt6833-afe-gpio.h -- Mediatek 6833 afe gpio ctrl definition
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+ */
+
+#ifndef _MT8186_AFE_GPIO_H_
+#define _MT8186_AFE_GPIO_H_
+
+struct mtk_base_afe;
+
+int mt8186_afe_gpio_init(struct device *dev);
+
+int mt8186_afe_gpio_request(struct device *dev, bool enable,
+ int dai, int uplink);
+
+#endif
diff --git a/sound/soc/mediatek/mt8186/mt8186-audsys-clk.c b/sound/soc/mediatek/mt8186/mt8186-audsys-clk.c
new file mode 100644
index 0000000..578969c
--- /dev/null
+++ b/sound/soc/mediatek/mt8186/mt8186-audsys-clk.c
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mt8186-audsys-clk.h -- Mediatek 8186 audsys clock control
+//
+// Copyright (c) 2022 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include "mt8186-afe-common.h"
+#include "mt8186-audsys-clk.h"
+#include "mt8186-audsys-clkid.h"
+#include "mt8186-reg.h"
+
+struct afe_gate {
+ int id;
+ const char *name;
+ const char *parent_name;
+ int reg;
+ u8 bit;
+ const struct clk_ops *ops;
+ unsigned long flags;
+ u8 cg_flags;
+};
+
+#define GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit, _flags, _cgflags) {\
+ .id = _id, \
+ .name = _name, \
+ .parent_name = _parent, \
+ .reg = _reg, \
+ .bit = _bit, \
+ .flags = _flags, \
+ .cg_flags = _cgflags, \
+ }
+
+#define GATE_AFE(_id, _name, _parent, _reg, _bit) \
+ GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit, \
+ CLK_SET_RATE_PARENT, CLK_GATE_SET_TO_DISABLE)
+
+#define GATE_AUD0(_id, _name, _parent, _bit) \
+ GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON0, _bit)
+
+#define GATE_AUD1(_id, _name, _parent, _bit) \
+ GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON1, _bit)
+
+#define GATE_AUD2(_id, _name, _parent, _bit) \
+ GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON2, _bit)
+
+static const struct afe_gate aud_clks[CLK_AUD_NR_CLK] = {
+ /* AUD0 */
+ GATE_AUD0(CLK_AUD_AFE, "aud_afe_clk", "top_audio", 2),
+ GATE_AUD0(CLK_AUD_22M, "aud_apll22m_clk", "top_aud_engen1", 8),
+ GATE_AUD0(CLK_AUD_24M, "aud_apll24m_clk", "top_aud_engen2", 9),
+ GATE_AUD0(CLK_AUD_APLL2_TUNER, "aud_apll2_tuner_clk", "top_aud_engen2", 18),
+ GATE_AUD0(CLK_AUD_APLL_TUNER, "aud_apll_tuner_clk", "top_aud_engen1", 19),
+ GATE_AUD0(CLK_AUD_TDM, "aud_tdm_clk", "top_aud_1", 20),
+ GATE_AUD0(CLK_AUD_ADC, "aud_adc_clk", "top_audio", 24),
+ GATE_AUD0(CLK_AUD_DAC, "aud_dac_clk", "top_audio", 25),
+ GATE_AUD0(CLK_AUD_DAC_PREDIS, "aud_dac_predis_clk", "top_audio", 26),
+ GATE_AUD0(CLK_AUD_TML, "aud_tml_clk", "top_audio", 27),
+ GATE_AUD0(CLK_AUD_NLE, "aud_nle_clk", "top_audio", 28),
+
+ /* AUD1 */
+ GATE_AUD1(CLK_AUD_I2S1_BCLK, "aud_i2s1_bclk", "top_audio", 4),
+ GATE_AUD1(CLK_AUD_I2S2_BCLK, "aud_i2s2_bclk", "top_audio", 5),
+ GATE_AUD1(CLK_AUD_I2S3_BCLK, "aud_i2s3_bclk", "top_audio", 6),
+ GATE_AUD1(CLK_AUD_I2S4_BCLK, "aud_i2s4_bclk", "top_audio", 7),
+ GATE_AUD1(CLK_AUD_CONNSYS_I2S_ASRC, "aud_connsys_i2s_asrc", "top_audio", 12),
+ GATE_AUD1(CLK_AUD_GENERAL1_ASRC, "aud_general1_asrc", "top_audio", 13),
+ GATE_AUD1(CLK_AUD_GENERAL2_ASRC, "aud_general2_asrc", "top_audio", 14),
+ GATE_AUD1(CLK_AUD_DAC_HIRES, "aud_dac_hires_clk", "top_audio_h", 15),
+ GATE_AUD1(CLK_AUD_ADC_HIRES, "aud_adc_hires_clk", "top_audio_h", 16),
+ GATE_AUD1(CLK_AUD_ADC_HIRES_TML, "aud_adc_hires_tml", "top_audio_h", 17),
+ GATE_AUD1(CLK_AUD_ADDA6_ADC, "aud_adda6_adc", "top_audio", 20),
+ GATE_AUD1(CLK_AUD_ADDA6_ADC_HIRES, "aud_adda6_adc_hires", "top_audio_h", 21),
+ GATE_AUD1(CLK_AUD_3RD_DAC, "aud_3rd_dac", "top_audio", 28),
+ GATE_AUD1(CLK_AUD_3RD_DAC_PREDIS, "aud_3rd_dac_predis", "top_audio", 29),
+ GATE_AUD1(CLK_AUD_3RD_DAC_TML, "aud_3rd_dac_tml", "top_audio", 30),
+ GATE_AUD1(CLK_AUD_3RD_DAC_HIRES, "aud_3rd_dac_hires", "top_audio_h", 31),
+
+ /* AUD2 */
+ GATE_AUD2(CLK_AUD_ETDM_IN1_BCLK, "aud_etdm_in1_bclk", "top_audio", 23),
+ GATE_AUD2(CLK_AUD_ETDM_OUT1_BCLK, "aud_etdm_out1_bclk", "top_audio", 24),
+};
+
+int mt8186_audsys_clk_register(struct mtk_base_afe *afe)
+{
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ struct clk *clk;
+ struct clk_lookup *cl;
+ int i;
+
+ afe_priv->lookup = devm_kcalloc(afe->dev, CLK_AUD_NR_CLK,
+ sizeof(*afe_priv->lookup),
+ GFP_KERNEL);
+
+ if (!afe_priv->lookup)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(aud_clks); i++) {
+ const struct afe_gate *gate = &aud_clks[i];
+
+ clk = clk_register_gate(afe->dev, gate->name, gate->parent_name,
+ gate->flags, afe->base_addr + gate->reg,
+ gate->bit, gate->cg_flags, NULL);
+
+ if (IS_ERR(clk)) {
+ dev_err(afe->dev, "Failed to register clk %s: %ld\n",
+ gate->name, PTR_ERR(clk));
+ continue;
+ }
+
+ /* add clk_lookup for devm_clk_get(SND_SOC_DAPM_CLOCK_SUPPLY) */
+ cl = kzalloc(sizeof(*cl), GFP_KERNEL);
+ if (!cl)
+ return -ENOMEM;
+
+ cl->clk = clk;
+ cl->con_id = gate->name;
+ cl->dev_id = dev_name(afe->dev);
+ clkdev_add(cl);
+
+ afe_priv->lookup[i] = cl;
+ }
+
+ return 0;
+}
+
+void mt8186_audsys_clk_unregister(struct mtk_base_afe *afe)
+{
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ struct clk *clk;
+ struct clk_lookup *cl;
+ int i;
+
+ if (!afe_priv)
+ return;
+
+ for (i = 0; i < CLK_AUD_NR_CLK; i++) {
+ cl = afe_priv->lookup[i];
+ if (!cl)
+ continue;
+
+ clk = cl->clk;
+ clk_unregister_gate(clk);
+
+ clkdev_drop(cl);
+ }
+}
diff --git a/sound/soc/mediatek/mt8186/mt8186-audsys-clk.h b/sound/soc/mediatek/mt8186/mt8186-audsys-clk.h
new file mode 100644
index 0000000..b8d6a06
--- /dev/null
+++ b/sound/soc/mediatek/mt8186/mt8186-audsys-clk.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * mt8186-audsys-clk.h -- Mediatek 8186 audsys clock definition
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Trevor Wu <trevor.wu@mediatek.com>
+ */
+
+#ifndef _MT8186_AUDSYS_CLK_H_
+#define _MT8186_AUDSYS_CLK_H_
+
+int mt8186_audsys_clk_register(struct mtk_base_afe *afe);
+void mt8186_audsys_clk_unregister(struct mtk_base_afe *afe);
+
+#endif
diff --git a/sound/soc/mediatek/mt8186/mt8186-audsys-clkid.h b/sound/soc/mediatek/mt8186/mt8186-audsys-clkid.h
new file mode 100644
index 0000000..3ce5937
--- /dev/null
+++ b/sound/soc/mediatek/mt8186/mt8186-audsys-clkid.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * mt8186-audsys-clkid.h -- Mediatek 8186 audsys clock id definition
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+ */
+
+#ifndef _MT8186_AUDSYS_CLKID_H_
+#define _MT8186_AUDSYS_CLKID_H_
+
+enum{
+ CLK_AUD_AFE,
+ CLK_AUD_22M,
+ CLK_AUD_24M,
+ CLK_AUD_APLL2_TUNER,
+ CLK_AUD_APLL_TUNER,
+ CLK_AUD_TDM,
+ CLK_AUD_ADC,
+ CLK_AUD_DAC,
+ CLK_AUD_DAC_PREDIS,
+ CLK_AUD_TML,
+ CLK_AUD_NLE,
+ CLK_AUD_I2S1_BCLK,
+ CLK_AUD_I2S2_BCLK,
+ CLK_AUD_I2S3_BCLK,
+ CLK_AUD_I2S4_BCLK,
+ CLK_AUD_CONNSYS_I2S_ASRC,
+ CLK_AUD_GENERAL1_ASRC,
+ CLK_AUD_GENERAL2_ASRC,
+ CLK_AUD_DAC_HIRES,
+ CLK_AUD_ADC_HIRES,
+ CLK_AUD_ADC_HIRES_TML,
+ CLK_AUD_ADDA6_ADC,
+ CLK_AUD_ADDA6_ADC_HIRES,
+ CLK_AUD_3RD_DAC,
+ CLK_AUD_3RD_DAC_PREDIS,
+ CLK_AUD_3RD_DAC_TML,
+ CLK_AUD_3RD_DAC_HIRES,
+ CLK_AUD_ETDM_IN1_BCLK,
+ CLK_AUD_ETDM_OUT1_BCLK,
+ CLK_AUD_NR_CLK,
+};
+
+#endif
diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-adda.c b/sound/soc/mediatek/mt8186/mt8186-dai-adda.c
new file mode 100644
index 0000000..db71b03
--- /dev/null
+++ b/sound/soc/mediatek/mt8186/mt8186-dai-adda.c
@@ -0,0 +1,873 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI ADDA Control
+//
+// Copyright (c) 2022 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include "mt8186-afe-clk.h"
+#include "mt8186-afe-common.h"
+#include "mt8186-afe-gpio.h"
+#include "mt8186-interconnection.h"
+
+enum {
+ UL_IIR_SW = 0,
+ UL_IIR_5HZ,
+ UL_IIR_10HZ,
+ UL_IIR_25HZ,
+ UL_IIR_50HZ,
+ UL_IIR_75HZ,
+};
+
+enum {
+ AUDIO_SDM_LEVEL_MUTE = 0,
+ AUDIO_SDM_LEVEL_NORMAL = 0x1d,
+ /* if you change level normal */
+ /* you need to change formula of hp impedance and dc trim too */
+};
+
+enum {
+ AUDIO_SDM_2ND = 0,
+ AUDIO_SDM_3RD,
+};
+
+enum {
+ DELAY_DATA_MISO1 = 0,
+ DELAY_DATA_MISO2,
+};
+
+enum {
+ MTK_AFE_ADDA_DL_RATE_8K = 0,
+ MTK_AFE_ADDA_DL_RATE_11K = 1,
+ MTK_AFE_ADDA_DL_RATE_12K = 2,
+ MTK_AFE_ADDA_DL_RATE_16K = 3,
+ MTK_AFE_ADDA_DL_RATE_22K = 4,
+ MTK_AFE_ADDA_DL_RATE_24K = 5,
+ MTK_AFE_ADDA_DL_RATE_32K = 6,
+ MTK_AFE_ADDA_DL_RATE_44K = 7,
+ MTK_AFE_ADDA_DL_RATE_48K = 8,
+ MTK_AFE_ADDA_DL_RATE_96K = 9,
+ MTK_AFE_ADDA_DL_RATE_192K = 10,
+};
+
+enum {
+ MTK_AFE_ADDA_UL_RATE_8K = 0,
+ MTK_AFE_ADDA_UL_RATE_16K = 1,
+ MTK_AFE_ADDA_UL_RATE_32K = 2,
+ MTK_AFE_ADDA_UL_RATE_48K = 3,
+ MTK_AFE_ADDA_UL_RATE_96K = 4,
+ MTK_AFE_ADDA_UL_RATE_192K = 5,
+ MTK_AFE_ADDA_UL_RATE_48K_HD = 6,
+};
+
+#define SDM_AUTO_RESET_THRESHOLD 0x190000
+
+struct mtk_afe_adda_priv {
+ int dl_rate;
+ int ul_rate;
+};
+
+static struct mtk_afe_adda_priv *get_adda_priv_by_name(struct mtk_base_afe *afe,
+ const char *name)
+{
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int dai_id;
+
+ if (strncmp(name, "aud_dac_hires_clk", 7) == 0 ||
+ strncmp(name, "aud_adc_hires_clk", 7) == 0)
+ dai_id = MT8186_DAI_ADDA;
+ else
+ return NULL;
+
+ return afe_priv->dai_priv[dai_id];
+}
+
+static unsigned int adda_dl_rate_transform(struct mtk_base_afe *afe,
+ unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_ADDA_DL_RATE_8K;
+ case 11025:
+ return MTK_AFE_ADDA_DL_RATE_11K;
+ case 12000:
+ return MTK_AFE_ADDA_DL_RATE_12K;
+ case 16000:
+ return MTK_AFE_ADDA_DL_RATE_16K;
+ case 22050:
+ return MTK_AFE_ADDA_DL_RATE_22K;
+ case 24000:
+ return MTK_AFE_ADDA_DL_RATE_24K;
+ case 32000:
+ return MTK_AFE_ADDA_DL_RATE_32K;
+ case 44100:
+ return MTK_AFE_ADDA_DL_RATE_44K;
+ case 48000:
+ return MTK_AFE_ADDA_DL_RATE_48K;
+ case 96000:
+ return MTK_AFE_ADDA_DL_RATE_96K;
+ case 192000:
+ return MTK_AFE_ADDA_DL_RATE_192K;
+ default:
+ dev_info(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
+ __func__, rate);
+ }
+
+ return MTK_AFE_ADDA_DL_RATE_48K;
+}
+
+static unsigned int adda_ul_rate_transform(struct mtk_base_afe *afe,
+ unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_ADDA_UL_RATE_8K;
+ case 16000:
+ return MTK_AFE_ADDA_UL_RATE_16K;
+ case 32000:
+ return MTK_AFE_ADDA_UL_RATE_32K;
+ case 48000:
+ return MTK_AFE_ADDA_UL_RATE_48K;
+ case 96000:
+ return MTK_AFE_ADDA_UL_RATE_96K;
+ case 192000:
+ return MTK_AFE_ADDA_UL_RATE_192K;
+ default:
+ dev_info(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
+ __func__, rate);
+ }
+
+ return MTK_AFE_ADDA_UL_RATE_48K;
+}
+
+/* dai component */
+static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN3, I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1 Switch", AFE_CONN3, I_DL12_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN3, I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN3, I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN3_1, I_DL4_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN3_1, I_DL5_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1 Switch", AFE_CONN3_1, I_DL6_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1 Switch", AFE_CONN3_1, I_DL8_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN3,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN3,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1 Switch", AFE_CONN3,
+ I_GAIN1_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1 Switch", AFE_CONN3,
+ I_PCM_1_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1 Switch", AFE_CONN3,
+ I_PCM_2_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH1 Switch", AFE_CONN3_1,
+ I_SRC_1_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("SRC_2_OUT_CH1 Switch", AFE_CONN3_1,
+ I_SRC_2_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_adda_dl_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN4, I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN4, I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN4, I_DL12_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN4, I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN4, I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN4, I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN4, I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN4_1, I_DL4_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN4_1, I_DL5_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2 Switch", AFE_CONN4_1, I_DL6_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2 Switch", AFE_CONN4_1, I_DL8_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN4,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN4,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2 Switch", AFE_CONN4,
+ I_GAIN1_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2 Switch", AFE_CONN4,
+ I_PCM_1_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2 Switch", AFE_CONN4,
+ I_PCM_2_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH2 Switch", AFE_CONN4_1,
+ I_SRC_1_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("SRC_2_OUT_CH2 Switch", AFE_CONN4_1,
+ I_SRC_2_OUT_CH2, 1, 0),
+};
+
+enum {
+ SUPPLY_SEQ_ADDA_AFE_ON,
+ SUPPLY_SEQ_ADDA_DL_ON,
+ SUPPLY_SEQ_ADDA_AUD_PAD_TOP,
+ SUPPLY_SEQ_ADDA_MTKAIF_CFG,
+ SUPPLY_SEQ_ADDA_FIFO,
+ SUPPLY_SEQ_ADDA_AP_DMIC,
+ SUPPLY_SEQ_ADDA_UL_ON,
+};
+
+static int mtk_adda_ul_src_dmic(struct mtk_base_afe *afe, int id)
+{
+ unsigned int reg;
+
+ switch (id) {
+ case MT8186_DAI_ADDA:
+ case MT8186_DAI_AP_DMIC:
+ reg = AFE_ADDA_UL_SRC_CON0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* dmic mode, 3.25M*/
+ regmap_update_bits(afe->regmap, reg,
+ DIGMIC_3P25M_1P625M_SEL_MASK_SFT, 0);
+ regmap_update_bits(afe->regmap, reg,
+ DMIC_LOW_POWER_CTL_MASK_SFT, 0);
+
+ /* turn on dmic, ch1, ch2 */
+ regmap_update_bits(afe->regmap, reg,
+ UL_SDM_3_LEVEL_MASK_SFT,
+ BIT(UL_SDM_3_LEVEL_SFT));
+ regmap_update_bits(afe->regmap, reg,
+ UL_MODE_3P25M_CH1_CTL_MASK_SFT,
+ BIT(UL_MODE_3P25M_CH1_CTL_SFT));
+ regmap_update_bits(afe->regmap, reg,
+ UL_MODE_3P25M_CH2_CTL_MASK_SFT,
+ BIT(UL_MODE_3P25M_CH2_CTL_SFT));
+
+ return 0;
+}
+
+static int mtk_adda_ul_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int mtkaif_dmic = afe_priv->mtkaif_dmic;
+
+ dev_dbg(afe->dev, "%s(), name %s, event 0x%x, mtkaif_dmic %d\n",
+ __func__, w->name, event, mtkaif_dmic);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8186_afe_gpio_request(afe->dev, true, MT8186_DAI_ADDA, 1);
+
+ /* update setting to dmic */
+ if (mtkaif_dmic) {
+ /* mtkaif_rxif_data_mode = 1, dmic */
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_RX_CFG0,
+ 0x1, 0x1);
+
+ /* dmic mode, 3.25M*/
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_RX_CFG0,
+ MTKAIF_RXIF_VOICE_MODE_MASK_SFT,
+ 0x0);
+ mtk_adda_ul_src_dmic(afe, MT8186_DAI_ADDA);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+ usleep_range(125, 135);
+ mt8186_afe_gpio_request(afe->dev, false, MT8186_DAI_ADDA, 1);
+
+ /* reset dmic */
+ afe_priv->mtkaif_dmic = 0;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_adda_pad_top_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2)
+ regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x39);
+ else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2)
+ regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x31);
+ else
+ regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x31);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_adda_mtkaif_cfg_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int delay_data;
+ int delay_cycle;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2) {
+ /* set protocol 2 */
+ regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0, 0x10000);
+ /* mtkaif_rxif_clkinv_adc inverse */
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_CFG0,
+ MTKAIF_RXIF_CLKINV_ADC_MASK_SFT,
+ BIT(MTKAIF_RXIF_CLKINV_ADC_SFT));
+
+ if (strcmp(w->name, "ADDA_MTKAIF_CFG") == 0) {
+ if (afe_priv->mtkaif_chosen_phase[0] < 0 &&
+ afe_priv->mtkaif_chosen_phase[1] < 0) {
+ dev_err(afe->dev,
+ "%s(), calib fail mtkaif_chosen_phase[0/1]:%d/%d\n",
+ __func__,
+ afe_priv->mtkaif_chosen_phase[0],
+ afe_priv->mtkaif_chosen_phase[1]);
+ break;
+ }
+
+ if (afe_priv->mtkaif_chosen_phase[0] < 0 ||
+ afe_priv->mtkaif_chosen_phase[1] < 0) {
+ dev_err(afe->dev,
+ "%s(), skip delay setting mtkaif_chosen_phase[0/1]:%d/%d\n",
+ __func__,
+ afe_priv->mtkaif_chosen_phase[0],
+ afe_priv->mtkaif_chosen_phase[1]);
+ break;
+ }
+ }
+
+ /* set delay for ch12 */
+ if (afe_priv->mtkaif_phase_cycle[0] >=
+ afe_priv->mtkaif_phase_cycle[1]) {
+ delay_data = DELAY_DATA_MISO1;
+ delay_cycle = afe_priv->mtkaif_phase_cycle[0] -
+ afe_priv->mtkaif_phase_cycle[1];
+ } else {
+ delay_data = DELAY_DATA_MISO2;
+ delay_cycle = afe_priv->mtkaif_phase_cycle[1] -
+ afe_priv->mtkaif_phase_cycle[0];
+ }
+
+ regmap_update_bits(afe->regmap,
+ AFE_ADDA_MTKAIF_RX_CFG2,
+ MTKAIF_RXIF_DELAY_DATA_MASK_SFT,
+ delay_data <<
+ MTKAIF_RXIF_DELAY_DATA_SFT);
+
+ regmap_update_bits(afe->regmap,
+ AFE_ADDA_MTKAIF_RX_CFG2,
+ MTKAIF_RXIF_DELAY_CYCLE_MASK_SFT,
+ delay_cycle <<
+ MTKAIF_RXIF_DELAY_CYCLE_SFT);
+
+ } else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2) {
+ regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0, 0x10000);
+ } else {
+ regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0, 0);
+ }
+
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_adda_dl_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+ dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n",
+ __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8186_afe_gpio_request(afe->dev, true, MT8186_DAI_ADDA, 0);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+ usleep_range(125, 135);
+ mt8186_afe_gpio_request(afe->dev, false, MT8186_DAI_ADDA, 0);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mt8186_adda_dmic_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+
+ ucontrol->value.integer.value[0] = afe_priv->mtkaif_dmic;
+
+ return 0;
+}
+
+static int mt8186_adda_dmic_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int dmic_on;
+
+ dmic_on = ucontrol->value.integer.value[0];
+
+ dev_dbg(afe->dev, "%s(), kcontrol name %s, dmic_on %d\n",
+ __func__, kcontrol->id.name, dmic_on);
+
+ if (afe_priv->mtkaif_dmic == dmic_on)
+ return 0;
+
+ afe_priv->mtkaif_dmic = dmic_on;
+
+ return 1;
+}
+
+static const struct snd_kcontrol_new mtk_adda_controls[] = {
+ SOC_SINGLE("ADDA_DL_GAIN", AFE_ADDA_DL_SRC2_CON1,
+ DL_2_GAIN_CTL_PRE_SFT, DL_2_GAIN_CTL_PRE_MASK, 0),
+ SOC_SINGLE_BOOL_EXT("MTKAIF_DMIC Switch", 0,
+ mt8186_adda_dmic_get, mt8186_adda_dmic_set),
+};
+
+/* ADDA UL MUX */
+enum {
+ ADDA_UL_MUX_MTKAIF = 0,
+ ADDA_UL_MUX_AP_DMIC,
+ ADDA_UL_MUX_MASK = 0x1,
+};
+
+static const char * const adda_ul_mux_map[] = {
+ "MTKAIF", "AP_DMIC"
+};
+
+static int adda_ul_map_value[] = {
+ ADDA_UL_MUX_MTKAIF,
+ ADDA_UL_MUX_AP_DMIC,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(adda_ul_mux_map_enum,
+ SND_SOC_NOPM,
+ 0,
+ ADDA_UL_MUX_MASK,
+ adda_ul_mux_map,
+ adda_ul_map_value);
+
+static const struct snd_kcontrol_new adda_ul_mux_control =
+ SOC_DAPM_ENUM("ADDA_UL_MUX Select", adda_ul_mux_map_enum);
+
+static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = {
+ /* inter-connections */
+ SND_SOC_DAPM_MIXER("ADDA_DL_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_adda_dl_ch1_mix,
+ ARRAY_SIZE(mtk_adda_dl_ch1_mix)),
+ SND_SOC_DAPM_MIXER("ADDA_DL_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_adda_dl_ch2_mix,
+ ARRAY_SIZE(mtk_adda_dl_ch2_mix)),
+
+ SND_SOC_DAPM_SUPPLY_S("ADDA Enable", SUPPLY_SEQ_ADDA_AFE_ON,
+ AFE_ADDA_UL_DL_CON0, ADDA_AFE_ON_SFT, 0,
+ NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY_S("ADDA Playback Enable", SUPPLY_SEQ_ADDA_DL_ON,
+ AFE_ADDA_DL_SRC2_CON0,
+ DL_2_SRC_ON_CTL_PRE_SFT, 0,
+ mtk_adda_dl_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("ADDA Capture Enable", SUPPLY_SEQ_ADDA_UL_ON,
+ AFE_ADDA_UL_SRC_CON0,
+ UL_SRC_ON_CTL_SFT, 0,
+ mtk_adda_ul_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("AUD_PAD_TOP", SUPPLY_SEQ_ADDA_AUD_PAD_TOP,
+ 0, 0, 0,
+ mtk_adda_pad_top_event,
+ SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_SUPPLY_S("ADDA_MTKAIF_CFG", SUPPLY_SEQ_ADDA_MTKAIF_CFG,
+ SND_SOC_NOPM, 0, 0,
+ mtk_adda_mtkaif_cfg_event,
+ SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_SUPPLY_S("AP_DMIC_EN", SUPPLY_SEQ_ADDA_AP_DMIC,
+ AFE_ADDA_UL_SRC_CON0,
+ UL_AP_DMIC_ON_SFT, 0,
+ NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY_S("ADDA_FIFO", SUPPLY_SEQ_ADDA_FIFO,
+ AFE_ADDA_UL_DL_CON0,
+ AFE_ADDA_FIFO_AUTO_RST_SFT, 1,
+ NULL, 0),
+
+ SND_SOC_DAPM_MUX("ADDA_UL_Mux", SND_SOC_NOPM, 0, 0,
+ &adda_ul_mux_control),
+
+ SND_SOC_DAPM_INPUT("AP_DMIC_INPUT"),
+
+ /* clock */
+ SND_SOC_DAPM_CLOCK_SUPPLY("top_mux_audio_h"),
+
+ SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_clk"),
+ SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_hires_clk"),
+ SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_predis_clk"),
+
+ SND_SOC_DAPM_CLOCK_SUPPLY("aud_adc_clk"),
+ SND_SOC_DAPM_CLOCK_SUPPLY("aud_adc_hires_clk"),
+};
+
+#define HIRES_THRESHOLD 48000
+static int mtk_afe_dac_hires_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_dapm_widget *w = source;
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_adda_priv *adda_priv;
+
+ adda_priv = get_adda_priv_by_name(afe, w->name);
+
+ if (!adda_priv) {
+ dev_err(afe->dev, "%s(), adda_priv == NULL", __func__);
+ return 0;
+ }
+
+ return (adda_priv->dl_rate > HIRES_THRESHOLD) ? 1 : 0;
+}
+
+static int mtk_afe_adc_hires_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_dapm_widget *w = source;
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_adda_priv *adda_priv;
+
+ adda_priv = get_adda_priv_by_name(afe, w->name);
+
+ if (!adda_priv) {
+ dev_err(afe->dev, "%s(), adda_priv == NULL", __func__);
+ return 0;
+ }
+
+ return (adda_priv->ul_rate > HIRES_THRESHOLD) ? 1 : 0;
+}
+
+static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = {
+ /* playback */
+ {"ADDA_DL_CH1", "DL1_CH1 Switch", "DL1"},
+ {"ADDA_DL_CH2", "DL1_CH1 Switch", "DL1"},
+ {"ADDA_DL_CH2", "DL1_CH2 Switch", "DL1"},
+
+ {"ADDA_DL_CH1", "DL12_CH1 Switch", "DL12"},
+ {"ADDA_DL_CH2", "DL12_CH2 Switch", "DL12"},
+
+ {"ADDA_DL_CH1", "DL6_CH1 Switch", "DL6"},
+ {"ADDA_DL_CH2", "DL6_CH2 Switch", "DL6"},
+
+ {"ADDA_DL_CH1", "DL8_CH1 Switch", "DL8"},
+ {"ADDA_DL_CH2", "DL8_CH2 Switch", "DL8"},
+
+ {"ADDA_DL_CH1", "DL2_CH1 Switch", "DL2"},
+ {"ADDA_DL_CH2", "DL2_CH1 Switch", "DL2"},
+ {"ADDA_DL_CH2", "DL2_CH2 Switch", "DL2"},
+
+ {"ADDA_DL_CH1", "DL3_CH1 Switch", "DL3"},
+ {"ADDA_DL_CH2", "DL3_CH1 Switch", "DL3"},
+ {"ADDA_DL_CH2", "DL3_CH2 Switch", "DL3"},
+
+ {"ADDA_DL_CH1", "DL4_CH1 Switch", "DL4"},
+ {"ADDA_DL_CH2", "DL4_CH2 Switch", "DL4"},
+
+ {"ADDA_DL_CH1", "DL5_CH1 Switch", "DL5"},
+ {"ADDA_DL_CH2", "DL5_CH2 Switch", "DL5"},
+
+ {"ADDA Playback", NULL, "ADDA_DL_CH1"},
+ {"ADDA Playback", NULL, "ADDA_DL_CH2"},
+
+ {"ADDA Playback", NULL, "ADDA Enable"},
+ {"ADDA Playback", NULL, "ADDA Playback Enable"},
+
+ /* capture */
+ {"ADDA_UL_Mux", "MTKAIF", "ADDA Capture"},
+ {"ADDA_UL_Mux", "AP_DMIC", "AP DMIC Capture"},
+
+ {"ADDA Capture", NULL, "ADDA Enable"},
+ {"ADDA Capture", NULL, "ADDA Capture Enable"},
+ {"ADDA Capture", NULL, "AUD_PAD_TOP"},
+ {"ADDA Capture", NULL, "ADDA_MTKAIF_CFG"},
+
+ {"AP DMIC Capture", NULL, "ADDA Enable"},
+ {"AP DMIC Capture", NULL, "ADDA Capture Enable"},
+ {"AP DMIC Capture", NULL, "ADDA_FIFO"},
+ {"AP DMIC Capture", NULL, "AP_DMIC_EN"},
+
+ {"AP DMIC Capture", NULL, "AP_DMIC_INPUT"},
+
+ /* clk */
+ {"ADDA Playback", NULL, "aud_dac_clk"},
+ {"ADDA Playback", NULL, "aud_dac_predis_clk"},
+ {"ADDA Playback", NULL, "aud_dac_hires_clk", mtk_afe_dac_hires_connect},
+
+ {"ADDA Capture Enable", NULL, "aud_adc_clk"},
+ {"ADDA Capture Enable", NULL, "aud_adc_hires_clk",
+ mtk_afe_adc_hires_connect},
+
+ /* hires source from apll1 */
+ {"top_mux_audio_h", NULL, APLL2_W_NAME},
+
+ {"aud_dac_hires_clk", NULL, "top_mux_audio_h"},
+ {"aud_adc_hires_clk", NULL, "top_mux_audio_h"},
+};
+
+/* dai ops */
+static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ unsigned int rate = params_rate(params);
+ int id = dai->id;
+ struct mtk_afe_adda_priv *adda_priv = afe_priv->dai_priv[id];
+
+ dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n",
+ __func__, id, substream->stream, rate);
+
+ if (!adda_priv) {
+ dev_err(afe->dev, "%s(), adda_priv == NULL", __func__);
+ return -EINVAL;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ unsigned int dl_src2_con0;
+ unsigned int dl_src2_con1;
+
+ adda_priv->dl_rate = rate;
+
+ /* set sampling rate */
+ dl_src2_con0 = adda_dl_rate_transform(afe, rate) <<
+ DL_2_INPUT_MODE_CTL_SFT;
+
+ /* set output mode, UP_SAMPLING_RATE_X8 */
+ dl_src2_con0 |= (0x3 << DL_2_OUTPUT_SEL_CTL_SFT);
+
+ /* turn off mute function */
+ dl_src2_con0 |= BIT(DL_2_MUTE_CH2_OFF_CTL_PRE_SFT);
+ dl_src2_con0 |= BIT(DL_2_MUTE_CH1_OFF_CTL_PRE_SFT);
+
+ /* set voice input data if input sample rate is 8k or 16k */
+ if (rate == 8000 || rate == 16000)
+ dl_src2_con0 |= BIT(DL_2_VOICE_MODE_CTL_PRE_SFT);
+
+ /* SA suggest apply -0.3db to audio/speech path */
+ dl_src2_con1 = MTK_AFE_ADDA_DL_GAIN_NORMAL <<
+ DL_2_GAIN_CTL_PRE_SFT;
+
+ /* turn on down-link gain */
+ dl_src2_con0 |= BIT(DL_2_GAIN_ON_CTL_PRE_SFT);
+
+ if (id == MT8186_DAI_ADDA) {
+ /* clean predistortion */
+ regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON0, 0);
+ regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON1, 0);
+
+ regmap_write(afe->regmap,
+ AFE_ADDA_DL_SRC2_CON0, dl_src2_con0);
+ regmap_write(afe->regmap,
+ AFE_ADDA_DL_SRC2_CON1, dl_src2_con1);
+
+ /* set sdm gain */
+ regmap_update_bits(afe->regmap,
+ AFE_ADDA_DL_SDM_DCCOMP_CON,
+ ATTGAIN_CTL_MASK_SFT,
+ AUDIO_SDM_LEVEL_NORMAL <<
+ ATTGAIN_CTL_SFT);
+
+ /* Use new 2nd sdm */
+ regmap_update_bits(afe->regmap,
+ AFE_ADDA_DL_SDM_DITHER_CON,
+ AFE_DL_SDM_DITHER_64TAP_EN_MASK_SFT,
+ BIT(AFE_DL_SDM_DITHER_64TAP_EN_SFT));
+ regmap_update_bits(afe->regmap,
+ AFE_ADDA_DL_SDM_AUTO_RESET_CON,
+ AFE_DL_USE_NEW_2ND_SDM_MASK_SFT,
+ BIT(AFE_DL_USE_NEW_2ND_SDM_SFT));
+ regmap_update_bits(afe->regmap,
+ AFE_ADDA_DL_SDM_DCCOMP_CON,
+ USE_3RD_SDM_MASK_SFT,
+ AUDIO_SDM_2ND << USE_3RD_SDM_SFT);
+
+ /* sdm auto reset */
+ regmap_write(afe->regmap,
+ AFE_ADDA_DL_SDM_AUTO_RESET_CON,
+ SDM_AUTO_RESET_THRESHOLD);
+ regmap_update_bits(afe->regmap,
+ AFE_ADDA_DL_SDM_AUTO_RESET_CON,
+ SDM_AUTO_RESET_TEST_ON_MASK_SFT,
+ BIT(SDM_AUTO_RESET_TEST_ON_SFT));
+ }
+ } else {
+ unsigned int ul_src_con0 = 0;
+ unsigned int voice_mode = adda_ul_rate_transform(afe, rate);
+
+ adda_priv->ul_rate = rate;
+ ul_src_con0 |= (voice_mode << 17) & (0x7 << 17);
+
+ /* enable iir */
+ ul_src_con0 |= (1 << UL_IIR_ON_TMP_CTL_SFT) &
+ UL_IIR_ON_TMP_CTL_MASK_SFT;
+ ul_src_con0 |= (UL_IIR_SW << UL_IIRMODE_CTL_SFT) &
+ UL_IIRMODE_CTL_MASK_SFT;
+ switch (id) {
+ case MT8186_DAI_ADDA:
+ case MT8186_DAI_AP_DMIC:
+ /* 35Hz @ 48k */
+ regmap_write(afe->regmap,
+ AFE_ADDA_IIR_COEF_02_01, 0);
+ regmap_write(afe->regmap,
+ AFE_ADDA_IIR_COEF_04_03, 0x3fb8);
+ regmap_write(afe->regmap,
+ AFE_ADDA_IIR_COEF_06_05, 0x3fb80000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_IIR_COEF_08_07, 0x3fb80000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_IIR_COEF_10_09, 0xc048);
+
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL_SRC_CON0, ul_src_con0);
+
+ /* Using Internal ADC */
+ regmap_update_bits(afe->regmap, AFE_ADDA_TOP_CON0, BIT(0), 0);
+
+ /* mtkaif_rxif_data_mode = 0, amic */
+ regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_RX_CFG0, BIT(0), 0);
+ break;
+ default:
+ break;
+ }
+
+ /* ap dmic */
+ switch (id) {
+ case MT8186_DAI_AP_DMIC:
+ mtk_adda_ul_src_dmic(afe, id);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_adda_ops = {
+ .hw_params = mtk_dai_adda_hw_params,
+};
+
+/* dai driver */
+#define MTK_ADDA_PLAYBACK_RATES (SNDRV_PCM_RATE_8000_48000 |\
+ SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_192000)
+
+#define MTK_ADDA_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\
+ SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 |\
+ SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_192000)
+
+#define MTK_ADDA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_adda_driver[] = {
+ {
+ .name = "ADDA",
+ .id = MT8186_DAI_ADDA,
+ .playback = {
+ .stream_name = "ADDA Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ADDA_PLAYBACK_RATES,
+ .formats = MTK_ADDA_FORMATS,
+ },
+ .capture = {
+ .stream_name = "ADDA Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ADDA_CAPTURE_RATES,
+ .formats = MTK_ADDA_FORMATS,
+ },
+ .ops = &mtk_dai_adda_ops,
+ },
+ {
+ .name = "AP_DMIC",
+ .id = MT8186_DAI_AP_DMIC,
+ .capture = {
+ .stream_name = "AP DMIC Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ADDA_CAPTURE_RATES,
+ .formats = MTK_ADDA_FORMATS,
+ },
+ .ops = &mtk_dai_adda_ops,
+ },
+};
+
+int mt8186_dai_adda_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mtk_dai_adda_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver);
+
+ dai->controls = mtk_adda_controls;
+ dai->num_controls = ARRAY_SIZE(mtk_adda_controls);
+ dai->dapm_widgets = mtk_dai_adda_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets);
+ dai->dapm_routes = mtk_dai_adda_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes);
+
+ /* set dai priv */
+ ret = mt8186_dai_set_priv(afe, MT8186_DAI_ADDA,
+ sizeof(struct mtk_afe_adda_priv), NULL);
+ if (ret)
+ return ret;
+
+ /* ap dmic priv share with adda */
+ afe_priv->dai_priv[MT8186_DAI_AP_DMIC] =
+ afe_priv->dai_priv[MT8186_DAI_ADDA];
+
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-hostless.c b/sound/soc/mediatek/mt8186/mt8186-dai-hostless.c
new file mode 100644
index 0000000..bf0d838
--- /dev/null
+++ b/sound/soc/mediatek/mt8186/mt8186-dai-hostless.c
@@ -0,0 +1,298 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI Hostless Control
+//
+// Copyright (c) 2022 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+
+#include "mt8186-afe-common.h"
+
+static const struct snd_pcm_hardware mt8186_hostless_hardware = {
+ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP_VALID),
+ .period_bytes_min = 256,
+ .period_bytes_max = 4 * 48 * 1024,
+ .periods_min = 2,
+ .periods_max = 256,
+ .buffer_bytes_max = 4 * 48 * 1024,
+ .fifo_size = 0,
+};
+
+/* dai component */
+static const struct snd_soc_dapm_route mtk_dai_hostless_routes[] = {
+ /* Hostless ADDA Loopback */
+ {"ADDA_DL_CH1", "ADDA_UL_CH1 Switch", "Hostless LPBK DL"},
+ {"ADDA_DL_CH1", "ADDA_UL_CH2 Switch", "Hostless LPBK DL"},
+ {"ADDA_DL_CH2", "ADDA_UL_CH1 Switch", "Hostless LPBK DL"},
+ {"ADDA_DL_CH2", "ADDA_UL_CH2 Switch", "Hostless LPBK DL"},
+ {"I2S1_CH1", "ADDA_UL_CH1 Switch", "Hostless LPBK DL"},
+ {"I2S1_CH2", "ADDA_UL_CH2 Switch", "Hostless LPBK DL"},
+ {"I2S3_CH1", "ADDA_UL_CH1 Switch", "Hostless LPBK DL"},
+ {"I2S3_CH1", "ADDA_UL_CH2 Switch", "Hostless LPBK DL"},
+ {"I2S3_CH2", "ADDA_UL_CH1 Switch", "Hostless LPBK DL"},
+ {"I2S3_CH2", "ADDA_UL_CH2 Switch", "Hostless LPBK DL"},
+ {"Hostless LPBK UL", NULL, "ADDA_UL_Mux"},
+
+ /* Hostelss FM */
+ /* connsys_i2s to hw gain 1*/
+ {"Hostless FM UL", NULL, "Connsys I2S"},
+
+ {"HW_GAIN1_IN_CH1", "CONNSYS_I2S_CH1 Switch", "Hostless FM DL"},
+ {"HW_GAIN1_IN_CH2", "CONNSYS_I2S_CH2 Switch", "Hostless FM DL"},
+ /* hw gain to adda dl */
+ {"Hostless FM UL", NULL, "HW Gain 1 Out"},
+
+ {"ADDA_DL_CH1", "GAIN1_OUT_CH1 Switch", "Hostless FM DL"},
+ {"ADDA_DL_CH2", "GAIN1_OUT_CH2 Switch", "Hostless FM DL"},
+ /* hw gain to i2s3 */
+ {"I2S3_CH1", "GAIN1_OUT_CH1 Switch", "Hostless FM DL"},
+ {"I2S3_CH2", "GAIN1_OUT_CH2 Switch", "Hostless FM DL"},
+ /* hw gain to i2s1 */
+ {"I2S1_CH1", "GAIN1_OUT_CH1 Switch", "Hostless FM DL"},
+ {"I2S1_CH2", "GAIN1_OUT_CH2 Switch", "Hostless FM DL"},
+
+ /* Hostless_SRC */
+ {"ADDA_DL_CH1", "SRC_1_OUT_CH1 Switch", "Hostless_SRC_1_DL"},
+ {"ADDA_DL_CH2", "SRC_1_OUT_CH2 Switch", "Hostless_SRC_1_DL"},
+ {"I2S1_CH1", "SRC_1_OUT_CH1 Switch", "Hostless_SRC_1_DL"},
+ {"I2S1_CH2", "SRC_1_OUT_CH2 Switch", "Hostless_SRC_1_DL"},
+ {"I2S3_CH1", "SRC_1_OUT_CH1 Switch", "Hostless_SRC_1_DL"},
+ {"I2S3_CH2", "SRC_1_OUT_CH2 Switch", "Hostless_SRC_1_DL"},
+ {"Hostless_SRC_1_UL", NULL, "HW_SRC_1_Out"},
+
+ /* Hostless_SRC_bargein */
+ {"HW_SRC_1_IN_CH1", "I2S0_CH1 Switch", "Hostless_SRC_Bargein_DL"},
+ {"HW_SRC_1_IN_CH2", "I2S0_CH2 Switch", "Hostless_SRC_Bargein_DL"},
+ {"Hostless_SRC_Bargein_UL", NULL, "I2S0"},
+
+ /* Hostless AAudio */
+ {"Hostless HW Gain AAudio In", NULL, "HW Gain 2 In"},
+ {"Hostless SRC AAudio UL", NULL, "HW Gain 2 Out"},
+ {"HW_SRC_2_IN_CH1", "HW_GAIN2_OUT_CH1 Switch", "Hostless SRC AAudio DL"},
+ {"HW_SRC_2_IN_CH2", "HW_GAIN2_OUT_CH2 Switch", "Hostless SRC AAudio DL"},
+};
+
+/* dai ops */
+static int mtk_dai_hostless_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int ret;
+
+ snd_soc_set_runtime_hwparams(substream, &mt8186_hostless_hardware);
+
+ ret = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0) {
+ dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_hostless_ops = {
+ .startup = mtk_dai_hostless_startup,
+};
+
+/* dai driver */
+#define MTK_HOSTLESS_RATES (SNDRV_PCM_RATE_8000_48000 |\
+ SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_176400 |\
+ SNDRV_PCM_RATE_192000)
+
+#define MTK_HOSTLESS_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_hostless_driver[] = {
+ {
+ .name = "Hostless LPBK DAI",
+ .id = MT8186_DAI_HOSTLESS_LPBK,
+ .playback = {
+ .stream_name = "Hostless LPBK DL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_HOSTLESS_RATES,
+ .formats = MTK_HOSTLESS_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Hostless LPBK UL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_HOSTLESS_RATES,
+ .formats = MTK_HOSTLESS_FORMATS,
+ },
+ .ops = &mtk_dai_hostless_ops,
+ },
+ {
+ .name = "Hostless FM DAI",
+ .id = MT8186_DAI_HOSTLESS_FM,
+ .playback = {
+ .stream_name = "Hostless FM DL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_HOSTLESS_RATES,
+ .formats = MTK_HOSTLESS_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Hostless FM UL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_HOSTLESS_RATES,
+ .formats = MTK_HOSTLESS_FORMATS,
+ },
+ .ops = &mtk_dai_hostless_ops,
+ },
+ {
+ .name = "Hostless_SRC_1_DAI",
+ .id = MT8186_DAI_HOSTLESS_SRC_1,
+ .playback = {
+ .stream_name = "Hostless_SRC_1_DL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_HOSTLESS_RATES,
+ .formats = MTK_HOSTLESS_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Hostless_SRC_1_UL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_HOSTLESS_RATES,
+ .formats = MTK_HOSTLESS_FORMATS,
+ },
+ .ops = &mtk_dai_hostless_ops,
+ },
+ {
+ .name = "Hostless_SRC_Bargein_DAI",
+ .id = MT8186_DAI_HOSTLESS_SRC_BARGEIN,
+ .playback = {
+ .stream_name = "Hostless_SRC_Bargein_DL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_HOSTLESS_RATES,
+ .formats = MTK_HOSTLESS_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Hostless_SRC_Bargein_UL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_HOSTLESS_RATES,
+ .formats = MTK_HOSTLESS_FORMATS,
+ },
+ .ops = &mtk_dai_hostless_ops,
+ },
+ /* BE dai */
+ {
+ .name = "Hostless_UL1 DAI",
+ .id = MT8186_DAI_HOSTLESS_UL1,
+ .capture = {
+ .stream_name = "Hostless_UL1 UL",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = MTK_HOSTLESS_RATES,
+ .formats = MTK_HOSTLESS_FORMATS,
+ },
+ .ops = &mtk_dai_hostless_ops,
+ },
+ {
+ .name = "Hostless_UL2 DAI",
+ .id = MT8186_DAI_HOSTLESS_UL2,
+ .capture = {
+ .stream_name = "Hostless_UL2 UL",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = MTK_HOSTLESS_RATES,
+ .formats = MTK_HOSTLESS_FORMATS,
+ },
+ .ops = &mtk_dai_hostless_ops,
+ },
+ {
+ .name = "Hostless_UL3 DAI",
+ .id = MT8186_DAI_HOSTLESS_UL3,
+ .capture = {
+ .stream_name = "Hostless_UL3 UL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_HOSTLESS_RATES,
+ .formats = MTK_HOSTLESS_FORMATS,
+ },
+ .ops = &mtk_dai_hostless_ops,
+ },
+ {
+ .name = "Hostless_UL5 DAI",
+ .id = MT8186_DAI_HOSTLESS_UL5,
+ .capture = {
+ .stream_name = "Hostless_UL5 UL",
+ .channels_min = 1,
+ .channels_max = 12,
+ .rates = MTK_HOSTLESS_RATES,
+ .formats = MTK_HOSTLESS_FORMATS,
+ },
+ .ops = &mtk_dai_hostless_ops,
+ },
+ {
+ .name = "Hostless_UL6 DAI",
+ .id = MT8186_DAI_HOSTLESS_UL6,
+ .capture = {
+ .stream_name = "Hostless_UL6 UL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_HOSTLESS_RATES,
+ .formats = MTK_HOSTLESS_FORMATS,
+ },
+ .ops = &mtk_dai_hostless_ops,
+ },
+ {
+ .name = "Hostless HW Gain AAudio DAI",
+ .id = MT8186_DAI_HOSTLESS_HW_GAIN_AAUDIO,
+ .capture = {
+ .stream_name = "Hostless HW Gain AAudio In",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_HOSTLESS_RATES,
+ .formats = MTK_HOSTLESS_FORMATS,
+ },
+ .ops = &mtk_dai_hostless_ops,
+ },
+ {
+ .name = "Hostless SRC AAudio DAI",
+ .id = MT8186_DAI_HOSTLESS_SRC_AAUDIO,
+ .playback = {
+ .stream_name = "Hostless SRC AAudio DL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_HOSTLESS_RATES,
+ .formats = MTK_HOSTLESS_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Hostless SRC AAudio UL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_HOSTLESS_RATES,
+ .formats = MTK_HOSTLESS_FORMATS,
+ },
+ .ops = &mtk_dai_hostless_ops,
+ },
+};
+
+int mt8186_dai_hostless_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mtk_dai_hostless_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_hostless_driver);
+
+ dai->dapm_routes = mtk_dai_hostless_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_hostless_routes);
+
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-hw-gain.c b/sound/soc/mediatek/mt8186/mt8186-dai-hw-gain.c
new file mode 100644
index 0000000..33edd6c
--- /dev/null
+++ b/sound/soc/mediatek/mt8186/mt8186-dai-hw-gain.c
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI HW Gain Control
+//
+// Copyright (c) 2022 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+
+#include <linux/regmap.h>
+#include "mt8186-afe-common.h"
+#include "mt8186-interconnection.h"
+
+#define HW_GAIN_1_EN_W_NAME "HW GAIN 1 Enable"
+#define HW_GAIN_2_EN_W_NAME "HW GAIN 2 Enable"
+
+/* dai component */
+static const struct snd_kcontrol_new mtk_hw_gain1_in_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH1 Switch", AFE_CONN13_1,
+ I_CONNSYS_I2S_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_hw_gain1_in_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH2 Switch", AFE_CONN14_1,
+ I_CONNSYS_I2S_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_hw_gain2_in_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN15,
+ I_ADDA_UL_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_hw_gain2_in_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN16,
+ I_ADDA_UL_CH2, 1, 0),
+};
+
+static int mtk_hw_gain_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ unsigned int gain_cur;
+ unsigned int gain_con1;
+
+ dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n",
+ __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (strcmp(w->name, HW_GAIN_1_EN_W_NAME) == 0) {
+ gain_cur = AFE_GAIN1_CUR;
+ gain_con1 = AFE_GAIN1_CON1;
+ } else {
+ gain_cur = AFE_GAIN2_CUR;
+ gain_con1 = AFE_GAIN2_CON1;
+ }
+
+ /* let hw gain ramp up, set cur gain to 0 */
+ regmap_update_bits(afe->regmap, gain_cur, AFE_GAIN1_CUR_MASK_SFT, 0);
+
+ /* set target gain to 0 */
+ regmap_update_bits(afe->regmap, gain_con1, GAIN1_TARGET_MASK_SFT, 0);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget mtk_dai_hw_gain_widgets[] = {
+ /* inter-connections */
+ SND_SOC_DAPM_MIXER("HW_GAIN1_IN_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_hw_gain1_in_ch1_mix,
+ ARRAY_SIZE(mtk_hw_gain1_in_ch1_mix)),
+ SND_SOC_DAPM_MIXER("HW_GAIN1_IN_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_hw_gain1_in_ch2_mix,
+ ARRAY_SIZE(mtk_hw_gain1_in_ch2_mix)),
+ SND_SOC_DAPM_MIXER("HW_GAIN2_IN_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_hw_gain2_in_ch1_mix,
+ ARRAY_SIZE(mtk_hw_gain2_in_ch1_mix)),
+ SND_SOC_DAPM_MIXER("HW_GAIN2_IN_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_hw_gain2_in_ch2_mix,
+ ARRAY_SIZE(mtk_hw_gain2_in_ch2_mix)),
+
+ SND_SOC_DAPM_SUPPLY(HW_GAIN_1_EN_W_NAME,
+ AFE_GAIN1_CON0, GAIN1_ON_SFT, 0,
+ mtk_hw_gain_event,
+ SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_SUPPLY(HW_GAIN_2_EN_W_NAME,
+ AFE_GAIN2_CON0, GAIN2_ON_SFT, 0,
+ mtk_hw_gain_event,
+ SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_INPUT("HW Gain 1 Out Endpoint"),
+ SND_SOC_DAPM_INPUT("HW Gain 2 Out Endpoint"),
+ SND_SOC_DAPM_OUTPUT("HW Gain 1 In Endpoint"),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_hw_gain_routes[] = {
+ {"HW Gain 1 In", NULL, "HW_GAIN1_IN_CH1"},
+ {"HW Gain 1 In", NULL, "HW_GAIN1_IN_CH2"},
+ {"HW Gain 2 In", NULL, "HW_GAIN2_IN_CH1"},
+ {"HW Gain 2 In", NULL, "HW_GAIN2_IN_CH2"},
+
+ {"HW Gain 1 In", NULL, HW_GAIN_1_EN_W_NAME},
+ {"HW Gain 1 Out", NULL, HW_GAIN_1_EN_W_NAME},
+ {"HW Gain 2 In", NULL, HW_GAIN_2_EN_W_NAME},
+ {"HW Gain 2 Out", NULL, HW_GAIN_2_EN_W_NAME},
+
+ {"HW Gain 1 In Endpoint", NULL, "HW Gain 1 In"},
+ {"HW Gain 1 Out", NULL, "HW Gain 1 Out Endpoint"},
+ {"HW Gain 2 Out", NULL, "HW Gain 2 Out Endpoint"},
+};
+
+static const struct snd_kcontrol_new mtk_hw_gain_controls[] = {
+ SOC_SINGLE("HW Gain 1 Volume", AFE_GAIN1_CON1,
+ GAIN1_TARGET_SFT, GAIN1_TARGET_MASK, 0),
+ SOC_SINGLE("HW Gain 2 Volume", AFE_GAIN2_CON1,
+ GAIN2_TARGET_SFT, GAIN2_TARGET_MASK, 0),
+};
+
+/* dai ops */
+static int mtk_dai_gain_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ unsigned int rate = params_rate(params);
+ unsigned int rate_reg = mt8186_rate_transform(afe->dev, rate, dai->id);
+
+ dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n",
+ __func__, dai->id, substream->stream, rate);
+
+ /* rate */
+ regmap_update_bits(afe->regmap,
+ dai->id == MT8186_DAI_HW_GAIN_1 ?
+ AFE_GAIN1_CON0 : AFE_GAIN2_CON0,
+ GAIN1_MODE_MASK_SFT,
+ rate_reg << GAIN1_MODE_SFT);
+
+ /* sample per step */
+ regmap_update_bits(afe->regmap,
+ dai->id == MT8186_DAI_HW_GAIN_1 ?
+ AFE_GAIN1_CON0 : AFE_GAIN2_CON0,
+ GAIN1_SAMPLE_PER_STEP_MASK_SFT,
+ (dai->id == MT8186_DAI_HW_GAIN_1 ? 0x40 : 0x0) <<
+ GAIN1_SAMPLE_PER_STEP_SFT);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_gain_ops = {
+ .hw_params = mtk_dai_gain_hw_params,
+};
+
+/* dai driver */
+#define MTK_HW_GAIN_RATES (SNDRV_PCM_RATE_8000_48000 |\
+ SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_176400 |\
+ SNDRV_PCM_RATE_192000)
+
+#define MTK_HW_GAIN_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_gain_driver[] = {
+ {
+ .name = "HW Gain 1",
+ .id = MT8186_DAI_HW_GAIN_1,
+ .playback = {
+ .stream_name = "HW Gain 1 In",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_HW_GAIN_RATES,
+ .formats = MTK_HW_GAIN_FORMATS,
+ },
+ .capture = {
+ .stream_name = "HW Gain 1 Out",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_HW_GAIN_RATES,
+ .formats = MTK_HW_GAIN_FORMATS,
+ },
+ .ops = &mtk_dai_gain_ops,
+ .symmetric_rate = 1,
+ .symmetric_channels = 1,
+ .symmetric_sample_bits = 1,
+ },
+ {
+ .name = "HW Gain 2",
+ .id = MT8186_DAI_HW_GAIN_2,
+ .playback = {
+ .stream_name = "HW Gain 2 In",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_HW_GAIN_RATES,
+ .formats = MTK_HW_GAIN_FORMATS,
+ },
+ .capture = {
+ .stream_name = "HW Gain 2 Out",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_HW_GAIN_RATES,
+ .formats = MTK_HW_GAIN_FORMATS,
+ },
+ .ops = &mtk_dai_gain_ops,
+ .symmetric_rate = 1,
+ .symmetric_channels = 1,
+ .symmetric_sample_bits = 1,
+ },
+};
+
+int mt8186_dai_hw_gain_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mtk_dai_gain_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_gain_driver);
+
+ dai->controls = mtk_hw_gain_controls;
+ dai->num_controls = ARRAY_SIZE(mtk_hw_gain_controls);
+ dai->dapm_widgets = mtk_dai_hw_gain_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_hw_gain_widgets);
+ dai->dapm_routes = mtk_dai_hw_gain_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_hw_gain_routes);
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c b/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c
new file mode 100644
index 0000000..5c1290b
--- /dev/null
+++ b/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c
@@ -0,0 +1,1286 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI I2S Control
+//
+// Copyright (c) 2022 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8186-afe-clk.h"
+#include "mt8186-afe-common.h"
+#include "mt8186-afe-gpio.h"
+#include "mt8186-interconnection.h"
+
+enum {
+ I2S_FMT_EIAJ = 0,
+ I2S_FMT_I2S = 1,
+};
+
+enum {
+ I2S_WLEN_16_BIT = 0,
+ I2S_WLEN_32_BIT = 1,
+};
+
+enum {
+ I2S_HD_NORMAL = 0,
+ I2S_HD_LOW_JITTER = 1,
+};
+
+enum {
+ I2S1_SEL_O28_O29 = 0,
+ I2S1_SEL_O03_O04 = 1,
+};
+
+enum {
+ I2S_IN_PAD_CONNSYS = 0,
+ I2S_IN_PAD_IO_MUX = 1,
+};
+
+struct mtk_afe_i2s_priv {
+ int id;
+ int rate; /* for determine which apll to use */
+ int low_jitter_en;
+ int master; /* only i2s0 has slave mode*/
+
+ const char *share_property_name;
+ int share_i2s_id;
+
+ int mclk_id;
+ int mclk_rate;
+ int mclk_apll;
+};
+
+static unsigned int get_i2s_wlen(snd_pcm_format_t format)
+{
+ return snd_pcm_format_physical_width(format) <= 16 ?
+ I2S_WLEN_16_BIT : I2S_WLEN_32_BIT;
+}
+
+#define MTK_AFE_I2S0_KCONTROL_NAME "I2S0_HD_Mux"
+#define MTK_AFE_I2S1_KCONTROL_NAME "I2S1_HD_Mux"
+#define MTK_AFE_I2S2_KCONTROL_NAME "I2S2_HD_Mux"
+#define MTK_AFE_I2S3_KCONTROL_NAME "I2S3_HD_Mux"
+#define MTK_AFE_I2S0_SRC_KCONTROL_NAME "I2S0_SRC_Mux"
+
+#define I2S0_HD_EN_W_NAME "I2S0_HD_EN"
+#define I2S1_HD_EN_W_NAME "I2S1_HD_EN"
+#define I2S2_HD_EN_W_NAME "I2S2_HD_EN"
+#define I2S3_HD_EN_W_NAME "I2S3_HD_EN"
+
+#define I2S0_MCLK_EN_W_NAME "I2S0_MCLK_EN"
+#define I2S1_MCLK_EN_W_NAME "I2S1_MCLK_EN"
+#define I2S2_MCLK_EN_W_NAME "I2S2_MCLK_EN"
+#define I2S3_MCLK_EN_W_NAME "I2S3_MCLK_EN"
+
+static int get_i2s_id_by_name(struct mtk_base_afe *afe,
+ const char *name)
+{
+ if (strncmp(name, "I2S0", 4) == 0)
+ return MT8186_DAI_I2S_0;
+ else if (strncmp(name, "I2S1", 4) == 0)
+ return MT8186_DAI_I2S_1;
+ else if (strncmp(name, "I2S2", 4) == 0)
+ return MT8186_DAI_I2S_2;
+ else if (strncmp(name, "I2S3", 4) == 0)
+ return MT8186_DAI_I2S_3;
+
+ return -EINVAL;
+}
+
+static struct mtk_afe_i2s_priv *get_i2s_priv_by_name(struct mtk_base_afe *afe,
+ const char *name)
+{
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int dai_id = get_i2s_id_by_name(afe, name);
+
+ if (dai_id < 0)
+ return NULL;
+
+ return afe_priv->dai_priv[dai_id];
+}
+
+/* low jitter control */
+static const char * const mt8186_i2s_hd_str[] = {
+ "Normal", "Low_Jitter"
+};
+
+static const struct soc_enum mt8186_i2s_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8186_i2s_hd_str),
+ mt8186_i2s_hd_str),
+};
+
+static int mt8186_i2s_hd_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_i2s_priv *i2s_priv;
+
+ i2s_priv = get_i2s_priv_by_name(afe, kcontrol->id.name);
+
+ if (!i2s_priv) {
+ dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__);
+ return -EINVAL;
+ }
+
+ ucontrol->value.integer.value[0] = i2s_priv->low_jitter_en;
+
+ return 0;
+}
+
+static int mt8186_i2s_hd_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_i2s_priv *i2s_priv;
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ int hd_en;
+
+ if (ucontrol->value.enumerated.item[0] >= e->items)
+ return -EINVAL;
+
+ hd_en = ucontrol->value.integer.value[0];
+
+ dev_dbg(afe->dev, "%s(), kcontrol name %s, hd_en %d\n",
+ __func__, kcontrol->id.name, hd_en);
+
+ i2s_priv = get_i2s_priv_by_name(afe, kcontrol->id.name);
+
+ if (!i2s_priv) {
+ dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__);
+ return -EINVAL;
+ }
+
+ if (i2s_priv->low_jitter_en == hd_en)
+ return 0;
+
+ i2s_priv->low_jitter_en = hd_en;
+
+ return 1;
+}
+
+static const struct snd_kcontrol_new mtk_dai_i2s_controls[] = {
+ SOC_ENUM_EXT(MTK_AFE_I2S0_KCONTROL_NAME, mt8186_i2s_enum[0],
+ mt8186_i2s_hd_get, mt8186_i2s_hd_set),
+ SOC_ENUM_EXT(MTK_AFE_I2S1_KCONTROL_NAME, mt8186_i2s_enum[0],
+ mt8186_i2s_hd_get, mt8186_i2s_hd_set),
+ SOC_ENUM_EXT(MTK_AFE_I2S2_KCONTROL_NAME, mt8186_i2s_enum[0],
+ mt8186_i2s_hd_get, mt8186_i2s_hd_set),
+ SOC_ENUM_EXT(MTK_AFE_I2S3_KCONTROL_NAME, mt8186_i2s_enum[0],
+ mt8186_i2s_hd_get, mt8186_i2s_hd_set),
+};
+
+/* dai component */
+/* i2s virtual mux to output widget */
+static const char * const i2s_mux_map[] = {
+ "Normal", "Dummy_Widget",
+};
+
+static int i2s_mux_map_value[] = {
+ 0, 1,
+};
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(i2s_mux_map_enum,
+ SND_SOC_NOPM,
+ 0,
+ 1,
+ i2s_mux_map,
+ i2s_mux_map_value);
+
+static const struct snd_kcontrol_new i2s0_in_mux_control =
+ SOC_DAPM_ENUM("I2S0 In Select", i2s_mux_map_enum);
+
+static const struct snd_kcontrol_new i2s1_out_mux_control =
+ SOC_DAPM_ENUM("I2S1 Out Select", i2s_mux_map_enum);
+
+static const struct snd_kcontrol_new i2s2_in_mux_control =
+ SOC_DAPM_ENUM("I2S2 In Select", i2s_mux_map_enum);
+
+static const struct snd_kcontrol_new i2s3_out_mux_control =
+ SOC_DAPM_ENUM("I2S3 Out Select", i2s_mux_map_enum);
+
+/* i2s in lpbk */
+static const char * const i2s_lpbk_mux_map[] = {
+ "Normal", "Lpbk",
+};
+
+static int i2s_lpbk_mux_map_value[] = {
+ 0, 1,
+};
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(i2s0_lpbk_mux_map_enum,
+ AFE_I2S_CON,
+ I2S_LOOPBACK_SFT,
+ 1,
+ i2s_lpbk_mux_map,
+ i2s_lpbk_mux_map_value);
+
+static const struct snd_kcontrol_new i2s0_lpbk_mux_control =
+ SOC_DAPM_ENUM("I2S Lpbk Select", i2s0_lpbk_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(i2s2_lpbk_mux_map_enum,
+ AFE_I2S_CON2,
+ I2S3_LOOPBACK_SFT,
+ 1,
+ i2s_lpbk_mux_map,
+ i2s_lpbk_mux_map_value);
+
+static const struct snd_kcontrol_new i2s2_lpbk_mux_control =
+ SOC_DAPM_ENUM("I2S Lpbk Select", i2s2_lpbk_mux_map_enum);
+
+/* interconnection */
+static const struct snd_kcontrol_new mtk_i2s3_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN0,
+ I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN0,
+ I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN0,
+ I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1 Switch", AFE_CONN0,
+ I_DL12_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH3 Switch", AFE_CONN0,
+ I_DL12_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1 Switch", AFE_CONN0_1,
+ I_DL6_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN0_1,
+ I_DL4_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN0_1,
+ I_DL5_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1 Switch", AFE_CONN0_1,
+ I_DL8_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1 Switch", AFE_CONN0,
+ I_GAIN1_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3 Switch", AFE_CONN0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1 Switch", AFE_CONN0,
+ I_PCM_1_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH1 Switch", AFE_CONN0_1,
+ I_SRC_1_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2s3_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN1,
+ I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN1,
+ I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN1,
+ I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN1,
+ I_DL12_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH4 Switch", AFE_CONN1,
+ I_DL12_CH4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2 Switch", AFE_CONN1_1,
+ I_DL6_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN1_1,
+ I_DL4_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN1_1,
+ I_DL5_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2 Switch", AFE_CONN1_1,
+ I_DL8_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2 Switch", AFE_CONN1,
+ I_GAIN1_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN1,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN1,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3 Switch", AFE_CONN1,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2 Switch", AFE_CONN1,
+ I_PCM_1_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2 Switch", AFE_CONN1,
+ I_PCM_2_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH2 Switch", AFE_CONN1_1,
+ I_SRC_1_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2s1_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN28,
+ I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN28,
+ I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN28,
+ I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1 Switch", AFE_CONN28,
+ I_DL12_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH3 Switch", AFE_CONN28,
+ I_DL12_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1 Switch", AFE_CONN28_1,
+ I_DL6_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN28_1,
+ I_DL4_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN28_1,
+ I_DL5_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1 Switch", AFE_CONN28_1,
+ I_DL8_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1 Switch", AFE_CONN28,
+ I_GAIN1_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN28,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1 Switch", AFE_CONN28,
+ I_PCM_1_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH1 Switch", AFE_CONN28_1,
+ I_SRC_1_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2s1_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN29,
+ I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN29,
+ I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN29,
+ I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN29,
+ I_DL12_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH4 Switch", AFE_CONN29,
+ I_DL12_CH4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2 Switch", AFE_CONN29_1,
+ I_DL6_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN29_1,
+ I_DL4_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN29_1,
+ I_DL5_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2 Switch", AFE_CONN29_1,
+ I_DL8_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2 Switch", AFE_CONN29,
+ I_GAIN1_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN29,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2 Switch", AFE_CONN29,
+ I_PCM_1_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2 Switch", AFE_CONN29,
+ I_PCM_2_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH2 Switch", AFE_CONN29_1,
+ I_SRC_1_OUT_CH2, 1, 0),
+};
+
+enum {
+ SUPPLY_SEQ_APLL,
+ SUPPLY_SEQ_I2S_MCLK_EN,
+ SUPPLY_SEQ_I2S_HD_EN,
+ SUPPLY_SEQ_I2S_EN,
+};
+
+static int mtk_i2s_en_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_i2s_priv *i2s_priv;
+
+ i2s_priv = get_i2s_priv_by_name(afe, w->name);
+
+ if (!i2s_priv) {
+ dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__);
+ return -EINVAL;
+ }
+
+ dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n",
+ __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8186_afe_gpio_request(afe->dev, true, i2s_priv->id, 0);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ mt8186_afe_gpio_request(afe->dev, false, i2s_priv->id, 0);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_apll_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+ dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n",
+ __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (strcmp(w->name, APLL1_W_NAME) == 0)
+ mt8186_apll1_enable(afe);
+ else
+ mt8186_apll2_enable(afe);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (strcmp(w->name, APLL1_W_NAME) == 0)
+ mt8186_apll1_disable(afe);
+ else
+ mt8186_apll2_disable(afe);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_mclk_en_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_i2s_priv *i2s_priv;
+
+ dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n",
+ __func__, w->name, event);
+
+ i2s_priv = get_i2s_priv_by_name(afe, w->name);
+
+ if (!i2s_priv) {
+ dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8186_mck_enable(afe, i2s_priv->mclk_id, i2s_priv->mclk_rate);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ i2s_priv->mclk_rate = 0;
+ mt8186_mck_disable(afe, i2s_priv->mclk_id);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget mtk_dai_i2s_widgets[] = {
+ SND_SOC_DAPM_INPUT("CONNSYS"),
+
+ SND_SOC_DAPM_MIXER("I2S1_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_i2s1_ch1_mix,
+ ARRAY_SIZE(mtk_i2s1_ch1_mix)),
+ SND_SOC_DAPM_MIXER("I2S1_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_i2s1_ch2_mix,
+ ARRAY_SIZE(mtk_i2s1_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("I2S3_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_i2s3_ch1_mix,
+ ARRAY_SIZE(mtk_i2s3_ch1_mix)),
+ SND_SOC_DAPM_MIXER("I2S3_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_i2s3_ch2_mix,
+ ARRAY_SIZE(mtk_i2s3_ch2_mix)),
+
+ /* i2s en*/
+ SND_SOC_DAPM_SUPPLY_S("I2S0_EN", SUPPLY_SEQ_I2S_EN,
+ AFE_I2S_CON, I2S_EN_SFT, 0,
+ mtk_i2s_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S("I2S1_EN", SUPPLY_SEQ_I2S_EN,
+ AFE_I2S_CON1, I2S_EN_SFT, 0,
+ mtk_i2s_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S("I2S2_EN", SUPPLY_SEQ_I2S_EN,
+ AFE_I2S_CON2, I2S_EN_SFT, 0,
+ mtk_i2s_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S("I2S3_EN", SUPPLY_SEQ_I2S_EN,
+ AFE_I2S_CON3, I2S_EN_SFT, 0,
+ mtk_i2s_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ /* i2s hd en */
+ SND_SOC_DAPM_SUPPLY_S(I2S0_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+ AFE_I2S_CON, I2S1_HD_EN_SFT, 0, NULL,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(I2S1_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+ AFE_I2S_CON1, I2S2_HD_EN_SFT, 0, NULL,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(I2S2_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+ AFE_I2S_CON2, I2S3_HD_EN_SFT, 0, NULL,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(I2S3_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+ AFE_I2S_CON3, I2S4_HD_EN_SFT, 0, NULL,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* i2s mclk en */
+ SND_SOC_DAPM_SUPPLY_S(I2S0_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_mclk_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(I2S1_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_mclk_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(I2S2_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_mclk_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(I2S3_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_mclk_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* apll */
+ SND_SOC_DAPM_SUPPLY_S(APLL1_W_NAME, SUPPLY_SEQ_APLL,
+ SND_SOC_NOPM, 0, 0,
+ mtk_apll_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(APLL2_W_NAME, SUPPLY_SEQ_APLL,
+ SND_SOC_NOPM, 0, 0,
+ mtk_apll_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* allow i2s on without codec on */
+ SND_SOC_DAPM_OUTPUT("I2S_DUMMY_OUT"),
+ SND_SOC_DAPM_MUX("I2S1_Out_Mux",
+ SND_SOC_NOPM, 0, 0, &i2s1_out_mux_control),
+ SND_SOC_DAPM_MUX("I2S3_Out_Mux",
+ SND_SOC_NOPM, 0, 0, &i2s3_out_mux_control),
+ SND_SOC_DAPM_INPUT("I2S_DUMMY_IN"),
+ SND_SOC_DAPM_MUX("I2S0_In_Mux",
+ SND_SOC_NOPM, 0, 0, &i2s0_in_mux_control),
+ SND_SOC_DAPM_MUX("I2S2_In_Mux",
+ SND_SOC_NOPM, 0, 0, &i2s2_in_mux_control),
+
+ /* i2s in lpbk */
+ SND_SOC_DAPM_MUX("I2S0_Lpbk_Mux",
+ SND_SOC_NOPM, 0, 0, &i2s0_lpbk_mux_control),
+ SND_SOC_DAPM_MUX("I2S2_Lpbk_Mux",
+ SND_SOC_NOPM, 0, 0, &i2s2_lpbk_mux_control),
+};
+
+static int mtk_afe_i2s_share_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_dapm_widget *w = sink;
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_i2s_priv *i2s_priv;
+
+ i2s_priv = get_i2s_priv_by_name(afe, sink->name);
+
+ if (!i2s_priv) {
+ dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__);
+ return 0;
+ }
+
+ if (i2s_priv->share_i2s_id < 0)
+ return 0;
+
+ return i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name);
+}
+
+static int mtk_afe_i2s_hd_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_dapm_widget *w = sink;
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_i2s_priv *i2s_priv;
+
+ i2s_priv = get_i2s_priv_by_name(afe, sink->name);
+
+ if (!i2s_priv) {
+ dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__);
+ return 0;
+ }
+
+ if (get_i2s_id_by_name(afe, sink->name) ==
+ get_i2s_id_by_name(afe, source->name))
+ return i2s_priv->low_jitter_en;
+
+ /* check if share i2s need hd en */
+ if (i2s_priv->share_i2s_id < 0)
+ return 0;
+
+ if (i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name))
+ return i2s_priv->low_jitter_en;
+
+ return 0;
+}
+
+static int mtk_afe_i2s_apll_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_dapm_widget *w = sink;
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_i2s_priv *i2s_priv;
+ int cur_apll;
+ int i2s_need_apll;
+
+ i2s_priv = get_i2s_priv_by_name(afe, w->name);
+
+ if (!i2s_priv) {
+ dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__);
+ return 0;
+ }
+
+ /* which apll */
+ cur_apll = mt8186_get_apll_by_name(afe, source->name);
+
+ /* choose APLL from i2s rate */
+ i2s_need_apll = mt8186_get_apll_by_rate(afe, i2s_priv->rate);
+
+ return (i2s_need_apll == cur_apll) ? 1 : 0;
+}
+
+static int mtk_afe_i2s_mclk_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_dapm_widget *w = sink;
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_i2s_priv *i2s_priv;
+
+ i2s_priv = get_i2s_priv_by_name(afe, sink->name);
+
+ if (!i2s_priv) {
+ dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__);
+ return 0;
+ }
+
+ if (get_i2s_id_by_name(afe, sink->name) ==
+ get_i2s_id_by_name(afe, source->name))
+ return (i2s_priv->mclk_rate > 0) ? 1 : 0;
+
+ /* check if share i2s need mclk */
+ if (i2s_priv->share_i2s_id < 0)
+ return 0;
+
+ if (i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name))
+ return (i2s_priv->mclk_rate > 0) ? 1 : 0;
+
+ return 0;
+}
+
+static int mtk_afe_mclk_apll_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_dapm_widget *w = sink;
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_i2s_priv *i2s_priv;
+ int cur_apll;
+
+ i2s_priv = get_i2s_priv_by_name(afe, w->name);
+
+ if (!i2s_priv) {
+ dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__);
+ return 0;
+ }
+
+ /* which apll */
+ cur_apll = mt8186_get_apll_by_name(afe, source->name);
+
+ return (i2s_priv->mclk_apll == cur_apll) ? 1 : 0;
+}
+
+static const struct snd_soc_dapm_route mtk_dai_i2s_routes[] = {
+ {"Connsys I2S", NULL, "CONNSYS"},
+
+ /* i2s0 */
+ {"I2S0", NULL, "I2S0_EN"},
+ {"I2S0", NULL, "I2S1_EN", mtk_afe_i2s_share_connect},
+ {"I2S0", NULL, "I2S2_EN", mtk_afe_i2s_share_connect},
+ {"I2S0", NULL, "I2S3_EN", mtk_afe_i2s_share_connect},
+
+ {"I2S0", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S0", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S0", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S0", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {I2S0_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+ {I2S0_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+ {"I2S0", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S0", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S0", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S0", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {I2S0_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+ {I2S0_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+
+ /* i2s1 */
+ {"I2S1_CH1", "DL1_CH1 Switch", "DL1"},
+ {"I2S1_CH2", "DL1_CH2 Switch", "DL1"},
+
+ {"I2S1_CH1", "DL2_CH1 Switch", "DL2"},
+ {"I2S1_CH2", "DL2_CH2 Switch", "DL2"},
+
+ {"I2S1_CH1", "DL3_CH1 Switch", "DL3"},
+ {"I2S1_CH2", "DL3_CH2 Switch", "DL3"},
+
+ {"I2S1_CH1", "DL12_CH1 Switch", "DL12"},
+ {"I2S1_CH2", "DL12_CH2 Switch", "DL12"},
+
+ {"I2S1_CH1", "DL12_CH3 Switch", "DL12"},
+ {"I2S1_CH2", "DL12_CH4 Switch", "DL12"},
+
+ {"I2S1_CH1", "DL6_CH1 Switch", "DL6"},
+ {"I2S1_CH2", "DL6_CH2 Switch", "DL6"},
+
+ {"I2S1_CH1", "DL4_CH1 Switch", "DL4"},
+ {"I2S1_CH2", "DL4_CH2 Switch", "DL4"},
+
+ {"I2S1_CH1", "DL5_CH1 Switch", "DL5"},
+ {"I2S1_CH2", "DL5_CH2 Switch", "DL5"},
+
+ {"I2S1_CH1", "DL8_CH1 Switch", "DL8"},
+ {"I2S1_CH2", "DL8_CH2 Switch", "DL8"},
+
+ {"I2S1", NULL, "I2S1_CH1"},
+ {"I2S1", NULL, "I2S1_CH2"},
+
+ {"I2S1", NULL, "I2S0_EN", mtk_afe_i2s_share_connect},
+ {"I2S1", NULL, "I2S1_EN"},
+ {"I2S1", NULL, "I2S2_EN", mtk_afe_i2s_share_connect},
+ {"I2S1", NULL, "I2S3_EN", mtk_afe_i2s_share_connect},
+
+ {"I2S1", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S1", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S1", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S1", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {I2S1_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+ {I2S1_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+ {"I2S1", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S1", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S1", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S1", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {I2S1_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+ {I2S1_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+
+ /* i2s2 */
+ {"I2S2", NULL, "I2S0_EN", mtk_afe_i2s_share_connect},
+ {"I2S2", NULL, "I2S1_EN", mtk_afe_i2s_share_connect},
+ {"I2S2", NULL, "I2S2_EN"},
+ {"I2S2", NULL, "I2S3_EN", mtk_afe_i2s_share_connect},
+
+ {"I2S2", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S2", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S2", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S2", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {I2S2_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+ {I2S2_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+ {"I2S2", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S2", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S2", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S2", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {I2S2_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+ {I2S2_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+
+ /* i2s3 */
+ {"I2S3_CH1", "DL1_CH1 Switch", "DL1"},
+ {"I2S3_CH2", "DL1_CH2 Switch", "DL1"},
+
+ {"I2S3_CH1", "DL2_CH1 Switch", "DL2"},
+ {"I2S3_CH2", "DL2_CH2 Switch", "DL2"},
+
+ {"I2S3_CH1", "DL3_CH1 Switch", "DL3"},
+ {"I2S3_CH2", "DL3_CH2 Switch", "DL3"},
+
+ {"I2S3_CH1", "DL12_CH1 Switch", "DL12"},
+ {"I2S3_CH2", "DL12_CH2 Switch", "DL12"},
+
+ {"I2S3_CH1", "DL12_CH3 Switch", "DL12"},
+ {"I2S3_CH2", "DL12_CH4 Switch", "DL12"},
+
+ {"I2S3_CH1", "DL6_CH1 Switch", "DL6"},
+ {"I2S3_CH2", "DL6_CH2 Switch", "DL6"},
+
+ {"I2S3_CH1", "DL4_CH1 Switch", "DL4"},
+ {"I2S3_CH2", "DL4_CH2 Switch", "DL4"},
+
+ {"I2S3_CH1", "DL5_CH1 Switch", "DL5"},
+ {"I2S3_CH2", "DL5_CH2 Switch", "DL5"},
+
+ {"I2S3_CH1", "DL8_CH1 Switch", "DL8"},
+ {"I2S3_CH2", "DL8_CH2 Switch", "DL8"},
+
+ {"I2S3", NULL, "I2S3_CH1"},
+ {"I2S3", NULL, "I2S3_CH2"},
+
+ {"I2S3", NULL, "I2S0_EN", mtk_afe_i2s_share_connect},
+ {"I2S3", NULL, "I2S1_EN", mtk_afe_i2s_share_connect},
+ {"I2S3", NULL, "I2S2_EN", mtk_afe_i2s_share_connect},
+ {"I2S3", NULL, "I2S3_EN"},
+
+ {"I2S3", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S3", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S3", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {"I2S3", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+ {I2S3_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+ {I2S3_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+ {"I2S3", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S3", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S3", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2S3", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {I2S3_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+ {I2S3_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+
+ /* allow i2s on without codec on */
+ {"I2S0", NULL, "I2S0_In_Mux"},
+ {"I2S0_In_Mux", "Dummy_Widget", "I2S_DUMMY_IN"},
+
+ {"I2S1_Out_Mux", "Dummy_Widget", "I2S1"},
+ {"I2S_DUMMY_OUT", NULL, "I2S1_Out_Mux"},
+
+ {"I2S2", NULL, "I2S2_In_Mux"},
+ {"I2S2_In_Mux", "Dummy_Widget", "I2S_DUMMY_IN"},
+
+ {"I2S3_Out_Mux", "Dummy_Widget", "I2S3"},
+ {"I2S_DUMMY_OUT", NULL, "I2S3_Out_Mux"},
+
+ /* i2s in lpbk */
+ {"I2S0_Lpbk_Mux", "Lpbk", "I2S3"},
+ {"I2S2_Lpbk_Mux", "Lpbk", "I2S1"},
+ {"I2S0", NULL, "I2S0_Lpbk_Mux"},
+ {"I2S2", NULL, "I2S2_Lpbk_Mux"},
+};
+
+/* dai ops */
+static int mtk_dai_connsys_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ unsigned int rate = params_rate(params);
+ unsigned int rate_reg = mt8186_rate_transform(afe->dev,
+ rate, dai->id);
+ unsigned int i2s_con = 0;
+
+ dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n",
+ __func__, dai->id, substream->stream, rate);
+
+ /* non-inverse, i2s mode, slave, 16bits, from connsys */
+ i2s_con |= 0 << INV_PAD_CTRL_SFT;
+ i2s_con |= I2S_FMT_I2S << I2S_FMT_SFT;
+ i2s_con |= 1 << I2S_SRC_SFT;
+ i2s_con |= get_i2s_wlen(SNDRV_PCM_FORMAT_S16_LE) << I2S_WLEN_SFT;
+ i2s_con |= 0 << I2SIN_PAD_SEL_SFT;
+ regmap_write(afe->regmap, AFE_CONNSYS_I2S_CON, i2s_con);
+
+ /* use asrc */
+ regmap_update_bits(afe->regmap, AFE_CONNSYS_I2S_CON,
+ I2S_BYPSRC_MASK_SFT, 0);
+
+ /* slave mode, set i2s for asrc */
+ regmap_update_bits(afe->regmap, AFE_CONNSYS_I2S_CON,
+ I2S_MODE_MASK_SFT, rate_reg << I2S_MODE_SFT);
+
+ if (rate == 44100)
+ regmap_write(afe->regmap, AFE_ASRC_2CH_CON3, 0x1b9000);
+ else if (rate == 32000)
+ regmap_write(afe->regmap, AFE_ASRC_2CH_CON3, 0x140000);
+ else
+ regmap_write(afe->regmap, AFE_ASRC_2CH_CON3, 0x1e0000);
+
+ /* Calibration setting */
+ regmap_write(afe->regmap, AFE_ASRC_2CH_CON4, 0x140000);
+ regmap_write(afe->regmap, AFE_ASRC_2CH_CON9, 0x36000);
+ regmap_write(afe->regmap, AFE_ASRC_2CH_CON10, 0x2fc00);
+ regmap_write(afe->regmap, AFE_ASRC_2CH_CON6, 0x7ef4);
+ regmap_write(afe->regmap, AFE_ASRC_2CH_CON5, 0xff5986);
+
+ /* 0:Stereo 1:Mono */
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON2,
+ CHSET_IS_MONO_MASK_SFT, 0);
+
+ return 0;
+}
+
+static int mtk_dai_connsys_i2s_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+
+ dev_dbg(afe->dev, "%s(), cmd %d, stream %d\n",
+ __func__, cmd, substream->stream);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ /* i2s enable */
+ regmap_update_bits(afe->regmap,
+ AFE_CONNSYS_I2S_CON,
+ I2S_EN_MASK_SFT,
+ BIT(I2S_EN_SFT));
+
+ /* calibrator enable */
+ regmap_update_bits(afe->regmap,
+ AFE_ASRC_2CH_CON5,
+ CALI_EN_MASK_SFT,
+ BIT(CALI_EN_SFT));
+
+ /* asrc enable */
+ regmap_update_bits(afe->regmap,
+ AFE_ASRC_2CH_CON0,
+ CON0_CHSET_STR_CLR_MASK_SFT,
+ BIT(CON0_CHSET_STR_CLR_SFT));
+ regmap_update_bits(afe->regmap,
+ AFE_ASRC_2CH_CON0,
+ CON0_ASM_ON_MASK_SFT,
+ BIT(CON0_ASM_ON_SFT));
+
+ afe_priv->dai_on[dai->id] = true;
+ return 0;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON0,
+ CON0_ASM_ON_MASK_SFT, 0);
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON5,
+ CALI_EN_MASK_SFT, 0);
+
+ /* i2s disable */
+ regmap_update_bits(afe->regmap, AFE_CONNSYS_I2S_CON,
+ I2S_EN_MASK_SFT, 0);
+
+ /* bypass asrc */
+ regmap_update_bits(afe->regmap, AFE_CONNSYS_I2S_CON,
+ I2S_BYPSRC_MASK_SFT, BIT(I2S_BYPSRC_SFT));
+
+ afe_priv->dai_on[dai->id] = false;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_connsys_i2s_ops = {
+ .hw_params = mtk_dai_connsys_i2s_hw_params,
+ .trigger = mtk_dai_connsys_i2s_trigger,
+};
+
+/* i2s */
+static int mtk_dai_i2s_config(struct mtk_base_afe *afe,
+ struct snd_pcm_hw_params *params,
+ int i2s_id)
+{
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_i2s_priv *i2s_priv = afe_priv->dai_priv[i2s_id];
+
+ unsigned int rate = params_rate(params);
+ unsigned int rate_reg = mt8186_rate_transform(afe->dev,
+ rate, i2s_id);
+ snd_pcm_format_t format = params_format(params);
+ unsigned int i2s_con = 0;
+ int ret;
+
+ dev_dbg(afe->dev, "%s(), id %d, rate %d, format %d\n",
+ __func__, i2s_id, rate, format);
+
+ if (!i2s_priv) {
+ dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__);
+ return -EINVAL;
+ }
+
+ i2s_priv->rate = rate;
+
+ switch (i2s_id) {
+ case MT8186_DAI_I2S_0:
+ i2s_con = I2S_IN_PAD_IO_MUX << I2SIN_PAD_SEL_SFT;
+ i2s_con |= rate_reg << I2S_OUT_MODE_SFT;
+ i2s_con |= I2S_FMT_I2S << I2S_FMT_SFT;
+ i2s_con |= get_i2s_wlen(format) << I2S_WLEN_SFT;
+ regmap_update_bits(afe->regmap, AFE_I2S_CON,
+ 0xffffeffa, i2s_con);
+ break;
+ case MT8186_DAI_I2S_1:
+ i2s_con = I2S1_SEL_O28_O29 << I2S2_SEL_O03_O04_SFT;
+ i2s_con |= rate_reg << I2S2_OUT_MODE_SFT;
+ i2s_con |= I2S_FMT_I2S << I2S2_FMT_SFT;
+ i2s_con |= get_i2s_wlen(format) << I2S2_WLEN_SFT;
+ regmap_update_bits(afe->regmap, AFE_I2S_CON1,
+ 0xffffeffa, i2s_con);
+ break;
+ case MT8186_DAI_I2S_2:
+ i2s_con = 8 << I2S3_UPDATE_WORD_SFT;
+ i2s_con |= rate_reg << I2S3_OUT_MODE_SFT;
+ i2s_con |= I2S_FMT_I2S << I2S3_FMT_SFT;
+ i2s_con |= get_i2s_wlen(format) << I2S3_WLEN_SFT;
+ regmap_update_bits(afe->regmap, AFE_I2S_CON2,
+ 0xffffeffa, i2s_con);
+ break;
+ case MT8186_DAI_I2S_3:
+ i2s_con = rate_reg << I2S4_OUT_MODE_SFT;
+ i2s_con |= I2S_FMT_I2S << I2S4_FMT_SFT;
+ i2s_con |= get_i2s_wlen(format) << I2S4_WLEN_SFT;
+ regmap_update_bits(afe->regmap, AFE_I2S_CON3,
+ 0xffffeffa, i2s_con);
+ break;
+ default:
+ dev_err(afe->dev, "%s(), id %d not support\n",
+ __func__, i2s_id);
+ return -EINVAL;
+ }
+
+ /* set share i2s */
+ if (i2s_priv && i2s_priv->share_i2s_id >= 0) {
+ ret = mtk_dai_i2s_config(afe, params, i2s_priv->share_i2s_id);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mtk_dai_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+ return mtk_dai_i2s_config(afe, params, dai->id);
+}
+
+static int mtk_dai_i2s_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_i2s_priv *i2s_priv = afe_priv->dai_priv[dai->id];
+ int apll;
+ int apll_rate;
+
+ if (!i2s_priv) {
+ dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__);
+ return -EINVAL;
+ }
+
+ if (dir != SND_SOC_CLOCK_OUT) {
+ dev_err(afe->dev, "%s(), dir != SND_SOC_CLOCK_OUT", __func__);
+ return -EINVAL;
+ }
+
+ dev_dbg(afe->dev, "%s(), freq %d\n", __func__, freq);
+
+ apll = mt8186_get_apll_by_rate(afe, freq);
+ apll_rate = mt8186_get_apll_rate(afe, apll);
+
+ if (freq > apll_rate) {
+ dev_err(afe->dev, "%s(), freq > apll rate", __func__);
+ return -EINVAL;
+ }
+
+ if (apll_rate % freq != 0) {
+ dev_err(afe->dev, "%s(), APLL cannot generate freq Hz", __func__);
+ return -EINVAL;
+ }
+
+ i2s_priv->mclk_rate = freq;
+ i2s_priv->mclk_apll = apll;
+
+ if (i2s_priv->share_i2s_id > 0) {
+ struct mtk_afe_i2s_priv *share_i2s_priv;
+
+ share_i2s_priv = afe_priv->dai_priv[i2s_priv->share_i2s_id];
+ if (!share_i2s_priv) {
+ dev_err(afe->dev, "%s(), share_i2s_priv == NULL", __func__);
+ return -EINVAL;
+ }
+
+ share_i2s_priv->mclk_rate = i2s_priv->mclk_rate;
+ share_i2s_priv->mclk_apll = i2s_priv->mclk_apll;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_i2s_ops = {
+ .hw_params = mtk_dai_i2s_hw_params,
+ .set_sysclk = mtk_dai_i2s_set_sysclk,
+};
+
+/* dai driver */
+#define MTK_CONNSYS_I2S_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+#define MTK_I2S_RATES (SNDRV_PCM_RATE_8000_48000 |\
+ SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_176400 |\
+ SNDRV_PCM_RATE_192000)
+
+#define MTK_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_i2s_driver[] = {
+ {
+ .name = "CONNSYS_I2S",
+ .id = MT8186_DAI_CONNSYS_I2S,
+ .capture = {
+ .stream_name = "Connsys I2S",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_CONNSYS_I2S_RATES,
+ .formats = MTK_I2S_FORMATS,
+ },
+ .ops = &mtk_dai_connsys_i2s_ops,
+ },
+ {
+ .name = "I2S0",
+ .id = MT8186_DAI_I2S_0,
+ .capture = {
+ .stream_name = "I2S0",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_I2S_RATES,
+ .formats = MTK_I2S_FORMATS,
+ },
+ .ops = &mtk_dai_i2s_ops,
+ },
+ {
+ .name = "I2S1",
+ .id = MT8186_DAI_I2S_1,
+ .playback = {
+ .stream_name = "I2S1",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_I2S_RATES,
+ .formats = MTK_I2S_FORMATS,
+ },
+ .ops = &mtk_dai_i2s_ops,
+ },
+ {
+ .name = "I2S2",
+ .id = MT8186_DAI_I2S_2,
+ .capture = {
+ .stream_name = "I2S2",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_I2S_RATES,
+ .formats = MTK_I2S_FORMATS,
+ },
+ .ops = &mtk_dai_i2s_ops,
+ },
+ {
+ .name = "I2S3",
+ .id = MT8186_DAI_I2S_3,
+ .playback = {
+ .stream_name = "I2S3",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_I2S_RATES,
+ .formats = MTK_I2S_FORMATS,
+ },
+ .ops = &mtk_dai_i2s_ops,
+ }
+};
+
+/* this enum is merely for mtk_afe_i2s_priv declare */
+enum {
+ DAI_I2S0 = 0,
+ DAI_I2S1,
+ DAI_I2S2,
+ DAI_I2S3,
+ DAI_I2S_NUM,
+};
+
+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;
+}
+
+static int mt8186_dai_i2s_set_priv(struct mtk_base_afe *afe)
+{
+ int i;
+ int ret;
+
+ for (i = 0; i < DAI_I2S_NUM; i++) {
+ ret = mt8186_dai_set_priv(afe, mt8186_i2s_priv[i].id,
+ sizeof(struct mtk_afe_i2s_priv),
+ &mt8186_i2s_priv[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int mt8186_dai_i2s_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+ int ret;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mtk_dai_i2s_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_i2s_driver);
+
+ dai->controls = mtk_dai_i2s_controls;
+ dai->num_controls = ARRAY_SIZE(mtk_dai_i2s_controls);
+ dai->dapm_widgets = mtk_dai_i2s_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_i2s_widgets);
+ dai->dapm_routes = mtk_dai_i2s_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_i2s_routes);
+
+ /* set all dai i2s private data */
+ ret = mt8186_dai_i2s_set_priv(afe);
+ if (ret)
+ return ret;
+
+ /* parse share i2s */
+ ret = mt8186_dai_i2s_get_share(afe);
+ if (ret)
+ return ret;
+
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-pcm.c b/sound/soc/mediatek/mt8186/mt8186-dai-pcm.c
new file mode 100644
index 0000000..0b0032e
--- /dev/null
+++ b/sound/soc/mediatek/mt8186/mt8186-dai-pcm.c
@@ -0,0 +1,423 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI I2S Control
+//
+// Copyright (c) 2022 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8186-afe-common.h"
+#include "mt8186-afe-gpio.h"
+#include "mt8186-interconnection.h"
+
+struct mtk_afe_pcm_priv {
+ unsigned int id;
+ unsigned int fmt;
+ unsigned int bck_invert;
+ unsigned int lck_invert;
+};
+
+enum aud_tx_lch_rpt {
+ AUD_TX_LCH_RPT_NO_REPEAT = 0,
+ AUD_TX_LCH_RPT_REPEAT = 1
+};
+
+enum aud_vbt_16k_mode {
+ AUD_VBT_16K_MODE_DISABLE = 0,
+ AUD_VBT_16K_MODE_ENABLE = 1
+};
+
+enum aud_ext_modem {
+ AUD_EXT_MODEM_SELECT_INTERNAL = 0,
+ AUD_EXT_MODEM_SELECT_EXTERNAL = 1
+};
+
+enum aud_pcm_sync_type {
+ /* bck sync length = 1 */
+ AUD_PCM_ONE_BCK_CYCLE_SYNC = 0,
+ /* bck sync length = PCM_INTF_CON1[9:13] */
+ AUD_PCM_EXTENDED_BCK_CYCLE_SYNC = 1
+};
+
+enum aud_bt_mode {
+ AUD_BT_MODE_DUAL_MIC_ON_TX = 0,
+ AUD_BT_MODE_SINGLE_MIC_ON_TX = 1
+};
+
+enum aud_pcm_afifo_src {
+ /* slave mode & external modem uses different crystal */
+ AUD_PCM_AFIFO_ASRC = 0,
+ /* slave mode & external modem uses the same crystal */
+ AUD_PCM_AFIFO_AFIFO = 1
+};
+
+enum aud_pcm_clock_source {
+ AUD_PCM_CLOCK_MASTER_MODE = 0,
+ AUD_PCM_CLOCK_SLAVE_MODE = 1
+};
+
+enum aud_pcm_wlen {
+ AUD_PCM_WLEN_PCM_32_BCK_CYCLES = 0,
+ AUD_PCM_WLEN_PCM_64_BCK_CYCLES = 1
+};
+
+enum aud_pcm_24bit {
+ AUD_PCM_24BIT_PCM_16_BITS = 0,
+ AUD_PCM_24BIT_PCM_24_BITS = 1
+};
+
+enum aud_pcm_mode {
+ AUD_PCM_MODE_PCM_MODE_8K = 0,
+ AUD_PCM_MODE_PCM_MODE_16K = 1,
+ AUD_PCM_MODE_PCM_MODE_32K = 2,
+ AUD_PCM_MODE_PCM_MODE_48K = 3,
+};
+
+enum aud_pcm_fmt {
+ AUD_PCM_FMT_I2S = 0,
+ AUD_PCM_FMT_EIAJ = 1,
+ AUD_PCM_FMT_PCM_MODE_A = 2,
+ AUD_PCM_FMT_PCM_MODE_B = 3
+};
+
+enum aud_bclk_out_inv {
+ AUD_BCLK_OUT_INV_NO_INVERSE = 0,
+ AUD_BCLK_OUT_INV_INVERSE = 1
+};
+
+enum aud_lrclk_out_inv {
+ AUD_LRCLK_OUT_INV_NO_INVERSE = 0,
+ AUD_LRCLK_OUT_INV_INVERSE = 1
+};
+
+enum aud_pcm_en {
+ AUD_PCM_EN_DISABLE = 0,
+ AUD_PCM_EN_ENABLE = 1
+};
+
+/* dai component */
+static const struct snd_kcontrol_new mtk_pcm_1_playback_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN7,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN7,
+ I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN7_1,
+ I_DL4_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_1_playback_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN8,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN8,
+ I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN8_1,
+ I_DL4_CH2, 1, 0),
+};
+
+static int mtk_pcm_en_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+ dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n",
+ __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8186_afe_gpio_request(afe->dev, true, MT8186_DAI_PCM, 0);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ mt8186_afe_gpio_request(afe->dev, false, MT8186_DAI_PCM, 0);
+ break;
+ }
+
+ return 0;
+}
+
+/* pcm in/out lpbk */
+static const char * const pcm_lpbk_mux_map[] = {
+ "Normal", "Lpbk",
+};
+
+static int pcm_lpbk_mux_map_value[] = {
+ 0, 1,
+};
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(pcm_in_lpbk_mux_map_enum,
+ PCM_INTF_CON1,
+ PCM_I2S_PCM_LOOPBACK_SFT,
+ 1,
+ pcm_lpbk_mux_map,
+ pcm_lpbk_mux_map_value);
+
+static const struct snd_kcontrol_new pcm_in_lpbk_mux_control =
+ SOC_DAPM_ENUM("PCM In Lpbk Select", pcm_in_lpbk_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(pcm_out_lpbk_mux_map_enum,
+ PCM_INTF_CON1,
+ PCM_I2S_PCM_LOOPBACK_SFT,
+ 1,
+ pcm_lpbk_mux_map,
+ pcm_lpbk_mux_map_value);
+
+static const struct snd_kcontrol_new pcm_out_lpbk_mux_control =
+ SOC_DAPM_ENUM("PCM Out Lpbk Select", pcm_out_lpbk_mux_map_enum);
+
+static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = {
+ /* inter-connections */
+ SND_SOC_DAPM_MIXER("PCM_1_PB_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_pcm_1_playback_ch1_mix,
+ ARRAY_SIZE(mtk_pcm_1_playback_ch1_mix)),
+ SND_SOC_DAPM_MIXER("PCM_1_PB_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_pcm_1_playback_ch2_mix,
+ ARRAY_SIZE(mtk_pcm_1_playback_ch2_mix)),
+
+ SND_SOC_DAPM_SUPPLY("PCM_1_EN",
+ PCM_INTF_CON1, PCM_EN_SFT, 0,
+ mtk_pcm_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* pcm in lpbk */
+ SND_SOC_DAPM_MUX("PCM_In_Lpbk_Mux",
+ SND_SOC_NOPM, 0, 0, &pcm_in_lpbk_mux_control),
+
+ /* pcm out lpbk */
+ SND_SOC_DAPM_MUX("PCM_Out_Lpbk_Mux",
+ SND_SOC_NOPM, 0, 0, &pcm_out_lpbk_mux_control),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = {
+ {"PCM 1 Playback", NULL, "PCM_1_PB_CH1"},
+ {"PCM 1 Playback", NULL, "PCM_1_PB_CH2"},
+
+ {"PCM 1 Playback", NULL, "PCM_1_EN"},
+ {"PCM 1 Capture", NULL, "PCM_1_EN"},
+
+ {"PCM_1_PB_CH1", "DL2_CH1 Switch", "DL2"},
+ {"PCM_1_PB_CH2", "DL2_CH2 Switch", "DL2"},
+
+ {"PCM_1_PB_CH1", "DL4_CH1 Switch", "DL4"},
+ {"PCM_1_PB_CH2", "DL4_CH2 Switch", "DL4"},
+
+ /* pcm out lpbk */
+ {"PCM_Out_Lpbk_Mux", "Lpbk", "PCM 1 Playback"},
+ {"I2S0", NULL, "PCM_Out_Lpbk_Mux"},
+
+ /* pcm in lpbk */
+ {"PCM_In_Lpbk_Mux", "Lpbk", "PCM 1 Capture"},
+ {"I2S3", NULL, "PCM_In_Lpbk_Mux"},
+};
+
+/* dai ops */
+static int mtk_dai_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int pcm_id = dai->id;
+ struct mtk_afe_pcm_priv *pcm_priv = afe_priv->dai_priv[pcm_id];
+ unsigned int rate = params_rate(params);
+ unsigned int rate_reg = mt8186_rate_transform(afe->dev, rate, dai->id);
+ snd_pcm_format_t format = params_format(params);
+ unsigned int data_width =
+ snd_pcm_format_width(format);
+ unsigned int wlen_width =
+ snd_pcm_format_physical_width(format);
+ unsigned int pcm_con = 0;
+
+ dev_dbg(afe->dev, "%s(), id %d, stream %d, widget active p %d, c %d\n",
+ __func__, dai->id, substream->stream, dai->playback_widget->active,
+ dai->capture_widget->active);
+ dev_dbg(afe->dev, "%s(), rate %d, rate_reg %d, data_width %d, wlen_width %d\n",
+ __func__, rate, rate_reg, data_width, wlen_width);
+
+ if (dai->playback_widget->active || dai->capture_widget->active)
+ return 0;
+
+ switch (dai->id) {
+ case MT8186_DAI_PCM:
+ pcm_con |= AUD_TX_LCH_RPT_NO_REPEAT << PCM_TX_LCH_RPT_SFT;
+ pcm_con |= AUD_VBT_16K_MODE_DISABLE << PCM_VBT_16K_MODE_SFT;
+ pcm_con |= AUD_EXT_MODEM_SELECT_EXTERNAL << PCM_EXT_MODEM_SFT;
+ pcm_con |= AUD_PCM_ONE_BCK_CYCLE_SYNC << PCM_SYNC_TYPE_SFT;
+ pcm_con |= AUD_BT_MODE_DUAL_MIC_ON_TX << PCM_BT_MODE_SFT;
+ pcm_con |= AUD_PCM_AFIFO_AFIFO << PCM_BYP_ASRC_SFT;
+ pcm_con |= AUD_PCM_CLOCK_MASTER_MODE << PCM_SLAVE_SFT;
+ pcm_con |= 0 << PCM_SYNC_LENGTH_SFT;
+
+ /* sampling rate */
+ pcm_con |= rate_reg << PCM_MODE_SFT;
+
+ /* format */
+ pcm_con |= pcm_priv->fmt << PCM_FMT_SFT;
+
+ /* 24bit data width */
+ if (data_width > 16)
+ pcm_con |= AUD_PCM_24BIT_PCM_24_BITS << PCM_24BIT_SFT;
+ else
+ pcm_con |= AUD_PCM_24BIT_PCM_16_BITS << PCM_24BIT_SFT;
+
+ /* wlen width*/
+ if (wlen_width > 16)
+ pcm_con |= AUD_PCM_WLEN_PCM_64_BCK_CYCLES << PCM_WLEN_SFT;
+ else
+ pcm_con |= AUD_PCM_WLEN_PCM_32_BCK_CYCLES << PCM_WLEN_SFT;
+
+ /* clock invert */
+ pcm_con |= pcm_priv->lck_invert << PCM_SYNC_OUT_INV_SFT;
+ pcm_con |= pcm_priv->bck_invert << PCM_BCLK_OUT_INV_SFT;
+
+ regmap_update_bits(afe->regmap, PCM_INTF_CON1, 0xfffffffe, pcm_con);
+ break;
+ default:
+ dev_err(afe->dev, "%s(), id %d not support\n", __func__, dai->id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mtk_dai_pcm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_pcm_priv *pcm_priv = afe_priv->dai_priv[dai->id];
+
+ if (!pcm_priv) {
+ dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
+ return -EINVAL;
+ }
+
+ /* DAI mode*/
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ pcm_priv->fmt = AUD_PCM_FMT_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ pcm_priv->fmt = AUD_PCM_FMT_EIAJ;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ pcm_priv->fmt = AUD_PCM_FMT_PCM_MODE_A;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ pcm_priv->fmt = AUD_PCM_FMT_PCM_MODE_B;
+ break;
+ default:
+ pcm_priv->fmt = AUD_PCM_FMT_I2S;
+ }
+
+ /* DAI clock inversion*/
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ pcm_priv->bck_invert = AUD_BCLK_OUT_INV_NO_INVERSE;
+ pcm_priv->lck_invert = AUD_LRCLK_OUT_INV_NO_INVERSE;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ pcm_priv->bck_invert = AUD_BCLK_OUT_INV_NO_INVERSE;
+ pcm_priv->lck_invert = AUD_BCLK_OUT_INV_INVERSE;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ pcm_priv->bck_invert = AUD_BCLK_OUT_INV_INVERSE;
+ pcm_priv->lck_invert = AUD_LRCLK_OUT_INV_NO_INVERSE;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ pcm_priv->bck_invert = AUD_BCLK_OUT_INV_INVERSE;
+ pcm_priv->lck_invert = AUD_BCLK_OUT_INV_INVERSE;
+ break;
+ default:
+ pcm_priv->bck_invert = AUD_BCLK_OUT_INV_NO_INVERSE;
+ pcm_priv->lck_invert = AUD_LRCLK_OUT_INV_NO_INVERSE;
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_pcm_ops = {
+ .hw_params = mtk_dai_pcm_hw_params,
+ .set_fmt = mtk_dai_pcm_set_fmt,
+};
+
+/* dai driver */
+#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000 |\
+ SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 |\
+ SNDRV_PCM_RATE_48000)
+
+#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
+ {
+ .name = "PCM 1",
+ .id = MT8186_DAI_PCM,
+ .playback = {
+ .stream_name = "PCM 1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .capture = {
+ .stream_name = "PCM 1 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_dai_pcm_ops,
+ .symmetric_rate = 1,
+ .symmetric_sample_bits = 1,
+ },
+};
+
+static struct mtk_afe_pcm_priv *init_pcm_priv_data(struct mtk_base_afe *afe)
+{
+ struct mtk_afe_pcm_priv *pcm_priv;
+
+ pcm_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_afe_pcm_priv),
+ GFP_KERNEL);
+ if (!pcm_priv)
+ return NULL;
+
+ pcm_priv->id = MT8186_DAI_PCM;
+ pcm_priv->fmt = AUD_PCM_FMT_I2S;
+ pcm_priv->bck_invert = AUD_BCLK_OUT_INV_NO_INVERSE;
+ pcm_priv->lck_invert = AUD_LRCLK_OUT_INV_NO_INVERSE;
+
+ return pcm_priv;
+}
+
+int mt8186_dai_pcm_register(struct mtk_base_afe *afe)
+{
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_pcm_priv *pcm_priv;
+ struct mtk_base_afe_dai *dai;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mtk_dai_pcm_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver);
+
+ dai->dapm_widgets = mtk_dai_pcm_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets);
+ dai->dapm_routes = mtk_dai_pcm_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes);
+
+ pcm_priv = init_pcm_priv_data(afe);
+ if (!pcm_priv)
+ return -ENOMEM;
+
+ afe_priv->dai_priv[MT8186_DAI_PCM] = pcm_priv;
+
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-src.c b/sound/soc/mediatek/mt8186/mt8186-dai-src.c
new file mode 100644
index 0000000..67989ff
--- /dev/null
+++ b/sound/soc/mediatek/mt8186/mt8186-dai-src.c
@@ -0,0 +1,695 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI SRC Control
+//
+// Copyright (c) 2022 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+
+#include <linux/regmap.h>
+#include "mt8186-afe-common.h"
+#include "mt8186-interconnection.h"
+
+struct mtk_afe_src_priv {
+ int dl_rate;
+ int ul_rate;
+};
+
+static const unsigned int src_iir_coeff_32_to_16[] = {
+ 0x0dbae6, 0xff9b0a, 0x0dbae6, 0x05e488, 0xe072b9, 0x000002,
+ 0x0dbae6, 0x000f3b, 0x0dbae6, 0x06a537, 0xe17d79, 0x000002,
+ 0x0dbae6, 0x01246a, 0x0dbae6, 0x087261, 0xe306be, 0x000002,
+ 0x0dbae6, 0x03437d, 0x0dbae6, 0x0bc16f, 0xe57c87, 0x000002,
+ 0x0dbae6, 0x072981, 0x0dbae6, 0x111dd3, 0xe94f2a, 0x000002,
+ 0x0dbae6, 0x0dc4a6, 0x0dbae6, 0x188611, 0xee85a0, 0x000002,
+ 0x0dbae6, 0x168b9a, 0x0dbae6, 0x200e8f, 0xf3ccf1, 0x000002,
+ 0x000000, 0x1b75cb, 0x1b75cb, 0x2374a2, 0x000000, 0x000001
+};
+
+static const unsigned int src_iir_coeff_44_to_16[] = {
+ 0x09ae28, 0xf7d97d, 0x09ae28, 0x212a3d, 0xe0ac3a, 0x000002,
+ 0x09ae28, 0xf8525a, 0x09ae28, 0x216d72, 0xe234be, 0x000002,
+ 0x09ae28, 0xf980f5, 0x09ae28, 0x22a057, 0xe45a81, 0x000002,
+ 0x09ae28, 0xfc0a08, 0x09ae28, 0x24d3bd, 0xe7752d, 0x000002,
+ 0x09ae28, 0x016162, 0x09ae28, 0x27da01, 0xeb6ea8, 0x000002,
+ 0x09ae28, 0x0b67df, 0x09ae28, 0x2aca4a, 0xef34c4, 0x000002,
+ 0x000000, 0x135c50, 0x135c50, 0x2c1079, 0x000000, 0x000001
+};
+
+static const unsigned int src_iir_coeff_44_to_32[] = {
+ 0x096966, 0x0c4d35, 0x096966, 0xedee81, 0xf05070, 0x000003,
+ 0x12d2cc, 0x193910, 0x12d2cc, 0xddbf4f, 0xe21e1d, 0x000002,
+ 0x12d2cc, 0x1a9e60, 0x12d2cc, 0xe18916, 0xe470fd, 0x000002,
+ 0x12d2cc, 0x1d06e0, 0x12d2cc, 0xe8a4a6, 0xe87b24, 0x000002,
+ 0x12d2cc, 0x207578, 0x12d2cc, 0xf4fe62, 0xef5917, 0x000002,
+ 0x12d2cc, 0x24055f, 0x12d2cc, 0x05ee2b, 0xf8b502, 0x000002,
+ 0x000000, 0x25a599, 0x25a599, 0x0fabe2, 0x000000, 0x000001
+};
+
+static const unsigned int src_iir_coeff_48_to_16[] = {
+ 0x0296a4, 0xfd69dd, 0x0296a4, 0x209439, 0xe01ff9, 0x000002,
+ 0x0f4ff3, 0xf0d6d4, 0x0f4ff3, 0x209bc9, 0xe076c3, 0x000002,
+ 0x0e8490, 0xf1fe63, 0x0e8490, 0x20cfd6, 0xe12124, 0x000002,
+ 0x14852f, 0xed794a, 0x14852f, 0x21503d, 0xe28b32, 0x000002,
+ 0x136222, 0xf17677, 0x136222, 0x225be1, 0xe56964, 0x000002,
+ 0x0a8d85, 0xfc4a97, 0x0a8d85, 0x24310c, 0xea6952, 0x000002,
+ 0x05eff5, 0x043455, 0x05eff5, 0x4ced8f, 0xe134d6, 0x000001,
+ 0x000000, 0x3aebe6, 0x3aebe6, 0x04f3b0, 0x000000, 0x000004
+};
+
+static const unsigned int src_iir_coeff_48_to_32[] = {
+ 0x10c1b8, 0x10a7df, 0x10c1b8, 0xe7514e, 0xe0b41f, 0x000002,
+ 0x10c1b8, 0x116257, 0x10c1b8, 0xe9402f, 0xe25aaa, 0x000002,
+ 0x10c1b8, 0x130c89, 0x10c1b8, 0xed3cc3, 0xe4dddb, 0x000002,
+ 0x10c1b8, 0x1600dd, 0x10c1b8, 0xf48000, 0xe90c55, 0x000002,
+ 0x10c1b8, 0x1a672e, 0x10c1b8, 0x00494c, 0xefa807, 0x000002,
+ 0x10c1b8, 0x1f38e6, 0x10c1b8, 0x0ee076, 0xf7c5f3, 0x000002,
+ 0x000000, 0x218370, 0x218370, 0x168b40, 0x000000, 0x000001
+};
+
+static const unsigned int src_iir_coeff_48_to_44[] = {
+ 0x0bf71c, 0x170f3f, 0x0bf71c, 0xe3a4c8, 0xf096cb, 0x000003,
+ 0x0bf71c, 0x17395e, 0x0bf71c, 0xe58085, 0xf210c8, 0x000003,
+ 0x0bf71c, 0x1782bd, 0x0bf71c, 0xe95ef6, 0xf4c899, 0x000003,
+ 0x0bf71c, 0x17cd97, 0x0bf71c, 0xf1608a, 0xfa3b18, 0x000003,
+ 0x000000, 0x2fdc6f, 0x2fdc6f, 0xf15663, 0x000000, 0x000001
+};
+
+static const unsigned int src_iir_coeff_96_to_16[] = {
+ 0x0805a1, 0xf21ae3, 0x0805a1, 0x3840bb, 0xe02a2e, 0x000002,
+ 0x0d5dd8, 0xe8f259, 0x0d5dd8, 0x1c0af6, 0xf04700, 0x000003,
+ 0x0bb422, 0xec08d9, 0x0bb422, 0x1bfccc, 0xf09216, 0x000003,
+ 0x08fde6, 0xf108be, 0x08fde6, 0x1bf096, 0xf10ae0, 0x000003,
+ 0x0ae311, 0xeeeda3, 0x0ae311, 0x37c646, 0xe385f5, 0x000002,
+ 0x044089, 0xfa7242, 0x044089, 0x37a785, 0xe56526, 0x000002,
+ 0x00c75c, 0xffb947, 0x00c75c, 0x378ba3, 0xe72c5f, 0x000002,
+ 0x000000, 0x0ef76e, 0x0ef76e, 0x377fda, 0x000000, 0x000001,
+};
+
+static const unsigned int src_iir_coeff_96_to_44[] = {
+ 0x08b543, 0xfd80f4, 0x08b543, 0x0e2332, 0xe06ed0, 0x000002,
+ 0x1b6038, 0xf90e7e, 0x1b6038, 0x0ec1ac, 0xe16f66, 0x000002,
+ 0x188478, 0xfbb921, 0x188478, 0x105859, 0xe2e596, 0x000002,
+ 0x13eff3, 0xffa707, 0x13eff3, 0x13455c, 0xe533b7, 0x000002,
+ 0x0dc239, 0x03d458, 0x0dc239, 0x17f120, 0xe8b617, 0x000002,
+ 0x0745f1, 0x05d790, 0x0745f1, 0x1e3d75, 0xed5f18, 0x000002,
+ 0x05641f, 0x085e2b, 0x05641f, 0x48efd0, 0xe3e9c8, 0x000001,
+ 0x000000, 0x28f632, 0x28f632, 0x273905, 0x000000, 0x000001,
+};
+
+static unsigned int mtk_get_src_freq_mode(struct mtk_base_afe *afe, int rate)
+{
+ switch (rate) {
+ case 8000:
+ return 0x50000;
+ case 11025:
+ return 0x6e400;
+ case 12000:
+ return 0x78000;
+ case 16000:
+ return 0xa0000;
+ case 22050:
+ return 0xdc800;
+ case 24000:
+ return 0xf0000;
+ case 32000:
+ return 0x140000;
+ case 44100:
+ return 0x1b9000;
+ case 48000:
+ return 0x1e0000;
+ case 88200:
+ return 0x372000;
+ case 96000:
+ return 0x3c0000;
+ case 176400:
+ return 0x6e4000;
+ case 192000:
+ return 0x780000;
+ default:
+ dev_err(afe->dev, "%s(), rate %d invalid!!!\n",
+ __func__, rate);
+ return 0;
+ }
+}
+
+static const unsigned int *get_iir_coeff(unsigned int rate_in,
+ unsigned int rate_out,
+ unsigned int *param_num)
+{
+ if (rate_in == 32000 && rate_out == 16000) {
+ *param_num = ARRAY_SIZE(src_iir_coeff_32_to_16);
+ return src_iir_coeff_32_to_16;
+ } else if (rate_in == 44100 && rate_out == 16000) {
+ *param_num = ARRAY_SIZE(src_iir_coeff_44_to_16);
+ return src_iir_coeff_44_to_16;
+ } else if (rate_in == 44100 && rate_out == 32000) {
+ *param_num = ARRAY_SIZE(src_iir_coeff_44_to_32);
+ return src_iir_coeff_44_to_32;
+ } else if ((rate_in == 48000 && rate_out == 16000) ||
+ (rate_in == 96000 && rate_out == 32000)) {
+ *param_num = ARRAY_SIZE(src_iir_coeff_48_to_16);
+ return src_iir_coeff_48_to_16;
+ } else if (rate_in == 48000 && rate_out == 32000) {
+ *param_num = ARRAY_SIZE(src_iir_coeff_48_to_32);
+ return src_iir_coeff_48_to_32;
+ } else if (rate_in == 48000 && rate_out == 44100) {
+ *param_num = ARRAY_SIZE(src_iir_coeff_48_to_44);
+ return src_iir_coeff_48_to_44;
+ } else if (rate_in == 96000 && rate_out == 16000) {
+ *param_num = ARRAY_SIZE(src_iir_coeff_96_to_16);
+ return src_iir_coeff_96_to_16;
+ } else if ((rate_in == 96000 && rate_out == 44100) ||
+ (rate_in == 48000 && rate_out == 22050)) {
+ *param_num = ARRAY_SIZE(src_iir_coeff_96_to_44);
+ return src_iir_coeff_96_to_44;
+ }
+
+ *param_num = 0;
+ return NULL;
+}
+
+static int mtk_set_src_1_param(struct mtk_base_afe *afe, int id)
+{
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_src_priv *src_priv = afe_priv->dai_priv[id];
+ unsigned int iir_coeff_num;
+ unsigned int iir_stage;
+ int rate_in = src_priv->dl_rate;
+ int rate_out = src_priv->ul_rate;
+ unsigned int out_freq_mode = mtk_get_src_freq_mode(afe, rate_out);
+ unsigned int in_freq_mode = mtk_get_src_freq_mode(afe, rate_in);
+
+ /* set out freq mode */
+ regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON3,
+ G_SRC_ASM_FREQ_4_MASK_SFT,
+ out_freq_mode << G_SRC_ASM_FREQ_4_SFT);
+
+ /* set in freq mode */
+ regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON4,
+ G_SRC_ASM_FREQ_5_MASK_SFT,
+ in_freq_mode << G_SRC_ASM_FREQ_5_SFT);
+
+ regmap_write(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON5, 0x3f5986);
+ regmap_write(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON5, 0x3f5987);
+ regmap_write(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON6, 0x1fbd);
+ regmap_write(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON2, 0);
+
+ /* set iir if in_rate > out_rate */
+ if (rate_in > rate_out) {
+ int i;
+ const unsigned int *iir_coeff = get_iir_coeff(rate_in, rate_out,
+ &iir_coeff_num);
+
+ if (iir_coeff_num == 0 || !iir_coeff) {
+ dev_err(afe->dev, "%s(), iir coeff error, num %d, coeff %p\n",
+ __func__, iir_coeff_num, iir_coeff);
+ return -EINVAL;
+ }
+
+ /* COEFF_SRAM_CTRL */
+ regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON0,
+ G_SRC_COEFF_SRAM_CTRL_MASK_SFT,
+ BIT(G_SRC_COEFF_SRAM_CTRL_SFT));
+ /* Clear coeff history to r/w coeff from the first position */
+ regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON13,
+ G_SRC_COEFF_SRAM_ADR_MASK_SFT, 0);
+ /* Write SRC coeff, should not read the reg during write */
+ for (i = 0; i < iir_coeff_num; i++)
+ regmap_write(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON12,
+ iir_coeff[i]);
+ /* disable sram access */
+ regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON0,
+ G_SRC_COEFF_SRAM_CTRL_MASK_SFT, 0);
+ /* CHSET_IIR_STAGE */
+ iir_stage = (iir_coeff_num / 6) - 1;
+ regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON2,
+ G_SRC_CHSET_IIR_STAGE_MASK_SFT,
+ iir_stage << G_SRC_CHSET_IIR_STAGE_SFT);
+ /* CHSET_IIR_EN */
+ regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON2,
+ G_SRC_CHSET_IIR_EN_MASK_SFT,
+ BIT(G_SRC_CHSET_IIR_EN_SFT));
+ } else {
+ /* CHSET_IIR_EN off */
+ regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON2,
+ G_SRC_CHSET_IIR_EN_MASK_SFT, 0);
+ }
+
+ return 0;
+}
+
+static int mtk_set_src_2_param(struct mtk_base_afe *afe, int id)
+{
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_src_priv *src_priv = afe_priv->dai_priv[id];
+ unsigned int iir_coeff_num;
+ unsigned int iir_stage;
+ int rate_in = src_priv->dl_rate;
+ int rate_out = src_priv->ul_rate;
+ unsigned int out_freq_mode = mtk_get_src_freq_mode(afe, rate_out);
+ unsigned int in_freq_mode = mtk_get_src_freq_mode(afe, rate_in);
+
+ /* set out freq mode */
+ regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON3,
+ G_SRC_ASM_FREQ_4_MASK_SFT,
+ out_freq_mode << G_SRC_ASM_FREQ_4_SFT);
+
+ /* set in freq mode */
+ regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON4,
+ G_SRC_ASM_FREQ_5_MASK_SFT,
+ in_freq_mode << G_SRC_ASM_FREQ_5_SFT);
+
+ regmap_write(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON5, 0x3f5986);
+ regmap_write(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON5, 0x3f5987);
+ regmap_write(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON6, 0x1fbd);
+ regmap_write(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON2, 0);
+
+ /* set iir if in_rate > out_rate */
+ if (rate_in > rate_out) {
+ int i;
+ const unsigned int *iir_coeff = get_iir_coeff(rate_in, rate_out,
+ &iir_coeff_num);
+
+ if (iir_coeff_num == 0 || !iir_coeff) {
+ dev_err(afe->dev, "%s(), iir coeff error, num %d, coeff %p\n",
+ __func__, iir_coeff_num, iir_coeff);
+ return -EINVAL;
+ }
+
+ /* COEFF_SRAM_CTRL */
+ regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON0,
+ G_SRC_COEFF_SRAM_CTRL_MASK_SFT,
+ BIT(G_SRC_COEFF_SRAM_CTRL_SFT));
+ /* Clear coeff history to r/w coeff from the first position */
+ regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON13,
+ G_SRC_COEFF_SRAM_ADR_MASK_SFT, 0);
+ /* Write SRC coeff, should not read the reg during write */
+ for (i = 0; i < iir_coeff_num; i++)
+ regmap_write(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON12,
+ iir_coeff[i]);
+ /* disable sram access */
+ regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON0,
+ G_SRC_COEFF_SRAM_CTRL_MASK_SFT, 0);
+ /* CHSET_IIR_STAGE */
+ iir_stage = (iir_coeff_num / 6) - 1;
+ regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON2,
+ G_SRC_CHSET_IIR_STAGE_MASK_SFT,
+ iir_stage << G_SRC_CHSET_IIR_STAGE_SFT);
+ /* CHSET_IIR_EN */
+ regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON2,
+ G_SRC_CHSET_IIR_EN_MASK_SFT,
+ BIT(G_SRC_CHSET_IIR_EN_SFT));
+ } else {
+ /* CHSET_IIR_EN off */
+ regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON2,
+ G_SRC_CHSET_IIR_EN_MASK_SFT, 0);
+ }
+
+ return 0;
+}
+
+#define HW_SRC_1_EN_W_NAME "HW_SRC_1_Enable"
+#define HW_SRC_2_EN_W_NAME "HW_SRC_2_Enable"
+
+static int mtk_hw_src_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int id;
+ struct mtk_afe_src_priv *src_priv;
+ unsigned int reg;
+
+ if (strcmp(w->name, HW_SRC_1_EN_W_NAME) == 0)
+ id = MT8186_DAI_SRC_1;
+ else
+ id = MT8186_DAI_SRC_2;
+
+ src_priv = afe_priv->dai_priv[id];
+
+ dev_dbg(afe->dev,
+ "%s(), name %s, event 0x%x, id %d, src_priv %p, dl_rate %d, ul_rate %d\n",
+ __func__, w->name, event, id, src_priv,
+ src_priv->dl_rate, src_priv->ul_rate);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (id == MT8186_DAI_SRC_1)
+ mtk_set_src_1_param(afe, id);
+ else
+ mtk_set_src_2_param(afe, id);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ reg = (id == MT8186_DAI_SRC_1) ?
+ AFE_GENERAL1_ASRC_2CH_CON0 : AFE_GENERAL2_ASRC_2CH_CON0;
+ /* ASM_ON */
+ regmap_update_bits(afe->regmap, reg,
+ G_SRC_ASM_ON_MASK_SFT,
+ BIT(G_SRC_ASM_ON_SFT));
+ /* CHSET_ON */
+ regmap_update_bits(afe->regmap, reg,
+ G_SRC_CHSET_ON_MASK_SFT,
+ BIT(G_SRC_CHSET_ON_SFT));
+ /* CHSET_STR_CLR */
+ regmap_update_bits(afe->regmap, reg,
+ G_SRC_CHSET_STR_CLR_MASK_SFT,
+ BIT(G_SRC_CHSET_STR_CLR_SFT));
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ reg = (id == MT8186_DAI_SRC_1) ?
+ AFE_GENERAL1_ASRC_2CH_CON0 : AFE_GENERAL2_ASRC_2CH_CON0;
+ /* ASM_OFF */
+ regmap_update_bits(afe->regmap, reg, G_SRC_ASM_ON_MASK_SFT, 0);
+ /* CHSET_OFF */
+ regmap_update_bits(afe->regmap, reg, G_SRC_CHSET_ON_MASK_SFT, 0);
+ /* CHSET_STR_CLR */
+ regmap_update_bits(afe->regmap, reg, G_SRC_CHSET_STR_CLR_MASK_SFT, 0);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* dai component */
+static const struct snd_kcontrol_new mtk_hw_src_1_in_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN40,
+ I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN40,
+ I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN40,
+ I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN40_1,
+ I_DL4_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1 Switch", AFE_CONN40_1,
+ I_DL6_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1 Switch", AFE_CONN40,
+ I_I2S0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN40_1,
+ I_DL5_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_hw_src_1_in_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN41,
+ I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN41,
+ I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN41,
+ I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN41_1,
+ I_DL4_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2 Switch", AFE_CONN41_1,
+ I_DL6_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2 Switch", AFE_CONN41,
+ I_I2S0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN41_1,
+ I_DL5_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_hw_src_2_in_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN42,
+ I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN42,
+ I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN42,
+ I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN42,
+ I_DL4_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN42_1,
+ I_DL5_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1 Switch", AFE_CONN42_1,
+ I_DL6_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN2_OUT_CH1 Switch", AFE_CONN42,
+ I_GAIN2_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_hw_src_2_in_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN43,
+ I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN43,
+ I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN43,
+ I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN43,
+ I_DL4_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN43_1,
+ I_DL5_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2 Switch", AFE_CONN43_1,
+ I_DL6_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN2_OUT_CH2 Switch", AFE_CONN43,
+ I_GAIN2_OUT_CH2, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget mtk_dai_src_widgets[] = {
+ /* inter-connections */
+ SND_SOC_DAPM_MIXER("HW_SRC_1_IN_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_hw_src_1_in_ch1_mix,
+ ARRAY_SIZE(mtk_hw_src_1_in_ch1_mix)),
+ SND_SOC_DAPM_MIXER("HW_SRC_1_IN_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_hw_src_1_in_ch2_mix,
+ ARRAY_SIZE(mtk_hw_src_1_in_ch2_mix)),
+ SND_SOC_DAPM_MIXER("HW_SRC_2_IN_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_hw_src_2_in_ch1_mix,
+ ARRAY_SIZE(mtk_hw_src_2_in_ch1_mix)),
+ SND_SOC_DAPM_MIXER("HW_SRC_2_IN_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_hw_src_2_in_ch2_mix,
+ ARRAY_SIZE(mtk_hw_src_2_in_ch2_mix)),
+
+ SND_SOC_DAPM_SUPPLY(HW_SRC_1_EN_W_NAME,
+ GENERAL_ASRC_EN_ON, GENERAL1_ASRC_EN_ON_SFT, 0,
+ mtk_hw_src_event,
+ SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_SUPPLY(HW_SRC_2_EN_W_NAME,
+ GENERAL_ASRC_EN_ON, GENERAL2_ASRC_EN_ON_SFT, 0,
+ mtk_hw_src_event,
+ SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_INPUT("HW SRC 1 Out Endpoint"),
+ SND_SOC_DAPM_INPUT("HW SRC 2 Out Endpoint"),
+ SND_SOC_DAPM_OUTPUT("HW SRC 1 In Endpoint"),
+ SND_SOC_DAPM_OUTPUT("HW SRC 2 In Endpoint"),
+};
+
+static int mtk_afe_src_en_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_dapm_widget *w = source;
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_src_priv *src_priv;
+
+ if (strcmp(w->name, HW_SRC_1_EN_W_NAME) == 0)
+ src_priv = afe_priv->dai_priv[MT8186_DAI_SRC_1];
+ else
+ src_priv = afe_priv->dai_priv[MT8186_DAI_SRC_2];
+
+ dev_dbg(afe->dev,
+ "%s(), source %s, sink %s, dl_rate %d, ul_rate %d\n",
+ __func__, source->name, sink->name,
+ src_priv->dl_rate, src_priv->ul_rate);
+
+ return (src_priv->dl_rate > 0 && src_priv->ul_rate > 0) ? 1 : 0;
+}
+
+static const struct snd_soc_dapm_route mtk_dai_src_routes[] = {
+ {"HW_SRC_1_IN_CH1", "DL1_CH1 Switch", "DL1"},
+ {"HW_SRC_1_IN_CH2", "DL1_CH2 Switch", "DL1"},
+ {"HW_SRC_2_IN_CH1", "DL1_CH1 Switch", "DL1"},
+ {"HW_SRC_2_IN_CH2", "DL1_CH2 Switch", "DL1"},
+ {"HW_SRC_1_IN_CH1", "DL2_CH1 Switch", "DL2"},
+ {"HW_SRC_1_IN_CH2", "DL2_CH2 Switch", "DL2"},
+ {"HW_SRC_2_IN_CH1", "DL2_CH1 Switch", "DL2"},
+ {"HW_SRC_2_IN_CH2", "DL2_CH2 Switch", "DL2"},
+ {"HW_SRC_1_IN_CH1", "DL3_CH1 Switch", "DL3"},
+ {"HW_SRC_1_IN_CH2", "DL3_CH2 Switch", "DL3"},
+ {"HW_SRC_2_IN_CH1", "DL3_CH1 Switch", "DL3"},
+ {"HW_SRC_2_IN_CH2", "DL3_CH2 Switch", "DL3"},
+ {"HW_SRC_1_IN_CH1", "DL6_CH1 Switch", "DL6"},
+ {"HW_SRC_1_IN_CH2", "DL6_CH2 Switch", "DL6"},
+ {"HW_SRC_2_IN_CH1", "DL6_CH1 Switch", "DL6"},
+ {"HW_SRC_2_IN_CH2", "DL6_CH2 Switch", "DL6"},
+ {"HW_SRC_1_IN_CH1", "DL5_CH1 Switch", "DL5"},
+ {"HW_SRC_1_IN_CH2", "DL5_CH2 Switch", "DL5"},
+ {"HW_SRC_2_IN_CH1", "DL5_CH1 Switch", "DL5"},
+ {"HW_SRC_2_IN_CH2", "DL5_CH2 Switch", "DL5"},
+ {"HW_SRC_1_IN_CH1", "DL4_CH1 Switch", "DL4"},
+ {"HW_SRC_1_IN_CH2", "DL4_CH2 Switch", "DL4"},
+ {"HW_SRC_2_IN_CH1", "DL4_CH1 Switch", "DL4"},
+ {"HW_SRC_2_IN_CH2", "DL4_CH2 Switch", "DL4"},
+
+ {"HW_SRC_1_In", NULL, "HW_SRC_1_IN_CH1"},
+ {"HW_SRC_1_In", NULL, "HW_SRC_1_IN_CH2"},
+
+ {"HW_SRC_2_In", NULL, "HW_SRC_2_IN_CH1"},
+ {"HW_SRC_2_In", NULL, "HW_SRC_2_IN_CH2"},
+
+ {"HW_SRC_1_In", NULL, HW_SRC_1_EN_W_NAME, mtk_afe_src_en_connect},
+ {"HW_SRC_1_Out", NULL, HW_SRC_1_EN_W_NAME, mtk_afe_src_en_connect},
+ {"HW_SRC_2_In", NULL, HW_SRC_2_EN_W_NAME, mtk_afe_src_en_connect},
+ {"HW_SRC_2_Out", NULL, HW_SRC_2_EN_W_NAME, mtk_afe_src_en_connect},
+
+ {"HW SRC 1 In Endpoint", NULL, "HW_SRC_1_In"},
+ {"HW SRC 2 In Endpoint", NULL, "HW_SRC_2_In"},
+ {"HW_SRC_1_Out", NULL, "HW SRC 1 Out Endpoint"},
+ {"HW_SRC_2_Out", NULL, "HW SRC 2 Out Endpoint"},
+};
+
+/* dai ops */
+static int mtk_dai_src_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int id = dai->id;
+ struct mtk_afe_src_priv *src_priv = afe_priv->dai_priv[id];
+ unsigned int sft, mask;
+ unsigned int rate = params_rate(params);
+ unsigned int rate_reg = mt8186_rate_transform(afe->dev, rate, id);
+
+ dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n",
+ __func__, id, substream->stream, rate);
+
+ /* rate */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ src_priv->dl_rate = rate;
+ if (id == MT8186_DAI_SRC_1) {
+ sft = GENERAL1_ASRCIN_MODE_SFT;
+ mask = GENERAL1_ASRCIN_MODE_MASK;
+ } else {
+ sft = GENERAL2_ASRCIN_MODE_SFT;
+ mask = GENERAL2_ASRCIN_MODE_MASK;
+ }
+ } else {
+ src_priv->ul_rate = rate;
+ if (id == MT8186_DAI_SRC_1) {
+ sft = GENERAL1_ASRCOUT_MODE_SFT;
+ mask = GENERAL1_ASRCOUT_MODE_MASK;
+ } else {
+ sft = GENERAL2_ASRCOUT_MODE_SFT;
+ mask = GENERAL2_ASRCOUT_MODE_MASK;
+ }
+ }
+
+ regmap_update_bits(afe->regmap, GENERAL_ASRC_MODE, mask << sft, rate_reg << sft);
+
+ return 0;
+}
+
+static int mtk_dai_src_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int id = dai->id;
+ struct mtk_afe_src_priv *src_priv = afe_priv->dai_priv[id];
+
+ dev_dbg(afe->dev, "%s(), id %d, stream %d\n",
+ __func__, id, substream->stream);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ src_priv->dl_rate = 0;
+ else
+ src_priv->ul_rate = 0;
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_src_ops = {
+ .hw_params = mtk_dai_src_hw_params,
+ .hw_free = mtk_dai_src_hw_free,
+};
+
+/* dai driver */
+#define MTK_SRC_RATES (SNDRV_PCM_RATE_8000_48000 |\
+ SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_176400 |\
+ SNDRV_PCM_RATE_192000)
+
+#define MTK_SRC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_src_driver[] = {
+ {
+ .name = "HW_SRC_1",
+ .id = MT8186_DAI_SRC_1,
+ .playback = {
+ .stream_name = "HW_SRC_1_In",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_SRC_RATES,
+ .formats = MTK_SRC_FORMATS,
+ },
+ .capture = {
+ .stream_name = "HW_SRC_1_Out",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_SRC_RATES,
+ .formats = MTK_SRC_FORMATS,
+ },
+ .ops = &mtk_dai_src_ops,
+ },
+ {
+ .name = "HW_SRC_2",
+ .id = MT8186_DAI_SRC_2,
+ .playback = {
+ .stream_name = "HW_SRC_2_In",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_SRC_RATES,
+ .formats = MTK_SRC_FORMATS,
+ },
+ .capture = {
+ .stream_name = "HW_SRC_2_Out",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_SRC_RATES,
+ .formats = MTK_SRC_FORMATS,
+ },
+ .ops = &mtk_dai_src_ops,
+ },
+};
+
+int mt8186_dai_src_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+ int ret;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mtk_dai_src_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_src_driver);
+
+ dai->dapm_widgets = mtk_dai_src_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_src_widgets);
+ dai->dapm_routes = mtk_dai_src_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_src_routes);
+
+ /* set dai priv */
+ ret = mt8186_dai_set_priv(afe, MT8186_DAI_SRC_1,
+ sizeof(struct mtk_afe_src_priv), NULL);
+ if (ret)
+ return ret;
+
+ ret = mt8186_dai_set_priv(afe, MT8186_DAI_SRC_2,
+ sizeof(struct mtk_afe_src_priv), NULL);
+ if (ret)
+ return ret;
+
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-tdm.c b/sound/soc/mediatek/mt8186/mt8186-dai-tdm.c
new file mode 100644
index 0000000..c6ead7c
--- /dev/null
+++ b/sound/soc/mediatek/mt8186/mt8186-dai-tdm.c
@@ -0,0 +1,698 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI TDM Control
+//
+// Copyright (c) 2022 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+
+#include "mt8186-afe-clk.h"
+#include "mt8186-afe-common.h"
+#include "mt8186-afe-gpio.h"
+#include "mt8186-interconnection.h"
+
+#define TDM_HD_EN_W_NAME "TDM_HD_EN"
+#define TDM_MCLK_EN_W_NAME "TDM_MCLK_EN"
+#define MTK_AFE_TDM_KCONTROL_NAME "TDM_HD_Mux"
+
+struct mtk_afe_tdm_priv {
+ unsigned int id;
+ unsigned int rate; /* for determine which apll to use */
+ unsigned int bck_invert;
+ unsigned int lck_invert;
+ unsigned int lrck_width;
+ unsigned int mclk_id;
+ unsigned int mclk_multiple; /* according to sample rate */
+ unsigned int mclk_rate;
+ unsigned int mclk_apll;
+ unsigned int tdm_mode;
+ unsigned int data_mode;
+ unsigned int slave_mode;
+ unsigned int low_jitter_en;
+};
+
+enum {
+ TDM_IN_I2S = 0,
+ TDM_IN_LJ = 1,
+ TDM_IN_RJ = 2,
+ TDM_IN_DSP_A = 4,
+ TDM_IN_DSP_B = 5,
+};
+
+enum {
+ TDM_DATA_ONE_PIN = 0,
+ TDM_DATA_MULTI_PIN,
+};
+
+enum {
+ TDM_BCK_NON_INV = 0,
+ TDM_BCK_INV = 1,
+};
+
+enum {
+ TDM_LCK_NON_INV = 0,
+ TDM_LCK_INV = 1,
+};
+
+static unsigned int get_tdm_lrck_width(snd_pcm_format_t format,
+ unsigned int mode)
+{
+ if (mode == TDM_IN_DSP_A || mode == TDM_IN_DSP_B)
+ return 0;
+
+ return snd_pcm_format_physical_width(format) - 1;
+}
+
+static unsigned int get_tdm_ch_fixup(unsigned int channels)
+{
+ if (channels > 4)
+ return 8;
+ else if (channels > 2)
+ return 4;
+
+ return 2;
+}
+
+static unsigned int get_tdm_ch_per_sdata(unsigned int mode,
+ unsigned int channels)
+{
+ if (mode == TDM_IN_DSP_A || mode == TDM_IN_DSP_B)
+ return get_tdm_ch_fixup(channels);
+
+ return 2;
+}
+
+enum {
+ SUPPLY_SEQ_APLL,
+ SUPPLY_SEQ_TDM_MCK_EN,
+ SUPPLY_SEQ_TDM_HD_EN,
+ SUPPLY_SEQ_TDM_EN,
+};
+
+static int get_tdm_id_by_name(const char *name)
+{
+ return MT8186_DAI_TDM_IN;
+}
+
+static int mtk_tdm_en_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int dai_id = get_tdm_id_by_name(w->name);
+ struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+
+ if (!tdm_priv) {
+ dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
+ return -EINVAL;
+ }
+
+ dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n",
+ __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8186_afe_gpio_request(afe->dev, true, tdm_priv->id, 0);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ mt8186_afe_gpio_request(afe->dev, false, tdm_priv->id, 0);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_tdm_mck_en_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int dai_id = get_tdm_id_by_name(w->name);
+ struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+
+ if (!tdm_priv) {
+ dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
+ return -EINVAL;
+ }
+
+ dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x, dai_id %d\n",
+ __func__, w->name, event, dai_id);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8186_mck_enable(afe, tdm_priv->mclk_id, tdm_priv->mclk_rate);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ tdm_priv->mclk_rate = 0;
+ mt8186_mck_disable(afe, tdm_priv->mclk_id);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* dai component */
+/* tdm virtual mux to output widget */
+static const char * const tdm_mux_map[] = {
+ "Normal", "Dummy_Widget",
+};
+
+static int tdm_mux_map_value[] = {
+ 0, 1,
+};
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(tdm_mux_map_enum,
+ SND_SOC_NOPM,
+ 0,
+ 1,
+ tdm_mux_map,
+ tdm_mux_map_value);
+
+static const struct snd_kcontrol_new tdm_in_mux_control =
+ SOC_DAPM_ENUM("TDM In Select", tdm_mux_map_enum);
+
+static const struct snd_soc_dapm_widget mtk_dai_tdm_widgets[] = {
+ SND_SOC_DAPM_CLOCK_SUPPLY("aud_tdm_clk"),
+
+ SND_SOC_DAPM_SUPPLY_S("TDM_EN", SUPPLY_SEQ_TDM_EN,
+ ETDM_IN1_CON0, ETDM_IN1_CON0_REG_ETDM_IN_EN_SFT,
+ 0, mtk_tdm_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ /* tdm hd en */
+ SND_SOC_DAPM_SUPPLY_S(TDM_HD_EN_W_NAME, SUPPLY_SEQ_TDM_HD_EN,
+ ETDM_IN1_CON2, ETDM_IN1_CON2_REG_CLOCK_SOURCE_SEL_SFT,
+ 0, NULL,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S(TDM_MCLK_EN_W_NAME, SUPPLY_SEQ_TDM_MCK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_tdm_mck_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_INPUT("TDM_DUMMY_IN"),
+
+ SND_SOC_DAPM_MUX("TDM_In_Mux",
+ SND_SOC_NOPM, 0, 0, &tdm_in_mux_control),
+};
+
+static int mtk_afe_tdm_mclk_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_dapm_widget *w = sink;
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int dai_id = get_tdm_id_by_name(w->name);
+ struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+
+ if (!tdm_priv) {
+ dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
+ return 0;
+ }
+
+ return (tdm_priv->mclk_rate > 0) ? 1 : 0;
+}
+
+static int mtk_afe_tdm_mclk_apll_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_dapm_widget *w = sink;
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int dai_id = get_tdm_id_by_name(w->name);
+ struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+ int cur_apll;
+
+ /* which apll */
+ cur_apll = mt8186_get_apll_by_name(afe, source->name);
+
+ return (tdm_priv->mclk_apll == cur_apll) ? 1 : 0;
+}
+
+static int mtk_afe_tdm_hd_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_dapm_widget *w = sink;
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int dai_id = get_tdm_id_by_name(w->name);
+ struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+
+ if (!tdm_priv) {
+ dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
+ return 0;
+ }
+
+ return tdm_priv->low_jitter_en;
+}
+
+static int mtk_afe_tdm_apll_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_dapm_widget *w = sink;
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int dai_id = get_tdm_id_by_name(w->name);
+ struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+ int cur_apll;
+ int tdm_need_apll;
+
+ if (!tdm_priv) {
+ dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
+ return 0;
+ }
+
+ /* which apll */
+ cur_apll = mt8186_get_apll_by_name(afe, source->name);
+
+ /* choose APLL from tdm rate */
+ tdm_need_apll = mt8186_get_apll_by_rate(afe, tdm_priv->rate);
+
+ return (tdm_need_apll == cur_apll) ? 1 : 0;
+}
+
+/* low jitter control */
+static const char * const mt8186_tdm_hd_str[] = {
+ "Normal", "Low_Jitter"
+};
+
+static const struct soc_enum mt8186_tdm_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8186_tdm_hd_str),
+ mt8186_tdm_hd_str),
+};
+
+static int mt8186_tdm_hd_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int dai_id = get_tdm_id_by_name(kcontrol->id.name);
+ struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+
+ if (!tdm_priv) {
+ dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
+ return -EINVAL;
+ }
+
+ ucontrol->value.integer.value[0] = tdm_priv->low_jitter_en;
+
+ return 0;
+}
+
+static int mt8186_tdm_hd_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int dai_id = get_tdm_id_by_name(kcontrol->id.name);
+ struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ int hd_en;
+
+ if (ucontrol->value.enumerated.item[0] >= e->items)
+ return -EINVAL;
+
+ hd_en = ucontrol->value.integer.value[0];
+
+ dev_dbg(afe->dev, "%s(), kcontrol name %s, hd_en %d\n",
+ __func__, kcontrol->id.name, hd_en);
+
+ if (!tdm_priv) {
+ dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
+ return -EINVAL;
+ }
+
+ if (tdm_priv->low_jitter_en == hd_en)
+ return 0;
+
+ tdm_priv->low_jitter_en = hd_en;
+
+ return 1;
+}
+
+static const struct snd_kcontrol_new mtk_dai_tdm_controls[] = {
+ SOC_ENUM_EXT(MTK_AFE_TDM_KCONTROL_NAME, mt8186_tdm_enum[0],
+ mt8186_tdm_hd_get, mt8186_tdm_hd_set),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_tdm_routes[] = {
+ {"TDM IN", NULL, "aud_tdm_clk"},
+ {"TDM IN", NULL, "TDM_EN"},
+ {"TDM IN", NULL, TDM_HD_EN_W_NAME, mtk_afe_tdm_hd_connect},
+ {TDM_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_tdm_apll_connect},
+ {TDM_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_tdm_apll_connect},
+
+ {"TDM IN", NULL, TDM_MCLK_EN_W_NAME, mtk_afe_tdm_mclk_connect},
+ {TDM_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_tdm_mclk_apll_connect},
+ {TDM_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_tdm_mclk_apll_connect},
+
+ /* allow tdm on without codec on */
+ {"TDM IN", NULL, "TDM_In_Mux"},
+ {"TDM_In_Mux", "Dummy_Widget", "TDM_DUMMY_IN"},
+};
+
+/* dai ops */
+static int mtk_dai_tdm_cal_mclk(struct mtk_base_afe *afe,
+ struct mtk_afe_tdm_priv *tdm_priv,
+ int freq)
+{
+ int apll;
+ int apll_rate;
+
+ apll = mt8186_get_apll_by_rate(afe, freq);
+ apll_rate = mt8186_get_apll_rate(afe, apll);
+
+ if (!freq || freq > apll_rate) {
+ dev_err(afe->dev,
+ "%s(), freq(%d Hz) invalid\n", __func__, freq);
+ return -EINVAL;
+ }
+
+ if (apll_rate % freq != 0) {
+ dev_err(afe->dev,
+ "%s(), APLL cannot generate %d Hz", __func__, freq);
+ return -EINVAL;
+ }
+
+ tdm_priv->mclk_rate = freq;
+ tdm_priv->mclk_apll = apll;
+
+ return 0;
+}
+
+static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ int tdm_id = dai->id;
+ struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[tdm_id];
+ unsigned int tdm_mode = tdm_priv->tdm_mode;
+ unsigned int data_mode = tdm_priv->data_mode;
+ unsigned int rate = params_rate(params);
+ unsigned int channels = params_channels(params);
+ snd_pcm_format_t format = params_format(params);
+ unsigned int bit_width =
+ snd_pcm_format_physical_width(format);
+ unsigned int tdm_channels = (data_mode == TDM_DATA_ONE_PIN) ?
+ get_tdm_ch_per_sdata(tdm_mode, channels) : 2;
+ unsigned int lrck_width =
+ get_tdm_lrck_width(format, tdm_mode);
+ unsigned int tdm_con = 0;
+ bool slave_mode = tdm_priv->slave_mode;
+ bool lrck_inv = tdm_priv->lck_invert;
+ bool bck_inv = tdm_priv->bck_invert;
+ unsigned int tran_rate;
+ unsigned int tran_relatch_rate;
+
+ if (!tdm_priv) {
+ dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
+ return -EINVAL;
+ }
+
+ tdm_priv->rate = rate;
+
+ tran_rate = mt8186_rate_transform(afe->dev, rate, dai->id);
+ tran_relatch_rate = mt8186_tdm_relatch_rate_transform(afe->dev, rate);
+
+ /* calculate mclk_rate, if not set explicitly */
+ if (!tdm_priv->mclk_rate) {
+ tdm_priv->mclk_rate = rate * tdm_priv->mclk_multiple;
+ mtk_dai_tdm_cal_mclk(afe,
+ tdm_priv,
+ tdm_priv->mclk_rate);
+ }
+
+ /* ETDM_IN1_CON0 */
+ tdm_con |= slave_mode << ETDM_IN1_CON0_REG_SLAVE_MODE_SFT;
+ tdm_con |= tdm_mode << ETDM_IN1_CON0_REG_FMT_SFT;
+ tdm_con |= (bit_width - 1) << ETDM_IN1_CON0_REG_BIT_LENGTH_SFT;
+ tdm_con |= (bit_width - 1) << ETDM_IN1_CON0_REG_WORD_LENGTH_SFT;
+ tdm_con |= (tdm_channels - 1) << ETDM_IN1_CON0_REG_CH_NUM_SFT;
+ /* need to disable sync mode otherwise this may cause latch data error */
+ tdm_con |= 0 << ETDM_IN1_CON0_REG_SYNC_MODE_SFT;
+ /* relatch 1x en clock fix to h26m */
+ tdm_con |= 0 << ETDM_IN1_CON0_REG_RELATCH_1X_EN_SEL_DOMAIN_SFT;
+ regmap_update_bits(afe->regmap, ETDM_IN1_CON0, ETDM_IN_CON0_CTRL_MASK, tdm_con);
+
+ /* ETDM_IN1_CON1 */
+ tdm_con = 0;
+ tdm_con |= 0 << ETDM_IN1_CON1_REG_LRCK_AUTO_MODE_SFT;
+ tdm_con |= 1 << ETDM_IN1_CON1_PINMUX_MCLK_CTRL_OE_SFT;
+ tdm_con |= (lrck_width - 1) << ETDM_IN1_CON1_REG_LRCK_WIDTH_SFT;
+ regmap_update_bits(afe->regmap, ETDM_IN1_CON1, ETDM_IN_CON1_CTRL_MASK, tdm_con);
+
+ /* ETDM_IN1_CON3 */
+ tdm_con = 0;
+ tdm_con = ETDM_IN_CON3_FS(tran_rate);
+ regmap_update_bits(afe->regmap, ETDM_IN1_CON3, ETDM_IN_CON3_CTRL_MASK, tdm_con);
+
+ /* ETDM_IN1_CON4 */
+ tdm_con = 0;
+ tdm_con = ETDM_IN_CON4_FS(tran_relatch_rate);
+ if (slave_mode) {
+ if (lrck_inv)
+ tdm_con |= ETDM_IN_CON4_CON0_SLAVE_LRCK_INV;
+ if (bck_inv)
+ tdm_con |= ETDM_IN_CON4_CON0_SLAVE_BCK_INV;
+ } else {
+ if (lrck_inv)
+ tdm_con |= ETDM_IN_CON4_CON0_MASTER_LRCK_INV;
+ if (bck_inv)
+ tdm_con |= ETDM_IN_CON4_CON0_MASTER_BCK_INV;
+ }
+ regmap_update_bits(afe->regmap, ETDM_IN1_CON4, ETDM_IN_CON4_CTRL_MASK, tdm_con);
+
+ /* ETDM_IN1_CON2 */
+ tdm_con = 0;
+ if (data_mode == TDM_DATA_MULTI_PIN) {
+ tdm_con |= ETDM_IN_CON2_MULTI_IP_2CH_MODE;
+ tdm_con |= ETDM_IN_CON2_MULTI_IP_CH(channels);
+ }
+ regmap_update_bits(afe->regmap, ETDM_IN1_CON2, ETDM_IN_CON2_CTRL_MASK, tdm_con);
+
+ /* ETDM_IN1_CON8 */
+ tdm_con = 0;
+ if (slave_mode) {
+ tdm_con |= 1 << ETDM_IN1_CON8_REG_ETDM_USE_AFIFO_SFT;
+ tdm_con |= 0 << ETDM_IN1_CON8_REG_AFIFO_CLOCK_DOMAIN_SEL_SFT;
+ tdm_con |= ETDM_IN_CON8_FS(tran_relatch_rate);
+ } else {
+ tdm_con |= 0 << ETDM_IN1_CON8_REG_ETDM_USE_AFIFO_SFT;
+ }
+ regmap_update_bits(afe->regmap, ETDM_IN1_CON8, ETDM_IN_CON8_CTRL_MASK, tdm_con);
+
+ return 0;
+}
+
+static int mtk_dai_tdm_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id];
+
+ if (!tdm_priv) {
+ dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
+ return -EINVAL;
+ }
+
+ if (dir != SND_SOC_CLOCK_IN) {
+ dev_err(afe->dev, "%s(), dir != SND_SOC_CLOCK_OUT", __func__);
+ return -EINVAL;
+ }
+
+ dev_dbg(afe->dev, "%s(), freq %d\n", __func__, freq);
+
+ return mtk_dai_tdm_cal_mclk(afe, tdm_priv, freq);
+}
+
+static int mtk_dai_tdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id];
+
+ if (!tdm_priv) {
+ dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
+ return -EINVAL;
+ }
+
+ /* DAI mode*/
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ tdm_priv->tdm_mode = TDM_IN_I2S;
+ tdm_priv->data_mode = TDM_DATA_MULTI_PIN;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ tdm_priv->tdm_mode = TDM_IN_LJ;
+ tdm_priv->data_mode = TDM_DATA_MULTI_PIN;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ tdm_priv->tdm_mode = TDM_IN_RJ;
+ tdm_priv->data_mode = TDM_DATA_MULTI_PIN;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ tdm_priv->tdm_mode = TDM_IN_DSP_A;
+ tdm_priv->data_mode = TDM_DATA_ONE_PIN;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ tdm_priv->tdm_mode = TDM_IN_DSP_B;
+ tdm_priv->data_mode = TDM_DATA_ONE_PIN;
+ break;
+ default:
+ dev_err(afe->dev, "%s(), invalid DAIFMT_FORMAT_MASK", __func__);
+ return -EINVAL;
+ }
+
+ /* DAI clock inversion*/
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ tdm_priv->bck_invert = TDM_BCK_NON_INV;
+ tdm_priv->lck_invert = TDM_LCK_NON_INV;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ tdm_priv->bck_invert = TDM_BCK_NON_INV;
+ tdm_priv->lck_invert = TDM_LCK_INV;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ tdm_priv->bck_invert = TDM_BCK_INV;
+ tdm_priv->lck_invert = TDM_LCK_NON_INV;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ tdm_priv->bck_invert = TDM_BCK_INV;
+ tdm_priv->lck_invert = TDM_LCK_INV;
+ break;
+ default:
+ dev_err(afe->dev, "%s(), invalid DAIFMT_INV_MASK", __func__);
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BP_FP:
+ tdm_priv->slave_mode = false;
+ break;
+ case SND_SOC_DAIFMT_BC_FC:
+ tdm_priv->slave_mode = true;
+ break;
+ default:
+ dev_err(afe->dev, "%s(), invalid DAIFMT_CLOCK_PROVIDER_MASK",
+ __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mtk_dai_tdm_set_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask,
+ unsigned int rx_mask,
+ int slots,
+ int slot_width)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id];
+
+ dev_dbg(dai->dev, "%s %d slot_width %d\n", __func__, dai->id, slot_width);
+
+ tdm_priv->lrck_width = slot_width;
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_tdm_ops = {
+ .hw_params = mtk_dai_tdm_hw_params,
+ .set_sysclk = mtk_dai_tdm_set_sysclk,
+ .set_fmt = mtk_dai_tdm_set_fmt,
+ .set_tdm_slot = mtk_dai_tdm_set_tdm_slot,
+};
+
+/* dai driver */
+#define MTK_TDM_RATES (SNDRV_PCM_RATE_8000_48000 |\
+ SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_176400 |\
+ SNDRV_PCM_RATE_192000)
+
+#define MTK_TDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_tdm_driver[] = {
+ {
+ .name = "TDM IN",
+ .id = MT8186_DAI_TDM_IN,
+ .capture = {
+ .stream_name = "TDM IN",
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = MTK_TDM_RATES,
+ .formats = MTK_TDM_FORMATS,
+ },
+ .ops = &mtk_dai_tdm_ops,
+ },
+};
+
+static struct mtk_afe_tdm_priv *init_tdm_priv_data(struct mtk_base_afe *afe)
+{
+ struct mtk_afe_tdm_priv *tdm_priv;
+
+ tdm_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_afe_tdm_priv),
+ GFP_KERNEL);
+ if (!tdm_priv)
+ return NULL;
+
+ tdm_priv->mclk_multiple = 512;
+ tdm_priv->mclk_id = MT8186_TDM_MCK;
+ tdm_priv->id = MT8186_DAI_TDM_IN;
+
+ return tdm_priv;
+}
+
+int mt8186_dai_tdm_register(struct mtk_base_afe *afe)
+{
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_tdm_priv *tdm_priv;
+ struct mtk_base_afe_dai *dai;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mtk_dai_tdm_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_tdm_driver);
+
+ dai->controls = mtk_dai_tdm_controls;
+ dai->num_controls = ARRAY_SIZE(mtk_dai_tdm_controls);
+ dai->dapm_widgets = mtk_dai_tdm_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_tdm_widgets);
+ dai->dapm_routes = mtk_dai_tdm_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_tdm_routes);
+
+ tdm_priv = init_tdm_priv_data(afe);
+ if (!tdm_priv)
+ return -ENOMEM;
+
+ afe_priv->dai_priv[MT8186_DAI_TDM_IN] = tdm_priv;
+
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt8186/mt8186-interconnection.h b/sound/soc/mediatek/mt8186/mt8186-interconnection.h
new file mode 100644
index 0000000..5b188d9
--- /dev/null
+++ b/sound/soc/mediatek/mt8186/mt8186-interconnection.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Mediatek MT8186 audio driver interconnection definition
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+ */
+
+#ifndef _MT8186_INTERCONNECTION_H_
+#define _MT8186_INTERCONNECTION_H_
+
+/* in port define */
+#define I_I2S0_CH1 0
+#define I_I2S0_CH2 1
+#define I_ADDA_UL_CH1 3
+#define I_ADDA_UL_CH2 4
+#define I_DL1_CH1 5
+#define I_DL1_CH2 6
+#define I_DL2_CH1 7
+#define I_DL2_CH2 8
+#define I_PCM_1_CAP_CH1 9
+#define I_GAIN1_OUT_CH1 10
+#define I_GAIN1_OUT_CH2 11
+#define I_GAIN2_OUT_CH1 12
+#define I_GAIN2_OUT_CH2 13
+#define I_PCM_2_CAP_CH1 14
+#define I_ADDA_UL_CH3 17
+#define I_ADDA_UL_CH4 18
+#define I_DL12_CH1 19
+#define I_DL12_CH2 20
+#define I_DL12_CH3 5
+#define I_DL12_CH4 6
+#define I_PCM_2_CAP_CH2 21
+#define I_PCM_1_CAP_CH2 22
+#define I_DL3_CH1 23
+#define I_DL3_CH2 24
+#define I_I2S2_CH1 25
+#define I_I2S2_CH2 26
+#define I_I2S2_CH3 27
+#define I_I2S2_CH4 28
+
+/* in port define >= 32 */
+#define I_32_OFFSET 32
+#define I_CONNSYS_I2S_CH1 (34 - I_32_OFFSET)
+#define I_CONNSYS_I2S_CH2 (35 - I_32_OFFSET)
+#define I_SRC_1_OUT_CH1 (36 - I_32_OFFSET)
+#define I_SRC_1_OUT_CH2 (37 - I_32_OFFSET)
+#define I_SRC_2_OUT_CH1 (38 - I_32_OFFSET)
+#define I_SRC_2_OUT_CH2 (39 - I_32_OFFSET)
+#define I_DL4_CH1 (40 - I_32_OFFSET)
+#define I_DL4_CH2 (41 - I_32_OFFSET)
+#define I_DL5_CH1 (42 - I_32_OFFSET)
+#define I_DL5_CH2 (43 - I_32_OFFSET)
+#define I_DL6_CH1 (44 - I_32_OFFSET)
+#define I_DL6_CH2 (45 - I_32_OFFSET)
+#define I_DL7_CH1 (46 - I_32_OFFSET)
+#define I_DL7_CH2 (47 - I_32_OFFSET)
+#define I_DL8_CH1 (48 - I_32_OFFSET)
+#define I_DL8_CH2 (49 - I_32_OFFSET)
+#define I_TDM_IN_CH1 (56 - I_32_OFFSET)
+#define I_TDM_IN_CH2 (57 - I_32_OFFSET)
+#define I_TDM_IN_CH3 (58 - I_32_OFFSET)
+#define I_TDM_IN_CH4 (59 - I_32_OFFSET)
+#define I_TDM_IN_CH5 (60 - I_32_OFFSET)
+#define I_TDM_IN_CH6 (61 - I_32_OFFSET)
+#define I_TDM_IN_CH7 (62 - I_32_OFFSET)
+#define I_TDM_IN_CH8 (63 - I_32_OFFSET)
+
+#endif
diff --git a/sound/soc/mediatek/mt8186/mt8186-misc-control.c b/sound/soc/mediatek/mt8186/mt8186-misc-control.c
new file mode 100644
index 0000000..2317de8
--- /dev/null
+++ b/sound/soc/mediatek/mt8186/mt8186-misc-control.c
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio Misc Control
+//
+// Copyright (c) 2022 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "../common/mtk-afe-fe-dai.h"
+#include "../common/mtk-afe-platform-driver.h"
+#include "mt8186-afe-common.h"
+
+static const char * const mt8186_sgen_mode_str[] = {
+ "I0I1", "I2", "I3I4", "I5I6",
+ "I7I8", "I9I22", "I10I11", "I12I13",
+ "I14I21", "I15I16", "I17I18", "I19I20",
+ "I23I24", "I25I26", "I27I28", "I33",
+ "I34I35", "I36I37", "I38I39", "I40I41",
+ "I42I43", "I44I45", "I46I47", "I48I49",
+ "I56I57", "I58I59", "I60I61", "I62I63",
+ "O0O1", "O2", "O3O4", "O5O6",
+ "O7O8", "O9O10", "O11", "O12",
+ "O13O14", "O15O16", "O17O18", "O19O20",
+ "O21O22", "O23O24", "O25", "O28O29",
+ "O34", "O35", "O32O33", "O36O37",
+ "O38O39", "O30O31", "O40O41", "O42O43",
+ "O44O45", "O46O47", "O48O49", "O50O51",
+ "O58O59", "O60O61", "O62O63", "O64O65",
+ "O66O67", "O68O69", "O26O27", "OFF",
+};
+
+static const int mt8186_sgen_mode_idx[] = {
+ 0, 2, 4, 6,
+ 8, 22, 10, 12,
+ 14, -1, 18, 20,
+ 24, 26, 28, 33,
+ 34, 36, 38, 40,
+ 42, 44, 46, 48,
+ 56, 58, 60, 62,
+ 128, 130, 132, 134,
+ 135, 138, 139, 140,
+ 142, 144, 166, 148,
+ 150, 152, 153, 156,
+ 162, 163, 160, 164,
+ 166, -1, 168, 170,
+ 172, 174, 176, 178,
+ 186, 188, 190, 192,
+ 194, 196, -1, -1,
+};
+
+static const char * const mt8186_sgen_rate_str[] = {
+ "8K", "11K", "12K", "16K",
+ "22K", "24K", "32K", "44K",
+ "48K", "88k", "96k", "176k",
+ "192k"
+};
+
+static const int mt8186_sgen_rate_idx[] = {
+ 0, 1, 2, 4,
+ 5, 6, 8, 9,
+ 10, 11, 12, 13,
+ 14
+};
+
+/* this order must match reg bit amp_div_ch1/2 */
+static const char * const mt8186_sgen_amp_str[] = {
+ "1/128", "1/64", "1/32", "1/16", "1/8", "1/4", "1/2", "1" };
+
+static int mt8186_sgen_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+
+ ucontrol->value.integer.value[0] = afe_priv->sgen_mode;
+
+ return 0;
+}
+
+static int mt8186_sgen_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ int mode;
+ int mode_idx;
+
+ if (ucontrol->value.enumerated.item[0] >= e->items)
+ return -EINVAL;
+
+ mode = ucontrol->value.integer.value[0];
+ mode_idx = mt8186_sgen_mode_idx[mode];
+
+ dev_dbg(afe->dev, "%s(), mode %d, mode_idx %d\n",
+ __func__, mode, mode_idx);
+
+ if (mode == afe_priv->sgen_mode)
+ return 0;
+
+ if (mode_idx >= 0) {
+ regmap_update_bits(afe->regmap, AFE_SINEGEN_CON2,
+ INNER_LOOP_BACK_MODE_MASK_SFT,
+ mode_idx << INNER_LOOP_BACK_MODE_SFT);
+ regmap_update_bits(afe->regmap, AFE_SINEGEN_CON0,
+ DAC_EN_MASK_SFT, BIT(DAC_EN_SFT));
+ } else {
+ /* disable sgen */
+ regmap_update_bits(afe->regmap, AFE_SINEGEN_CON0,
+ DAC_EN_MASK_SFT, 0);
+ regmap_update_bits(afe->regmap, AFE_SINEGEN_CON2,
+ INNER_LOOP_BACK_MODE_MASK_SFT,
+ 0x3f << INNER_LOOP_BACK_MODE_SFT);
+ }
+
+ afe_priv->sgen_mode = mode;
+
+ return 1;
+}
+
+static int mt8186_sgen_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+
+ ucontrol->value.integer.value[0] = afe_priv->sgen_rate;
+
+ return 0;
+}
+
+static int mt8186_sgen_rate_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ int rate;
+
+ if (ucontrol->value.enumerated.item[0] >= e->items)
+ return -EINVAL;
+
+ rate = ucontrol->value.integer.value[0];
+
+ dev_dbg(afe->dev, "%s(), rate %d\n", __func__, rate);
+
+ if (rate == afe_priv->sgen_rate)
+ return 0;
+
+ regmap_update_bits(afe->regmap, AFE_SINEGEN_CON0,
+ SINE_MODE_CH1_MASK_SFT,
+ mt8186_sgen_rate_idx[rate] << SINE_MODE_CH1_SFT);
+
+ regmap_update_bits(afe->regmap, AFE_SINEGEN_CON0,
+ SINE_MODE_CH2_MASK_SFT,
+ mt8186_sgen_rate_idx[rate] << SINE_MODE_CH2_SFT);
+
+ afe_priv->sgen_rate = rate;
+
+ return 1;
+}
+
+static int mt8186_sgen_amplitude_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+
+ ucontrol->value.integer.value[0] = afe_priv->sgen_amplitude;
+ return 0;
+}
+
+static int mt8186_sgen_amplitude_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8186_afe_private *afe_priv = afe->platform_priv;
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ int amplitude;
+
+ if (ucontrol->value.enumerated.item[0] >= e->items)
+ return -EINVAL;
+
+ amplitude = ucontrol->value.integer.value[0];
+ if (amplitude > AMP_DIV_CH1_MASK) {
+ dev_err(afe->dev, "%s(), amplitude %d invalid\n",
+ __func__, amplitude);
+ return -EINVAL;
+ }
+
+ dev_dbg(afe->dev, "%s(), amplitude %d\n", __func__, amplitude);
+
+ if (amplitude == afe_priv->sgen_amplitude)
+ return 0;
+
+ regmap_update_bits(afe->regmap, AFE_SINEGEN_CON0,
+ AMP_DIV_CH1_MASK_SFT,
+ amplitude << AMP_DIV_CH1_SFT);
+ regmap_update_bits(afe->regmap, AFE_SINEGEN_CON0,
+ AMP_DIV_CH2_MASK_SFT,
+ amplitude << AMP_DIV_CH2_SFT);
+
+ afe_priv->sgen_amplitude = amplitude;
+
+ return 1;
+}
+
+static const struct soc_enum mt8186_afe_sgen_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8186_sgen_mode_str),
+ mt8186_sgen_mode_str),
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8186_sgen_rate_str),
+ mt8186_sgen_rate_str),
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8186_sgen_amp_str),
+ mt8186_sgen_amp_str),
+};
+
+static const struct snd_kcontrol_new mt8186_afe_sgen_controls[] = {
+ SOC_ENUM_EXT("Audio_SineGen_Switch", mt8186_afe_sgen_enum[0],
+ mt8186_sgen_get, mt8186_sgen_set),
+ SOC_ENUM_EXT("Audio_SineGen_SampleRate", mt8186_afe_sgen_enum[1],
+ mt8186_sgen_rate_get, mt8186_sgen_rate_set),
+ SOC_ENUM_EXT("Audio_SineGen_Amplitude", mt8186_afe_sgen_enum[2],
+ mt8186_sgen_amplitude_get, mt8186_sgen_amplitude_set),
+ SOC_SINGLE("Audio_SineGen_Mute_Ch1", AFE_SINEGEN_CON0,
+ MUTE_SW_CH1_MASK_SFT, MUTE_SW_CH1_MASK, 0),
+ SOC_SINGLE("Audio_SineGen_Mute_Ch2", AFE_SINEGEN_CON0,
+ MUTE_SW_CH2_MASK_SFT, MUTE_SW_CH2_MASK, 0),
+ SOC_SINGLE("Audio_SineGen_Freq_Div_Ch1", AFE_SINEGEN_CON0,
+ FREQ_DIV_CH1_SFT, FREQ_DIV_CH1_MASK, 0),
+ SOC_SINGLE("Audio_SineGen_Freq_Div_Ch2", AFE_SINEGEN_CON0,
+ FREQ_DIV_CH2_SFT, FREQ_DIV_CH2_MASK, 0),
+};
+
+int mt8186_add_misc_control(struct snd_soc_component *component)
+{
+ snd_soc_add_component_controls(component,
+ mt8186_afe_sgen_controls,
+ ARRAY_SIZE(mt8186_afe_sgen_controls));
+
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt8186/mt8186-reg.h b/sound/soc/mediatek/mt8186/mt8186-reg.h
new file mode 100644
index 0000000..53c3eb7
--- /dev/null
+++ b/sound/soc/mediatek/mt8186/mt8186-reg.h
@@ -0,0 +1,2913 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * mt8186-reg.h -- Mediatek 8186 audio driver reg definition
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+ */
+
+#ifndef _MT8186_REG_H_
+#define _MT8186_REG_H_
+
+/* reg bit enum */
+enum {
+ MT8186_MEMIF_PBUF_SIZE_32_BYTES,
+ MT8186_MEMIF_PBUF_SIZE_64_BYTES,
+ MT8186_MEMIF_PBUF_SIZE_128_BYTES,
+ MT8186_MEMIF_PBUF_SIZE_256_BYTES,
+ MT8186_MEMIF_PBUF_SIZE_NUM,
+};
+
+/*****************************************************************************
+ * R E G I S T E R D E F I N I T I O N
+ *****************************************************************************/
+/* AUDIO_TOP_CON0 */
+#define RESERVED_SFT 31
+#define RESERVED_MASK_SFT BIT(31)
+#define AHB_IDLE_EN_INT_SFT 30
+#define AHB_IDLE_EN_INT_MASK_SFT BIT(30)
+#define AHB_IDLE_EN_EXT_SFT 29
+#define AHB_IDLE_EN_EXT_MASK_SFT BIT(29)
+#define PDN_NLE_SFT 28
+#define PDN_NLE_MASK_SFT BIT(28)
+#define PDN_TML_SFT 27
+#define PDN_TML_MASK_SFT BIT(27)
+#define PDN_DAC_PREDIS_SFT 26
+#define PDN_DAC_PREDIS_MASK_SFT BIT(26)
+#define PDN_DAC_SFT 25
+#define PDN_DAC_MASK_SFT BIT(25)
+#define PDN_ADC_SFT 24
+#define PDN_ADC_MASK_SFT BIT(24)
+#define PDN_TDM_CK_SFT 20
+#define PDN_TDM_CK_MASK_SFT BIT(20)
+#define PDN_APLL_TUNER_SFT 19
+#define PDN_APLL_TUNER_MASK_SFT BIT(19)
+#define PDN_APLL2_TUNER_SFT 18
+#define PDN_APLL2_TUNER_MASK_SFT BIT(18)
+#define APB3_SEL_SFT 14
+#define APB3_SEL_MASK_SFT BIT(14)
+#define APB_R2T_SFT 13
+#define APB_R2T_MASK_SFT BIT(13)
+#define APB_W2T_SFT 12
+#define APB_W2T_MASK_SFT BIT(12)
+#define PDN_24M_SFT 9
+#define PDN_24M_MASK_SFT BIT(9)
+#define PDN_22M_SFT 8
+#define PDN_22M_MASK_SFT BIT(8)
+#define PDN_AFE_SFT 2
+#define PDN_AFE_MASK_SFT BIT(2)
+
+/* AUDIO_TOP_CON1 */
+#define PDN_3RD_DAC_HIRES_SFT 31
+#define PDN_3RD_DAC_HIRES_MASK_SFT BIT(31)
+#define PDN_3RD_DAC_TML_SFT 30
+#define PDN_3RD_DAC_TML_MASK_SFT BIT(30)
+#define PDN_3RD_DAC_PREDIS_SFT 29
+#define PDN_3RD_DAC_PREDIS_MASK_SFT BIT(29)
+#define PDN_3RD_DAC_SFT 28
+#define PDN_3RD_DAC_MASK_SFT BIT(28)
+#define I2S_SOFT_RST5_SFT 22
+#define I2S_SOFT_RST5_MASK_SFT BIT(22)
+#define PDN_ADDA6_ADC_HIRES_SFT 21
+#define PDN_ADDA6_ADC_HIRES_MASK_SFT BIT(21)
+#define PDN_ADDA6_ADC_SFT 20
+#define PDN_ADDA6_ADC_MASK_SFT BIT(20)
+#define PDN_ADC_HIRES_TML_SFT 17
+#define PDN_ADC_HIRES_TML_MASK_SFT BIT(17)
+#define PDN_ADC_HIRES_SFT 16
+#define PDN_ADC_HIRES_MASK_SFT BIT(16)
+#define PDN_DAC_HIRES_SFT 15
+#define PDN_DAC_HIRES_MASK_SFT BIT(15)
+#define PDN_GENERAL2_ASRC_SFT 14
+#define PDN_GENERAL2_ASRC_MASK_SFT BIT(14)
+#define PDN_GENERAL1_ASRC_SFT 13
+#define PDN_GENERAL1_ASRC_MASK_SFT BIT(13)
+#define PDN_CONNSYS_I2S_ASRC_SFT 12
+#define PDN_CONNSYS_I2S_ASRC_MASK_SFT BIT(12)
+#define I2S4_BCLK_SW_CG_SFT 7
+#define I2S4_BCLK_SW_CG_MASK_SFT BIT(7)
+#define I2S3_BCLK_SW_CG_SFT 6
+#define I2S3_BCLK_SW_CG_MASK_SFT BIT(6)
+#define I2S2_BCLK_SW_CG_SFT 5
+#define I2S2_BCLK_SW_CG_MASK_SFT BIT(5)
+#define I2S1_BCLK_SW_CG_SFT 4
+#define I2S1_BCLK_SW_CG_MASK_SFT BIT(4)
+#define I2S_SOFT_RST2_SFT 2
+#define I2S_SOFT_RST2_MASK_SFT BIT(2)
+#define I2S_SOFT_RST_SFT 1
+#define I2S_SOFT_RST_MASK_SFT BIT(1)
+
+/* AUDIO_TOP_CON3 */
+#define BUSY_SFT 31
+#define BUSY_MASK_SFT BIT(31)
+#define OS_DISABLE_SFT 30
+#define OS_DISABLE_MASK_SFT BIT(30)
+#define CG_DISABLE_SFT 29
+#define CG_DISABLE_MASK_SFT BIT(29)
+#define CLEAR_FLAG_SFT 0
+#define CLEAR_FLAG_MASK_SFT BIT(0)
+
+/* AFE_DAC_CON0 */
+#define VUL12_ON_SFT 31
+#define VUL12_ON_MASK_SFT BIT(31)
+#define MOD_DAI_ON_SFT 30
+#define MOD_DAI_ON_MASK_SFT BIT(30)
+#define DAI_ON_SFT 29
+#define DAI_ON_MASK_SFT BIT(29)
+#define DAI2_ON_SFT 28
+#define DAI2_ON_MASK_SFT BIT(28)
+#define VUL6_ON_SFT 23
+#define VUL6_ON_MASK_SFT BIT(23)
+#define VUL5_ON_SFT 22
+#define VUL5_ON_MASK_SFT BIT(22)
+#define VUL4_ON_SFT 21
+#define VUL4_ON_MASK_SFT BIT(21)
+#define VUL3_ON_SFT 20
+#define VUL3_ON_MASK_SFT BIT(20)
+#define VUL2_ON_SFT 19
+#define VUL2_ON_MASK_SFT BIT(19)
+#define VUL_ON_SFT 18
+#define VUL_ON_MASK_SFT BIT(18)
+#define AWB2_ON_SFT 17
+#define AWB2_ON_MASK_SFT BIT(17)
+#define AWB_ON_SFT 16
+#define AWB_ON_MASK_SFT BIT(16)
+#define DL12_ON_SFT 15
+#define DL12_ON_MASK_SFT BIT(15)
+#define DL8_ON_SFT 11
+#define DL8_ON_MASK_SFT BIT(11)
+#define DL7_ON_SFT 10
+#define DL7_ON_MASK_SFT BIT(10)
+#define DL6_ON_SFT 9
+#define DL6_ON_MASK_SFT BIT(9)
+#define DL5_ON_SFT 8
+#define DL5_ON_MASK_SFT BIT(8)
+#define DL4_ON_SFT 7
+#define DL4_ON_MASK_SFT BIT(7)
+#define DL3_ON_SFT 6
+#define DL3_ON_MASK_SFT BIT(6)
+#define DL2_ON_SFT 5
+#define DL2_ON_MASK_SFT BIT(5)
+#define DL1_ON_SFT 4
+#define DL1_ON_MASK_SFT BIT(4)
+#define AUDIO_AFE_ON_SFT 0
+#define AUDIO_AFE_ON_MASK_SFT BIT(0)
+
+/* AFE_DAC_MON */
+#define AFE_ON_RETM_SFT 0
+#define AFE_ON_RETM_MASK_SFT BIT(0)
+
+/* AFE_I2S_CON */
+#define BCK_NEG_EG_LATCH_SFT 30
+#define BCK_NEG_EG_LATCH_MASK_SFT BIT(30)
+#define BCK_INV_SFT 29
+#define BCK_INV_MASK_SFT BIT(29)
+#define I2SIN_PAD_SEL_SFT 28
+#define I2SIN_PAD_SEL_MASK_SFT BIT(28)
+#define I2S_LOOPBACK_SFT 20
+#define I2S_LOOPBACK_MASK_SFT BIT(20)
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT BIT(17)
+#define I2S1_HD_EN_SFT 12
+#define I2S1_HD_EN_MASK_SFT BIT(12)
+#define I2S_OUT_MODE_SFT 8
+#define I2S_OUT_MODE_MASK_SFT GENMASK(11, 8)
+#define INV_PAD_CTRL_SFT 7
+#define INV_PAD_CTRL_MASK_SFT BIT(7)
+#define I2S_BYPSRC_SFT 6
+#define I2S_BYPSRC_MASK_SFT BIT(6)
+#define INV_LRCK_SFT 5
+#define INV_LRCK_MASK_SFT BIT(5)
+#define I2S_FMT_SFT 3
+#define I2S_FMT_MASK_SFT BIT(3)
+#define I2S_SRC_SFT 2
+#define I2S_SRC_MASK_SFT BIT(2)
+#define I2S_WLEN_SFT 1
+#define I2S_WLEN_MASK_SFT BIT(1)
+#define I2S_EN_SFT 0
+#define I2S_EN_MASK_SFT BIT(0)
+
+/* AFE_I2S_CON1 */
+#define I2S2_LR_SWAP_SFT 31
+#define I2S2_LR_SWAP_MASK_SFT BIT(31)
+#define I2S2_SEL_O19_O20_SFT 18
+#define I2S2_SEL_O19_O20_MASK_SFT BIT(18)
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT BIT(17)
+#define I2S2_SEL_O03_O04_SFT 16
+#define I2S2_SEL_O03_O04_MASK_SFT BIT(16)
+#define I2S2_HD_EN_SFT 12
+#define I2S2_HD_EN_MASK_SFT BIT(12)
+#define I2S2_OUT_MODE_SFT 8
+#define I2S2_OUT_MODE_MASK_SFT GENMASK(11, 8)
+#define INV_LRCK_SFT 5
+#define INV_LRCK_MASK_SFT BIT(5)
+#define I2S2_FMT_SFT 3
+#define I2S2_FMT_MASK_SFT BIT(3)
+#define I2S2_WLEN_SFT 1
+#define I2S2_WLEN_MASK_SFT BIT(1)
+#define I2S2_EN_SFT 0
+#define I2S2_EN_MASK_SFT BIT(0)
+
+/* AFE_I2S_CON2 */
+#define I2S3_LR_SWAP_SFT 31
+#define I2S3_LR_SWAP_MASK_SFT BIT(31)
+#define I2S3_UPDATE_WORD_SFT 24
+#define I2S3_UPDATE_WORD_MASK_SFT GENMASK(28, 24)
+#define I2S3_BCK_INV_SFT 23
+#define I2S3_BCK_INV_MASK_SFT BIT(23)
+#define I2S3_FPGA_BIT_TEST_SFT 22
+#define I2S3_FPGA_BIT_TEST_MASK_SFT BIT(22)
+#define I2S3_FPGA_BIT_SFT 21
+#define I2S3_FPGA_BIT_MASK_SFT BIT(21)
+#define I2S3_LOOPBACK_SFT 20
+#define I2S3_LOOPBACK_MASK_SFT BIT(20)
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT BIT(17)
+#define I2S3_HD_EN_SFT 12
+#define I2S3_HD_EN_MASK_SFT BIT(12)
+#define I2S3_OUT_MODE_SFT 8
+#define I2S3_OUT_MODE_MASK_SFT GENMASK(11, 8)
+#define I2S3_FMT_SFT 3
+#define I2S3_FMT_MASK_SFT BIT(3)
+#define I2S3_WLEN_SFT 1
+#define I2S3_WLEN_MASK_SFT BIT(1)
+#define I2S3_EN_SFT 0
+#define I2S3_EN_MASK_SFT BIT(0)
+
+/* AFE_I2S_CON3 */
+#define I2S4_LR_SWAP_SFT 31
+#define I2S4_LR_SWAP_MASK_SFT BIT(31)
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT BIT(17)
+#define I2S4_HD_EN_SFT 12
+#define I2S4_HD_EN_MASK_SFT BIT(12)
+#define I2S4_OUT_MODE_SFT 8
+#define I2S4_OUT_MODE_MASK_SFT GENMASK(11, 8)
+#define INV_LRCK_SFT 5
+#define INV_LRCK_MASK_SFT BIT(5)
+#define I2S4_FMT_SFT 3
+#define I2S4_FMT_MASK_SFT BIT(3)
+#define I2S4_WLEN_SFT 1
+#define I2S4_WLEN_MASK_SFT BIT(1)
+#define I2S4_EN_SFT 0
+#define I2S4_EN_MASK_SFT BIT(0)
+
+/* AFE_I2S_CON4 */
+#define I2S_LOOPBACK_SFT 20
+#define I2S_LOOPBACK_MASK 0x1
+#define I2S_LOOPBACK_MASK_SFT BIT(20)
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK 0x1
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT BIT(17)
+#define INV_LRCK_SFT 5
+#define INV_LRCK_MASK 0x1
+#define INV_LRCK_MASK_SFT BIT(5)
+
+/* AFE_CONNSYS_I2S_CON */
+#define BCK_NEG_EG_LATCH_SFT 30
+#define BCK_NEG_EG_LATCH_MASK_SFT BIT(30)
+#define BCK_INV_SFT 29
+#define BCK_INV_MASK_SFT BIT(29)
+#define I2SIN_PAD_SEL_SFT 28
+#define I2SIN_PAD_SEL_MASK_SFT BIT(28)
+#define I2S_LOOPBACK_SFT 20
+#define I2S_LOOPBACK_MASK_SFT BIT(20)
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT BIT(17)
+#define I2S_MODE_SFT 8
+#define I2S_MODE_MASK_SFT GENMASK(11, 8)
+#define INV_PAD_CTRL_SFT 7
+#define INV_PAD_CTRL_MASK_SFT BIT(7)
+#define I2S_BYPSRC_SFT 6
+#define I2S_BYPSRC_MASK_SFT BIT(6)
+#define INV_LRCK_SFT 5
+#define INV_LRCK_MASK_SFT BIT(5)
+#define I2S_FMT_SFT 3
+#define I2S_FMT_MASK_SFT BIT(3)
+#define I2S_SRC_SFT 2
+#define I2S_SRC_MASK_SFT BIT(2)
+#define I2S_WLEN_SFT 1
+#define I2S_WLEN_MASK_SFT BIT(1)
+#define I2S_EN_SFT 0
+#define I2S_EN_MASK_SFT BIT(0)
+
+/* AFE_ASRC_2CH_CON2 */
+#define CHSET_O16BIT_SFT 19
+#define CHSET_O16BIT_MASK_SFT BIT(19)
+#define CHSET_CLR_IIR_HISTORY_SFT 17
+#define CHSET_CLR_IIR_HISTORY_MASK_SFT BIT(17)
+#define CHSET_IS_MONO_SFT 16
+#define CHSET_IS_MONO_MASK_SFT BIT(16)
+#define CHSET_IIR_EN_SFT 11
+#define CHSET_IIR_EN_MASK_SFT BIT(11)
+#define CHSET_IIR_STAGE_SFT 8
+#define CHSET_IIR_STAGE_MASK_SFT GENMASK(10, 8)
+#define CHSET_STR_CLR_SFT 5
+#define CHSET_STR_CLR_MASK_SFT BIT(5)
+#define CHSET_ON_SFT 2
+#define CHSET_ON_MASK_SFT BIT(2)
+#define COEFF_SRAM_CTRL_SFT 1
+#define COEFF_SRAM_CTRL_MASK_SFT BIT(1)
+#define ASM_ON_SFT 0
+#define ASM_ON_MASK_SFT BIT(0)
+
+/* AFE_GAIN1_CON0 */
+#define GAIN1_SAMPLE_PER_STEP_SFT 8
+#define GAIN1_SAMPLE_PER_STEP_MASK_SFT GENMASK(15, 8)
+#define GAIN1_MODE_SFT 4
+#define GAIN1_MODE_MASK_SFT GENMASK(7, 4)
+#define GAIN1_ON_SFT 0
+#define GAIN1_ON_MASK_SFT BIT(0)
+
+/* AFE_GAIN1_CON1 */
+#define GAIN1_TARGET_SFT 0
+#define GAIN1_TARGET_MASK 0xfffffff
+#define GAIN1_TARGET_MASK_SFT GENMASK(27, 0)
+
+/* AFE_GAIN2_CON0 */
+#define GAIN2_SAMPLE_PER_STEP_SFT 8
+#define GAIN2_SAMPLE_PER_STEP_MASK_SFT GENMASK(15, 8)
+#define GAIN2_MODE_SFT 4
+#define GAIN2_MODE_MASK_SFT GENMASK(7, 4)
+#define GAIN2_ON_SFT 0
+#define GAIN2_ON_MASK_SFT BIT(0)
+
+/* AFE_GAIN2_CON1 */
+#define GAIN2_TARGET_SFT 0
+#define GAIN2_TARGET_MASK 0xfffffff
+#define GAIN2_TARGET_MASK_SFT GENMASK(27, 0)
+
+/* AFE_GAIN1_CUR */
+#define AFE_GAIN1_CUR_SFT 0
+#define AFE_GAIN1_CUR_MASK_SFT GENMASK(27, 0)
+
+/* AFE_GAIN2_CUR */
+#define AFE_GAIN2_CUR_SFT 0
+#define AFE_GAIN2_CUR_MASK_SFT GENMASK(27, 0)
+
+/* PCM_INTF_CON1 */
+#define PCM_FIX_VALUE_SEL_SFT 31
+#define PCM_FIX_VALUE_SEL_MASK_SFT BIT(31)
+#define PCM_BUFFER_LOOPBACK_SFT 30
+#define PCM_BUFFER_LOOPBACK_MASK_SFT BIT(30)
+#define PCM_PARALLEL_LOOPBACK_SFT 29
+#define PCM_PARALLEL_LOOPBACK_MASK_SFT BIT(29)
+#define PCM_SERIAL_LOOPBACK_SFT 28
+#define PCM_SERIAL_LOOPBACK_MASK_SFT BIT(28)
+#define PCM_DAI_PCM_LOOPBACK_SFT 27
+#define PCM_DAI_PCM_LOOPBACK_MASK_SFT BIT(27)
+#define PCM_I2S_PCM_LOOPBACK_SFT 26
+#define PCM_I2S_PCM_LOOPBACK_MASK_SFT BIT(26)
+#define PCM_SYNC_DELSEL_SFT 25
+#define PCM_SYNC_DELSEL_MASK_SFT BIT(25)
+#define PCM_TX_LR_SWAP_SFT 24
+#define PCM_TX_LR_SWAP_MASK_SFT BIT(24)
+#define PCM_SYNC_OUT_INV_SFT 23
+#define PCM_SYNC_OUT_INV_MASK_SFT BIT(23)
+#define PCM_BCLK_OUT_INV_SFT 22
+#define PCM_BCLK_OUT_INV_MASK_SFT BIT(22)
+#define PCM_SYNC_IN_INV_SFT 21
+#define PCM_SYNC_IN_INV_MASK_SFT BIT(21)
+#define PCM_BCLK_IN_INV_SFT 20
+#define PCM_BCLK_IN_INV_MASK_SFT BIT(20)
+#define PCM_TX_LCH_RPT_SFT 19
+#define PCM_TX_LCH_RPT_MASK_SFT BIT(19)
+#define PCM_VBT_16K_MODE_SFT 18
+#define PCM_VBT_16K_MODE_MASK_SFT BIT(18)
+#define PCM_EXT_MODEM_SFT 17
+#define PCM_EXT_MODEM_MASK_SFT BIT(17)
+#define PCM_24BIT_SFT 16
+#define PCM_24BIT_MASK_SFT BIT(16)
+#define PCM_WLEN_SFT 14
+#define PCM_WLEN_MASK_SFT GENMASK(15, 14)
+#define PCM_SYNC_LENGTH_SFT 9
+#define PCM_SYNC_LENGTH_MASK_SFT GENMASK(13, 9)
+#define PCM_SYNC_TYPE_SFT 8
+#define PCM_SYNC_TYPE_MASK_SFT BIT(8)
+#define PCM_BT_MODE_SFT 7
+#define PCM_BT_MODE_MASK_SFT BIT(7)
+#define PCM_BYP_ASRC_SFT 6
+#define PCM_BYP_ASRC_MASK_SFT BIT(6)
+#define PCM_SLAVE_SFT 5
+#define PCM_SLAVE_MASK_SFT BIT(5)
+#define PCM_MODE_SFT 3
+#define PCM_MODE_MASK_SFT GENMASK(4, 3)
+#define PCM_FMT_SFT 1
+#define PCM_FMT_MASK_SFT GENMASK(2, 1)
+#define PCM_EN_SFT 0
+#define PCM_EN_MASK_SFT BIT(0)
+
+/* PCM_INTF_CON2 */
+#define PCM1_TX_FIFO_OV_SFT 31
+#define PCM1_TX_FIFO_OV_MASK_SFT BIT(31)
+#define PCM1_RX_FIFO_OV_SFT 30
+#define PCM1_RX_FIFO_OV_MASK_SFT BIT(30)
+#define PCM2_TX_FIFO_OV_SFT 29
+#define PCM2_TX_FIFO_OV_MASK_SFT BIT(29)
+#define PCM2_RX_FIFO_OV_SFT 28
+#define PCM2_RX_FIFO_OV_MASK_SFT BIT(28)
+#define PCM1_SYNC_GLITCH_SFT 27
+#define PCM1_SYNC_GLITCH_MASK_SFT BIT(27)
+#define PCM2_SYNC_GLITCH_SFT 26
+#define PCM2_SYNC_GLITCH_MASK_SFT BIT(26)
+#define TX3_RCH_DBG_MODE_SFT 17
+#define TX3_RCH_DBG_MODE_MASK_SFT BIT(17)
+#define PCM1_PCM2_LOOPBACK_SFT 16
+#define PCM1_PCM2_LOOPBACK_MASK_SFT BIT(16)
+#define DAI_PCM_LOOPBACK_CH_SFT 14
+#define DAI_PCM_LOOPBACK_CH_MASK_SFT GENMASK(15, 14)
+#define I2S_PCM_LOOPBACK_CH_SFT 12
+#define I2S_PCM_LOOPBACK_CH_MASK_SFT GENMASK(13, 12)
+#define TX_FIX_VALUE_SFT 0
+#define TX_FIX_VALUE_MASK_SFT GENMASK(7, 0)
+
+/* PCM2_INTF_CON */
+#define PCM2_TX_FIX_VALUE_SFT 24
+#define PCM2_TX_FIX_VALUE_MASK_SFT GENMASK(31, 24)
+#define PCM2_FIX_VALUE_SEL_SFT 23
+#define PCM2_FIX_VALUE_SEL_MASK_SFT BIT(23)
+#define PCM2_BUFFER_LOOPBACK_SFT 22
+#define PCM2_BUFFER_LOOPBACK_MASK_SFT BIT(22)
+#define PCM2_PARALLEL_LOOPBACK_SFT 21
+#define PCM2_PARALLEL_LOOPBACK_MASK_SFT BIT(21)
+#define PCM2_SERIAL_LOOPBACK_SFT 20
+#define PCM2_SERIAL_LOOPBACK_MASK_SFT BIT(20)
+#define PCM2_DAI_PCM_LOOPBACK_SFT 19
+#define PCM2_DAI_PCM_LOOPBACK_MASK_SFT BIT(19)
+#define PCM2_I2S_PCM_LOOPBACK_SFT 18
+#define PCM2_I2S_PCM_LOOPBACK_MASK_SFT BIT(18)
+#define PCM2_SYNC_DELSEL_SFT 17
+#define PCM2_SYNC_DELSEL_MASK_SFT BIT(17)
+#define PCM2_TX_LR_SWAP_SFT 16
+#define PCM2_TX_LR_SWAP_MASK_SFT BIT(16)
+#define PCM2_SYNC_IN_INV_SFT 15
+#define PCM2_SYNC_IN_INV_MASK_SFT BIT(15)
+#define PCM2_BCLK_IN_INV_SFT 14
+#define PCM2_BCLK_IN_INV_MASK_SFT BIT(14)
+#define PCM2_TX_LCH_RPT_SFT 13
+#define PCM2_TX_LCH_RPT_MASK_SFT BIT(13)
+#define PCM2_VBT_16K_MODE_SFT 12
+#define PCM2_VBT_16K_MODE_MASK_SFT BIT(12)
+#define PCM2_LOOPBACK_CH_SEL_SFT 10
+#define PCM2_LOOPBACK_CH_SEL_MASK_SFT GENMASK(11, 10)
+#define PCM2_TX2_BT_MODE_SFT 8
+#define PCM2_TX2_BT_MODE_MASK_SFT BIT(8)
+#define PCM2_BT_MODE_SFT 7
+#define PCM2_BT_MODE_MASK_SFT BIT(7)
+#define PCM2_AFIFO_SFT 6
+#define PCM2_AFIFO_MASK_SFT BIT(6)
+#define PCM2_WLEN_SFT 5
+#define PCM2_WLEN_MASK_SFT BIT(5)
+#define PCM2_MODE_SFT 3
+#define PCM2_MODE_MASK_SFT GENMASK(4, 3)
+#define PCM2_FMT_SFT 1
+#define PCM2_FMT_MASK_SFT GENMASK(2, 1)
+#define PCM2_EN_SFT 0
+#define PCM2_EN_MASK_SFT BIT(0)
+
+// AFE_CM1_CON
+#define CHANNEL_MERGE0_DEBUG_MODE_SFT (31)
+#define CHANNEL_MERGE0_DEBUG_MODE_MASK_SFT BIT(31)
+#define VUL3_BYPASS_CM_SFT (30)
+#define VUL3_BYPASS_CM_MASK (0x1)
+#define VUL3_BYPASS_CM_MASK_SFT BIT(30)
+#define CM1_DEBUG_MODE_SEL_SFT (29)
+#define CM1_DEBUG_MODE_SEL_MASK_SFT BIT(29)
+#define CHANNEL_MERGE0_UPDATE_CNT_SFT (16)
+#define CHANNEL_MERGE0_UPDATE_CNT_MASK_SFT GENMASK(28, 16)
+#define CM1_FS_SELECT_SFT (8)
+#define CM1_FS_SELECT_MASK_SFT GENMASK(12, 8)
+#define CHANNEL_MERGE0_CHNUM_SFT (3)
+#define CHANNEL_MERGE0_CHNUM_MASK_SFT GENMASK(7, 3)
+#define CHANNEL_MERGE0_BYTE_SWAP_SFT (1)
+#define CHANNEL_MERGE0_BYTE_SWAP_MASK_SFT BIT(1)
+#define CHANNEL_MERGE0_EN_SFT (0)
+#define CHANNEL_MERGE0_EN_MASK_SFT BIT(0)
+
+/* AFE_ADDA_MTKAIF_CFG0 */
+#define MTKAIF_RXIF_CLKINV_ADC_SFT 31
+#define MTKAIF_RXIF_CLKINV_ADC_MASK_SFT BIT(31)
+#define MTKAIF_RXIF_BYPASS_SRC_SFT 17
+#define MTKAIF_RXIF_BYPASS_SRC_MASK_SFT BIT(17)
+#define MTKAIF_RXIF_PROTOCOL2_SFT 16
+#define MTKAIF_RXIF_PROTOCOL2_MASK_SFT BIT(16)
+#define MTKAIF_TXIF_BYPASS_SRC_SFT 5
+#define MTKAIF_TXIF_BYPASS_SRC_MASK_SFT BIT(5)
+#define MTKAIF_TXIF_PROTOCOL2_SFT 4
+#define MTKAIF_TXIF_PROTOCOL2_MASK_SFT BIT(4)
+#define MTKAIF_TXIF_8TO5_SFT 2
+#define MTKAIF_TXIF_8TO5_MASK_SFT BIT(2)
+#define MTKAIF_RXIF_8TO5_SFT 1
+#define MTKAIF_RXIF_8TO5_MASK_SFT BIT(1)
+#define MTKAIF_IF_LOOPBACK1_SFT 0
+#define MTKAIF_IF_LOOPBACK1_MASK_SFT BIT(0)
+
+/* AFE_ADDA_MTKAIF_RX_CFG2 */
+#define MTKAIF_RXIF_DETECT_ON_PROTOCOL2_SFT 16
+#define MTKAIF_RXIF_DETECT_ON_PROTOCOL2_MASK_SFT BIT(16)
+#define MTKAIF_RXIF_DELAY_CYCLE_SFT 12
+#define MTKAIF_RXIF_DELAY_CYCLE_MASK_SFT GENMASK(15, 12)
+#define MTKAIF_RXIF_DELAY_DATA_SFT 8
+#define MTKAIF_RXIF_DELAY_DATA_MASK 0x1
+#define MTKAIF_RXIF_DELAY_DATA_MASK_SFT BIT(8)
+#define MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_SFT 4
+#define MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_MASK_SFT GENMASK(6, 4)
+
+/* AFE_ADDA_DL_SRC2_CON0 */
+#define DL_2_INPUT_MODE_CTL_SFT 28
+#define DL_2_INPUT_MODE_CTL_MASK_SFT GENMASK(31, 28)
+#define DL_2_CH1_SATURATION_EN_CTL_SFT 27
+#define DL_2_CH1_SATURATION_EN_CTL_MASK_SFT BIT(27)
+#define DL_2_CH2_SATURATION_EN_CTL_SFT 26
+#define DL_2_CH2_SATURATION_EN_CTL_MASK_SFT BIT(26)
+#define DL_2_OUTPUT_SEL_CTL_SFT 24
+#define DL_2_OUTPUT_SEL_CTL_MASK_SFT GENMASK(25, 24)
+#define DL_2_FADEIN_0START_EN_SFT 16
+#define DL_2_FADEIN_0START_EN_MASK_SFT GENMASK(17, 16)
+#define DL_DISABLE_HW_CG_CTL_SFT 15
+#define DL_DISABLE_HW_CG_CTL_MASK_SFT BIT(15)
+#define C_DATA_EN_SEL_CTL_PRE_SFT 14
+#define C_DATA_EN_SEL_CTL_PRE_MASK_SFT BIT(14)
+#define DL_2_SIDE_TONE_ON_CTL_PRE_SFT 13
+#define DL_2_SIDE_TONE_ON_CTL_PRE_MASK_SFT BIT(13)
+#define DL_2_MUTE_CH1_OFF_CTL_PRE_SFT 12
+#define DL_2_MUTE_CH1_OFF_CTL_PRE_MASK_SFT BIT(12)
+#define DL_2_MUTE_CH2_OFF_CTL_PRE_SFT 11
+#define DL_2_MUTE_CH2_OFF_CTL_PRE_MASK_SFT BIT(11)
+#define DL2_ARAMPSP_CTL_PRE_SFT 9
+#define DL2_ARAMPSP_CTL_PRE_MASK_SFT GENMASK(10, 9)
+#define DL_2_IIRMODE_CTL_PRE_SFT 6
+#define DL_2_IIRMODE_CTL_PRE_MASK_SFT GENMASK(8, 6)
+#define DL_2_VOICE_MODE_CTL_PRE_SFT 5
+#define DL_2_VOICE_MODE_CTL_PRE_MASK_SFT BIT(5)
+#define D2_2_MUTE_CH1_ON_CTL_PRE_SFT 4
+#define D2_2_MUTE_CH1_ON_CTL_PRE_MASK_SFT BIT(4)
+#define D2_2_MUTE_CH2_ON_CTL_PRE_SFT 3
+#define D2_2_MUTE_CH2_ON_CTL_PRE_MASK_SFT BIT(3)
+#define DL_2_IIR_ON_CTL_PRE_SFT 2
+#define DL_2_IIR_ON_CTL_PRE_MASK_SFT BIT(2)
+#define DL_2_GAIN_ON_CTL_PRE_SFT 1
+#define DL_2_GAIN_ON_CTL_PRE_MASK_SFT BIT(1)
+#define DL_2_SRC_ON_CTL_PRE_SFT 0
+#define DL_2_SRC_ON_CTL_PRE_MASK_SFT BIT(0)
+
+/* AFE_ADDA_DL_SRC2_CON1 */
+#define DL_2_GAIN_CTL_PRE_SFT 16
+#define DL_2_GAIN_CTL_PRE_MASK 0xffff
+#define DL_2_GAIN_CTL_PRE_MASK_SFT GENMASK(31, 16)
+#define DL_2_GAIN_MODE_CTL_SFT 0
+#define DL_2_GAIN_MODE_CTL_MASK_SFT BIT(0)
+
+/* AFE_ADDA_UL_SRC_CON0 */
+#define ULCF_CFG_EN_CTL_SFT 31
+#define ULCF_CFG_EN_CTL_MASK_SFT BIT(31)
+#define UL_DMIC_PHASE_SEL_CH1_SFT 27
+#define UL_DMIC_PHASE_SEL_CH1_MASK_SFT GENMASK(29, 27)
+#define UL_DMIC_PHASE_SEL_CH2_SFT 24
+#define UL_DMIC_PHASE_SEL_CH2_MASK_SFT GENMASK(26, 24)
+#define UL_MODE_3P25M_CH2_CTL_SFT 22
+#define UL_MODE_3P25M_CH2_CTL_MASK_SFT BIT(22)
+#define UL_MODE_3P25M_CH1_CTL_SFT 21
+#define UL_MODE_3P25M_CH1_CTL_MASK_SFT BIT(21)
+#define UL_VOICE_MODE_CH1_CH2_CTL_SFT 17
+#define UL_VOICE_MODE_CH1_CH2_CTL_MASK_SFT GENMASK(19, 17)
+#define UL_AP_DMIC_ON_SFT 16
+#define UL_AP_DMIC_ON_MASK_SFT BIT(16)
+#define DMIC_LOW_POWER_CTL_SFT 14
+#define DMIC_LOW_POWER_CTL_MASK_SFT GENMASK(15, 14)
+#define UL_DISABLE_HW_CG_CTL_SFT 12
+#define UL_DISABLE_HW_CG_CTL_MASK_SFT BIT(12)
+#define UL_IIR_ON_TMP_CTL_SFT 10
+#define UL_IIR_ON_TMP_CTL_MASK_SFT BIT(10)
+#define UL_IIRMODE_CTL_SFT 7
+#define UL_IIRMODE_CTL_MASK_SFT GENMASK(9, 7)
+#define DIGMIC_4P33M_SEL_SFT 6
+#define DIGMIC_4P33M_SEL_MASK_SFT BIT(6)
+#define DIGMIC_3P25M_1P625M_SEL_SFT 5
+#define DIGMIC_3P25M_1P625M_SEL_MASK_SFT BIT(5)
+#define UL_LOOP_BACK_MODE_SFT 2
+#define UL_LOOP_BACK_MODE_MASK_SFT BIT(2)
+#define UL_SDM_3_LEVEL_SFT 1
+#define UL_SDM_3_LEVEL_MASK_SFT BIT(1)
+#define UL_SRC_ON_CTL_SFT 0
+#define UL_SRC_ON_CTL_MASK_SFT BIT(0)
+
+/* AFE_ADDA_UL_SRC_CON1 */
+#define C_DAC_EN_CTL_SFT 27
+#define C_DAC_EN_CTL_MASK_SFT BIT(27)
+#define C_MUTE_SW_CTL_SFT 26
+#define C_MUTE_SW_CTL_MASK_SFT BIT(26)
+#define ASDM_SRC_SEL_CTL_SFT 25
+#define ASDM_SRC_SEL_CTL_MASK_SFT BIT(25)
+#define C_AMP_DIV_CH2_CTL_SFT 21
+#define C_AMP_DIV_CH2_CTL_MASK_SFT GENMASK(23, 21)
+#define C_FREQ_DIV_CH2_CTL_SFT 16
+#define C_FREQ_DIV_CH2_CTL_MASK_SFT GENMASK(20, 16)
+#define C_SINE_MODE_CH2_CTL_SFT 12
+#define C_SINE_MODE_CH2_CTL_MASK_SFT GENMASK(15, 12)
+#define C_AMP_DIV_CH1_CTL_SFT 9
+#define C_AMP_DIV_CH1_CTL_MASK_SFT GENMASK(11, 9)
+#define C_FREQ_DIV_CH1_CTL_SFT 4
+#define C_FREQ_DIV_CH1_CTL_MASK_SFT GENMASK(8, 4)
+#define C_SINE_MODE_CH1_CTL_SFT 0
+#define C_SINE_MODE_CH1_CTL_MASK_SFT GENMASK(3, 0)
+
+/* AFE_ADDA_TOP_CON0 */
+#define C_LOOP_BACK_MODE_CTL_SFT 12
+#define C_LOOP_BACK_MODE_CTL_MASK_SFT GENMASK(15, 12)
+#define ADDA_UL_GAIN_MODE_SFT 8
+#define ADDA_UL_GAIN_MODE_MASK_SFT GENMASK(9, 8)
+#define C_EXT_ADC_CTL_SFT 0
+#define C_EXT_ADC_CTL_MASK_SFT BIT(0)
+
+/* AFE_ADDA_UL_DL_CON0 */
+#define AFE_ADDA_UL_LR_SWAP_SFT 31
+#define AFE_ADDA_UL_LR_SWAP_MASK_SFT BIT(31)
+#define AFE_ADDA_CKDIV_RST_SFT 30
+#define AFE_ADDA_CKDIV_RST_MASK_SFT BIT(30)
+#define AFE_ADDA_FIFO_AUTO_RST_SFT 29
+#define AFE_ADDA_FIFO_AUTO_RST_MASK_SFT BIT(29)
+#define AFE_ADDA_UL_FIFO_DIGMIC_TESTIN_SFT 21
+#define AFE_ADDA_UL_FIFO_DIGMIC_TESTIN_MASK_SFT GENMASK(22, 21)
+#define AFE_ADDA_UL_FIFO_DIGMIC_WDATA_TESTEN_SFT 20
+#define AFE_ADDA_UL_FIFO_DIGMIC_WDATA_TESTEN_MASK_SFT BIT(20)
+#define AFE_ADDA6_UL_LR_SWAP_SFT 15
+#define AFE_ADDA6_UL_LR_SWAP_MASK_SFT BIT(15)
+#define AFE_ADDA6_CKDIV_RST_SFT 14
+#define AFE_ADDA6_CKDIV_RST_MASK_SFT BIT(14)
+#define AFE_ADDA6_FIFO_AUTO_RST_SFT 13
+#define AFE_ADDA6_FIFO_AUTO_RST_MASK_SFT BIT(13)
+#define AFE_ADDA6_UL_FIFO_DIGMIC_TESTIN_SFT 5
+#define AFE_ADDA6_UL_FIFO_DIGMIC_TESTIN_MASK_SFT GENMASK(6, 5)
+#define AFE_ADDA6_UL_FIFO_DIGMIC_WDATA_TESTEN_SFT 4
+#define AFE_ADDA6_UL_FIFO_DIGMIC_WDATA_TESTEN_MASK_SFT BIT(4)
+#define ADDA_AFE_ON_SFT 0
+#define ADDA_AFE_ON_MASK_SFT BIT(0)
+
+/* AFE_SIDETONE_CON0 */
+#define R_RDY_SFT 30
+#define R_RDY_MASK_SFT BIT(30)
+#define W_RDY_SFT 29
+#define W_RDY_MASK_SFT BIT(29)
+#define R_W_EN_SFT 25
+#define R_W_EN_MASK_SFT BIT(25)
+#define R_W_SEL_SFT 24
+#define R_W_SEL_MASK_SFT BIT(24)
+#define SEL_CH2_SFT 23
+#define SEL_CH2_MASK_SFT BIT(23)
+#define SIDE_TONE_COEFFICIENT_ADDR_SFT 16
+#define SIDE_TONE_COEFFICIENT_ADDR_MASK_SFT GENMASK(20, 16)
+#define SIDE_TONE_COEFFICIENT_SFT 0
+#define SIDE_TONE_COEFFICIENT_MASK_SFT GENMASK(15, 0)
+
+/* AFE_SIDETONE_COEFF */
+#define SIDE_TONE_COEFF_SFT 0
+#define SIDE_TONE_COEFF_MASK_SFT GENMASK(15, 0)
+
+/* AFE_SIDETONE_CON1 */
+#define STF_BYPASS_MODE_SFT 31
+#define STF_BYPASS_MODE_MASK_SFT BIT(31)
+#define STF_BYPASS_MODE_O28_O29_SFT 30
+#define STF_BYPASS_MODE_O28_O29_MASK_SFT BIT(30)
+#define STF_BYPASS_MODE_I2S4_SFT 29
+#define STF_BYPASS_MODE_I2S4_MASK_SFT BIT(29)
+#define STF_BYPASS_MODE_DL3_SFT 27
+#define STF_BYPASS_MODE_DL3_MASK_SFT BIT(27)
+#define STF_BYPASS_MODE_I2S7_SFT 26
+#define STF_BYPASS_MODE_I2S7_MASK_SFT BIT(26)
+#define STF_BYPASS_MODE_I2S9_SFT 25
+#define STF_BYPASS_MODE_I2S9_MASK_SFT BIT(25)
+#define STF_O19O20_OUT_EN_SEL_SFT 13
+#define STF_O19O20_OUT_EN_SEL_MASK_SFT BIT(13)
+#define STF_SOURCE_FROM_O19O20_SFT 12
+#define STF_SOURCE_FROM_O19O20_MASK_SFT BIT(12)
+#define SIDE_TONE_ON_SFT 8
+#define SIDE_TONE_ON_MASK_SFT BIT(8)
+#define SIDE_TONE_HALF_TAP_NUM_SFT 0
+#define SIDE_TONE_HALF_TAP_NUM_MASK_SFT GENMASK(5, 0)
+
+/* AFE_SIDETONE_GAIN */
+#define POSITIVE_GAIN_SFT 16
+#define POSITIVE_GAIN_MASK_SFT GENMASK(18, 16)
+#define SIDE_TONE_GAIN_SFT 0
+#define SIDE_TONE_GAIN_MASK_SFT GENMASK(15, 0)
+
+/* AFE_ADDA_DL_SDM_DCCOMP_CON */
+#define USE_3RD_SDM_SFT 28
+#define USE_3RD_SDM_MASK_SFT BIT(28)
+#define DL_FIFO_START_POINT_SFT 24
+#define DL_FIFO_START_POINT_MASK_SFT GENMASK(26, 24)
+#define DL_FIFO_SWAP_SFT 20
+#define DL_FIFO_SWAP_MASK_SFT BIT(20)
+#define C_AUDSDM1ORDSELECT_CTL_SFT 19
+#define C_AUDSDM1ORDSELECT_CTL_MASK_SFT BIT(19)
+#define C_SDM7BITSEL_CTL_SFT 18
+#define C_SDM7BITSEL_CTL_MASK_SFT BIT(18)
+#define GAIN_AT_SDM_RST_PRE_CTL_SFT 15
+#define GAIN_AT_SDM_RST_PRE_CTL_MASK_SFT BIT(15)
+#define DL_DCM_AUTO_IDLE_EN_SFT 14
+#define DL_DCM_AUTO_IDLE_EN_MASK_SFT BIT(14)
+#define AFE_DL_SRC_DCM_EN_SFT 13
+#define AFE_DL_SRC_DCM_EN_MASK_SFT BIT(13)
+#define AFE_DL_POST_SRC_DCM_EN_SFT 12
+#define AFE_DL_POST_SRC_DCM_EN_MASK_SFT BIT(12)
+#define AUD_SDM_MONO_SFT 9
+#define AUD_SDM_MONO_MASK_SFT BIT(9)
+#define AUD_DC_COMP_EN_SFT 8
+#define AUD_DC_COMP_EN_MASK_SFT BIT(8)
+#define ATTGAIN_CTL_SFT 0
+#define ATTGAIN_CTL_MASK_SFT GENMASK(5, 0)
+
+/* AFE_SINEGEN_CON0 */
+#define DAC_EN_SFT 26
+#define DAC_EN_MASK 0x1
+#define DAC_EN_MASK_SFT BIT(26)
+#define MUTE_SW_CH2_SFT 25
+#define MUTE_SW_CH2_MASK 0x1
+#define MUTE_SW_CH2_MASK_SFT BIT(25)
+#define MUTE_SW_CH1_SFT 24
+#define MUTE_SW_CH1_MASK 0x1
+#define MUTE_SW_CH1_MASK_SFT BIT(24)
+#define SINE_MODE_CH2_SFT 20
+#define SINE_MODE_CH2_MASK 0xf
+#define SINE_MODE_CH2_MASK_SFT GENMASK(23, 20)
+#define AMP_DIV_CH2_SFT 17
+#define AMP_DIV_CH2_MASK 0x7
+#define AMP_DIV_CH2_MASK_SFT GENMASK(19, 17)
+#define FREQ_DIV_CH2_SFT 12
+#define FREQ_DIV_CH2_MASK 0x1f
+#define FREQ_DIV_CH2_MASK_SFT GENMASK(16, 12)
+#define SINE_MODE_CH1_SFT 8
+#define SINE_MODE_CH1_MASK 0xf
+#define SINE_MODE_CH1_MASK_SFT GENMASK(11, 8)
+#define AMP_DIV_CH1_SFT 5
+#define AMP_DIV_CH1_MASK 0x7
+#define AMP_DIV_CH1_MASK_SFT GENMASK(7, 5)
+#define FREQ_DIV_CH1_SFT 0
+#define FREQ_DIV_CH1_MASK 0x1f
+#define FREQ_DIV_CH1_MASK_SFT GENMASK(4, 0)
+
+/* AFE_SINEGEN_CON2 */
+#define INNER_LOOP_BACK_MODE_SFT 0
+#define INNER_LOOP_BACK_MODE_MASK_SFT GENMASK(7, 0)
+
+/* AFE_HD_ENGEN_ENABLE */
+#define AFE_24M_ON_SFT 1
+#define AFE_24M_ON_MASK_SFT BIT(1)
+#define AFE_22M_ON_SFT 0
+#define AFE_22M_ON_MASK_SFT BIT(0)
+
+/* AFE_ADDA_DL_NLE_FIFO_MON */
+#define DL_NLE_FIFO_WBIN_SFT 8
+#define DL_NLE_FIFO_WBIN_MASK_SFT GENMASK(11, 8)
+#define DL_NLE_FIFO_RBIN_SFT 4
+#define DL_NLE_FIFO_RBIN_MASK_SFT GENMASK(7, 4)
+#define DL_NLE_FIFO_RDACTIVE_SFT 3
+#define DL_NLE_FIFO_RDACTIVE_MASK_SFT BIT(3)
+#define DL_NLE_FIFO_STARTRD_SFT 2
+#define DL_NLE_FIFO_STARTRD_MASK_SFT BIT(2)
+#define DL_NLE_FIFO_RD_EMPTY_SFT 1
+#define DL_NLE_FIFO_RD_EMPTY_MASK_SFT BIT(1)
+#define DL_NLE_FIFO_WR_FULL_SFT 0
+#define DL_NLE_FIFO_WR_FULL_MASK_SFT BIT(0)
+
+/* AFE_DL1_CON0 */
+#define DL1_MODE_SFT 24
+#define DL1_MODE_MASK 0xf
+#define DL1_MODE_MASK_SFT GENMASK(27, 24)
+#define DL1_MINLEN_SFT 20
+#define DL1_MINLEN_MASK 0xf
+#define DL1_MINLEN_MASK_SFT GENMASK(23, 20)
+#define DL1_MAXLEN_SFT 16
+#define DL1_MAXLEN_MASK 0xf
+#define DL1_MAXLEN_MASK_SFT GENMASK(19, 16)
+#define DL1_SW_CLEAR_BUF_EMPTY_SFT 15
+#define DL1_SW_CLEAR_BUF_EMPTY_MASK 0x1
+#define DL1_SW_CLEAR_BUF_EMPTY_MASK_SFT BIT(15)
+#define DL1_PBUF_SIZE_SFT 12
+#define DL1_PBUF_SIZE_MASK 0x3
+#define DL1_PBUF_SIZE_MASK_SFT GENMASK(13, 12)
+#define DL1_MONO_SFT 8
+#define DL1_MONO_MASK 0x1
+#define DL1_MONO_MASK_SFT BIT(8)
+#define DL1_NORMAL_MODE_SFT 5
+#define DL1_NORMAL_MODE_MASK 0x1
+#define DL1_NORMAL_MODE_MASK_SFT BIT(5)
+#define DL1_HALIGN_SFT 4
+#define DL1_HALIGN_MASK 0x1
+#define DL1_HALIGN_MASK_SFT BIT(4)
+#define DL1_HD_MODE_SFT 0
+#define DL1_HD_MODE_MASK 0x3
+#define DL1_HD_MODE_MASK_SFT GENMASK(1, 0)
+
+/* AFE_DL2_CON0 */
+#define DL2_MODE_SFT 24
+#define DL2_MODE_MASK 0xf
+#define DL2_MODE_MASK_SFT GENMASK(27, 24)
+#define DL2_MINLEN_SFT 20
+#define DL2_MINLEN_MASK 0xf
+#define DL2_MINLEN_MASK_SFT GENMASK(23, 20)
+#define DL2_MAXLEN_SFT 16
+#define DL2_MAXLEN_MASK 0xf
+#define DL2_MAXLEN_MASK_SFT GENMASK(19, 16)
+#define DL2_SW_CLEAR_BUF_EMPTY_SFT 15
+#define DL2_SW_CLEAR_BUF_EMPTY_MASK 0x1
+#define DL2_SW_CLEAR_BUF_EMPTY_MASK_SFT BIT(15)
+#define DL2_PBUF_SIZE_SFT 12
+#define DL2_PBUF_SIZE_MASK 0x3
+#define DL2_PBUF_SIZE_MASK_SFT GENMASK(13, 12)
+#define DL2_MONO_SFT 8
+#define DL2_MONO_MASK 0x1
+#define DL2_MONO_MASK_SFT BIT(8)
+#define DL2_NORMAL_MODE_SFT 5
+#define DL2_NORMAL_MODE_MASK 0x1
+#define DL2_NORMAL_MODE_MASK_SFT BIT(5)
+#define DL2_HALIGN_SFT 4
+#define DL2_HALIGN_MASK 0x1
+#define DL2_HALIGN_MASK_SFT BIT(4)
+#define DL2_HD_MODE_SFT 0
+#define DL2_HD_MODE_MASK 0x3
+#define DL2_HD_MODE_MASK_SFT GENMASK(1, 0)
+
+/* AFE_DL3_CON0 */
+#define DL3_MODE_SFT 24
+#define DL3_MODE_MASK 0xf
+#define DL3_MODE_MASK_SFT GENMASK(27, 24)
+#define DL3_MINLEN_SFT 20
+#define DL3_MINLEN_MASK 0xf
+#define DL3_MINLEN_MASK_SFT GENMASK(23, 20)
+#define DL3_MAXLEN_SFT 16
+#define DL3_MAXLEN_MASK 0xf
+#define DL3_MAXLEN_MASK_SFT GENMASK(19, 16)
+#define DL3_SW_CLEAR_BUF_EMPTY_SFT 15
+#define DL3_SW_CLEAR_BUF_EMPTY_MASK 0x1
+#define DL3_SW_CLEAR_BUF_EMPTY_MASK_SFT BIT(15)
+#define DL3_PBUF_SIZE_SFT 12
+#define DL3_PBUF_SIZE_MASK 0x3
+#define DL3_PBUF_SIZE_MASK_SFT GENMASK(13, 12)
+#define DL3_MONO_SFT 8
+#define DL3_MONO_MASK 0x1
+#define DL3_MONO_MASK_SFT BIT(8)
+#define DL3_NORMAL_MODE_SFT 5
+#define DL3_NORMAL_MODE_MASK 0x1
+#define DL3_NORMAL_MODE_MASK_SFT BIT(5)
+#define DL3_HALIGN_SFT 4
+#define DL3_HALIGN_MASK 0x1
+#define DL3_HALIGN_MASK_SFT BIT(4)
+#define DL3_HD_MODE_SFT 0
+#define DL3_HD_MODE_MASK 0x3
+#define DL3_HD_MODE_MASK_SFT GENMASK(1, 0)
+
+/* AFE_DL4_CON0 */
+#define DL4_MODE_SFT 24
+#define DL4_MODE_MASK 0xf
+#define DL4_MODE_MASK_SFT GENMASK(27, 24)
+#define DL4_MINLEN_SFT 20
+#define DL4_MINLEN_MASK 0xf
+#define DL4_MINLEN_MASK_SFT GENMASK(23, 20)
+#define DL4_MAXLEN_SFT 16
+#define DL4_MAXLEN_MASK 0xf
+#define DL4_MAXLEN_MASK_SFT GENMASK(19, 16)
+#define DL4_SW_CLEAR_BUF_EMPTY_SFT 15
+#define DL4_SW_CLEAR_BUF_EMPTY_MASK 0x1
+#define DL4_SW_CLEAR_BUF_EMPTY_MASK_SFT BIT(15)
+#define DL4_PBUF_SIZE_SFT 12
+#define DL4_PBUF_SIZE_MASK 0x3
+#define DL4_PBUF_SIZE_MASK_SFT GENMASK(13, 12)
+#define DL4_MONO_SFT 8
+#define DL4_MONO_MASK 0x1
+#define DL4_MONO_MASK_SFT BIT(8)
+#define DL4_NORMAL_MODE_SFT 5
+#define DL4_NORMAL_MODE_MASK 0x1
+#define DL4_NORMAL_MODE_MASK_SFT BIT(5)
+#define DL4_HALIGN_SFT 4
+#define DL4_HALIGN_MASK 0x1
+#define DL4_HALIGN_MASK_SFT BIT(4)
+#define DL4_HD_MODE_SFT 0
+#define DL4_HD_MODE_MASK 0x3
+#define DL4_HD_MODE_MASK_SFT GENMASK(1, 0)
+
+/* AFE_DL5_CON0 */
+#define DL5_MODE_SFT 24
+#define DL5_MODE_MASK 0xf
+#define DL5_MODE_MASK_SFT GENMASK(27, 24)
+#define DL5_MINLEN_SFT 20
+#define DL5_MINLEN_MASK 0xf
+#define DL5_MINLEN_MASK_SFT GENMASK(23, 20)
+#define DL5_MAXLEN_SFT 16
+#define DL5_MAXLEN_MASK 0xf
+#define DL5_MAXLEN_MASK_SFT GENMASK(19, 16)
+#define DL5_SW_CLEAR_BUF_EMPTY_SFT 15
+#define DL5_SW_CLEAR_BUF_EMPTY_MASK 0x1
+#define DL5_SW_CLEAR_BUF_EMPTY_MASK_SFT BIT(15)
+#define DL5_PBUF_SIZE_SFT 12
+#define DL5_PBUF_SIZE_MASK 0x3
+#define DL5_PBUF_SIZE_MASK_SFT GENMASK(13, 12)
+#define DL5_MONO_SFT 8
+#define DL5_MONO_MASK 0x1
+#define DL5_MONO_MASK_SFT BIT(8)
+#define DL5_NORMAL_MODE_SFT 5
+#define DL5_NORMAL_MODE_MASK 0x1
+#define DL5_NORMAL_MODE_MASK_SFT BIT(5)
+#define DL5_HALIGN_SFT 4
+#define DL5_HALIGN_MASK 0x1
+#define DL5_HALIGN_MASK_SFT BIT(4)
+#define DL5_HD_MODE_SFT 0
+#define DL5_HD_MODE_MASK 0x3
+#define DL5_HD_MODE_MASK_SFT GENMASK(1, 0)
+
+/* AFE_DL6_CON0 */
+#define DL6_MODE_SFT 24
+#define DL6_MODE_MASK 0xf
+#define DL6_MODE_MASK_SFT GENMASK(27, 24)
+#define DL6_MINLEN_SFT 20
+#define DL6_MINLEN_MASK 0xf
+#define DL6_MINLEN_MASK_SFT GENMASK(23, 20)
+#define DL6_MAXLEN_SFT 16
+#define DL6_MAXLEN_MASK 0xf
+#define DL6_MAXLEN_MASK_SFT GENMASK(19, 16)
+#define DL6_SW_CLEAR_BUF_EMPTY_SFT 15
+#define DL6_SW_CLEAR_BUF_EMPTY_MASK 0x1
+#define DL6_SW_CLEAR_BUF_EMPTY_MASK_SFT BIT(15)
+#define DL6_PBUF_SIZE_SFT 12
+#define DL6_PBUF_SIZE_MASK 0x3
+#define DL6_PBUF_SIZE_MASK_SFT GENMASK(13, 12)
+#define DL6_MONO_SFT 8
+#define DL6_MONO_MASK 0x1
+#define DL6_MONO_MASK_SFT BIT(8)
+#define DL6_NORMAL_MODE_SFT 5
+#define DL6_NORMAL_MODE_MASK 0x1
+#define DL6_NORMAL_MODE_MASK_SFT BIT(5)
+#define DL6_HALIGN_SFT 4
+#define DL6_HALIGN_MASK 0x1
+#define DL6_HALIGN_MASK_SFT BIT(4)
+#define DL6_HD_MODE_SFT 0
+#define DL6_HD_MODE_MASK 0x3
+#define DL6_HD_MODE_MASK_SFT GENMASK(1, 0)
+
+/* AFE_DL7_CON0 */
+#define DL7_MODE_SFT 24
+#define DL7_MODE_MASK 0xf
+#define DL7_MODE_MASK_SFT GENMASK(27, 24)
+#define DL7_MINLEN_SFT 20
+#define DL7_MINLEN_MASK 0xf
+#define DL7_MINLEN_MASK_SFT GENMASK(23, 20)
+#define DL7_MAXLEN_SFT 16
+#define DL7_MAXLEN_MASK 0xf
+#define DL7_MAXLEN_MASK_SFT GENMASK(19, 16)
+#define DL7_SW_CLEAR_BUF_EMPTY_SFT 15
+#define DL7_SW_CLEAR_BUF_EMPTY_MASK 0x1
+#define DL7_SW_CLEAR_BUF_EMPTY_MASK_SFT BIT(15)
+#define DL7_PBUF_SIZE_SFT 12
+#define DL7_PBUF_SIZE_MASK 0x3
+#define DL7_PBUF_SIZE_MASK_SFT GENMASK(13, 12)
+#define DL7_MONO_SFT 8
+#define DL7_MONO_MASK 0x1
+#define DL7_MONO_MASK_SFT BIT(8)
+#define DL7_NORMAL_MODE_SFT 5
+#define DL7_NORMAL_MODE_MASK 0x1
+#define DL7_NORMAL_MODE_MASK_SFT BIT(5)
+#define DL7_HALIGN_SFT 4
+#define DL7_HALIGN_MASK 0x1
+#define DL7_HALIGN_MASK_SFT BIT(4)
+#define DL7_HD_MODE_SFT 0
+#define DL7_HD_MODE_MASK 0x3
+#define DL7_HD_MODE_MASK_SFT GENMASK(1, 0)
+
+/* AFE_DL8_CON0 */
+#define DL8_MODE_SFT 24
+#define DL8_MODE_MASK 0xf
+#define DL8_MODE_MASK_SFT GENMASK(27, 24)
+#define DL8_MINLEN_SFT 20
+#define DL8_MINLEN_MASK 0xf
+#define DL8_MINLEN_MASK_SFT GENMASK(23, 20)
+#define DL8_MAXLEN_SFT 16
+#define DL8_MAXLEN_MASK 0xf
+#define DL8_MAXLEN_MASK_SFT GENMASK(19, 16)
+#define DL8_SW_CLEAR_BUF_EMPTY_SFT 15
+#define DL8_SW_CLEAR_BUF_EMPTY_MASK 0x1
+#define DL8_SW_CLEAR_BUF_EMPTY_MASK_SFT BIT(15)
+#define DL8_PBUF_SIZE_SFT 12
+#define DL8_PBUF_SIZE_MASK 0x3
+#define DL8_PBUF_SIZE_MASK_SFT GENMASK(13, 12)
+#define DL8_MONO_SFT 8
+#define DL8_MONO_MASK 0x1
+#define DL8_MONO_MASK_SFT BIT(8)
+#define DL8_NORMAL_MODE_SFT 5
+#define DL8_NORMAL_MODE_MASK 0x1
+#define DL8_NORMAL_MODE_MASK_SFT BIT(5)
+#define DL8_HALIGN_SFT 4
+#define DL8_HALIGN_MASK 0x1
+#define DL8_HALIGN_MASK_SFT BIT(4)
+#define DL8_HD_MODE_SFT 0
+#define DL8_HD_MODE_MASK 0x3
+#define DL8_HD_MODE_MASK_SFT GENMASK(1, 0)
+
+/* AFE_DL12_CON0 */
+#define DL12_MODE_SFT 24
+#define DL12_MODE_MASK 0xf
+#define DL12_MODE_MASK_SFT GENMASK(27, 24)
+#define DL12_MINLEN_SFT 20
+#define DL12_MINLEN_MASK 0xf
+#define DL12_MINLEN_MASK_SFT GENMASK(23, 20)
+#define DL12_MAXLEN_SFT 16
+#define DL12_MAXLEN_MASK 0xf
+#define DL12_MAXLEN_MASK_SFT GENMASK(19, 16)
+#define DL12_SW_CLEAR_BUF_EMPTY_SFT 15
+#define DL12_SW_CLEAR_BUF_EMPTY_MASK 0x1
+#define DL12_SW_CLEAR_BUF_EMPTY_MASK_SFT BIT(15)
+#define DL12_PBUF_SIZE_SFT 12
+#define DL12_PBUF_SIZE_MASK 0x3
+#define DL12_PBUF_SIZE_MASK_SFT GENMASK(13, 12)
+#define DL12_4CH_EN_SFT 11
+#define DL12_4CH_EN_MASK 0x1
+#define DL12_4CH_EN_MASK_SFT BIT(11)
+#define DL12_MONO_SFT 8
+#define DL12_MONO_MASK 0x1
+#define DL12_MONO_MASK_SFT BIT(8)
+#define DL12_NORMAL_MODE_SFT 5
+#define DL12_NORMAL_MODE_MASK 0x1
+#define DL12_NORMAL_MODE_MASK_SFT BIT(5)
+#define DL12_HALIGN_SFT 4
+#define DL12_HALIGN_MASK 0x1
+#define DL12_HALIGN_MASK_SFT BIT(4)
+#define DL12_HD_MODE_SFT 0
+#define DL12_HD_MODE_MASK 0x3
+#define DL12_HD_MODE_MASK_SFT GENMASK(1, 0)
+
+/* AFE_AWB_CON0 */
+#define AWB_MODE_SFT 24
+#define AWB_MODE_MASK 0xf
+#define AWB_MODE_MASK_SFT GENMASK(27, 24)
+#define AWB_SW_CLEAR_BUF_FULL_SFT 15
+#define AWB_SW_CLEAR_BUF_FULL_MASK 0x1
+#define AWB_SW_CLEAR_BUF_FULL_MASK_SFT BIT(15)
+#define AWB_R_MONO_SFT 9
+#define AWB_R_MONO_MASK 0x1
+#define AWB_R_MONO_MASK_SFT BIT(9)
+#define AWB_MONO_SFT 8
+#define AWB_MONO_MASK 0x1
+#define AWB_MONO_MASK_SFT BIT(8)
+#define AWB_WR_SIGN_SFT 6
+#define AWB_WR_SIGN_MASK 0x1
+#define AWB_WR_SIGN_MASK_SFT BIT(6)
+#define AWB_NORMAL_MODE_SFT 5
+#define AWB_NORMAL_MODE_MASK 0x1
+#define AWB_NORMAL_MODE_MASK_SFT BIT(5)
+#define AWB_HALIGN_SFT 4
+#define AWB_HALIGN_MASK 0x1
+#define AWB_HALIGN_MASK_SFT BIT(4)
+#define AWB_HD_MODE_SFT 0
+#define AWB_HD_MODE_MASK 0x3
+#define AWB_HD_MODE_MASK_SFT GENMASK(1, 0)
+
+/* AFE_AWB2_CON0 */
+#define AWB2_MODE_SFT 24
+#define AWB2_MODE_MASK 0xf
+#define AWB2_MODE_MASK_SFT GENMASK(27, 24)
+#define AWB2_SW_CLEAR_BUF_FULL_SFT 15
+#define AWB2_SW_CLEAR_BUF_FULL_MASK 0x1
+#define AWB2_SW_CLEAR_BUF_FULL_MASK_SFT BIT(15)
+#define AWB2_R_MONO_SFT 9
+#define AWB2_R_MONO_MASK 0x1
+#define AWB2_R_MONO_MASK_SFT BIT(9)
+#define AWB2_MONO_SFT 8
+#define AWB2_MONO_MASK 0x1
+#define AWB2_MONO_MASK_SFT BIT(8)
+#define AWB2_WR_SIGN_SFT 6
+#define AWB2_WR_SIGN_MASK 0x1
+#define AWB2_WR_SIGN_MASK_SFT BIT(6)
+#define AWB2_NORMAL_MODE_SFT 5
+#define AWB2_NORMAL_MODE_MASK 0x1
+#define AWB2_NORMAL_MODE_MASK_SFT BIT(5)
+#define AWB2_HALIGN_SFT 4
+#define AWB2_HALIGN_MASK 0x1
+#define AWB2_HALIGN_MASK_SFT BIT(4)
+#define AWB2_HD_MODE_SFT 0
+#define AWB2_HD_MODE_MASK 0x3
+#define AWB2_HD_MODE_MASK_SFT GENMASK(1, 0)
+
+/* AFE_VUL_CON0 */
+#define VUL_MODE_SFT 24
+#define VUL_MODE_MASK 0xf
+#define VUL_MODE_MASK_SFT GENMASK(27, 24)
+#define VUL_SW_CLEAR_BUF_FULL_SFT 15
+#define VUL_SW_CLEAR_BUF_FULL_MASK 0x1
+#define VUL_SW_CLEAR_BUF_FULL_MASK_SFT BIT(15)
+#define VUL_R_MONO_SFT 9
+#define VUL_R_MONO_MASK 0x1
+#define VUL_R_MONO_MASK_SFT BIT(9)
+#define VUL_MONO_SFT 8
+#define VUL_MONO_MASK 0x1
+#define VUL_MONO_MASK_SFT BIT(8)
+#define VUL_WR_SIGN_SFT 6
+#define VUL_WR_SIGN_MASK 0x1
+#define VUL_WR_SIGN_MASK_SFT BIT(6)
+#define VUL_NORMAL_MODE_SFT 5
+#define VUL_NORMAL_MODE_MASK 0x1
+#define VUL_NORMAL_MODE_MASK_SFT BIT(5)
+#define VUL_HALIGN_SFT 4
+#define VUL_HALIGN_MASK 0x1
+#define VUL_HALIGN_MASK_SFT BIT(4)
+#define VUL_HD_MODE_SFT 0
+#define VUL_HD_MODE_MASK 0x3
+#define VUL_HD_MODE_MASK_SFT GENMASK(1, 0)
+
+/* AFE_VUL12_CON0 */
+#define VUL12_MODE_SFT 24
+#define VUL12_MODE_MASK 0xf
+#define VUL12_MODE_MASK_SFT GENMASK(27, 24)
+#define VUL12_SW_CLEAR_BUF_FULL_SFT 15
+#define VUL12_SW_CLEAR_BUF_FULL_MASK 0x1
+#define VUL12_SW_CLEAR_BUF_FULL_MASK_SFT BIT(15)
+#define VUL12_4CH_EN_SFT 11
+#define VUL12_4CH_EN_MASK 0x1
+#define VUL12_4CH_EN_MASK_SFT BIT(11)
+#define VUL12_R_MONO_SFT 9
+#define VUL12_R_MONO_MASK 0x1
+#define VUL12_R_MONO_MASK_SFT BIT(9)
+#define VUL12_MONO_SFT 8
+#define VUL12_MONO_MASK 0x1
+#define VUL12_MONO_MASK_SFT BIT(8)
+#define VUL12_WR_SIGN_SFT 6
+#define VUL12_WR_SIGN_MASK 0x1
+#define VUL12_WR_SIGN_MASK_SFT BIT(6)
+#define VUL12_NORMAL_MODE_SFT 5
+#define VUL12_NORMAL_MODE_MASK 0x1
+#define VUL12_NORMAL_MODE_MASK_SFT BIT(5)
+#define VUL12_HALIGN_SFT 4
+#define VUL12_HALIGN_MASK 0x1
+#define VUL12_HALIGN_MASK_SFT BIT(4)
+#define VUL12_HD_MODE_SFT 0
+#define VUL12_HD_MODE_MASK 0x3
+#define VUL12_HD_MODE_MASK_SFT GENMASK(1, 0)
+
+/* AFE_VUL2_CON0 */
+#define VUL2_MODE_SFT 24
+#define VUL2_MODE_MASK 0xf
+#define VUL2_MODE_MASK_SFT GENMASK(27, 24)
+#define VUL2_SW_CLEAR_BUF_FULL_SFT 15
+#define VUL2_SW_CLEAR_BUF_FULL_MASK 0x1
+#define VUL2_SW_CLEAR_BUF_FULL_MASK_SFT BIT(15)
+#define VUL2_R_MONO_SFT 9
+#define VUL2_R_MONO_MASK 0x1
+#define VUL2_R_MONO_MASK_SFT BIT(9)
+#define VUL2_MONO_SFT 8
+#define VUL2_MONO_MASK 0x1
+#define VUL2_MONO_MASK_SFT BIT(8)
+#define VUL2_WR_SIGN_SFT 6
+#define VUL2_WR_SIGN_MASK 0x1
+#define VUL2_WR_SIGN_MASK_SFT BIT(6)
+#define VUL2_NORMAL_MODE_SFT 5
+#define VUL2_NORMAL_MODE_MASK 0x1
+#define VUL2_NORMAL_MODE_MASK_SFT BIT(5)
+#define VUL2_HALIGN_SFT 4
+#define VUL2_HALIGN_MASK 0x1
+#define VUL2_HALIGN_MASK_SFT BIT(4)
+#define VUL2_HD_MODE_SFT 0
+#define VUL2_HD_MODE_MASK 0x3
+#define VUL2_HD_MODE_MASK_SFT GENMASK(1, 0)
+
+/* AFE_VUL3_CON0 */
+#define VUL3_MODE_SFT 24
+#define VUL3_MODE_MASK 0xf
+#define VUL3_MODE_MASK_SFT GENMASK(27, 24)
+#define VUL3_SW_CLEAR_BUF_FULL_SFT 15
+#define VUL3_SW_CLEAR_BUF_FULL_MASK 0x1
+#define VUL3_SW_CLEAR_BUF_FULL_MASK_SFT BIT(15)
+#define VUL3_R_MONO_SFT 9
+#define VUL3_R_MONO_MASK 0x1
+#define VUL3_R_MONO_MASK_SFT BIT(9)
+#define VUL3_MONO_SFT 8
+#define VUL3_MONO_MASK 0x1
+#define VUL3_MONO_MASK_SFT BIT(8)
+#define VUL3_WR_SIGN_SFT 6
+#define VUL3_WR_SIGN_MASK 0x1
+#define VUL3_WR_SIGN_MASK_SFT BIT(6)
+#define VUL3_NORMAL_MODE_SFT 5
+#define VUL3_NORMAL_MODE_MASK 0x1
+#define VUL3_NORMAL_MODE_MASK_SFT BIT(5)
+#define VUL3_HALIGN_SFT 4
+#define VUL3_HALIGN_MASK 0x1
+#define VUL3_HALIGN_MASK_SFT BIT(4)
+#define VUL3_HD_MODE_SFT 0
+#define VUL3_HD_MODE_MASK 0x3
+#define VUL3_HD_MODE_MASK_SFT GENMASK(1, 0)
+
+/* AFE_VUL4_CON0 */
+#define VUL4_MODE_SFT 24
+#define VUL4_MODE_MASK 0xf
+#define VUL4_MODE_MASK_SFT GENMASK(27, 24)
+#define VUL4_SW_CLEAR_BUF_FULL_SFT 15
+#define VUL4_SW_CLEAR_BUF_FULL_MASK 0x1
+#define VUL4_SW_CLEAR_BUF_FULL_MASK_SFT BIT(15)
+#define VUL4_R_MONO_SFT 9
+#define VUL4_R_MONO_MASK 0x1
+#define VUL4_R_MONO_MASK_SFT BIT(9)
+#define VUL4_MONO_SFT 8
+#define VUL4_MONO_MASK 0x1
+#define VUL4_MONO_MASK_SFT BIT(8)
+#define VUL4_WR_SIGN_SFT 6
+#define VUL4_WR_SIGN_MASK 0x1
+#define VUL4_WR_SIGN_MASK_SFT BIT(6)
+#define VUL4_NORMAL_MODE_SFT 5
+#define VUL4_NORMAL_MODE_MASK 0x1
+#define VUL4_NORMAL_MODE_MASK_SFT BIT(5)
+#define VUL4_HALIGN_SFT 4
+#define VUL4_HALIGN_MASK 0x1
+#define VUL4_HALIGN_MASK_SFT BIT(4)
+#define VUL4_HD_MODE_SFT 0
+#define VUL4_HD_MODE_MASK 0x3
+#define VUL4_HD_MODE_MASK_SFT GENMASK(1, 0)
+
+/* AFE_VUL5_CON0 */
+#define VUL5_MODE_SFT 24
+#define VUL5_MODE_MASK 0xf
+#define VUL5_MODE_MASK_SFT GENMASK(27, 24)
+#define VUL5_SW_CLEAR_BUF_FULL_SFT 15
+#define VUL5_SW_CLEAR_BUF_FULL_MASK 0x1
+#define VUL5_SW_CLEAR_BUF_FULL_MASK_SFT BIT(15)
+#define VUL5_R_MONO_SFT 9
+#define VUL5_R_MONO_MASK 0x1
+#define VUL5_R_MONO_MASK_SFT BIT(9)
+#define VUL5_MONO_SFT 8
+#define VUL5_MONO_MASK 0x1
+#define VUL5_MONO_MASK_SFT BIT(8)
+#define VUL5_WR_SIGN_SFT 6
+#define VUL5_WR_SIGN_MASK 0x1
+#define VUL5_WR_SIGN_MASK_SFT BIT(6)
+#define VUL5_NORMAL_MODE_SFT 5
+#define VUL5_NORMAL_MODE_MASK 0x1
+#define VUL5_NORMAL_MODE_MASK_SFT BIT(5)
+#define VUL5_HALIGN_SFT 4
+#define VUL5_HALIGN_MASK 0x1
+#define VUL5_HALIGN_MASK_SFT BIT(4)
+#define VUL5_HD_MODE_SFT 0
+#define VUL5_HD_MODE_MASK 0x3
+#define VUL5_HD_MODE_MASK_SFT GENMASK(1, 0)
+
+/* AFE_VUL6_CON0 */
+#define VUL6_MODE_SFT 24
+#define VUL6_MODE_MASK 0xf
+#define VUL6_MODE_MASK_SFT GENMASK(27, 24)
+#define VUL6_SW_CLEAR_BUF_FULL_SFT 15
+#define VUL6_SW_CLEAR_BUF_FULL_MASK 0x1
+#define VUL6_SW_CLEAR_BUF_FULL_MASK_SFT BIT(15)
+#define VUL6_R_MONO_SFT 9
+#define VUL6_R_MONO_MASK 0x1
+#define VUL6_R_MONO_MASK_SFT BIT(9)
+#define VUL6_MONO_SFT 8
+#define VUL6_MONO_MASK 0x1
+#define VUL6_MONO_MASK_SFT BIT(8)
+#define VUL6_WR_SIGN_SFT 6
+#define VUL6_WR_SIGN_MASK 0x1
+#define VUL6_WR_SIGN_MASK_SFT BIT(6)
+#define VUL6_NORMAL_MODE_SFT 5
+#define VUL6_NORMAL_MODE_MASK 0x1
+#define VUL6_NORMAL_MODE_MASK_SFT BIT(5)
+#define VUL6_HALIGN_SFT 4
+#define VUL6_HALIGN_MASK 0x1
+#define VUL6_HALIGN_MASK_SFT BIT(4)
+#define VUL6_HD_MODE_SFT 0
+#define VUL6_HD_MODE_MASK 0x3
+#define VUL6_HD_MODE_MASK_SFT GENMASK(1, 0)
+
+/* AFE_DAI_CON0 */
+#define DAI_MODE_SFT 24
+#define DAI_MODE_MASK 0x3
+#define DAI_MODE_MASK_SFT GENMASK(25, 24)
+#define DAI_SW_CLEAR_BUF_FULL_SFT 15
+#define DAI_SW_CLEAR_BUF_FULL_MASK 0x1
+#define DAI_SW_CLEAR_BUF_FULL_MASK_SFT BIT(15)
+#define DAI_DUPLICATE_WR_SFT 10
+#define DAI_DUPLICATE_WR_MASK 0x1
+#define DAI_DUPLICATE_WR_MASK_SFT BIT(10)
+#define DAI_MONO_SFT 8
+#define DAI_MONO_MASK 0x1
+#define DAI_MONO_MASK_SFT BIT(8)
+#define DAI_WR_SIGN_SFT 6
+#define DAI_WR_SIGN_MASK 0x1
+#define DAI_WR_SIGN_MASK_SFT BIT(6)
+#define DAI_NORMAL_MODE_SFT 5
+#define DAI_NORMAL_MODE_MASK 0x1
+#define DAI_NORMAL_MODE_MASK_SFT BIT(5)
+#define DAI_HALIGN_SFT 4
+#define DAI_HALIGN_MASK 0x1
+#define DAI_HALIGN_MASK_SFT BIT(4)
+#define DAI_HD_MODE_SFT 0
+#define DAI_HD_MODE_MASK 0x3
+#define DAI_HD_MODE_MASK_SFT GENMASK(1, 0)
+
+/* AFE_MOD_DAI_CON0 */
+#define MOD_DAI_MODE_SFT 24
+#define MOD_DAI_MODE_MASK 0x3
+#define MOD_DAI_MODE_MASK_SFT GENMASK(25, 24)
+#define MOD_DAI_SW_CLEAR_BUF_FULL_SFT 15
+#define MOD_DAI_SW_CLEAR_BUF_FULL_MASK 0x1
+#define MOD_DAI_SW_CLEAR_BUF_FULL_MASK_SFT BIT(15)
+#define MOD_DAI_DUPLICATE_WR_SFT 10
+#define MOD_DAI_DUPLICATE_WR_MASK 0x1
+#define MOD_DAI_DUPLICATE_WR_MASK_SFT BIT(10)
+#define MOD_DAI_MONO_SFT 8
+#define MOD_DAI_MONO_MASK 0x1
+#define MOD_DAI_MONO_MASK_SFT BIT(8)
+#define MOD_DAI_WR_SIGN_SFT 6
+#define MOD_DAI_WR_SIGN_MASK 0x1
+#define MOD_DAI_WR_SIGN_MASK_SFT BIT(6)
+#define MOD_DAI_NORMAL_MODE_SFT 5
+#define MOD_DAI_NORMAL_MODE_MASK 0x1
+#define MOD_DAI_NORMAL_MODE_MASK_SFT BIT(5)
+#define MOD_DAI_HALIGN_SFT 4
+#define MOD_DAI_HALIGN_MASK 0x1
+#define MOD_DAI_HALIGN_MASK_SFT BIT(4)
+#define MOD_DAI_HD_MODE_SFT 0
+#define MOD_DAI_HD_MODE_MASK 0x3
+#define MOD_DAI_HD_MODE_MASK_SFT GENMASK(1, 0)
+
+/* AFE_DAI2_CON0 */
+#define DAI2_MODE_SFT 24
+#define DAI2_MODE_MASK 0xf
+#define DAI2_MODE_MASK_SFT GENMASK(27, 24)
+#define DAI2_SW_CLEAR_BUF_FULL_SFT 15
+#define DAI2_SW_CLEAR_BUF_FULL_MASK 0x1
+#define DAI2_SW_CLEAR_BUF_FULL_MASK_SFT BIT(15)
+#define DAI2_DUPLICATE_WR_SFT 10
+#define DAI2_DUPLICATE_WR_MASK 0x1
+#define DAI2_DUPLICATE_WR_MASK_SFT BIT(10)
+#define DAI2_MONO_SFT 8
+#define DAI2_MONO_MASK 0x1
+#define DAI2_MONO_MASK_SFT BIT(8)
+#define DAI2_WR_SIGN_SFT 6
+#define DAI2_WR_SIGN_MASK 0x1
+#define DAI2_WR_SIGN_MASK_SFT BIT(6)
+#define DAI2_NORMAL_MODE_SFT 5
+#define DAI2_NORMAL_MODE_MASK 0x1
+#define DAI2_NORMAL_MODE_MASK_SFT BIT(5)
+#define DAI2_HALIGN_SFT 4
+#define DAI2_HALIGN_MASK 0x1
+#define DAI2_HALIGN_MASK_SFT BIT(4)
+#define DAI2_HD_MODE_SFT 0
+#define DAI2_HD_MODE_MASK 0x3
+#define DAI2_HD_MODE_MASK_SFT GENMASK(1, 0)
+
+/* AFE_MEMIF_CON0 */
+#define CPU_COMPACT_MODE_SFT 2
+#define CPU_COMPACT_MODE_MASK_SFT BIT(2)
+#define CPU_HD_ALIGN_SFT 1
+#define CPU_HD_ALIGN_MASK_SFT BIT(1)
+#define SYSRAM_SIGN_SFT 0
+#define SYSRAM_SIGN_MASK_SFT BIT(0)
+
+/* AFE_IRQ_MCU_CON0 */
+#define IRQ31_MCU_ON_SFT 31
+#define IRQ31_MCU_ON_MASK 0x1
+#define IRQ31_MCU_ON_MASK_SFT BIT(31)
+#define IRQ26_MCU_ON_SFT 26
+#define IRQ26_MCU_ON_MASK 0x1
+#define IRQ26_MCU_ON_MASK_SFT BIT(26)
+#define IRQ25_MCU_ON_SFT 25
+#define IRQ25_MCU_ON_MASK 0x1
+#define IRQ25_MCU_ON_MASK_SFT BIT(25)
+#define IRQ24_MCU_ON_SFT 24
+#define IRQ24_MCU_ON_MASK 0x1
+#define IRQ24_MCU_ON_MASK_SFT BIT(24)
+#define IRQ23_MCU_ON_SFT 23
+#define IRQ23_MCU_ON_MASK 0x1
+#define IRQ23_MCU_ON_MASK_SFT BIT(23)
+#define IRQ22_MCU_ON_SFT 22
+#define IRQ22_MCU_ON_MASK 0x1
+#define IRQ22_MCU_ON_MASK_SFT BIT(22)
+#define IRQ21_MCU_ON_SFT 21
+#define IRQ21_MCU_ON_MASK 0x1
+#define IRQ21_MCU_ON_MASK_SFT BIT(21)
+#define IRQ20_MCU_ON_SFT 20
+#define IRQ20_MCU_ON_MASK 0x1
+#define IRQ20_MCU_ON_MASK_SFT BIT(20)
+#define IRQ19_MCU_ON_SFT 19
+#define IRQ19_MCU_ON_MASK 0x1
+#define IRQ19_MCU_ON_MASK_SFT BIT(19)
+#define IRQ18_MCU_ON_SFT 18
+#define IRQ18_MCU_ON_MASK 0x1
+#define IRQ18_MCU_ON_MASK_SFT BIT(18)
+#define IRQ17_MCU_ON_SFT 17
+#define IRQ17_MCU_ON_MASK 0x1
+#define IRQ17_MCU_ON_MASK_SFT BIT(17)
+#define IRQ16_MCU_ON_SFT 16
+#define IRQ16_MCU_ON_MASK 0x1
+#define IRQ16_MCU_ON_MASK_SFT BIT(16)
+#define IRQ15_MCU_ON_SFT 15
+#define IRQ15_MCU_ON_MASK 0x1
+#define IRQ15_MCU_ON_MASK_SFT BIT(15)
+#define IRQ14_MCU_ON_SFT 14
+#define IRQ14_MCU_ON_MASK 0x1
+#define IRQ14_MCU_ON_MASK_SFT BIT(14)
+#define IRQ13_MCU_ON_SFT 13
+#define IRQ13_MCU_ON_MASK 0x1
+#define IRQ13_MCU_ON_MASK_SFT BIT(13)
+#define IRQ12_MCU_ON_SFT 12
+#define IRQ12_MCU_ON_MASK 0x1
+#define IRQ12_MCU_ON_MASK_SFT BIT(12)
+#define IRQ11_MCU_ON_SFT 11
+#define IRQ11_MCU_ON_MASK 0x1
+#define IRQ11_MCU_ON_MASK_SFT BIT(11)
+#define IRQ10_MCU_ON_SFT 10
+#define IRQ10_MCU_ON_MASK 0x1
+#define IRQ10_MCU_ON_MASK_SFT BIT(10)
+#define IRQ9_MCU_ON_SFT 9
+#define IRQ9_MCU_ON_MASK 0x1
+#define IRQ9_MCU_ON_MASK_SFT BIT(9)
+#define IRQ8_MCU_ON_SFT 8
+#define IRQ8_MCU_ON_MASK 0x1
+#define IRQ8_MCU_ON_MASK_SFT BIT(8)
+#define IRQ7_MCU_ON_SFT 7
+#define IRQ7_MCU_ON_MASK 0x1
+#define IRQ7_MCU_ON_MASK_SFT BIT(7)
+#define IRQ6_MCU_ON_SFT 6
+#define IRQ6_MCU_ON_MASK 0x1
+#define IRQ6_MCU_ON_MASK_SFT BIT(6)
+#define IRQ5_MCU_ON_SFT 5
+#define IRQ5_MCU_ON_MASK 0x1
+#define IRQ5_MCU_ON_MASK_SFT BIT(5)
+#define IRQ4_MCU_ON_SFT 4
+#define IRQ4_MCU_ON_MASK 0x1
+#define IRQ4_MCU_ON_MASK_SFT BIT(4)
+#define IRQ3_MCU_ON_SFT 3
+#define IRQ3_MCU_ON_MASK 0x1
+#define IRQ3_MCU_ON_MASK_SFT BIT(3)
+#define IRQ2_MCU_ON_SFT 2
+#define IRQ2_MCU_ON_MASK 0x1
+#define IRQ2_MCU_ON_MASK_SFT BIT(2)
+#define IRQ1_MCU_ON_SFT 1
+#define IRQ1_MCU_ON_MASK 0x1
+#define IRQ1_MCU_ON_MASK_SFT BIT(1)
+#define IRQ0_MCU_ON_SFT 0
+#define IRQ0_MCU_ON_MASK 0x1
+#define IRQ0_MCU_ON_MASK_SFT BIT(0)
+
+/* AFE_IRQ_MCU_CON1 */
+#define IRQ7_MCU_MODE_SFT 28
+#define IRQ7_MCU_MODE_MASK 0xf
+#define IRQ7_MCU_MODE_MASK_SFT GENMASK(31, 28)
+#define IRQ6_MCU_MODE_SFT 24
+#define IRQ6_MCU_MODE_MASK 0xf
+#define IRQ6_MCU_MODE_MASK_SFT GENMASK(27, 24)
+#define IRQ5_MCU_MODE_SFT 20
+#define IRQ5_MCU_MODE_MASK 0xf
+#define IRQ5_MCU_MODE_MASK_SFT GENMASK(23, 20)
+#define IRQ4_MCU_MODE_SFT 16
+#define IRQ4_MCU_MODE_MASK 0xf
+#define IRQ4_MCU_MODE_MASK_SFT GENMASK(19, 16)
+#define IRQ3_MCU_MODE_SFT 12
+#define IRQ3_MCU_MODE_MASK 0xf
+#define IRQ3_MCU_MODE_MASK_SFT GENMASK(15, 12)
+#define IRQ2_MCU_MODE_SFT 8
+#define IRQ2_MCU_MODE_MASK 0xf
+#define IRQ2_MCU_MODE_MASK_SFT GENMASK(11, 8)
+#define IRQ1_MCU_MODE_SFT 4
+#define IRQ1_MCU_MODE_MASK 0xf
+#define IRQ1_MCU_MODE_MASK_SFT GENMASK(7, 4)
+#define IRQ0_MCU_MODE_SFT 0
+#define IRQ0_MCU_MODE_MASK 0xf
+#define IRQ0_MCU_MODE_MASK_SFT GENMASK(3, 0)
+
+/* AFE_IRQ_MCU_CON2 */
+#define IRQ15_MCU_MODE_SFT 28
+#define IRQ15_MCU_MODE_MASK 0xf
+#define IRQ15_MCU_MODE_MASK_SFT GENMASK(31, 28)
+#define IRQ14_MCU_MODE_SFT 24
+#define IRQ14_MCU_MODE_MASK 0xf
+#define IRQ14_MCU_MODE_MASK_SFT GENMASK(27, 24)
+#define IRQ13_MCU_MODE_SFT 20
+#define IRQ13_MCU_MODE_MASK 0xf
+#define IRQ13_MCU_MODE_MASK_SFT GENMASK(23, 20)
+#define IRQ12_MCU_MODE_SFT 16
+#define IRQ12_MCU_MODE_MASK 0xf
+#define IRQ12_MCU_MODE_MASK_SFT GENMASK(19, 16)
+#define IRQ11_MCU_MODE_SFT 12
+#define IRQ11_MCU_MODE_MASK 0xf
+#define IRQ11_MCU_MODE_MASK_SFT GENMASK(15, 12)
+#define IRQ10_MCU_MODE_SFT 8
+#define IRQ10_MCU_MODE_MASK 0xf
+#define IRQ10_MCU_MODE_MASK_SFT GENMASK(11, 8)
+#define IRQ9_MCU_MODE_SFT 4
+#define IRQ9_MCU_MODE_MASK 0xf
+#define IRQ9_MCU_MODE_MASK_SFT GENMASK(7, 4)
+#define IRQ8_MCU_MODE_SFT 0
+#define IRQ8_MCU_MODE_MASK 0xf
+#define IRQ8_MCU_MODE_MASK_SFT GENMASK(3, 0)
+
+/* AFE_IRQ_MCU_CON3 */
+#define IRQ23_MCU_MODE_SFT 28
+#define IRQ23_MCU_MODE_MASK 0xf
+#define IRQ23_MCU_MODE_MASK_SFT GENMASK(31, 28)
+#define IRQ22_MCU_MODE_SFT 24
+#define IRQ22_MCU_MODE_MASK 0xf
+#define IRQ22_MCU_MODE_MASK_SFT GENMASK(27, 24)
+#define IRQ21_MCU_MODE_SFT 20
+#define IRQ21_MCU_MODE_MASK 0xf
+#define IRQ21_MCU_MODE_MASK_SFT GENMASK(23, 20)
+#define IRQ20_MCU_MODE_SFT 16
+#define IRQ20_MCU_MODE_MASK 0xf
+#define IRQ20_MCU_MODE_MASK_SFT GENMASK(19, 16)
+#define IRQ19_MCU_MODE_SFT 12
+#define IRQ19_MCU_MODE_MASK 0xf
+#define IRQ19_MCU_MODE_MASK_SFT GENMASK(15, 12)
+#define IRQ18_MCU_MODE_SFT 8
+#define IRQ18_MCU_MODE_MASK 0xf
+#define IRQ18_MCU_MODE_MASK_SFT GENMASK(11, 8)
+#define IRQ17_MCU_MODE_SFT 4
+#define IRQ17_MCU_MODE_MASK 0xf
+#define IRQ17_MCU_MODE_MASK_SFT GENMASK(7, 4)
+#define IRQ16_MCU_MODE_SFT 0
+#define IRQ16_MCU_MODE_MASK 0xf
+#define IRQ16_MCU_MODE_MASK_SFT GENMASK(3, 0)
+
+/* AFE_IRQ_MCU_CON4 */
+#define IRQ26_MCU_MODE_SFT 8
+#define IRQ26_MCU_MODE_MASK 0xf
+#define IRQ26_MCU_MODE_MASK_SFT GENMASK(11, 8)
+#define IRQ25_MCU_MODE_SFT 4
+#define IRQ25_MCU_MODE_MASK 0xf
+#define IRQ25_MCU_MODE_MASK_SFT GENMASK(7, 4)
+#define IRQ24_MCU_MODE_SFT 0
+#define IRQ24_MCU_MODE_MASK 0xf
+#define IRQ24_MCU_MODE_MASK_SFT GENMASK(3, 0)
+
+/* AFE_IRQ_MCU_CLR */
+#define IRQ31_MCU_CLR_SFT 31
+#define IRQ31_MCU_CLR_MASK_SFT BIT(31)
+#define IRQ26_MCU_CLR_SFT 26
+#define IRQ26_MCU_CLR_MASK_SFT BIT(26)
+#define IRQ25_MCU_CLR_SFT 25
+#define IRQ25_MCU_CLR_MASK_SFT BIT(25)
+#define IRQ24_MCU_CLR_SFT 24
+#define IRQ24_MCU_CLR_MASK_SFT BIT(24)
+#define IRQ23_MCU_CLR_SFT 23
+#define IRQ23_MCU_CLR_MASK_SFT BIT(23)
+#define IRQ22_MCU_CLR_SFT 22
+#define IRQ22_MCU_CLR_MASK_SFT BIT(22)
+#define IRQ21_MCU_CLR_SFT 21
+#define IRQ21_MCU_CLR_MASK_SFT BIT(21)
+#define IRQ20_MCU_CLR_SFT 20
+#define IRQ20_MCU_CLR_MASK_SFT BIT(20)
+#define IRQ19_MCU_CLR_SFT 19
+#define IRQ19_MCU_CLR_MASK_SFT BIT(19)
+#define IRQ18_MCU_CLR_SFT 18
+#define IRQ18_MCU_CLR_MASK_SFT BIT(18)
+#define IRQ17_MCU_CLR_SFT 17
+#define IRQ17_MCU_CLR_MASK_SFT BIT(17)
+#define IRQ16_MCU_CLR_SFT 16
+#define IRQ16_MCU_CLR_MASK_SFT BIT(16)
+#define IRQ15_MCU_CLR_SFT 15
+#define IRQ15_MCU_CLR_MASK_SFT BIT(15)
+#define IRQ14_MCU_CLR_SFT 14
+#define IRQ14_MCU_CLR_MASK_SFT BIT(14)
+#define IRQ13_MCU_CLR_SFT 13
+#define IRQ13_MCU_CLR_MASK_SFT BIT(13)
+#define IRQ12_MCU_CLR_SFT 12
+#define IRQ12_MCU_CLR_MASK_SFT BIT(12)
+#define IRQ11_MCU_CLR_SFT 11
+#define IRQ11_MCU_CLR_MASK_SFT BIT(11)
+#define IRQ10_MCU_CLR_SFT 10
+#define IRQ10_MCU_CLR_MASK_SFT BIT(10)
+#define IRQ9_MCU_CLR_SFT 9
+#define IRQ9_MCU_CLR_MASK_SFT BIT(9)
+#define IRQ8_MCU_CLR_SFT 8
+#define IRQ8_MCU_CLR_MASK_SFT BIT(8)
+#define IRQ7_MCU_CLR_SFT 7
+#define IRQ7_MCU_CLR_MASK_SFT BIT(7)
+#define IRQ6_MCU_CLR_SFT 6
+#define IRQ6_MCU_CLR_MASK_SFT BIT(6)
+#define IRQ5_MCU_CLR_SFT 5
+#define IRQ5_MCU_CLR_MASK_SFT BIT(5)
+#define IRQ4_MCU_CLR_SFT 4
+#define IRQ4_MCU_CLR_MASK_SFT BIT(4)
+#define IRQ3_MCU_CLR_SFT 3
+#define IRQ3_MCU_CLR_MASK_SFT BIT(3)
+#define IRQ2_MCU_CLR_SFT 2
+#define IRQ2_MCU_CLR_MASK_SFT BIT(2)
+#define IRQ1_MCU_CLR_SFT 1
+#define IRQ1_MCU_CLR_MASK_SFT BIT(1)
+#define IRQ0_MCU_CLR_SFT 0
+#define IRQ0_MCU_CLR_MASK_SFT BIT(0)
+
+/* AFE_IRQ_MCU_EN */
+#define IRQ31_MCU_EN_SFT 31
+#define IRQ30_MCU_EN_SFT 30
+#define IRQ29_MCU_EN_SFT 29
+#define IRQ28_MCU_EN_SFT 28
+#define IRQ27_MCU_EN_SFT 27
+#define IRQ26_MCU_EN_SFT 26
+#define IRQ25_MCU_EN_SFT 25
+#define IRQ24_MCU_EN_SFT 24
+#define IRQ23_MCU_EN_SFT 23
+#define IRQ22_MCU_EN_SFT 22
+#define IRQ21_MCU_EN_SFT 21
+#define IRQ20_MCU_EN_SFT 20
+#define IRQ19_MCU_EN_SFT 19
+#define IRQ18_MCU_EN_SFT 18
+#define IRQ17_MCU_EN_SFT 17
+#define IRQ16_MCU_EN_SFT 16
+#define IRQ15_MCU_EN_SFT 15
+#define IRQ14_MCU_EN_SFT 14
+#define IRQ13_MCU_EN_SFT 13
+#define IRQ12_MCU_EN_SFT 12
+#define IRQ11_MCU_EN_SFT 11
+#define IRQ10_MCU_EN_SFT 10
+#define IRQ9_MCU_EN_SFT 9
+#define IRQ8_MCU_EN_SFT 8
+#define IRQ7_MCU_EN_SFT 7
+#define IRQ6_MCU_EN_SFT 6
+#define IRQ5_MCU_EN_SFT 5
+#define IRQ4_MCU_EN_SFT 4
+#define IRQ3_MCU_EN_SFT 3
+#define IRQ2_MCU_EN_SFT 2
+#define IRQ1_MCU_EN_SFT 1
+#define IRQ0_MCU_EN_SFT 0
+
+/* AFE_IRQ_MCU_SCP_EN */
+#define IRQ31_MCU_SCP_EN_SFT 31
+#define IRQ30_MCU_SCP_EN_SFT 30
+#define IRQ29_MCU_SCP_EN_SFT 29
+#define IRQ28_MCU_SCP_EN_SFT 28
+#define IRQ27_MCU_SCP_EN_SFT 27
+#define IRQ26_MCU_SCP_EN_SFT 26
+#define IRQ25_MCU_SCP_EN_SFT 25
+#define IRQ24_MCU_SCP_EN_SFT 24
+#define IRQ23_MCU_SCP_EN_SFT 23
+#define IRQ22_MCU_SCP_EN_SFT 22
+#define IRQ21_MCU_SCP_EN_SFT 21
+#define IRQ20_MCU_SCP_EN_SFT 20
+#define IRQ19_MCU_SCP_EN_SFT 19
+#define IRQ18_MCU_SCP_EN_SFT 18
+#define IRQ17_MCU_SCP_EN_SFT 17
+#define IRQ16_MCU_SCP_EN_SFT 16
+#define IRQ15_MCU_SCP_EN_SFT 15
+#define IRQ14_MCU_SCP_EN_SFT 14
+#define IRQ13_MCU_SCP_EN_SFT 13
+#define IRQ12_MCU_SCP_EN_SFT 12
+#define IRQ11_MCU_SCP_EN_SFT 11
+#define IRQ10_MCU_SCP_EN_SFT 10
+#define IRQ9_MCU_SCP_EN_SFT 9
+#define IRQ8_MCU_SCP_EN_SFT 8
+#define IRQ7_MCU_SCP_EN_SFT 7
+#define IRQ6_MCU_SCP_EN_SFT 6
+#define IRQ5_MCU_SCP_EN_SFT 5
+#define IRQ4_MCU_SCP_EN_SFT 4
+#define IRQ3_MCU_SCP_EN_SFT 3
+#define IRQ2_MCU_SCP_EN_SFT 2
+#define IRQ1_MCU_SCP_EN_SFT 1
+#define IRQ0_MCU_SCP_EN_SFT 0
+
+/* AFE_IRQ_MCU_DSP_EN */
+#define IRQ31_MCU_DSP_EN_SFT 31
+#define IRQ30_MCU_DSP_EN_SFT 30
+#define IRQ29_MCU_DSP_EN_SFT 29
+#define IRQ28_MCU_DSP_EN_SFT 28
+#define IRQ27_MCU_DSP_EN_SFT 27
+#define IRQ26_MCU_DSP_EN_SFT 26
+#define IRQ25_MCU_DSP_EN_SFT 25
+#define IRQ24_MCU_DSP_EN_SFT 24
+#define IRQ23_MCU_DSP_EN_SFT 23
+#define IRQ22_MCU_DSP_EN_SFT 22
+#define IRQ21_MCU_DSP_EN_SFT 21
+#define IRQ20_MCU_DSP_EN_SFT 20
+#define IRQ19_MCU_DSP_EN_SFT 19
+#define IRQ18_MCU_DSP_EN_SFT 18
+#define IRQ17_MCU_DSP_EN_SFT 17
+#define IRQ16_MCU_DSP_EN_SFT 16
+#define IRQ15_MCU_DSP_EN_SFT 15
+#define IRQ14_MCU_DSP_EN_SFT 14
+#define IRQ13_MCU_DSP_EN_SFT 13
+#define IRQ12_MCU_DSP_EN_SFT 12
+#define IRQ11_MCU_DSP_EN_SFT 11
+#define IRQ10_MCU_DSP_EN_SFT 10
+#define IRQ9_MCU_DSP_EN_SFT 9
+#define IRQ8_MCU_DSP_EN_SFT 8
+#define IRQ7_MCU_DSP_EN_SFT 7
+#define IRQ6_MCU_DSP_EN_SFT 6
+#define IRQ5_MCU_DSP_EN_SFT 5
+#define IRQ4_MCU_DSP_EN_SFT 4
+#define IRQ3_MCU_DSP_EN_SFT 3
+#define IRQ2_MCU_DSP_EN_SFT 2
+#define IRQ1_MCU_DSP_EN_SFT 1
+#define IRQ0_MCU_DSP_EN_SFT 0
+
+/* AFE_AUD_PAD_TOP */
+#define AUD_PAD_TOP_MON_SFT 15
+#define AUD_PAD_TOP_MON_MASK_SFT GENMASK(31, 15)
+#define AUD_PAD_TOP_FIFO_RSP_SFT 4
+#define AUD_PAD_TOP_FIFO_RSP_MASK_SFT GENMASK(7, 4)
+#define RG_RX_PROTOCOL2_SFT 3
+#define RG_RX_PROTOCOL2_MASK_SFT BIT(3)
+#define RESERVDED_01_SFT 1
+#define RESERVDED_01_MASK_SFT GENMASK(2, 1)
+#define RG_RX_FIFO_ON_SFT 0
+#define RG_RX_FIFO_ON_MASK_SFT BIT(0)
+
+/* AFE_ADDA_MTKAIF_SYNCWORD_CFG */
+#define RG_ADDA6_MTKAIF_RX_SYNC_WORD2_DISABLE_SFT 23
+#define RG_ADDA6_MTKAIF_RX_SYNC_WORD2_DISABLE_MASK_SFT BIT(23)
+
+/* AFE_ADDA_MTKAIF_RX_CFG0 */
+#define MTKAIF_RXIF_VOICE_MODE_SFT 20
+#define MTKAIF_RXIF_VOICE_MODE_MASK_SFT GENMASK(23, 20)
+#define MTKAIF_RXIF_DETECT_ON_SFT 16
+#define MTKAIF_RXIF_DETECT_ON_MASK_SFT BIT(16)
+#define MTKAIF_RXIF_DATA_BIT_SFT 8
+#define MTKAIF_RXIF_DATA_BIT_MASK_SFT GENMASK(10, 8)
+#define MTKAIF_RXIF_FIFO_RSP_SFT 4
+#define MTKAIF_RXIF_FIFO_RSP_MASK_SFT GENMASK(6, 4)
+#define MTKAIF_RXIF_DATA_MODE_SFT 0
+#define MTKAIF_RXIF_DATA_MODE_MASK_SFT BIT(0)
+
+/* GENERAL_ASRC_MODE */
+#define GENERAL2_ASRCOUT_MODE_SFT 12
+#define GENERAL2_ASRCOUT_MODE_MASK 0xf
+#define GENERAL2_ASRCOUT_MODE_MASK_SFT GENMASK(15, 12)
+#define GENERAL2_ASRCIN_MODE_SFT 8
+#define GENERAL2_ASRCIN_MODE_MASK 0xf
+#define GENERAL2_ASRCIN_MODE_MASK_SFT GENMASK(11, 8)
+#define GENERAL1_ASRCOUT_MODE_SFT 4
+#define GENERAL1_ASRCOUT_MODE_MASK 0xf
+#define GENERAL1_ASRCOUT_MODE_MASK_SFT GENMASK(7, 4)
+#define GENERAL1_ASRCIN_MODE_SFT 0
+#define GENERAL1_ASRCIN_MODE_MASK 0xf
+#define GENERAL1_ASRCIN_MODE_MASK_SFT GENMASK(3, 0)
+
+/* GENERAL_ASRC_EN_ON */
+#define GENERAL2_ASRC_EN_ON_SFT 1
+#define GENERAL2_ASRC_EN_ON_MASK_SFT BIT(1)
+#define GENERAL1_ASRC_EN_ON_SFT 0
+#define GENERAL1_ASRC_EN_ON_MASK_SFT BIT(0)
+
+/* AFE_GENERAL1_ASRC_2CH_CON0 */
+#define G_SRC_CHSET_STR_CLR_SFT 4
+#define G_SRC_CHSET_STR_CLR_MASK_SFT BIT(4)
+#define G_SRC_CHSET_ON_SFT 2
+#define G_SRC_CHSET_ON_MASK_SFT BIT(2)
+#define G_SRC_COEFF_SRAM_CTRL_SFT 1
+#define G_SRC_COEFF_SRAM_CTRL_MASK_SFT BIT(1)
+#define G_SRC_ASM_ON_SFT 0
+#define G_SRC_ASM_ON_MASK_SFT BIT(0)
+
+/* AFE_GENERAL1_ASRC_2CH_CON3 */
+#define G_SRC_ASM_FREQ_4_SFT 0
+#define G_SRC_ASM_FREQ_4_MASK_SFT GENMASK(23, 0)
+
+/* AFE_GENERAL1_ASRC_2CH_CON4 */
+#define G_SRC_ASM_FREQ_5_SFT 0
+#define G_SRC_ASM_FREQ_5_MASK_SFT GENMASK(23, 0)
+
+/* AFE_GENERAL1_ASRC_2CH_CON13 */
+#define G_SRC_COEFF_SRAM_ADR_SFT 0
+#define G_SRC_COEFF_SRAM_ADR_MASK_SFT GENMASK(5, 0)
+
+/* AFE_GENERAL1_ASRC_2CH_CON2 */
+#define G_SRC_CHSET_O16BIT_SFT 19
+#define G_SRC_CHSET_O16BIT_MASK_SFT BIT(19)
+#define G_SRC_CHSET_CLR_IIR_HISTORY_SFT 17
+#define G_SRC_CHSET_CLR_IIR_HISTORY_MASK_SFT BIT(17)
+#define G_SRC_CHSET_IS_MONO_SFT 16
+#define G_SRC_CHSET_IS_MONO_MASK_SFT BIT(16)
+#define G_SRC_CHSET_IIR_EN_SFT 11
+#define G_SRC_CHSET_IIR_EN_MASK_SFT BIT(11)
+#define G_SRC_CHSET_IIR_STAGE_SFT 8
+#define G_SRC_CHSET_IIR_STAGE_MASK_SFT GENMASK(10, 8)
+#define G_SRC_CHSET_STR_CLR_RU_SFT 5
+#define G_SRC_CHSET_STR_CLR_RU_MASK_SFT BIT(5)
+#define G_SRC_CHSET_ON_SFT 2
+#define G_SRC_CHSET_ON_MASK_SFT BIT(2)
+#define G_SRC_COEFF_SRAM_CTRL_SFT 1
+#define G_SRC_COEFF_SRAM_CTRL_MASK_SFT BIT(1)
+#define G_SRC_ASM_ON_SFT 0
+#define G_SRC_ASM_ON_MASK_SFT BIT(0)
+
+/* AFE_ADDA_DL_SDM_DITHER_CON */
+#define AFE_DL_SDM_DITHER_64TAP_EN_SFT 20
+#define AFE_DL_SDM_DITHER_64TAP_EN_MASK_SFT BIT(20)
+#define AFE_DL_SDM_DITHER_EN_SFT 16
+#define AFE_DL_SDM_DITHER_EN_MASK_SFT BIT(16)
+#define AFE_DL_SDM_DITHER_GAIN_SFT 0
+#define AFE_DL_SDM_DITHER_GAIN_MASK_SFT GENMASK(7, 0)
+
+/* AFE_ADDA_DL_SDM_AUTO_RESET_CON */
+#define SDM_AUTO_RESET_TEST_ON_SFT 31
+#define SDM_AUTO_RESET_TEST_ON_MASK_SFT BIT(31)
+#define AFE_DL_USE_NEW_2ND_SDM_SFT 28
+#define AFE_DL_USE_NEW_2ND_SDM_MASK_SFT BIT(28)
+#define SDM_AUTO_RESET_COUNT_TH_SFT 0
+#define SDM_AUTO_RESET_COUNT_TH_MASK_SFT GENMASK(23, 0)
+
+/* AFE_ASRC_2CH_CON0 */
+#define CON0_CHSET_STR_CLR_SFT 4
+#define CON0_CHSET_STR_CLR_MASK_SFT BIT(4)
+#define CON0_ASM_ON_SFT 0
+#define CON0_ASM_ON_MASK_SFT BIT(0)
+
+/* AFE_ASRC_2CH_CON5 */
+#define CALI_EN_SFT 0
+#define CALI_EN_MASK_SFT BIT(0)
+
+/* FPGA_CFG4 */
+#define IRQ_COUNTER_SFT 3
+#define IRQ_COUNTER_MASK_SFT GENMASK(31, 3)
+#define IRQ_CLK_COUNTER_CLEAN_SFT 2
+#define IRQ_CLK_COUNTER_CLEAN_MASK_SFT BIT(2)
+#define IRQ_CLK_COUNTER_PAUSE_SFT 1
+#define IRQ_CLK_COUNTER_PAUSE_MASK_SFT BIT(1)
+#define IRQ_CLK_COUNTER_ON_SFT 0
+#define IRQ_CLK_COUNTER_ON_MASK_SFT BIT(0)
+
+/* FPGA_CFG5 */
+#define WR_MSTR_ON_SFT 16
+#define WR_MSTR_ON_MASK_SFT GENMASK(28, 16)
+#define WR_AG_SEL_SFT 0
+#define WR_AG_SEL_MASK_SFT GENMASK(12, 0)
+
+/* FPGA_CFG6 */
+#define WR_MSTR_REQ_REAL_SFT 16
+#define WR_MSTR_REQ_REAL_MASK_SFT GENMASK(28, 16)
+#define WR_MSTR_REQ_IN_SFT 0
+#define WR_MSTR_REQ_IN_MASK_SFT GENMASK(12, 0)
+
+/* FPGA_CFG7 */
+#define MEM1_WDATA_MON0_SFT 0
+#define MEM1_WDATA_MON0_MASK_SFT GENMASK(31, 0)
+
+/* FPGA_CFG8 */
+#define MEM1_WDATA_MON1_SFT 0
+#define MEM1_WDATA_MON1_MASK_SFT GENMASK(31, 0)
+
+/* FPGA_CFG9 */
+#define MEM_WE_SFT 31
+#define MEM_WE_MASK_SFT BIT(31)
+#define AFE_HREADY_SFT 30
+#define AFE_HREADY_MASK_SFT BIT(30)
+#define MEM_WR_REQ_SFT 29
+#define MEM_WR_REQ_MASK_SFT BIT(29)
+#define WR_AG_REG_MON_SFT 16
+#define WR_AG_REG_MON_MASK_SFT GENMASK(28, 16)
+#define HCLK_CK_SFT 15
+#define HCLK_CK_MASK_SFT BIT(15)
+#define MEM_RD_REQ_SFT 14
+#define MEM_RD_REQ_MASK_SFT BIT(14)
+#define RD_AG_REQ_MON_SFT 0
+#define RD_AG_REQ_MON_MASK_SFT GENMASK(13, 0)
+
+/* FPGA_CFG10 */
+#define MEM_BYTE_0_SFT 0
+#define MEM_BYTE_0_MASK_SFT GENMASK(31, 0)
+
+/* FPGA_CFG11 */
+#define MEM_BYTE_1_SFT 0
+#define MEM_BYTE_1_MASK_SFT GENMASK(31, 0)
+
+/* FPGA_CFG12 */
+#define RDATA_CNT_SFT 30
+#define RDATA_CNT_MASK_SFT GENMASK(31, 30)
+#define MS2_HREADY_SFT 29
+#define MS2_HREADY_MASK_SFT BIT(29)
+#define MS1_HREADY_SFT 28
+#define MS1_HREADY_MASK_SFT BIT(28)
+#define AG_SEL_SFT 0
+#define AG_SEL_MASK_SFT GENMASK(25, 0)
+
+/* FPGA_CFG13 */
+#define AFE_ST_SFT 27
+#define AFE_ST_MASK_SFT GENMASK(31, 27)
+#define AG_IN_SERVICE_SFT 0
+#define AG_IN_SERVICE_MASK_SFT GENMASK(25, 0)
+
+/* ETDM_IN1_CON0 */
+#define ETDM_IN1_CON0_REG_ETDM_IN_EN_SFT 0
+#define ETDM_IN1_CON0_REG_ETDM_IN_EN_MASK_SFT BIT(0)
+#define ETDM_IN1_CON0_REG_SYNC_MODE_SFT 1
+#define ETDM_IN1_CON0_REG_SYNC_MODE_MASK_SFT BIT(1)
+#define ETDM_IN1_CON0_REG_LSB_FIRST_SFT 3
+#define ETDM_IN1_CON0_REG_LSB_FIRST_MASK_SFT BIT(3)
+#define ETDM_IN1_CON0_REG_SOFT_RST_SFT 4
+#define ETDM_IN1_CON0_REG_SOFT_RST_MASK_SFT BIT(4)
+#define ETDM_IN1_CON0_REG_SLAVE_MODE_SFT 5
+#define ETDM_IN1_CON0_REG_SLAVE_MODE_MASK_SFT BIT(5)
+#define ETDM_IN1_CON0_REG_FMT_SFT 6
+#define ETDM_IN1_CON0_REG_FMT_MASK_SFT GENMASK(8, 6)
+#define ETDM_IN1_CON0_REG_LRCK_EDGE_SEL_SFT 10
+#define ETDM_IN1_CON0_REG_LRCK_EDGE_SEL_MASK_SFT BIT(10)
+#define ETDM_IN1_CON0_REG_BIT_LENGTH_SFT 11
+#define ETDM_IN1_CON0_REG_BIT_LENGTH_MASK_SFT GENMASK(15, 11)
+#define ETDM_IN1_CON0_REG_WORD_LENGTH_SFT 16
+#define ETDM_IN1_CON0_REG_WORD_LENGTH_MASK_SFT GENMASK(20, 16)
+#define ETDM_IN1_CON0_REG_CH_NUM_SFT 23
+#define ETDM_IN1_CON0_REG_CH_NUM_MASK_SFT GENMASK(27, 23)
+#define ETDM_IN1_CON0_REG_RELATCH_1X_EN_SEL_DOMAIN_SFT 28
+#define ETDM_IN1_CON0_REG_RELATCH_1X_EN_SEL_DOMAIN_MASK_SFT GENMASK(31, 28)
+#define ETDM_IN1_CON0_REG_VALID_TOGETHER_SFT 31
+#define ETDM_IN1_CON0_REG_VALID_TOGETHER_MASK_SFT BIT(31)
+#define ETDM_IN_CON0_CTRL_MASK 0x1f9ff9e2
+
+/* ETDM_IN1_CON1 */
+#define ETDM_IN1_CON1_REG_INITIAL_COUNT_SFT 0
+#define ETDM_IN1_CON1_REG_INITIAL_COUNT_MASK_SFT GENMASK(4, 0)
+#define ETDM_IN1_CON1_REG_INITIAL_POINT_SFT 5
+#define ETDM_IN1_CON1_REG_INITIAL_POINT_MASK_SFT GENMASK(9, 5)
+#define ETDM_IN1_CON1_REG_LRCK_AUTO_OFF_SFT 10
+#define ETDM_IN1_CON1_REG_LRCK_AUTO_OFF_MASK_SFT BIT(10)
+#define ETDM_IN1_CON1_REG_BCK_AUTO_OFF_SFT 11
+#define ETDM_IN1_CON1_REG_BCK_AUTO_OFF_MASK_SFT BIT(11)
+#define ETDM_IN1_CON1_REG_INITIAL_LRCK_SFT 13
+#define ETDM_IN1_CON1_REG_INITIAL_LRCK_MASK_SFT BIT(13)
+#define ETDM_IN1_CON1_REG_LRCK_RESET_SFT 15
+#define ETDM_IN1_CON1_REG_LRCK_RESET_MASK_SFT BIT(15)
+#define ETDM_IN1_CON1_PINMUX_MCLK_CTRL_OE_SFT 16
+#define ETDM_IN1_CON1_PINMUX_MCLK_CTRL_OE_MASK_SFT BIT(16)
+#define ETDM_IN1_CON1_REG_OUTPUT_CR_EN_SFT 18
+#define ETDM_IN1_CON1_REG_OUTPUT_CR_EN_MASK_SFT BIT(18)
+#define ETDM_IN1_CON1_REG_LR_ALIGN_SFT 19
+#define ETDM_IN1_CON1_REG_LR_ALIGN_MASK_SFT BIT(19)
+#define ETDM_IN1_CON1_REG_LRCK_WIDTH_SFT 20
+#define ETDM_IN1_CON1_REG_LRCK_WIDTH_MASK_SFT GENMASK(29, 20)
+#define ETDM_IN1_CON1_REG_DIRECT_INPUT_MASTER_BCK_SFT 30
+#define ETDM_IN1_CON1_REG_DIRECT_INPUT_MASTER_BCK_MASK_SFT BIT(30)
+#define ETDM_IN1_CON1_REG_LRCK_AUTO_MODE_SFT 31
+#define ETDM_IN1_CON1_REG_LRCK_AUTO_MODE_MASK_SFT BIT(31)
+#define ETDM_IN_CON1_CTRL_MASK 0xbff10000
+
+/* ETDM_IN1_CON2 */
+#define ETDM_IN1_CON2_REG_UPDATE_POINT_SFT 0
+#define ETDM_IN1_CON2_REG_UPDATE_POINT_MASK_SFT GENMASK(4, 0)
+#define ETDM_IN1_CON2_REG_UPDATE_GAP_SFT 5
+#define ETDM_IN1_CON2_REG_UPDATE_GAP_MASK_SFT GENMASK(9, 5)
+#define ETDM_IN1_CON2_REG_CLOCK_SOURCE_SEL_SFT 10
+#define ETDM_IN1_CON2_REG_CLOCK_SOURCE_SEL_MASK_SFT GENMASK(12, 10)
+#define ETDM_IN1_CON2_REG_AGENT_USE_ETDM_BCK_SFT 13
+#define ETDM_IN1_CON2_REG_AGENT_USE_ETDM_BCK_MASK_SFT BIT(13)
+#define ETDM_IN1_CON2_REG_CK_EN_SEL_AUTO_SFT 14
+#define ETDM_IN1_CON2_REG_CK_EN_SEL_AUTO_MASK_SFT BIT(14)
+#define ETDM_IN1_CON2_REG_MULTI_IP_ONE_DATA_CH_NUM_SFT 15
+#define ETDM_IN1_CON2_REG_MULTI_IP_ONE_DATA_CH_NUM_MASK_SFT GENMASK(19, 15)
+#define ETDM_IN1_CON2_REG_MASK_AUTO_SFT 20
+#define ETDM_IN1_CON2_REG_MASK_AUTO_MASK_SFT BIT(20)
+#define ETDM_IN1_CON2_REG_MASK_NUM_SFT 21
+#define ETDM_IN1_CON2_REG_MASK_NUM_MASK_SFT GENMASK(25, 21)
+#define ETDM_IN1_CON2_REG_UPDATE_POINT_AUTO_SFT 26
+#define ETDM_IN1_CON2_REG_UPDATE_POINT_AUTO_MASK_SFT BIT(26)
+#define ETDM_IN1_CON2_REG_SDATA_DELAY_0P5T_EN_SFT 27
+#define ETDM_IN1_CON2_REG_SDATA_DELAY_0P5T_EN_MASK_SFT BIT(27)
+#define ETDM_IN1_CON2_REG_SDATA_DELAY_BCK_INV_SFT 28
+#define ETDM_IN1_CON2_REG_SDATA_DELAY_BCK_INV_MASK_SFT BIT(28)
+#define ETDM_IN1_CON2_REG_LRCK_DELAY_0P5T_EN_SFT 29
+#define ETDM_IN1_CON2_REG_LRCK_DELAY_0P5T_EN_MASK_SFT BIT(29)
+#define ETDM_IN1_CON2_REG_LRCK_DELAY_BCK_INV_SFT 30
+#define ETDM_IN1_CON2_REG_LRCK_DELAY_BCK_INV_MASK_SFT BIT(30)
+#define ETDM_IN1_CON2_REG_MULTI_IP_MODE_SFT 31
+#define ETDM_IN1_CON2_REG_MULTI_IP_MODE_MASK_SFT BIT(31)
+#define ETDM_IN_CON2_CTRL_MASK 0x800f8000
+#define ETDM_IN_CON2_MULTI_IP_CH(x) (((x) - 1) << 15)
+#define ETDM_IN_CON2_MULTI_IP_2CH_MODE BIT(31)
+
+/* ETDM_IN1_CON3 */
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_0_SFT 0
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_0_MASK_SFT BIT(0)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_1_SFT 1
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_1_MASK_SFT BIT(1)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_2_SFT 2
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_2_MASK_SFT BIT(2)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_3_SFT 3
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_3_MASK_SFT BIT(3)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_4_SFT 4
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_4_MASK_SFT BIT(4)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_5_SFT 5
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_5_MASK_SFT BIT(5)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_6_SFT 6
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_6_MASK_SFT BIT(6)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_7_SFT 7
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_7_MASK_SFT BIT(7)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_8_SFT 8
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_8_MASK_SFT BIT(8)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_9_SFT 9
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_9_MASK_SFT BIT(9)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_10_SFT 10
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_10_MASK_SFT BIT(10)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_11_SFT 11
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_11_MASK_SFT BIT(11)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_12_SFT 12
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_12_MASK_SFT BIT(12)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_13_SFT 13
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_13_MASK_SFT BIT(13)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_14_SFT 14
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_14_MASK_SFT BIT(14)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_15_SFT 15
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_15_MASK_SFT BIT(15)
+#define ETDM_IN1_CON3_REG_RJ_DATA_RIGHT_ALIGN_SFT 16
+#define ETDM_IN1_CON3_REG_RJ_DATA_RIGHT_ALIGN_MASK_SFT BIT(16)
+#define ETDM_IN1_CON3_REG_MONITOR_SEL_SFT 17
+#define ETDM_IN1_CON3_REG_MONITOR_SEL_MASK_SFT GENMASK(18, 17)
+#define ETDM_IN1_CON3_REG_CNT_UPPER_LIMIT_SFT 19
+#define ETDM_IN1_CON3_REG_CNT_UPPER_LIMIT_MASK_SFT GENMASK(24, 19)
+#define ETDM_IN1_CON3_REG_COMPACT_SAMPLE_END_DIS_SFT 25
+#define ETDM_IN1_CON3_REG_COMPACT_SAMPLE_END_DIS_MASK_SFT BIT(25)
+#define ETDM_IN1_CON3_REG_FS_TIMING_SEL_SFT 26
+#define ETDM_IN1_CON3_REG_FS_TIMING_SEL_MASK_SFT GENMASK(30, 26)
+#define ETDM_IN1_CON3_REG_SAMPLE_END_MODE_SFT 31
+#define ETDM_IN1_CON3_REG_SAMPLE_END_MODE_MASK_SFT BIT(31)
+#define ETDM_IN_CON3_CTRL_MASK (0x7c000000)
+#define ETDM_IN_CON3_FS(x) (((x) & 0x1f) << 26)
+
+/* ETDM_IN1_CON4 */
+#define ETDM_IN1_CON4_REG_DSD_MODE_SFT 0
+#define ETDM_IN1_CON4_REG_DSD_MODE_MASK_SFT GENMASK(5, 0)
+#define ETDM_IN1_CON4_REG_DSD_REPACK_AUTO_MODE_SFT 8
+#define ETDM_IN1_CON4_REG_DSD_REPACK_AUTO_MODE_MASK_SFT BIT(8)
+#define ETDM_IN1_CON4_REG_REPACK_WORD_LENGTH_SFT 9
+#define ETDM_IN1_CON4_REG_REPACK_WORD_LENGTH_MASK_SFT GENMASK(10, 9)
+#define ETDM_IN1_CON4_REG_ASYNC_RESET_SFT 11
+#define ETDM_IN1_CON4_REG_ASYNC_RESET_MASK_SFT BIT(11)
+#define ETDM_IN1_CON4_REG_DSD_CHNUM_SFT 12
+#define ETDM_IN1_CON4_REG_DSD_CHNUM_MASK_SFT GENMASK(15, 12)
+#define ETDM_IN1_CON4_REG_SLAVE_BCK_INV_SFT 16
+#define ETDM_IN1_CON4_REG_SLAVE_BCK_INV_MASK_SFT BIT(16)
+#define ETDM_IN1_CON4_REG_SLAVE_LRCK_INV_SFT 17
+#define ETDM_IN1_CON4_REG_SLAVE_LRCK_INV_MASK_SFT BIT(17)
+#define ETDM_IN1_CON4_REG_MASTER_BCK_INV_SFT 18
+#define ETDM_IN1_CON4_REG_MASTER_BCK_INV_MASK_SFT BIT(18)
+#define ETDM_IN1_CON4_REG_MASTER_LRCK_INV_SFT 19
+#define ETDM_IN1_CON4_REG_MASTER_LRCK_INV_MASK_SFT BIT(19)
+#define ETDM_IN1_CON4_REG_RELATCH_1X_EN_SEL_SFT 20
+#define ETDM_IN1_CON4_REG_RELATCH_1X_EN_SEL_MASK_SFT GENMASK(24, 20)
+#define ETDM_IN1_CON4_REG_SAMPLE_END_POINT_SFT 25
+#define ETDM_IN1_CON4_REG_SAMPLE_END_POINT_MASK_SFT GENMASK(29, 25)
+#define ETDM_IN1_CON4_REG_WAIT_LAST_SAMPLE_SFT 30
+#define ETDM_IN1_CON4_REG_WAIT_LAST_SAMPLE_MASK_SFT BIT(30)
+#define ETDM_IN1_CON4_REG_MASTER_BCK_FORCE_ON_SFT 31
+#define ETDM_IN1_CON4_REG_MASTER_BCK_FORCE_ON_MASK_SFT BIT(31)
+#define ETDM_IN_CON4_CTRL_MASK 0x1ff0000
+#define ETDM_IN_CON4_FS(x) (((x) & 0x1f) << 20)
+#define ETDM_IN_CON4_CON0_MASTER_LRCK_INV BIT(19)
+#define ETDM_IN_CON4_CON0_MASTER_BCK_INV BIT(18)
+#define ETDM_IN_CON4_CON0_SLAVE_LRCK_INV BIT(17)
+#define ETDM_IN_CON4_CON0_SLAVE_BCK_INV BIT(16)
+
+/* ETDM_IN1_CON5 */
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_0_SFT 0
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_0_MASK_SFT BIT(0)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_1_SFT 1
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_1_MASK_SFT BIT(1)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_2_SFT 2
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_2_MASK_SFT BIT(2)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_3_SFT 3
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_3_MASK_SFT BIT(3)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_4_SFT 4
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_4_MASK_SFT BIT(4)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_5_SFT 5
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_5_MASK_SFT BIT(5)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_6_SFT 6
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_6_MASK_SFT BIT(6)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_7_SFT 7
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_7_MASK_SFT BIT(7)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_8_SFT 8
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_8_MASK_SFT BIT(8)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_9_SFT 9
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_9_MASK_SFT BIT(9)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_10_SFT 10
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_10_MASK_SFT BIT(10)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_11_SFT 11
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_11_MASK_SFT BIT(11)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_12_SFT 12
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_12_MASK_SFT BIT(12)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_13_SFT 13
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_13_MASK_SFT BIT(13)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_14_SFT 14
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_14_MASK_SFT BIT(14)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_15_SFT 15
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_15_MASK_SFT BIT(15)
+#define ETDM_IN1_CON5_REG_LR_SWAP_0_SFT 16
+#define ETDM_IN1_CON5_REG_LR_SWAP_0_MASK_SFT BIT(16)
+#define ETDM_IN1_CON5_REG_LR_SWAP_1_SFT 17
+#define ETDM_IN1_CON5_REG_LR_SWAP_1_MASK_SFT BIT(17)
+#define ETDM_IN1_CON5_REG_LR_SWAP_2_SFT 18
+#define ETDM_IN1_CON5_REG_LR_SWAP_2_MASK_SFT BIT(18)
+#define ETDM_IN1_CON5_REG_LR_SWAP_3_SFT 19
+#define ETDM_IN1_CON5_REG_LR_SWAP_3_MASK_SFT BIT(19)
+#define ETDM_IN1_CON5_REG_LR_SWAP_4_SFT 20
+#define ETDM_IN1_CON5_REG_LR_SWAP_4_MASK_SFT BIT(20)
+#define ETDM_IN1_CON5_REG_LR_SWAP_5_SFT 21
+#define ETDM_IN1_CON5_REG_LR_SWAP_5_MASK_SFT BIT(21)
+#define ETDM_IN1_CON5_REG_LR_SWAP_6_SFT 22
+#define ETDM_IN1_CON5_REG_LR_SWAP_6_MASK_SFT BIT(22)
+#define ETDM_IN1_CON5_REG_LR_SWAP_7_SFT 23
+#define ETDM_IN1_CON5_REG_LR_SWAP_7_MASK_SFT BIT(23)
+#define ETDM_IN1_CON5_REG_LR_SWAP_8_SFT 24
+#define ETDM_IN1_CON5_REG_LR_SWAP_8_MASK_SFT BIT(24)
+#define ETDM_IN1_CON5_REG_LR_SWAP_9_SFT 25
+#define ETDM_IN1_CON5_REG_LR_SWAP_9_MASK_SFT BIT(25)
+#define ETDM_IN1_CON5_REG_LR_SWAP_10_SFT 26
+#define ETDM_IN1_CON5_REG_LR_SWAP_10_MASK_SFT BIT(26)
+#define ETDM_IN1_CON5_REG_LR_SWAP_11_SFT 27
+#define ETDM_IN1_CON5_REG_LR_SWAP_11_MASK_SFT BIT(27)
+#define ETDM_IN1_CON5_REG_LR_SWAP_12_SFT 28
+#define ETDM_IN1_CON5_REG_LR_SWAP_12_MASK_SFT BIT(28)
+#define ETDM_IN1_CON5_REG_LR_SWAP_13_SFT 29
+#define ETDM_IN1_CON5_REG_LR_SWAP_13_MASK_SFT BIT(29)
+#define ETDM_IN1_CON5_REG_LR_SWAP_14_SFT 30
+#define ETDM_IN1_CON5_REG_LR_SWAP_14_MASK_SFT BIT(30)
+#define ETDM_IN1_CON5_REG_LR_SWAP_15_SFT 31
+#define ETDM_IN1_CON5_REG_LR_SWAP_15_MASK_SFT BIT(31)
+
+/* ETDM_IN1_CON6 */
+#define ETDM_IN1_CON6_LCH_DATA_REG_SFT 0
+#define ETDM_IN1_CON6_LCH_DATA_REG_MASK_SFT GENMASK(31, 0)
+
+/* ETDM_IN1_CON7 */
+#define ETDM_IN1_CON7_RCH_DATA_REG_SFT 0
+#define ETDM_IN1_CON7_RCH_DATA_REG_MASK_SFT GENMASK(31, 0)
+
+/* ETDM_IN1_CON8 */
+#define ETDM_IN1_CON8_REG_AFIFO_THRESHOLD_SFT 29
+#define ETDM_IN1_CON8_REG_AFIFO_THRESHOLD_MASK_SFT GENMASK(30, 29)
+#define ETDM_IN1_CON8_REG_CK_EN_SEL_MANUAL_SFT 16
+#define ETDM_IN1_CON8_REG_CK_EN_SEL_MANUAL_MASK_SFT GENMASK(25, 16)
+#define ETDM_IN1_CON8_REG_AFIFO_SW_RESET_SFT 15
+#define ETDM_IN1_CON8_REG_AFIFO_SW_RESET_MASK_SFT BIT(15)
+#define ETDM_IN1_CON8_REG_AFIFO_RESET_SEL_SFT 14
+#define ETDM_IN1_CON8_REG_AFIFO_RESET_SEL_MASK_SFT BIT(14)
+#define ETDM_IN1_CON8_REG_AFIFO_AUTO_RESET_DIS_SFT 9
+#define ETDM_IN1_CON8_REG_AFIFO_AUTO_RESET_DIS_MASK_SFT BIT(9)
+#define ETDM_IN1_CON8_REG_ETDM_USE_AFIFO_SFT 8
+#define ETDM_IN1_CON8_REG_ETDM_USE_AFIFO_MASK_SFT BIT(8)
+#define ETDM_IN1_CON8_REG_AFIFO_CLOCK_DOMAIN_SEL_SFT 5
+#define ETDM_IN1_CON8_REG_AFIFO_CLOCK_DOMAIN_SEL_MASK_SFT GENMASK(7, 5)
+#define ETDM_IN1_CON8_REG_AFIFO_MODE_SFT 0
+#define ETDM_IN1_CON8_REG_AFIFO_MODE_MASK_SFT GENMASK(4, 0)
+#define ETDM_IN_CON8_FS(x) (((x) & 0x1f) << 0)
+#define ETDM_IN_CON8_CTRL_MASK 0x13f
+
+#define AUDIO_TOP_CON0 0x0000
+#define AUDIO_TOP_CON1 0x0004
+#define AUDIO_TOP_CON2 0x0008
+#define AUDIO_TOP_CON3 0x000c
+#define AFE_DAC_CON0 0x0010
+#define AFE_I2S_CON 0x0018
+#define AFE_CONN0 0x0020
+#define AFE_CONN1 0x0024
+#define AFE_CONN2 0x0028
+#define AFE_CONN3 0x002c
+#define AFE_CONN4 0x0030
+#define AFE_I2S_CON1 0x0034
+#define AFE_I2S_CON2 0x0038
+#define AFE_I2S_CON3 0x0040
+#define AFE_CONN5 0x0044
+#define AFE_CONN_24BIT 0x0048
+#define AFE_DL1_CON0 0x004c
+#define AFE_DL1_BASE_MSB 0x0050
+#define AFE_DL1_BASE 0x0054
+#define AFE_DL1_CUR_MSB 0x0058
+#define AFE_DL1_CUR 0x005c
+#define AFE_DL1_END_MSB 0x0060
+#define AFE_DL1_END 0x0064
+#define AFE_DL2_CON0 0x0068
+#define AFE_DL2_BASE_MSB 0x006c
+#define AFE_DL2_BASE 0x0070
+#define AFE_DL2_CUR_MSB 0x0074
+#define AFE_DL2_CUR 0x0078
+#define AFE_DL2_END_MSB 0x007c
+#define AFE_DL2_END 0x0080
+#define AFE_DL3_CON0 0x0084
+#define AFE_DL3_BASE_MSB 0x0088
+#define AFE_DL3_BASE 0x008c
+#define AFE_DL3_CUR_MSB 0x0090
+#define AFE_DL3_CUR 0x0094
+#define AFE_DL3_END_MSB 0x0098
+#define AFE_DL3_END 0x009c
+#define AFE_CONN6 0x00bc
+#define AFE_DL4_CON0 0x00cc
+#define AFE_DL4_BASE_MSB 0x00d0
+#define AFE_DL4_BASE 0x00d4
+#define AFE_DL4_CUR_MSB 0x00d8
+#define AFE_DL4_CUR 0x00dc
+#define AFE_DL4_END_MSB 0x00e0
+#define AFE_DL4_END 0x00e4
+#define AFE_DL12_CON0 0x00e8
+#define AFE_DL12_BASE_MSB 0x00ec
+#define AFE_DL12_BASE 0x00f0
+#define AFE_DL12_CUR_MSB 0x00f4
+#define AFE_DL12_CUR 0x00f8
+#define AFE_DL12_END_MSB 0x00fc
+#define AFE_DL12_END 0x0100
+#define AFE_ADDA_DL_SRC2_CON0 0x0108
+#define AFE_ADDA_DL_SRC2_CON1 0x010c
+#define AFE_ADDA_UL_SRC_CON0 0x0114
+#define AFE_ADDA_UL_SRC_CON1 0x0118
+#define AFE_ADDA_TOP_CON0 0x0120
+#define AFE_ADDA_UL_DL_CON0 0x0124
+#define AFE_ADDA_SRC_DEBUG 0x012c
+#define AFE_ADDA_SRC_DEBUG_MON0 0x0130
+#define AFE_ADDA_SRC_DEBUG_MON1 0x0134
+#define AFE_ADDA_UL_SRC_MON0 0x0148
+#define AFE_ADDA_UL_SRC_MON1 0x014c
+#define AFE_SECURE_CON0 0x0150
+#define AFE_SRAM_BOUND 0x0154
+#define AFE_SECURE_CON1 0x0158
+#define AFE_SECURE_CONN0 0x015c
+#define AFE_VUL_CON0 0x0170
+#define AFE_VUL_BASE_MSB 0x0174
+#define AFE_VUL_BASE 0x0178
+#define AFE_VUL_CUR_MSB 0x017c
+#define AFE_VUL_CUR 0x0180
+#define AFE_VUL_END_MSB 0x0184
+#define AFE_VUL_END 0x0188
+#define AFE_SIDETONE_DEBUG 0x01d0
+#define AFE_SIDETONE_MON 0x01d4
+#define AFE_SINEGEN_CON2 0x01dc
+#define AFE_SIDETONE_CON0 0x01e0
+#define AFE_SIDETONE_COEFF 0x01e4
+#define AFE_SIDETONE_CON1 0x01e8
+#define AFE_SIDETONE_GAIN 0x01ec
+#define AFE_SINEGEN_CON0 0x01f0
+#define AFE_TOP_CON0 0x0200
+#define AFE_VUL2_CON0 0x020c
+#define AFE_VUL2_BASE_MSB 0x0210
+#define AFE_VUL2_BASE 0x0214
+#define AFE_VUL2_CUR_MSB 0x0218
+#define AFE_VUL2_CUR 0x021c
+#define AFE_VUL2_END_MSB 0x0220
+#define AFE_VUL2_END 0x0224
+#define AFE_VUL3_CON0 0x0228
+#define AFE_VUL3_BASE_MSB 0x022c
+#define AFE_VUL3_BASE 0x0230
+#define AFE_VUL3_CUR_MSB 0x0234
+#define AFE_VUL3_CUR 0x0238
+#define AFE_VUL3_END_MSB 0x023c
+#define AFE_VUL3_END 0x0240
+#define AFE_BUSY 0x0244
+#define AFE_BUS_CFG 0x0250
+#define AFE_ADDA_PREDIS_CON0 0x0260
+#define AFE_ADDA_PREDIS_CON1 0x0264
+#define AFE_I2S_MON 0x027c
+#define AFE_ADDA_IIR_COEF_02_01 0x0290
+#define AFE_ADDA_IIR_COEF_04_03 0x0294
+#define AFE_ADDA_IIR_COEF_06_05 0x0298
+#define AFE_ADDA_IIR_COEF_08_07 0x029c
+#define AFE_ADDA_IIR_COEF_10_09 0x02a0
+#define AFE_IRQ_MCU_CON1 0x02e4
+#define AFE_IRQ_MCU_CON2 0x02e8
+#define AFE_DAC_MON 0x02ec
+#define AFE_IRQ_MCU_CON3 0x02f0
+#define AFE_IRQ_MCU_CON4 0x02f4
+#define AFE_IRQ_MCU_CNT0 0x0300
+#define AFE_IRQ_MCU_CNT6 0x0304
+#define AFE_IRQ_MCU_CNT8 0x0308
+#define AFE_IRQ_MCU_DSP2_EN 0x030c
+#define AFE_IRQ0_MCU_CNT_MON 0x0310
+#define AFE_IRQ6_MCU_CNT_MON 0x0314
+#define AFE_VUL4_CON0 0x0358
+#define AFE_VUL4_BASE_MSB 0x035c
+#define AFE_VUL4_BASE 0x0360
+#define AFE_VUL4_CUR_MSB 0x0364
+#define AFE_VUL4_CUR 0x0368
+#define AFE_VUL4_END_MSB 0x036c
+#define AFE_VUL4_END 0x0370
+#define AFE_VUL12_CON0 0x0374
+#define AFE_VUL12_BASE_MSB 0x0378
+#define AFE_VUL12_BASE 0x037c
+#define AFE_VUL12_CUR_MSB 0x0380
+#define AFE_VUL12_CUR 0x0384
+#define AFE_VUL12_END_MSB 0x0388
+#define AFE_VUL12_END 0x038c
+#define AFE_IRQ3_MCU_CNT_MON 0x0398
+#define AFE_IRQ4_MCU_CNT_MON 0x039c
+#define AFE_IRQ_MCU_CON0 0x03a0
+#define AFE_IRQ_MCU_STATUS 0x03a4
+#define AFE_IRQ_MCU_CLR 0x03a8
+#define AFE_IRQ_MCU_CNT1 0x03ac
+#define AFE_IRQ_MCU_CNT2 0x03b0
+#define AFE_IRQ_MCU_EN 0x03b4
+#define AFE_IRQ_MCU_MON2 0x03b8
+#define AFE_IRQ_MCU_CNT5 0x03bc
+#define AFE_IRQ1_MCU_CNT_MON 0x03c0
+#define AFE_IRQ2_MCU_CNT_MON 0x03c4
+#define AFE_IRQ5_MCU_CNT_MON 0x03cc
+#define AFE_IRQ_MCU_DSP_EN 0x03d0
+#define AFE_IRQ_MCU_SCP_EN 0x03d4
+#define AFE_IRQ_MCU_CNT7 0x03dc
+#define AFE_IRQ7_MCU_CNT_MON 0x03e0
+#define AFE_IRQ_MCU_CNT3 0x03e4
+#define AFE_IRQ_MCU_CNT4 0x03e8
+#define AFE_IRQ_MCU_CNT11 0x03ec
+#define AFE_APLL1_TUNER_CFG 0x03f0
+#define AFE_APLL2_TUNER_CFG 0x03f4
+#define AFE_IRQ_MCU_MISS_CLR 0x03f8
+#define AFE_CONN33 0x0408
+#define AFE_IRQ_MCU_CNT12 0x040c
+#define AFE_GAIN1_CON0 0x0410
+#define AFE_GAIN1_CON1 0x0414
+#define AFE_GAIN1_CON2 0x0418
+#define AFE_GAIN1_CON3 0x041c
+#define AFE_CONN7 0x0420
+#define AFE_GAIN1_CUR 0x0424
+#define AFE_GAIN2_CON0 0x0428
+#define AFE_GAIN2_CON1 0x042c
+#define AFE_GAIN2_CON2 0x0430
+#define AFE_GAIN2_CON3 0x0434
+#define AFE_CONN8 0x0438
+#define AFE_GAIN2_CUR 0x043c
+#define AFE_CONN9 0x0440
+#define AFE_CONN10 0x0444
+#define AFE_CONN11 0x0448
+#define AFE_CONN12 0x044c
+#define AFE_CONN13 0x0450
+#define AFE_CONN14 0x0454
+#define AFE_CONN15 0x0458
+#define AFE_CONN16 0x045c
+#define AFE_CONN17 0x0460
+#define AFE_CONN18 0x0464
+#define AFE_CONN19 0x0468
+#define AFE_CONN20 0x046c
+#define AFE_CONN21 0x0470
+#define AFE_CONN22 0x0474
+#define AFE_CONN23 0x0478
+#define AFE_CONN24 0x047c
+#define AFE_CONN_RS 0x0494
+#define AFE_CONN_DI 0x0498
+#define AFE_CONN25 0x04b0
+#define AFE_CONN26 0x04b4
+#define AFE_CONN27 0x04b8
+#define AFE_CONN28 0x04bc
+#define AFE_CONN29 0x04c0
+#define AFE_CONN30 0x04c4
+#define AFE_CONN31 0x04c8
+#define AFE_CONN32 0x04cc
+#define AFE_SRAM_DELSEL_CON1 0x04f4
+#define AFE_CONN56 0x0500
+#define AFE_CONN57 0x0504
+#define AFE_CONN58 0x0508
+#define AFE_CONN59 0x050c
+#define AFE_CONN56_1 0x0510
+#define AFE_CONN57_1 0x0514
+#define AFE_CONN58_1 0x0518
+#define AFE_CONN59_1 0x051c
+#define PCM_INTF_CON1 0x0530
+#define PCM_INTF_CON2 0x0538
+#define PCM2_INTF_CON 0x053c
+#define AFE_CM1_CON 0x0550
+#define AFE_CONN34 0x0580
+#define FPGA_CFG0 0x05b0
+#define FPGA_CFG1 0x05b4
+#define FPGA_CFG2 0x05c0
+#define FPGA_CFG3 0x05c4
+#define AUDIO_TOP_DBG_CON 0x05c8
+#define AUDIO_TOP_DBG_MON0 0x05cc
+#define AUDIO_TOP_DBG_MON1 0x05d0
+#define AFE_IRQ8_MCU_CNT_MON 0x05e4
+#define AFE_IRQ11_MCU_CNT_MON 0x05e8
+#define AFE_IRQ12_MCU_CNT_MON 0x05ec
+#define AFE_IRQ_MCU_CNT9 0x0600
+#define AFE_IRQ_MCU_CNT10 0x0604
+#define AFE_IRQ_MCU_CNT13 0x0608
+#define AFE_IRQ_MCU_CNT14 0x060c
+#define AFE_IRQ_MCU_CNT15 0x0610
+#define AFE_IRQ_MCU_CNT16 0x0614
+#define AFE_IRQ_MCU_CNT17 0x0618
+#define AFE_IRQ_MCU_CNT18 0x061c
+#define AFE_IRQ_MCU_CNT19 0x0620
+#define AFE_IRQ_MCU_CNT20 0x0624
+#define AFE_IRQ_MCU_CNT21 0x0628
+#define AFE_IRQ_MCU_CNT22 0x062c
+#define AFE_IRQ_MCU_CNT23 0x0630
+#define AFE_IRQ_MCU_CNT24 0x0634
+#define AFE_IRQ_MCU_CNT25 0x0638
+#define AFE_IRQ_MCU_CNT26 0x063c
+#define AFE_IRQ9_MCU_CNT_MON 0x0660
+#define AFE_IRQ10_MCU_CNT_MON 0x0664
+#define AFE_IRQ13_MCU_CNT_MON 0x0668
+#define AFE_IRQ14_MCU_CNT_MON 0x066c
+#define AFE_IRQ15_MCU_CNT_MON 0x0670
+#define AFE_IRQ16_MCU_CNT_MON 0x0674
+#define AFE_IRQ17_MCU_CNT_MON 0x0678
+#define AFE_IRQ18_MCU_CNT_MON 0x067c
+#define AFE_IRQ19_MCU_CNT_MON 0x0680
+#define AFE_IRQ20_MCU_CNT_MON 0x0684
+#define AFE_IRQ21_MCU_CNT_MON 0x0688
+#define AFE_IRQ22_MCU_CNT_MON 0x068c
+#define AFE_IRQ23_MCU_CNT_MON 0x0690
+#define AFE_IRQ24_MCU_CNT_MON 0x0694
+#define AFE_IRQ25_MCU_CNT_MON 0x0698
+#define AFE_IRQ26_MCU_CNT_MON 0x069c
+#define AFE_IRQ31_MCU_CNT_MON 0x06a0
+#define AFE_GENERAL_REG0 0x0800
+#define AFE_GENERAL_REG1 0x0804
+#define AFE_GENERAL_REG2 0x0808
+#define AFE_GENERAL_REG3 0x080c
+#define AFE_GENERAL_REG4 0x0810
+#define AFE_GENERAL_REG5 0x0814
+#define AFE_GENERAL_REG6 0x0818
+#define AFE_GENERAL_REG7 0x081c
+#define AFE_GENERAL_REG8 0x0820
+#define AFE_GENERAL_REG9 0x0824
+#define AFE_GENERAL_REG10 0x0828
+#define AFE_GENERAL_REG11 0x082c
+#define AFE_GENERAL_REG12 0x0830
+#define AFE_GENERAL_REG13 0x0834
+#define AFE_GENERAL_REG14 0x0838
+#define AFE_GENERAL_REG15 0x083c
+#define AFE_CBIP_CFG0 0x0840
+#define AFE_CBIP_MON0 0x0844
+#define AFE_CBIP_SLV_MUX_MON0 0x0848
+#define AFE_CBIP_SLV_DECODER_MON0 0x084c
+#define AFE_ADDA6_MTKAIF_MON0 0x0854
+#define AFE_ADDA6_MTKAIF_MON1 0x0858
+#define AFE_AWB_CON0 0x085c
+#define AFE_AWB_BASE_MSB 0x0860
+#define AFE_AWB_BASE 0x0864
+#define AFE_AWB_CUR_MSB 0x0868
+#define AFE_AWB_CUR 0x086c
+#define AFE_AWB_END_MSB 0x0870
+#define AFE_AWB_END 0x0874
+#define AFE_AWB2_CON0 0x0878
+#define AFE_AWB2_BASE_MSB 0x087c
+#define AFE_AWB2_BASE 0x0880
+#define AFE_AWB2_CUR_MSB 0x0884
+#define AFE_AWB2_CUR 0x0888
+#define AFE_AWB2_END_MSB 0x088c
+#define AFE_AWB2_END 0x0890
+#define AFE_DAI_CON0 0x0894
+#define AFE_DAI_BASE_MSB 0x0898
+#define AFE_DAI_BASE 0x089c
+#define AFE_DAI_CUR_MSB 0x08a0
+#define AFE_DAI_CUR 0x08a4
+#define AFE_DAI_END_MSB 0x08a8
+#define AFE_DAI_END 0x08ac
+#define AFE_DAI2_CON0 0x08b0
+#define AFE_DAI2_BASE_MSB 0x08b4
+#define AFE_DAI2_BASE 0x08b8
+#define AFE_DAI2_CUR_MSB 0x08bc
+#define AFE_DAI2_CUR 0x08c0
+#define AFE_DAI2_END_MSB 0x08c4
+#define AFE_DAI2_END 0x08c8
+#define AFE_MEMIF_CON0 0x08cc
+#define AFE_CONN0_1 0x0900
+#define AFE_CONN1_1 0x0904
+#define AFE_CONN2_1 0x0908
+#define AFE_CONN3_1 0x090c
+#define AFE_CONN4_1 0x0910
+#define AFE_CONN5_1 0x0914
+#define AFE_CONN6_1 0x0918
+#define AFE_CONN7_1 0x091c
+#define AFE_CONN8_1 0x0920
+#define AFE_CONN9_1 0x0924
+#define AFE_CONN10_1 0x0928
+#define AFE_CONN11_1 0x092c
+#define AFE_CONN12_1 0x0930
+#define AFE_CONN13_1 0x0934
+#define AFE_CONN14_1 0x0938
+#define AFE_CONN15_1 0x093c
+#define AFE_CONN16_1 0x0940
+#define AFE_CONN17_1 0x0944
+#define AFE_CONN18_1 0x0948
+#define AFE_CONN19_1 0x094c
+#define AFE_CONN20_1 0x0950
+#define AFE_CONN21_1 0x0954
+#define AFE_CONN22_1 0x0958
+#define AFE_CONN23_1 0x095c
+#define AFE_CONN24_1 0x0960
+#define AFE_CONN25_1 0x0964
+#define AFE_CONN26_1 0x0968
+#define AFE_CONN27_1 0x096c
+#define AFE_CONN28_1 0x0970
+#define AFE_CONN29_1 0x0974
+#define AFE_CONN30_1 0x0978
+#define AFE_CONN31_1 0x097c
+#define AFE_CONN32_1 0x0980
+#define AFE_CONN33_1 0x0984
+#define AFE_CONN34_1 0x0988
+#define AFE_CONN_RS_1 0x098c
+#define AFE_CONN_DI_1 0x0990
+#define AFE_CONN_24BIT_1 0x0994
+#define AFE_CONN_REG 0x0998
+#define AFE_CONN35 0x09a0
+#define AFE_CONN36 0x09a4
+#define AFE_CONN37 0x09a8
+#define AFE_CONN38 0x09ac
+#define AFE_CONN35_1 0x09b0
+#define AFE_CONN36_1 0x09b4
+#define AFE_CONN37_1 0x09b8
+#define AFE_CONN38_1 0x09bc
+#define AFE_CONN39 0x09c0
+#define AFE_CONN40 0x09c4
+#define AFE_CONN41 0x09c8
+#define AFE_CONN42 0x09cc
+#define AFE_CONN39_1 0x09e0
+#define AFE_CONN40_1 0x09e4
+#define AFE_CONN41_1 0x09e8
+#define AFE_CONN42_1 0x09ec
+#define AFE_I2S_CON4 0x09f8
+#define AFE_CONN60 0x0a64
+#define AFE_CONN61 0x0a68
+#define AFE_CONN62 0x0a6c
+#define AFE_CONN63 0x0a70
+#define AFE_CONN64 0x0a74
+#define AFE_CONN65 0x0a78
+#define AFE_CONN66 0x0a7c
+#define AFE_ADDA6_TOP_CON0 0x0a80
+#define AFE_ADDA6_UL_SRC_CON0 0x0a84
+#define AFE_ADDA6_UL_SRC_CON1 0x0a88
+#define AFE_ADDA6_SRC_DEBUG 0x0a8c
+#define AFE_ADDA6_SRC_DEBUG_MON0 0x0a90
+#define AFE_ADDA6_ULCF_CFG_02_01 0x0aa0
+#define AFE_ADDA6_ULCF_CFG_04_03 0x0aa4
+#define AFE_ADDA6_ULCF_CFG_06_05 0x0aa8
+#define AFE_ADDA6_ULCF_CFG_08_07 0x0aac
+#define AFE_ADDA6_ULCF_CFG_10_09 0x0ab0
+#define AFE_ADDA6_ULCF_CFG_12_11 0x0ab4
+#define AFE_ADDA6_ULCF_CFG_14_13 0x0ab8
+#define AFE_ADDA6_ULCF_CFG_16_15 0x0abc
+#define AFE_ADDA6_ULCF_CFG_18_17 0x0ac0
+#define AFE_ADDA6_ULCF_CFG_20_19 0x0ac4
+#define AFE_ADDA6_ULCF_CFG_22_21 0x0ac8
+#define AFE_ADDA6_ULCF_CFG_24_23 0x0acc
+#define AFE_ADDA6_ULCF_CFG_26_25 0x0ad0
+#define AFE_ADDA6_ULCF_CFG_28_27 0x0ad4
+#define AFE_ADDA6_ULCF_CFG_30_29 0x0ad8
+#define AFE_ADD6A_UL_SRC_MON0 0x0ae4
+#define AFE_ADDA6_UL_SRC_MON1 0x0ae8
+#define AFE_CONN43 0x0af8
+#define AFE_CONN43_1 0x0afc
+#define AFE_MOD_DAI_CON0 0x0b00
+#define AFE_MOD_DAI_BASE_MSB 0x0b04
+#define AFE_MOD_DAI_BASE 0x0b08
+#define AFE_MOD_DAI_CUR_MSB 0x0b0c
+#define AFE_MOD_DAI_CUR 0x0b10
+#define AFE_MOD_DAI_END_MSB 0x0b14
+#define AFE_MOD_DAI_END 0x0b18
+#define AFE_AWB_RCH_MON 0x0b70
+#define AFE_AWB_LCH_MON 0x0b74
+#define AFE_VUL_RCH_MON 0x0b78
+#define AFE_VUL_LCH_MON 0x0b7c
+#define AFE_VUL12_RCH_MON 0x0b80
+#define AFE_VUL12_LCH_MON 0x0b84
+#define AFE_VUL2_RCH_MON 0x0b88
+#define AFE_VUL2_LCH_MON 0x0b8c
+#define AFE_DAI_DATA_MON 0x0b90
+#define AFE_MOD_DAI_DATA_MON 0x0b94
+#define AFE_DAI2_DATA_MON 0x0b98
+#define AFE_AWB2_RCH_MON 0x0b9c
+#define AFE_AWB2_LCH_MON 0x0ba0
+#define AFE_VUL3_RCH_MON 0x0ba4
+#define AFE_VUL3_LCH_MON 0x0ba8
+#define AFE_VUL4_RCH_MON 0x0bac
+#define AFE_VUL4_LCH_MON 0x0bb0
+#define AFE_VUL5_RCH_MON 0x0bb4
+#define AFE_VUL5_LCH_MON 0x0bb8
+#define AFE_VUL6_RCH_MON 0x0bbc
+#define AFE_VUL6_LCH_MON 0x0bc0
+#define AFE_DL1_RCH_MON 0x0bc4
+#define AFE_DL1_LCH_MON 0x0bc8
+#define AFE_DL2_RCH_MON 0x0bcc
+#define AFE_DL2_LCH_MON 0x0bd0
+#define AFE_DL12_RCH1_MON 0x0bd4
+#define AFE_DL12_LCH1_MON 0x0bd8
+#define AFE_DL12_RCH2_MON 0x0bdc
+#define AFE_DL12_LCH2_MON 0x0be0
+#define AFE_DL3_RCH_MON 0x0be4
+#define AFE_DL3_LCH_MON 0x0be8
+#define AFE_DL4_RCH_MON 0x0bec
+#define AFE_DL4_LCH_MON 0x0bf0
+#define AFE_DL5_RCH_MON 0x0bf4
+#define AFE_DL5_LCH_MON 0x0bf8
+#define AFE_DL6_RCH_MON 0x0bfc
+#define AFE_DL6_LCH_MON 0x0c00
+#define AFE_DL7_RCH_MON 0x0c04
+#define AFE_DL7_LCH_MON 0x0c08
+#define AFE_DL8_RCH_MON 0x0c0c
+#define AFE_DL8_LCH_MON 0x0c10
+#define AFE_VUL5_CON0 0x0c14
+#define AFE_VUL5_BASE_MSB 0x0c18
+#define AFE_VUL5_BASE 0x0c1c
+#define AFE_VUL5_CUR_MSB 0x0c20
+#define AFE_VUL5_CUR 0x0c24
+#define AFE_VUL5_END_MSB 0x0c28
+#define AFE_VUL5_END 0x0c2c
+#define AFE_VUL6_CON0 0x0c30
+#define AFE_VUL6_BASE_MSB 0x0c34
+#define AFE_VUL6_BASE 0x0c38
+#define AFE_VUL6_CUR_MSB 0x0c3c
+#define AFE_VUL6_CUR 0x0c40
+#define AFE_VUL6_END_MSB 0x0c44
+#define AFE_VUL6_END 0x0c48
+#define AFE_ADDA_DL_SDM_DCCOMP_CON 0x0c50
+#define AFE_ADDA_DL_SDM_TEST 0x0c54
+#define AFE_ADDA_DL_DC_COMP_CFG0 0x0c58
+#define AFE_ADDA_DL_DC_COMP_CFG1 0x0c5c
+#define AFE_ADDA_DL_SDM_FIFO_MON 0x0c60
+#define AFE_ADDA_DL_SRC_LCH_MON 0x0c64
+#define AFE_ADDA_DL_SRC_RCH_MON 0x0c68
+#define AFE_ADDA_DL_SDM_OUT_MON 0x0c6c
+#define AFE_ADDA_DL_SDM_DITHER_CON 0x0c70
+#define AFE_ADDA_DL_SDM_AUTO_RESET_CON 0x0c74
+#define AFE_CONNSYS_I2S_CON 0x0c78
+#define AFE_CONNSYS_I2S_MON 0x0c7c
+#define AFE_ASRC_2CH_CON0 0x0c80
+#define AFE_ASRC_2CH_CON1 0x0c84
+#define AFE_ASRC_2CH_CON2 0x0c88
+#define AFE_ASRC_2CH_CON3 0x0c8c
+#define AFE_ASRC_2CH_CON4 0x0c90
+#define AFE_ASRC_2CH_CON5 0x0c94
+#define AFE_ASRC_2CH_CON6 0x0c98
+#define AFE_ASRC_2CH_CON7 0x0c9c
+#define AFE_ASRC_2CH_CON8 0x0ca0
+#define AFE_ASRC_2CH_CON9 0x0ca4
+#define AFE_ASRC_2CH_CON10 0x0ca8
+#define AFE_ASRC_2CH_CON12 0x0cb0
+#define AFE_ASRC_2CH_CON13 0x0cb4
+#define AFE_ADDA6_IIR_COEF_02_01 0x0ce0
+#define AFE_ADDA6_IIR_COEF_04_03 0x0ce4
+#define AFE_ADDA6_IIR_COEF_06_05 0x0ce8
+#define AFE_ADDA6_IIR_COEF_08_07 0x0cec
+#define AFE_ADDA6_IIR_COEF_10_09 0x0cf0
+#define AFE_CONN67 0x0cf4
+#define AFE_CONN68 0x0cf8
+#define AFE_CONN69 0x0cfc
+#define AFE_SE_PROT_SIDEBAND 0x0d38
+#define AFE_SE_DOMAIN_SIDEBAND0 0x0d3c
+#define AFE_ADDA_PREDIS_CON2 0x0d40
+#define AFE_ADDA_PREDIS_CON3 0x0d44
+#define AFE_SE_DOMAIN_SIDEBAND1 0x0d54
+#define AFE_SE_DOMAIN_SIDEBAND2 0x0d58
+#define AFE_SE_DOMAIN_SIDEBAND3 0x0d5c
+#define AFE_CONN44 0x0d70
+#define AFE_CONN45 0x0d74
+#define AFE_CONN46 0x0d78
+#define AFE_CONN47 0x0d7c
+#define AFE_CONN44_1 0x0d80
+#define AFE_CONN45_1 0x0d84
+#define AFE_CONN46_1 0x0d88
+#define AFE_CONN47_1 0x0d8c
+#define AFE_HD_ENGEN_ENABLE 0x0dd0
+#define AFE_ADDA_DL_NLE_FIFO_MON 0x0dfc
+#define AFE_ADDA_MTKAIF_CFG0 0x0e00
+#define AFE_CONN67_1 0x0e04
+#define AFE_CONN68_1 0x0e08
+#define AFE_CONN69_1 0x0e0c
+#define AFE_ADDA_MTKAIF_SYNCWORD_CFG 0x0e14
+#define AFE_ADDA_MTKAIF_RX_CFG0 0x0e20
+#define AFE_ADDA_MTKAIF_RX_CFG1 0x0e24
+#define AFE_ADDA_MTKAIF_RX_CFG2 0x0e28
+#define AFE_ADDA_MTKAIF_MON0 0x0e34
+#define AFE_ADDA_MTKAIF_MON1 0x0e38
+#define AFE_AUD_PAD_TOP 0x0e40
+#define AFE_DL_NLE_R_CFG0 0x0e44
+#define AFE_DL_NLE_R_CFG1 0x0e48
+#define AFE_DL_NLE_L_CFG0 0x0e4c
+#define AFE_DL_NLE_L_CFG1 0x0e50
+#define AFE_DL_NLE_R_MON0 0x0e54
+#define AFE_DL_NLE_R_MON1 0x0e58
+#define AFE_DL_NLE_R_MON2 0x0e5c
+#define AFE_DL_NLE_L_MON0 0x0e60
+#define AFE_DL_NLE_L_MON1 0x0e64
+#define AFE_DL_NLE_L_MON2 0x0e68
+#define AFE_DL_NLE_GAIN_CFG0 0x0e6c
+#define AFE_ADDA6_MTKAIF_CFG0 0x0e70
+#define AFE_ADDA6_MTKAIF_RX_CFG0 0x0e74
+#define AFE_ADDA6_MTKAIF_RX_CFG1 0x0e78
+#define AFE_ADDA6_MTKAIF_RX_CFG2 0x0e7c
+#define AFE_GENERAL1_ASRC_2CH_CON0 0x0e80
+#define AFE_GENERAL1_ASRC_2CH_CON1 0x0e84
+#define AFE_GENERAL1_ASRC_2CH_CON2 0x0e88
+#define AFE_GENERAL1_ASRC_2CH_CON3 0x0e8c
+#define AFE_GENERAL1_ASRC_2CH_CON4 0x0e90
+#define AFE_GENERAL1_ASRC_2CH_CON5 0x0e94
+#define AFE_GENERAL1_ASRC_2CH_CON6 0x0e98
+#define AFE_GENERAL1_ASRC_2CH_CON7 0x0e9c
+#define AFE_GENERAL1_ASRC_2CH_CON8 0x0ea0
+#define AFE_GENERAL1_ASRC_2CH_CON9 0x0ea4
+#define AFE_GENERAL1_ASRC_2CH_CON10 0x0ea8
+#define AFE_GENERAL1_ASRC_2CH_CON12 0x0eb0
+#define AFE_GENERAL1_ASRC_2CH_CON13 0x0eb4
+#define GENERAL_ASRC_MODE 0x0eb8
+#define GENERAL_ASRC_EN_ON 0x0ebc
+#define AFE_CONN48 0x0ec0
+#define AFE_CONN49 0x0ec4
+#define AFE_CONN50 0x0ec8
+#define AFE_CONN51 0x0ecc
+#define AFE_CONN52 0x0ed0
+#define AFE_CONN53 0x0ed4
+#define AFE_CONN54 0x0ed8
+#define AFE_CONN55 0x0edc
+#define AFE_CONN48_1 0x0ee0
+#define AFE_CONN49_1 0x0ee4
+#define AFE_CONN50_1 0x0ee8
+#define AFE_CONN51_1 0x0eec
+#define AFE_CONN52_1 0x0ef0
+#define AFE_CONN53_1 0x0ef4
+#define AFE_CONN54_1 0x0ef8
+#define AFE_CONN55_1 0x0efc
+#define AFE_GENERAL2_ASRC_2CH_CON0 0x0f00
+#define AFE_GENERAL2_ASRC_2CH_CON1 0x0f04
+#define AFE_GENERAL2_ASRC_2CH_CON2 0x0f08
+#define AFE_GENERAL2_ASRC_2CH_CON3 0x0f0c
+#define AFE_GENERAL2_ASRC_2CH_CON4 0x0f10
+#define AFE_GENERAL2_ASRC_2CH_CON5 0x0f14
+#define AFE_GENERAL2_ASRC_2CH_CON6 0x0f18
+#define AFE_GENERAL2_ASRC_2CH_CON7 0x0f1c
+#define AFE_GENERAL2_ASRC_2CH_CON8 0x0f20
+#define AFE_GENERAL2_ASRC_2CH_CON9 0x0f24
+#define AFE_GENERAL2_ASRC_2CH_CON10 0x0f28
+#define AFE_GENERAL2_ASRC_2CH_CON12 0x0f30
+#define AFE_GENERAL2_ASRC_2CH_CON13 0x0f34
+#define AFE_DL5_CON0 0x0f4c
+#define AFE_DL5_BASE_MSB 0x0f50
+#define AFE_DL5_BASE 0x0f54
+#define AFE_DL5_CUR_MSB 0x0f58
+#define AFE_DL5_CUR 0x0f5c
+#define AFE_DL5_END_MSB 0x0f60
+#define AFE_DL5_END 0x0f64
+#define AFE_DL6_CON0 0x0f68
+#define AFE_DL6_BASE_MSB 0x0f6c
+#define AFE_DL6_BASE 0x0f70
+#define AFE_DL6_CUR_MSB 0x0f74
+#define AFE_DL6_CUR 0x0f78
+#define AFE_DL6_END_MSB 0x0f7c
+#define AFE_DL6_END 0x0f80
+#define AFE_DL7_CON0 0x0f84
+#define AFE_DL7_BASE_MSB 0x0f88
+#define AFE_DL7_BASE 0x0f8c
+#define AFE_DL7_CUR_MSB 0x0f90
+#define AFE_DL7_CUR 0x0f94
+#define AFE_DL7_END_MSB 0x0f98
+#define AFE_DL7_END 0x0f9c
+#define AFE_DL8_CON0 0x0fa0
+#define AFE_DL8_BASE_MSB 0x0fa4
+#define AFE_DL8_BASE 0x0fa8
+#define AFE_DL8_CUR_MSB 0x0fac
+#define AFE_DL8_CUR 0x0fb0
+#define AFE_DL8_END_MSB 0x0fb4
+#define AFE_DL8_END 0x0fb8
+#define AFE_SE_SECURE_CON 0x1004
+#define AFE_PROT_SIDEBAND_MON 0x1008
+#define AFE_DOMAIN_SIDEBAND0_MON 0x100c
+#define AFE_DOMAIN_SIDEBAND1_MON 0x1010
+#define AFE_DOMAIN_SIDEBAND2_MON 0x1014
+#define AFE_DOMAIN_SIDEBAND3_MON 0x1018
+#define AFE_SECURE_MASK_CONN0 0x1020
+#define AFE_SECURE_MASK_CONN1 0x1024
+#define AFE_SECURE_MASK_CONN2 0x1028
+#define AFE_SECURE_MASK_CONN3 0x102c
+#define AFE_SECURE_MASK_CONN4 0x1030
+#define AFE_SECURE_MASK_CONN5 0x1034
+#define AFE_SECURE_MASK_CONN6 0x1038
+#define AFE_SECURE_MASK_CONN7 0x103c
+#define AFE_SECURE_MASK_CONN8 0x1040
+#define AFE_SECURE_MASK_CONN9 0x1044
+#define AFE_SECURE_MASK_CONN10 0x1048
+#define AFE_SECURE_MASK_CONN11 0x104c
+#define AFE_SECURE_MASK_CONN12 0x1050
+#define AFE_SECURE_MASK_CONN13 0x1054
+#define AFE_SECURE_MASK_CONN14 0x1058
+#define AFE_SECURE_MASK_CONN15 0x105c
+#define AFE_SECURE_MASK_CONN16 0x1060
+#define AFE_SECURE_MASK_CONN17 0x1064
+#define AFE_SECURE_MASK_CONN18 0x1068
+#define AFE_SECURE_MASK_CONN19 0x106c
+#define AFE_SECURE_MASK_CONN20 0x1070
+#define AFE_SECURE_MASK_CONN21 0x1074
+#define AFE_SECURE_MASK_CONN22 0x1078
+#define AFE_SECURE_MASK_CONN23 0x107c
+#define AFE_SECURE_MASK_CONN24 0x1080
+#define AFE_SECURE_MASK_CONN25 0x1084
+#define AFE_SECURE_MASK_CONN26 0x1088
+#define AFE_SECURE_MASK_CONN27 0x108c
+#define AFE_SECURE_MASK_CONN28 0x1090
+#define AFE_SECURE_MASK_CONN29 0x1094
+#define AFE_SECURE_MASK_CONN30 0x1098
+#define AFE_SECURE_MASK_CONN31 0x109c
+#define AFE_SECURE_MASK_CONN32 0x10a0
+#define AFE_SECURE_MASK_CONN33 0x10a4
+#define AFE_SECURE_MASK_CONN34 0x10a8
+#define AFE_SECURE_MASK_CONN35 0x10ac
+#define AFE_SECURE_MASK_CONN36 0x10b0
+#define AFE_SECURE_MASK_CONN37 0x10b4
+#define AFE_SECURE_MASK_CONN38 0x10b8
+#define AFE_SECURE_MASK_CONN39 0x10bc
+#define AFE_SECURE_MASK_CONN40 0x10c0
+#define AFE_SECURE_MASK_CONN41 0x10c4
+#define AFE_SECURE_MASK_CONN42 0x10c8
+#define AFE_SECURE_MASK_CONN43 0x10cc
+#define AFE_SECURE_MASK_CONN44 0x10d0
+#define AFE_SECURE_MASK_CONN45 0x10d4
+#define AFE_SECURE_MASK_CONN46 0x10d8
+#define AFE_SECURE_MASK_CONN47 0x10dc
+#define AFE_SECURE_MASK_CONN48 0x10e0
+#define AFE_SECURE_MASK_CONN49 0x10e4
+#define AFE_SECURE_MASK_CONN50 0x10e8
+#define AFE_SECURE_MASK_CONN51 0x10ec
+#define AFE_SECURE_MASK_CONN52 0x10f0
+#define AFE_SECURE_MASK_CONN53 0x10f4
+#define AFE_SECURE_MASK_CONN54 0x10f8
+#define AFE_SECURE_MASK_CONN55 0x10fc
+#define AFE_SECURE_MASK_CONN56 0x1100
+#define AFE_SECURE_MASK_CONN57 0x1104
+#define AFE_SECURE_MASK_CONN0_1 0x1108
+#define AFE_SECURE_MASK_CONN1_1 0x110c
+#define AFE_SECURE_MASK_CONN2_1 0x1110
+#define AFE_SECURE_MASK_CONN3_1 0x1114
+#define AFE_SECURE_MASK_CONN4_1 0x1118
+#define AFE_SECURE_MASK_CONN5_1 0x111c
+#define AFE_SECURE_MASK_CONN6_1 0x1120
+#define AFE_SECURE_MASK_CONN7_1 0x1124
+#define AFE_SECURE_MASK_CONN8_1 0x1128
+#define AFE_SECURE_MASK_CONN9_1 0x112c
+#define AFE_SECURE_MASK_CONN10_1 0x1130
+#define AFE_SECURE_MASK_CONN11_1 0x1134
+#define AFE_SECURE_MASK_CONN12_1 0x1138
+#define AFE_SECURE_MASK_CONN13_1 0x113c
+#define AFE_SECURE_MASK_CONN14_1 0x1140
+#define AFE_SECURE_MASK_CONN15_1 0x1144
+#define AFE_SECURE_MASK_CONN16_1 0x1148
+#define AFE_SECURE_MASK_CONN17_1 0x114c
+#define AFE_SECURE_MASK_CONN18_1 0x1150
+#define AFE_SECURE_MASK_CONN19_1 0x1154
+#define AFE_SECURE_MASK_CONN20_1 0x1158
+#define AFE_SECURE_MASK_CONN21_1 0x115c
+#define AFE_SECURE_MASK_CONN22_1 0x1160
+#define AFE_SECURE_MASK_CONN23_1 0x1164
+#define AFE_SECURE_MASK_CONN24_1 0x1168
+#define AFE_SECURE_MASK_CONN25_1 0x116c
+#define AFE_SECURE_MASK_CONN26_1 0x1170
+#define AFE_SECURE_MASK_CONN27_1 0x1174
+#define AFE_SECURE_MASK_CONN28_1 0x1178
+#define AFE_SECURE_MASK_CONN29_1 0x117c
+#define AFE_SECURE_MASK_CONN30_1 0x1180
+#define AFE_SECURE_MASK_CONN31_1 0x1184
+#define AFE_SECURE_MASK_CONN32_1 0x1188
+#define AFE_SECURE_MASK_CONN33_1 0x118c
+#define AFE_SECURE_MASK_CONN34_1 0x1190
+#define AFE_SECURE_MASK_CONN35_1 0x1194
+#define AFE_SECURE_MASK_CONN36_1 0x1198
+#define AFE_SECURE_MASK_CONN37_1 0x119c
+#define AFE_SECURE_MASK_CONN38_1 0x11a0
+#define AFE_SECURE_MASK_CONN39_1 0x11a4
+#define AFE_SECURE_MASK_CONN40_1 0x11a8
+#define AFE_SECURE_MASK_CONN41_1 0x11ac
+#define AFE_SECURE_MASK_CONN42_1 0x11b0
+#define AFE_SECURE_MASK_CONN43_1 0x11b4
+#define AFE_SECURE_MASK_CONN44_1 0x11b8
+#define AFE_SECURE_MASK_CONN45_1 0x11bc
+#define AFE_SECURE_MASK_CONN46_1 0x11c0
+#define AFE_SECURE_MASK_CONN47_1 0x11c4
+#define AFE_SECURE_MASK_CONN48_1 0x11c8
+#define AFE_SECURE_MASK_CONN49_1 0x11cc
+#define AFE_SECURE_MASK_CONN50_1 0x11d0
+#define AFE_SECURE_MASK_CONN51_1 0x11d4
+#define AFE_SECURE_MASK_CONN52_1 0x11d8
+#define AFE_SECURE_MASK_CONN53_1 0x11dc
+#define AFE_SECURE_MASK_CONN54_1 0x11e0
+#define AFE_SECURE_MASK_CONN55_1 0x11e4
+#define AFE_SECURE_MASK_CONN56_1 0x11e8
+#define AFE_CONN60_1 0x11f0
+#define AFE_CONN61_1 0x11f4
+#define AFE_CONN62_1 0x11f8
+#define AFE_CONN63_1 0x11fc
+#define AFE_CONN64_1 0x1220
+#define AFE_CONN65_1 0x1224
+#define AFE_CONN66_1 0x1228
+#define FPGA_CFG4 0x1230
+#define FPGA_CFG5 0x1234
+#define FPGA_CFG6 0x1238
+#define FPGA_CFG7 0x123c
+#define FPGA_CFG8 0x1240
+#define FPGA_CFG9 0x1244
+#define FPGA_CFG10 0x1248
+#define FPGA_CFG11 0x124c
+#define FPGA_CFG12 0x1250
+#define FPGA_CFG13 0x1254
+#define ETDM_IN1_CON0 0x1430
+#define ETDM_IN1_CON1 0x1434
+#define ETDM_IN1_CON2 0x1438
+#define ETDM_IN1_CON3 0x143c
+#define ETDM_IN1_CON4 0x1440
+#define ETDM_IN1_CON5 0x1444
+#define ETDM_IN1_CON6 0x1448
+#define ETDM_IN1_CON7 0x144c
+#define ETDM_IN1_CON8 0x1450
+#define ETDM_OUT1_CON0 0x1454
+#define ETDM_OUT1_CON1 0x1458
+#define ETDM_OUT1_CON2 0x145c
+#define ETDM_OUT1_CON3 0x1460
+#define ETDM_OUT1_CON4 0x1464
+#define ETDM_OUT1_CON5 0x1468
+#define ETDM_OUT1_CON6 0x146c
+#define ETDM_OUT1_CON7 0x1470
+#define ETDM_OUT1_CON8 0x1474
+#define ETDM_IN1_MON 0x1478
+#define ETDM_OUT1_MON 0x147c
+#define ETDM_0_3_COWORK_CON0 0x18b0
+#define ETDM_0_3_COWORK_CON1 0x18b4
+#define ETDM_0_3_COWORK_CON3 0x18bc
+
+#define AFE_MAX_REGISTER ETDM_0_3_COWORK_CON3
+
+#define AFE_IRQ_STATUS_BITS 0x87FFFFFF
+#define AFE_IRQ_CNT_SHIFT 0
+#define AFE_IRQ_CNT_MASK 0x3ffff
+#endif
diff --git a/sound/soc/mediatek/mt8195/mt8195-afe-clk.c b/sound/soc/mediatek/mt8195/mt8195-afe-clk.c
index efd5cc3..2ee3872c 100644
--- a/sound/soc/mediatek/mt8195/mt8195-afe-clk.c
+++ b/sound/soc/mediatek/mt8195/mt8195-afe-clk.c
@@ -284,7 +284,7 @@ static int mt8195_afe_enable_apll_tuner(struct mtk_base_afe *afe,
{
struct mt8195_afe_tuner_cfg *cfg = mt8195_afe_found_apll_tuner(id);
unsigned long flags;
- int ret = 0;
+ int ret;
if (!cfg)
return -EINVAL;
@@ -308,7 +308,7 @@ static int mt8195_afe_enable_apll_tuner(struct mtk_base_afe *afe,
spin_unlock_irqrestore(&cfg->ctrl_lock, flags);
- return ret;
+ return 0;
}
static int mt8195_afe_disable_apll_tuner(struct mtk_base_afe *afe,
@@ -316,7 +316,7 @@ static int mt8195_afe_disable_apll_tuner(struct mtk_base_afe *afe,
{
struct mt8195_afe_tuner_cfg *cfg = mt8195_afe_found_apll_tuner(id);
unsigned long flags;
- int ret = 0;
+ int ret;
if (!cfg)
return -EINVAL;
@@ -338,7 +338,7 @@ static int mt8195_afe_disable_apll_tuner(struct mtk_base_afe *afe,
if (ret)
return ret;
- return ret;
+ return 0;
}
int mt8195_afe_get_mclk_source_clk_id(int sel)
diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c
index c02c10d..c2e2680 100644
--- a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c
+++ b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c
@@ -2172,11 +2172,11 @@ static int mtk_dai_etdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return -EINVAL;
}
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BC_FC:
etdm_data->slave_mode = true;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_BP_FP:
etdm_data->slave_mode = false;
break;
default:
diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c b/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c
index 12644de..caceb0d 100644
--- a/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c
+++ b/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c
@@ -266,11 +266,11 @@ static int mtk_dai_pcm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return -EINVAL;
}
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BC_FC:
pcmif_priv->slave_mode = 1;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_BP_FP:
pcmif_priv->slave_mode = 0;
break;
default:
diff --git a/sound/soc/meson/aiu-encoder-i2s.c b/sound/soc/meson/aiu-encoder-i2s.c
index 67729de..a0dd914 100644
--- a/sound/soc/meson/aiu-encoder-i2s.c
+++ b/sound/soc/meson/aiu-encoder-i2s.c
@@ -229,7 +229,7 @@ static int aiu_encoder_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
unsigned int skew;
/* Only CPU Master / Codec Slave supported ATM */
- if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
+ if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_BP_FP)
return -EINVAL;
if (inv == SND_SOC_DAIFMT_NB_IF ||
diff --git a/sound/soc/meson/axg-tdm-interface.c b/sound/soc/meson/axg-tdm-interface.c
index e076ced..c040c83 100644
--- a/sound/soc/meson/axg-tdm-interface.c
+++ b/sound/soc/meson/axg-tdm-interface.c
@@ -119,19 +119,19 @@ static int axg_tdm_iface_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BP_FP:
if (!iface->mclk) {
dev_err(dai->dev, "cpu clock master: mclk missing\n");
return -ENODEV;
}
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_BC_FC:
break;
- case SND_SOC_DAIFMT_CBS_CFM:
- case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_BP_FC:
+ case SND_SOC_DAIFMT_BC_FP:
dev_err(dai->dev, "only CBS_CFS and CBM_CFM are supported\n");
fallthrough;
default:
@@ -326,8 +326,8 @@ static int axg_tdm_iface_hw_params(struct snd_pcm_substream *substream,
if (ret)
return ret;
- if ((iface->fmt & SND_SOC_DAIFMT_MASTER_MASK) ==
- SND_SOC_DAIFMT_CBS_CFS) {
+ if ((iface->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) ==
+ SND_SOC_DAIFMT_BP_FP) {
ret = axg_tdm_iface_set_sclk(dai, params);
if (ret)
return ret;
diff --git a/sound/soc/meson/meson-codec-glue.c b/sound/soc/meson/meson-codec-glue.c
index 2870cfa..80c5ed1 100644
--- a/sound/soc/meson/meson-codec-glue.c
+++ b/sound/soc/meson/meson-codec-glue.c
@@ -13,7 +13,7 @@
static struct snd_soc_dapm_widget *
meson_codec_glue_get_input(struct snd_soc_dapm_widget *w)
{
- struct snd_soc_dapm_path *p = NULL;
+ struct snd_soc_dapm_path *p;
struct snd_soc_dapm_widget *in;
snd_soc_dapm_widget_for_each_source_path(w, p) {
diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
index 7afe1a1..467b0f2 100644
--- a/sound/soc/mxs/mxs-saif.c
+++ b/sound/soc/mxs/mxs-saif.c
@@ -358,8 +358,8 @@ static int mxs_saif_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
* Saif internally could be slave when working on EXTMASTER mode.
* We just hide this to machine driver.
*/
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BP_FP:
if (saif->id == saif->master_id)
scr &= ~BM_SAIF_CTRL_SLAVE_MODE;
else
diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c
index 9433cc9..b791a2b 100644
--- a/sound/soc/pxa/magician.c
+++ b/sound/soc/pxa/magician.c
@@ -91,13 +91,13 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream,
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_MSB |
- SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_BC_FC);
if (ret < 0)
return ret;
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
- SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_CBS_CFS);
+ SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_BP_FP);
if (ret < 0)
return ret;
@@ -129,14 +129,14 @@ static int magician_capture_hw_params(struct snd_pcm_substream *substream,
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai,
SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS);
+ SND_SOC_DAIFMT_BC_FC);
if (ret < 0)
return ret;
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai,
SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS);
+ SND_SOC_DAIFMT_BP_FP);
if (ret < 0)
return ret;
diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c
index 7e39210..382e9d8 100644
--- a/sound/soc/pxa/mmp-sspa.c
+++ b/sound/soc/pxa/mmp-sspa.c
@@ -171,11 +171,11 @@ static int mmp_sspa_set_dai_fmt(struct snd_soc_dai *cpu_dai,
sspa->sp = SSPA_SP_WEN | SSPA_SP_S_RST | SSPA_SP_FFLUSH;
sspa->ctrl = 0;
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BP_FP:
sspa->sp |= SSPA_SP_MSL;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_BC_FC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index 7f13a35..0f504a9 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -372,10 +372,10 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
{
struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
- case SND_SOC_DAIFMT_CBM_CFS:
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BC_FC:
+ case SND_SOC_DAIFMT_BC_FP:
+ case SND_SOC_DAIFMT_BP_FP:
break;
default:
return -EINVAL;
@@ -432,14 +432,14 @@ static int pxa_ssp_configure_dai_fmt(struct ssp_priv *priv)
sscr1 |= SSCR1_RxTresh(8) | SSCR1_TxTresh(7);
- switch (priv->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ switch (priv->dai_fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BC_FC:
sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR | SSCR1_SCFR;
break;
- case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_BC_FP:
sscr1 |= SSCR1_SCLKDIR | SSCR1_SCFR;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_BP_FP:
break;
default:
return -EINVAL;
@@ -484,9 +484,9 @@ static int pxa_ssp_configure_dai_fmt(struct ssp_priv *priv)
pxa_ssp_write_reg(ssp, SSCR1, sscr1);
pxa_ssp_write_reg(ssp, SSPSP, sspsp);
- switch (priv->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
- case SND_SOC_DAIFMT_CBM_CFS:
+ switch (priv->dai_fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BC_FC:
+ case SND_SOC_DAIFMT_BC_FP:
scfr = pxa_ssp_read_reg(ssp, SSCR1) | SSCR1_SCFR;
pxa_ssp_write_reg(ssp, SSCR1, scfr);
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index 746e6ec..ffcf44e 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -129,11 +129,11 @@ static int pxa2xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
break;
}
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BP_FP:
pxa_i2s.master = 1;
break;
- case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_BC_FP:
pxa_i2s.master = 0;
break;
default:
diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c
index b0a4f7c..e54b896 100644
--- a/sound/soc/qcom/apq8016_sbc.c
+++ b/sound/soc/qcom/apq8016_sbc.c
@@ -172,7 +172,7 @@ static int msm8916_qdsp6_dai_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
+ snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP);
return apq8016_dai_init(rtd, qdsp6_dai_get_lpass_id(cpu_dai));
}
diff --git a/sound/soc/qcom/qdsp6/audioreach.c b/sound/soc/qcom/qdsp6/audioreach.c
index 98c0efa..01dac32 100644
--- a/sound/soc/qcom/qdsp6/audioreach.c
+++ b/sound/soc/qcom/qdsp6/audioreach.c
@@ -732,10 +732,10 @@ static int audioreach_i2s_set_media_format(struct q6apm_graph *graph,
intf_cfg->cfg.sd_line_idx = module->sd_line_idx;
switch (cfg->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
- case SND_SOC_DAIFMT_CBC_CFC:
+ case SND_SOC_DAIFMT_BP_FP:
intf_cfg->cfg.ws_src = CONFIG_I2S_WS_SRC_INTERNAL;
break;
- case SND_SOC_DAIFMT_CBP_CFP:
+ case SND_SOC_DAIFMT_BC_FC:
/* CPU is slave */
intf_cfg->cfg.ws_src = CONFIG_I2S_WS_SRC_EXTERNAL;
break;
diff --git a/sound/soc/qcom/qdsp6/q6adm.c b/sound/soc/qcom/qdsp6/q6adm.c
index 72c5719..01f3838 100644
--- a/sound/soc/qcom/qdsp6/q6adm.c
+++ b/sound/soc/qcom/qdsp6/q6adm.c
@@ -90,7 +90,7 @@ struct q6adm_session_map_node_v5 {
static struct q6copp *q6adm_find_copp(struct q6adm *adm, int port_idx,
int copp_idx)
{
- struct q6copp *c = NULL;
+ struct q6copp *c;
struct q6copp *ret = NULL;
unsigned long flags;
@@ -180,7 +180,7 @@ static int q6adm_callback(struct apr_device *adev, struct apr_resp_pkt *data)
u32 status;
u16 copp_id;
u16 reserved;
- } __packed * open = data->payload;
+ } __packed *open = data->payload;
copp = q6adm_find_copp(adm, port_idx, copp_idx);
if (!copp)
@@ -299,7 +299,7 @@ static struct q6copp *q6adm_find_matching_copp(struct q6adm *adm,
int channel_mode, int bit_width,
int app_type)
{
- struct q6copp *c = NULL;
+ struct q6copp *c;
struct q6copp *ret = NULL;
unsigned long flags;
diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c
index 6257248..919e326 100644
--- a/sound/soc/qcom/qdsp6/q6afe.c
+++ b/sound/soc/qcom/qdsp6/q6afe.c
@@ -1328,11 +1328,11 @@ int q6afe_i2s_port_prepare(struct q6afe_port *port, struct q6afe_i2s_cfg *cfg)
pcfg->i2s_cfg.bit_width = cfg->bit_width;
pcfg->i2s_cfg.data_format = AFE_LINEAR_PCM_DATA;
- switch (cfg->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (cfg->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BP_FP:
pcfg->i2s_cfg.ws_src = AFE_PORT_CONFIG_I2S_WS_SRC_INTERNAL;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_BC_FC:
/* CPU is slave */
pcfg->i2s_cfg.ws_src = AFE_PORT_CONFIG_I2S_WS_SRC_EXTERNAL;
break;
diff --git a/sound/soc/qcom/sc7180.c b/sound/soc/qcom/sc7180.c
index efccb5c..f5f7c64 100644
--- a/sound/soc/qcom/sc7180.c
+++ b/sound/soc/qcom/sc7180.c
@@ -155,7 +155,7 @@ static int sc7180_snd_startup(struct snd_pcm_substream *substream)
}
snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_CBS_CFS |
+ SND_SOC_DAIFMT_BC_FC |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_I2S);
diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c
index 61fda79..d8d3556 100644
--- a/sound/soc/qcom/sdm845.c
+++ b/sound/soc/qcom/sdm845.c
@@ -316,8 +316,8 @@ static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd)
static int sdm845_snd_startup(struct snd_pcm_substream *substream)
{
- unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
- unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS;
+ unsigned int fmt = SND_SOC_DAIFMT_BP_FP;
+ unsigned int codec_dai_fmt = SND_SOC_DAIFMT_BC_FC;
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card);
@@ -356,7 +356,7 @@ static int sdm845_snd_startup(struct snd_pcm_substream *substream)
snd_soc_dai_set_sysclk(cpu_dai,
Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT,
MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
- snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
+ snd_soc_dai_set_fmt(cpu_dai, fmt);
break;
diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c
index 6e1184c..ce4a571 100644
--- a/sound/soc/qcom/sm8250.c
+++ b/sound/soc/qcom/sm8250.c
@@ -96,8 +96,8 @@ static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
static int sm8250_snd_startup(struct snd_pcm_substream *substream)
{
- unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
- unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS;
+ unsigned int fmt = SND_SOC_DAIFMT_BP_FP;
+ unsigned int codec_dai_fmt = SND_SOC_DAIFMT_BC_FC;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
diff --git a/sound/soc/rockchip/rk3288_hdmi_analog.c b/sound/soc/rockchip/rk3288_hdmi_analog.c
index bcdedde..0c6bd9a 100644
--- a/sound/soc/rockchip/rk3288_hdmi_analog.c
+++ b/sound/soc/rockchip/rk3288_hdmi_analog.c
@@ -169,7 +169,7 @@ static struct snd_soc_card snd_soc_card_rk = {
static int snd_rk_mc_probe(struct platform_device *pdev)
{
- int ret = 0;
+ int ret;
struct snd_soc_card *card = &snd_soc_card_rk;
struct device_node *np = pdev->dev.of_node;
struct rk_drvdata *machine;
@@ -253,7 +253,7 @@ static int snd_rk_mc_probe(struct platform_device *pdev)
return dev_err_probe(&pdev->dev, ret,
"Soc register card failed\n");
- return ret;
+ return 0;
}
static const struct of_device_id rockchip_sound_of_match[] = {
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 4ce5d25..47a3971 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -199,13 +199,13 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
pm_runtime_get_sync(cpu_dai->dev);
mask = I2S_CKR_MSS_MASK;
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BP_FP:
/* Set source clock in Master mode */
val = I2S_CKR_MSS_MASTER;
i2s->is_master_mode = true;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_BC_FC:
val = I2S_CKR_MSS_SLAVE;
i2s->is_master_mode = false;
break;
diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c
index 98700e7..48b3ecf 100644
--- a/sound/soc/rockchip/rockchip_i2s_tdm.c
+++ b/sound/soc/rockchip/rockchip_i2s_tdm.c
@@ -411,12 +411,12 @@ static int rockchip_i2s_tdm_set_fmt(struct snd_soc_dai *cpu_dai,
}
mask = I2S_CKR_MSS_MASK;
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBC_CFC:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BP_FP:
val = I2S_CKR_MSS_MASTER;
i2s_tdm->is_master_mode = true;
break;
- case SND_SOC_DAIFMT_CBP_CFP:
+ case SND_SOC_DAIFMT_BC_FC:
val = I2S_CKR_MSS_SLAVE;
i2s_tdm->is_master_mode = false;
break;
diff --git a/sound/soc/samsung/aries_wm8994.c b/sound/soc/samsung/aries_wm8994.c
index bb0cf42..edee02d 100644
--- a/sound/soc/samsung/aries_wm8994.c
+++ b/sound/soc/samsung/aries_wm8994.c
@@ -628,8 +628,10 @@ static int aries_audio_probe(struct platform_device *pdev)
return -EINVAL;
codec = of_get_child_by_name(dev->of_node, "codec");
- if (!codec)
- return -EINVAL;
+ if (!codec) {
+ ret = -EINVAL;
+ goto out;
+ }
for_each_card_prelinks(card, i, dai_link) {
dai_link->codecs->of_node = of_parse_phandle(codec,
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index 70c8271..fdd9561 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -671,11 +671,11 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return -EINVAL;
}
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BC_FC:
tmp |= mod_slave;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_BP_FP:
/*
* Set default source clock in Master mode, only when the
* CLK_I2S_RCLK_SRC clock is not exposed so we ensure any
diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c
index 4c4dfde..c2eb353 100644
--- a/sound/soc/samsung/pcm.c
+++ b/sound/soc/samsung/pcm.c
@@ -340,8 +340,8 @@ static int s3c_pcm_set_fmt(struct snd_soc_dai *cpu_dai,
goto exit;
}
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BP_FP:
/* Nothing to do, Master by default */
break;
default:
diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c
index de66cc4..1bec722 100644
--- a/sound/soc/samsung/s3c-i2s-v2.c
+++ b/sound/soc/samsung/s3c-i2s-v2.c
@@ -252,12 +252,12 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
iismod = readl(i2s->regs + S3C2412_IISMOD);
pr_debug("hw_params r: IISMOD: %x \n", iismod);
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BC_FC:
i2s->master = 0;
iismod |= S3C2412_IISMOD_SLAVE;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_BP_FP:
i2s->master = 1;
iismod &= ~S3C2412_IISMOD_SLAVE;
break;
diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c
index 0f46304..4082ad7 100644
--- a/sound/soc/samsung/s3c24xx-i2s.c
+++ b/sound/soc/samsung/s3c24xx-i2s.c
@@ -169,11 +169,11 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
pr_debug("hw_params r: IISMOD: %x \n", iismod);
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BC_CFC:
iismod |= S3C2410_IISMOD_SLAVE;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_BP_FP:
iismod &= ~S3C2410_IISMOD_SLAVE;
break;
default:
diff --git a/sound/soc/samsung/snow.c b/sound/soc/samsung/snow.c
index 0237210..da342da 100644
--- a/sound/soc/samsung/snow.c
+++ b/sound/soc/samsung/snow.c
@@ -216,7 +216,7 @@ static int snow_probe(struct platform_device *pdev)
return dev_err_probe(&pdev->dev, ret,
"snd_soc_register_card failed\n");
- return ret;
+ return 0;
}
static int snow_remove(struct platform_device *pdev)
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index e9a1eb6..f3edc2e 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -1646,10 +1646,10 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
int ret;
/* set clock master audio interface */
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BC_FC:
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_BP_FP:
fsi->clk_master = 1; /* cpu is master */
break;
default:
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index eb762ab..a4180dc 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -756,10 +756,10 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
/* set clock master for audio interface */
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
- case SND_SOC_DAIFMT_CBP_CFP:
+ case SND_SOC_DAIFMT_BC_FC:
rdai->clk_master = 0;
break;
- case SND_SOC_DAIFMT_CBC_CFC:
+ case SND_SOC_DAIFMT_BP_FP:
rdai->clk_master = 1; /* cpu is master */
break;
default:
diff --git a/sound/soc/sh/rz-ssi.c b/sound/soc/sh/rz-ssi.c
index e392de7..beaf1a8 100644
--- a/sound/soc/sh/rz-ssi.c
+++ b/sound/soc/sh/rz-ssi.c
@@ -767,7 +767,7 @@ static int rz_ssi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai);
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
- case SND_SOC_DAIFMT_CBC_CFC:
+ case SND_SOC_DAIFMT_BP_FP:
break;
default:
dev_err(ssi->dev, "Codec should be clk and frame consumer\n");
diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c
index 15b01bc..bf7a3c6 100644
--- a/sound/soc/sh/ssi.c
+++ b/sound/soc/sh/ssi.c
@@ -291,16 +291,16 @@ static int ssi_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return -EINVAL;
}
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BC_FC:
break;
- case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_BP_FC:
ssicr |= CR_SCK_MASTER;
break;
- case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_BC_FP:
ssicr |= CR_SWS_MASTER;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_BP_FP:
ssicr |= CR_SWS_MASTER | CR_SCK_MASTER;
break;
default:
diff --git a/sound/soc/soc-card.c b/sound/soc/soc-card.c
index 4158f5a..285ab4c 100644
--- a/sound/soc/soc-card.c
+++ b/sound/soc/soc-card.c
@@ -197,6 +197,12 @@ int snd_soc_card_late_probe(struct snd_soc_card *card)
return 0;
}
+void snd_soc_card_fixup_controls(struct snd_soc_card *card)
+{
+ if (card->fixup_controls)
+ card->fixup_controls(card);
+}
+
int snd_soc_card_remove(struct snd_soc_card *card)
{
int ret = 0;
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 9574f86..57f7105 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1214,7 +1214,6 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
{
struct snd_soc_dai *cpu_dai;
struct snd_soc_dai *codec_dai;
- unsigned int inv_dai_fmt;
unsigned int i;
int ret;
@@ -1227,18 +1226,11 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
return ret;
}
- /*
- * Flip the polarity for the "CPU" end of a CODEC<->CODEC link
- */
- inv_dai_fmt = snd_soc_daifmt_clock_provider_flipped(dai_fmt);
+ /* Flip the polarity for the "CPU" end of link */
+ dai_fmt = snd_soc_daifmt_clock_provider_flipped(dai_fmt);
for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
- unsigned int fmt = dai_fmt;
-
- if (snd_soc_component_is_codec(cpu_dai->component))
- fmt = inv_dai_fmt;
-
- ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+ ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
if (ret != 0 && ret != -ENOTSUPP)
return ret;
}
@@ -2074,6 +2066,7 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
goto probe_end;
snd_soc_dapm_new_widgets(card);
+ snd_soc_card_fixup_controls(card);
ret = snd_card_register(card->snd_card);
if (ret < 0) {
diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c
index 6078afe..d530e8c 100644
--- a/sound/soc/soc-dai.c
+++ b/sound/soc/soc-dai.c
@@ -208,8 +208,7 @@ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
int ret = -ENOTSUPP;
- if (dai->driver->ops &&
- dai->driver->ops->set_fmt)
+ if (dai->driver->ops && dai->driver->ops->set_fmt)
ret = dai->driver->ops->set_fmt(dai, fmt);
return soc_dai_ret(dai, ret);
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
index d867f44..184910e 100644
--- a/sound/soc/soc-ops.c
+++ b/sound/soc/soc-ops.c
@@ -14,7 +14,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
-#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/bitops.h>
#include <linux/ctype.h>
@@ -203,7 +202,8 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw);
* Callback to provide information about a single mixer control, or a double
* mixer control that spans 2 registers of the SX TLV type. SX TLV controls
* have a range that represents both positive and negative values either side
- * of zero but without a sign bit.
+ * of zero but without a sign bit. min is the minimum register value, max is
+ * the number of steps.
*
* Returns 0 for success.
*/
@@ -212,12 +212,21 @@ int snd_soc_info_volsw_sx(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
+ int max;
- snd_soc_info_volsw(kcontrol, uinfo);
- /* Max represents the number of levels in an SX control not the
- * maximum value, so add the minimum value back on
- */
- uinfo->value.integer.max += mc->min;
+ if (mc->platform_max)
+ max = mc->platform_max;
+ else
+ max = mc->max;
+
+ if (max == 1 && !strstr(kcontrol->id.name, " Volume"))
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ else
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+
+ uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = max;
return 0;
}
diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig
index 4542868..e90f173 100644
--- a/sound/soc/sof/Kconfig
+++ b/sound/soc/sof/Kconfig
@@ -252,6 +252,13 @@
When selected, the probe is handled in two steps, for example to
avoid lockdeps if request_module is used in the probe.
+# Supported IPC versions
+config SND_SOC_SOF_IPC3
+ bool
+
+config SND_SOC_SOF_INTEL_IPC4
+ bool
+
source "sound/soc/sof/amd/Kconfig"
source "sound/soc/sof/imx/Kconfig"
source "sound/soc/sof/intel/Kconfig"
diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile
index 92b5e83..9a74ed1 100644
--- a/sound/soc/sof/Makefile
+++ b/sound/soc/sof/Makefile
@@ -1,10 +1,18 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\
- control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o\
- ipc3-topology.o ipc3-control.o ipc3.o ipc3-pcm.o ipc3-loader.o\
- ipc3-dtrace.o\
- ipc4.o ipc4-loader.o
+ control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o
+
+# IPC implementations
+ifneq ($(CONFIG_SND_SOC_SOF_IPC3),)
+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
+endif
+
+# SOF client support
ifneq ($(CONFIG_SND_SOC_SOF_CLIENT),)
snd-sof-objs += sof-client.o
endif
diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig
index 085232e..190c85d 100644
--- a/sound/soc/sof/amd/Kconfig
+++ b/sound/soc/sof/amd/Kconfig
@@ -17,6 +17,7 @@
config SND_SOC_SOF_AMD_COMMON
tristate
select SND_SOC_SOF
+ select SND_SOC_SOF_IPC3
select SND_SOC_SOF_PCI_DEV
select SND_AMD_ACP_CONFIG
select SND_SOC_ACPI if ACPI
diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h
index 40fbf11..56cefd4 100644
--- a/sound/soc/sof/amd/acp-dsp-offset.h
+++ b/sound/soc/sof/amd/acp-dsp-offset.h
@@ -46,12 +46,14 @@
#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_8 0xC3C
#define ACPAXI2AXI_ATU_CTRL 0xC40
#define ACP_SOFT_RESET 0x1000
+#define ACP_CONTROL 0x1004
#define ACP_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 from ACP_INTR block */
#define ACP_EXTERNAL_INTR_ENB 0x1800
diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c
index 0c27257..c40d290 100644
--- a/sound/soc/sof/amd/acp.c
+++ b/sound/soc/sof/amd/acp.c
@@ -413,10 +413,46 @@ static int acp_init(struct snd_sof_dev *sdev)
dev_err(sdev->dev, "ACP power on failed\n");
return ret;
}
+
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, 0x01);
/* Reset */
return acp_reset(sdev);
}
+int amd_sof_acp_suspend(struct snd_sof_dev *sdev, u32 target_state)
+{
+ int ret;
+
+ ret = acp_reset(sdev);
+ if (ret) {
+ dev_err(sdev->dev, "ACP Reset failed\n");
+ return ret;
+ }
+
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, 0x00);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(amd_sof_acp_suspend, SND_SOC_SOF_AMD_COMMON);
+
+int amd_sof_acp_resume(struct snd_sof_dev *sdev)
+{
+ int ret;
+
+ ret = acp_init(sdev);
+ if (ret) {
+ dev_err(sdev->dev, "ACP Init failed\n");
+ return ret;
+ }
+
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CLKMUX_SEL, 0x03);
+
+ ret = acp_memory_init(sdev);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS(amd_sof_acp_resume, SND_SOC_SOF_AMD_COMMON);
+
int amd_sof_acp_probe(struct snd_sof_dev *sdev)
{
struct pci_dev *pci = to_pci_dev(sdev->dev);
diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h
index 291b44c..4c42b8f 100644
--- a/sound/soc/sof/amd/acp.h
+++ b/sound/soc/sof/amd/acp.h
@@ -216,6 +216,10 @@ int acp_sof_trace_init(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
struct sof_ipc_dma_trace_params_ext *dtrace_params);
int acp_sof_trace_release(struct snd_sof_dev *sdev);
+/* PM Callbacks */
+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;
};
diff --git a/sound/soc/sof/amd/pci-rn.c b/sound/soc/sof/amd/pci-rn.c
index d5d9bcc..3a7fed2 100644
--- a/sound/soc/sof/amd/pci-rn.c
+++ b/sound/soc/sof/amd/pci-rn.c
@@ -49,6 +49,7 @@ static const struct sof_amd_acp_desc renoir_chip_info = {
static const struct sof_dev_desc renoir_desc = {
.machines = snd_soc_acpi_amd_sof_machines,
+ .use_acpi_target_states = true,
.resindex_lpe_base = 0,
.resindex_pcicfg_base = -1,
.resindex_imr_base = -1,
@@ -166,6 +167,9 @@ static struct pci_driver snd_sof_pci_amd_rn_driver = {
.id_table = rn_pci_ids,
.probe = acp_pci_rn_probe,
.remove = acp_pci_rn_remove,
+ .driver = {
+ .pm = &sof_pci_pm,
+ },
};
module_pci_driver(snd_sof_pci_amd_rn_driver);
diff --git a/sound/soc/sof/amd/renoir.c b/sound/soc/sof/amd/renoir.c
index 7019036..9261c8b 100644
--- a/sound/soc/sof/amd/renoir.c
+++ b/sound/soc/sof/amd/renoir.c
@@ -173,6 +173,10 @@ struct snd_sof_dsp_ops sof_renoir_ops = {
/* 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);
diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c
index 53719c0..c99b5e6 100644
--- a/sound/soc/sof/core.c
+++ b/sound/soc/sof/core.c
@@ -189,7 +189,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
ret = snd_sof_probe(sdev);
if (ret < 0) {
dev_err(sdev->dev, "error: failed to probe DSP %d\n", ret);
- return ret;
+ goto probe_err;
}
sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE);
@@ -317,6 +317,8 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
snd_sof_free_debug(sdev);
dsp_err:
snd_sof_remove(sdev);
+probe_err:
+ sof_ops_free(sdev);
/* all resources freed, update state to match */
sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED);
@@ -374,6 +376,7 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
!sof_ops(sdev)->block_read || !sof_ops(sdev)->block_write ||
!sof_ops(sdev)->send_msg || !sof_ops(sdev)->load_firmware ||
!sof_ops(sdev)->ipc_msg_data) {
+ sof_ops_free(sdev);
dev_err(dev, "error: missing mandatory ops\n");
return -EINVAL;
}
@@ -457,6 +460,8 @@ int snd_sof_device_remove(struct device *dev)
snd_sof_remove(sdev);
}
+ sof_ops_free(sdev);
+
/* release firmware */
snd_sof_fw_unload(sdev);
diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c
index cf1271e..c5d797e 100644
--- a/sound/soc/sof/debug.c
+++ b/sound/soc/sof/debug.c
@@ -428,7 +428,7 @@ static void snd_sof_ipc_dump(struct snd_sof_dev *sdev)
}
}
-void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev)
+void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev, const char *msg)
{
if (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_RETAIN_DSP_CONTEXT) ||
sof_debug_check_flag(SOF_DBG_RETAIN_CTX)) {
@@ -441,8 +441,7 @@ void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev)
/* dump vital information to the logs */
snd_sof_ipc_dump(sdev);
- snd_sof_dsp_dbg_dump(sdev, "Firmware exception",
- SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX);
+ snd_sof_dsp_dbg_dump(sdev, msg, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX);
sof_fw_trace_fw_crashed(sdev);
}
EXPORT_SYMBOL(snd_sof_handle_fw_exception);
diff --git a/sound/soc/sof/imx/Kconfig b/sound/soc/sof/imx/Kconfig
index 9b8d5bb..cc6e695 100644
--- a/sound/soc/sof/imx/Kconfig
+++ b/sound/soc/sof/imx/Kconfig
@@ -15,6 +15,7 @@
tristate
select SND_SOC_SOF_OF_DEV
select SND_SOC_SOF
+ select SND_SOC_SOF_IPC3
select SND_SOC_SOF_XTENSA
select SND_SOC_SOF_COMPRESS
help
diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig
index 0def2aa..80cdc37 100644
--- a/sound/soc/sof/intel/Kconfig
+++ b/sound/soc/sof/intel/Kconfig
@@ -40,6 +40,7 @@
config SND_SOC_SOF_BAYTRAIL
tristate "SOF support for Baytrail, Braswell and Cherrytrail"
default SND_SOC_SOF_ACPI
+ select SND_SOC_SOF_IPC3
select SND_SOC_SOF_INTEL_COMMON
select SND_SOC_SOF_INTEL_ATOM_HIFI_EP
select SND_SOC_SOF_ACPI_DEV
@@ -60,6 +61,7 @@
config SND_SOC_SOF_BROADWELL
tristate "SOF support for Broadwell"
default SND_SOC_SOF_ACPI
+ select SND_SOC_SOF_IPC3
select SND_SOC_SOF_INTEL_COMMON
select SND_SOC_SOF_INTEL_HIFI_EP_IPC
select SND_SOC_SOF_ACPI_DEV
@@ -85,6 +87,7 @@
tristate "SOF support for Tangier/Merrifield"
default SND_SOC_SOF_PCI
select SND_SOC_SOF_PCI_DEV
+ select SND_SOC_SOF_IPC3
select SND_SOC_SOF_INTEL_ATOM_HIFI_EP
help
This adds support for Sound Open Firmware for Intel(R) platforms
@@ -95,6 +98,8 @@
config SND_SOC_SOF_INTEL_APL
tristate
select SND_SOC_SOF_HDA_COMMON
+ select SND_SOC_SOF_IPC3
+ select SND_SOC_SOF_INTEL_IPC4
config SND_SOC_SOF_APOLLOLAKE
tristate "SOF support for Apollolake"
@@ -120,6 +125,8 @@
tristate
select SND_SOC_SOF_HDA_COMMON
select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
+ select SND_SOC_SOF_IPC3
+ select SND_SOC_SOF_INTEL_IPC4
config SND_SOC_SOF_CANNONLAKE
tristate "SOF support for Cannonlake"
@@ -154,6 +161,8 @@
tristate
select SND_SOC_SOF_HDA_COMMON
select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
+ select SND_SOC_SOF_IPC3
+ select SND_SOC_SOF_INTEL_IPC4
config SND_SOC_SOF_ICELAKE
tristate "SOF support for Icelake"
@@ -179,6 +188,8 @@
tristate
select SND_SOC_SOF_HDA_COMMON
select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
+ select SND_SOC_SOF_IPC3
+ select SND_SOC_SOF_INTEL_IPC4
config SND_SOC_SOF_TIGERLAKE
tristate "SOF support for Tigerlake"
diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
index 9823230..70721de 100644
--- a/sound/soc/sof/intel/hda-dai.c
+++ b/sound/soc/sof/intel/hda-dai.c
@@ -10,10 +10,23 @@
#include <sound/pcm_params.h>
#include <sound/hdaudio_ext.h>
+#include <sound/intel-nhlt.h>
+#include <sound/sof/ipc4/header.h>
+#include <uapi/sound/sof/header.h>
+#include "../ipc4-priv.h"
+#include "../ipc4-topology.h"
#include "../sof-priv.h"
#include "../sof-audio.h"
#include "hda.h"
+/*
+ * The default method is to fetch NHLT from BIOS. With this parameter set
+ * it is possible to override that with NHLT in the SOF topology manifest.
+ */
+static bool hda_use_tplg_nhlt;
+module_param_named(sof_use_tplg_nhlt, hda_use_tplg_nhlt, bool, 0444);
+MODULE_PARM_DESC(sof_use_tplg_nhlt, "SOF topology nhlt override");
+
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
struct hda_pipe_params {
@@ -257,7 +270,6 @@ static int hda_link_dma_trigger(struct snd_pcm_substream *substream, int cmd)
struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
int ret;
- dev_dbg(cpu_dai->dev, "%s: cmd=%d\n", __func__, cmd);
if (!hext_stream)
return 0;
@@ -369,8 +381,7 @@ static int hda_dai_config_pause_push_ipc(struct snd_soc_dapm_widget *w)
return ret;
}
-static int ipc3_hda_dai_prepare(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+static int hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
struct hdac_ext_stream *hext_stream =
snd_soc_dai_get_dma_data(dai, substream);
@@ -408,13 +419,15 @@ static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream,
struct snd_soc_dapm_widget *w;
int ret;
+ dev_dbg(dai->dev, "%s: cmd=%d dai %s direction %d\n", __func__, cmd,
+ dai->name, substream->stream);
+
ret = hda_link_dma_trigger(substream, cmd);
if (ret < 0)
return ret;
w = snd_soc_dai_get_widget(dai, substream->stream);
- dev_dbg(dai->dev, "%s: cmd=%d\n", __func__, cmd);
switch (cmd) {
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
@@ -438,6 +451,91 @@ static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream,
return 0;
}
+/*
+ * In contrast to IPC3, the dai trigger in IPC4 mixes pipeline state changes
+ * (over IPC channel) and DMA state change (direct host register changes).
+ */
+static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(dai, substream);
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component);
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_sof_widget *swidget;
+ struct snd_soc_dapm_widget *w;
+ struct snd_soc_dai *codec_dai;
+ struct hdac_stream *hstream;
+ struct snd_soc_dai *cpu_dai;
+ int ret;
+
+ dev_dbg(dai->dev, "%s: cmd=%d dai %s direction %d\n", __func__, cmd,
+ dai->name, substream->stream);
+
+ hstream = substream->runtime->private_data;
+ rtd = asoc_substream_to_rtd(substream);
+ cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ codec_dai = asoc_rtd_to_codec(rtd, 0);
+
+ w = snd_soc_dai_get_widget(dai, substream->stream);
+ swidget = w->dobj.private;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ snd_hdac_ext_link_stream_start(hext_stream);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_STOP:
+ {
+ struct snd_sof_widget *pipe_widget = swidget->pipe_widget;
+ struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
+
+ ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+ SOF_IPC4_PIPE_PAUSED);
+ if (ret < 0)
+ return ret;
+
+ pipeline->state = SOF_IPC4_PIPE_PAUSED;
+
+ snd_hdac_ext_link_stream_clear(hext_stream);
+
+ ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+ SOF_IPC4_PIPE_RESET);
+ if (ret < 0)
+ return ret;
+
+ pipeline->state = SOF_IPC4_PIPE_RESET;
+
+ ret = hda_link_dma_cleanup(substream, hstream, cpu_dai, codec_dai, false);
+ if (ret < 0) {
+ dev_err(sdev->dev, "%s: failed to clean up link DMA\n", __func__);
+ return ret;
+ }
+ break;
+ }
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ {
+ struct snd_sof_widget *pipe_widget = swidget->pipe_widget;
+ struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
+
+ ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+ SOF_IPC4_PIPE_PAUSED);
+ if (ret < 0)
+ return ret;
+
+ pipeline->state = SOF_IPC4_PIPE_PAUSED;
+
+ snd_hdac_ext_link_stream_clear(hext_stream);
+ break;
+ }
+ default:
+ dev_err(sdev->dev, "%s: unknown trigger command %d\n", __func__, cmd);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int hda_dai_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
@@ -454,7 +552,7 @@ static const struct snd_soc_dai_ops ipc3_hda_dai_ops = {
.hw_params = hda_dai_hw_params,
.hw_free = hda_dai_hw_free,
.trigger = ipc3_hda_dai_trigger,
- .prepare = ipc3_hda_dai_prepare,
+ .prepare = hda_dai_prepare,
};
static int hda_dai_suspend(struct hdac_bus *bus)
@@ -497,6 +595,14 @@ static int hda_dai_suspend(struct hdac_bus *bus)
return 0;
}
+
+static const struct snd_soc_dai_ops ipc4_hda_dai_ops = {
+ .hw_params = hda_dai_hw_params,
+ .hw_free = hda_dai_hw_free,
+ .trigger = ipc4_hda_dai_trigger,
+ .prepare = hda_dai_prepare,
+};
+
#endif
/* only one flag used so far to harden hw_params/hw_free/trigger/prepare */
@@ -608,6 +714,59 @@ static const struct snd_soc_dai_ops ipc3_ssp_dai_ops = {
.shutdown = ssp_dai_shutdown,
};
+static int ipc4_be_dai_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct snd_sof_widget *pipe_widget;
+ struct sof_ipc4_pipeline *pipeline;
+ struct snd_sof_widget *swidget;
+ struct snd_soc_dapm_widget *w;
+ struct snd_sof_dev *sdev;
+ int ret;
+
+ w = snd_soc_dai_get_widget(dai, substream->stream);
+ swidget = w->dobj.private;
+ pipe_widget = swidget->pipe_widget;
+ pipeline = pipe_widget->private;
+ sdev = snd_soc_component_get_drvdata(swidget->scomp);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_STOP:
+ ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+ SOF_IPC4_PIPE_PAUSED);
+ if (ret < 0)
+ return ret;
+ pipeline->state = SOF_IPC4_PIPE_PAUSED;
+
+ ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+ SOF_IPC4_PIPE_RESET);
+ if (ret < 0)
+ return ret;
+ pipeline->state = SOF_IPC4_PIPE_RESET;
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+ SOF_IPC4_PIPE_PAUSED);
+ if (ret < 0)
+ return ret;
+ pipeline->state = SOF_IPC4_PIPE_PAUSED;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops ipc4_dmic_dai_ops = {
+ .trigger = ipc4_be_dai_trigger,
+};
+
+static const struct snd_soc_dai_ops ipc4_ssp_dai_ops = {
+ .trigger = ipc4_be_dai_trigger,
+};
+
void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
{
int i;
@@ -627,11 +786,48 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
#endif
}
break;
+ case SOF_INTEL_IPC4:
+ {
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+
+ for (i = 0; i < ops->num_drv; i++) {
+ if (strstr(ops->drv[i].name, "DMIC")) {
+ ops->drv[i].ops = &ipc4_dmic_dai_ops;
+ continue;
+ }
+ if (strstr(ops->drv[i].name, "SSP")) {
+ ops->drv[i].ops = &ipc4_ssp_dai_ops;
+ continue;
+ }
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+ if (strstr(ops->drv[i].name, "iDisp") ||
+ strstr(ops->drv[i].name, "Analog") ||
+ strstr(ops->drv[i].name, "Digital"))
+ ops->drv[i].ops = &ipc4_hda_dai_ops;
+#endif
+ }
+
+ if (!hda_use_tplg_nhlt)
+ ipc4_data->nhlt = intel_nhlt_init(sdev->dev);
+
+ break;
+ }
default:
break;
}
}
+void hda_ops_free(struct snd_sof_dev *sdev)
+{
+ if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+
+ if (!hda_use_tplg_nhlt)
+ intel_nhlt_free(ipc4_data->nhlt);
+ }
+}
+EXPORT_SYMBOL_NS(hda_ops_free, SND_SOC_SOF_INTEL_HDA_COMMON);
+
/*
* common dai driver for skl+ platforms.
* some products who use this DAI array only physically have a subset of
diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c
index e24eea7..263ad45 100644
--- a/sound/soc/sof/intel/hda-dsp.c
+++ b/sound/soc/sof/intel/hda-dsp.c
@@ -940,13 +940,7 @@ void hda_dsp_d0i3_work(struct work_struct *work)
int hda_dsp_core_get(struct snd_sof_dev *sdev, int core)
{
- struct sof_ipc_pm_core_config pm_core_config = {
- .hdr = {
- .cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE,
- .size = sizeof(pm_core_config),
- },
- .enable_mask = sdev->enabled_cores_mask | BIT(core),
- };
+ const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
int ret, ret1;
/* power up core */
@@ -961,9 +955,12 @@ int hda_dsp_core_get(struct snd_sof_dev *sdev, int core)
if (sdev->fw_state != SOF_FW_BOOT_COMPLETE || core == SOF_DSP_PRIMARY_CORE)
return 0;
+ /* No need to continue the set_core_state ops is not available */
+ if (!pm_ops->set_core_state)
+ return 0;
+
/* Now notify DSP for secondary cores */
- ret = sof_ipc_tx_message(sdev->ipc, &pm_core_config, sizeof(pm_core_config),
- &pm_core_config, sizeof(pm_core_config));
+ ret = pm_ops->set_core_state(sdev, core, true);
if (ret < 0) {
dev_err(sdev->dev, "failed to enable secondary core '%d' failed with %d\n",
core, ret);
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
index 0f57ef5..f4e4cd7 100644
--- a/sound/soc/sof/intel/hda.h
+++ b/sound/soc/sof/intel/hda.h
@@ -764,6 +764,7 @@ int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w, unsigned int quirk_f
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);
/* IPC4 */
irqreturn_t cnl_ipc4_irq_thread(int irq, void *context);
diff --git a/sound/soc/sof/intel/pci-apl.c b/sound/soc/sof/intel/pci-apl.c
index 2de3658..998e219 100644
--- a/sound/soc/sof/intel/pci-apl.c
+++ b/sound/soc/sof/intel/pci-apl.c
@@ -44,6 +44,7 @@ static const struct sof_dev_desc bxt_desc = {
.nocodec_tplg_filename = "sof-apl-nocodec.tplg",
.ops = &sof_apl_ops,
.ops_init = sof_apl_ops_init,
+ .ops_free = hda_ops_free,
};
static const struct sof_dev_desc glk_desc = {
diff --git a/sound/soc/sof/intel/pci-cnl.c b/sound/soc/sof/intel/pci-cnl.c
index 87e587a..c797356f 100644
--- a/sound/soc/sof/intel/pci-cnl.c
+++ b/sound/soc/sof/intel/pci-cnl.c
@@ -73,6 +73,7 @@ static const struct sof_dev_desc cfl_desc = {
.nocodec_tplg_filename = "sof-cnl-nocodec.tplg",
.ops = &sof_cnl_ops,
.ops_init = sof_cnl_ops_init,
+ .ops_free = hda_ops_free,
};
static const struct sof_dev_desc cml_desc = {
diff --git a/sound/soc/sof/intel/pci-icl.c b/sound/soc/sof/intel/pci-icl.c
index 1c7f16c..48f24f8 100644
--- a/sound/soc/sof/intel/pci-icl.c
+++ b/sound/soc/sof/intel/pci-icl.c
@@ -45,6 +45,7 @@ static const struct sof_dev_desc icl_desc = {
.nocodec_tplg_filename = "sof-icl-nocodec.tplg",
.ops = &sof_icl_ops,
.ops_init = sof_icl_ops_init,
+ .ops_free = hda_ops_free,
};
static const struct sof_dev_desc jsl_desc = {
diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c
index 58a9bd9..ccc44ba3 100644
--- a/sound/soc/sof/intel/pci-tgl.c
+++ b/sound/soc/sof/intel/pci-tgl.c
@@ -73,6 +73,7 @@ static const struct sof_dev_desc tglh_desc = {
.nocodec_tplg_filename = "sof-tgl-nocodec.tplg",
.ops = &sof_tgl_ops,
.ops_init = sof_tgl_ops_init,
+ .ops_free = hda_ops_free,
};
static const struct sof_dev_desc ehl_desc = {
diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c
index 1ddc492..dcad7c3 100644
--- a/sound/soc/sof/intel/tgl.c
+++ b/sound/soc/sof/intel/tgl.c
@@ -24,40 +24,30 @@ static const struct snd_sof_debugfs_map tgl_dsp_debugfs[] = {
static int tgl_dsp_core_get(struct snd_sof_dev *sdev, int core)
{
- struct sof_ipc_pm_core_config pm_core_config = {
- .hdr = {
- .cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE,
- .size = sizeof(pm_core_config),
- },
- .enable_mask = sdev->enabled_cores_mask | BIT(core),
- };
+ const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
/* power up primary core if not already powered up and return */
if (core == SOF_DSP_PRIMARY_CORE)
return hda_dsp_enable_core(sdev, BIT(core));
- /* notify DSP for secondary cores */
- return sof_ipc_tx_message(sdev->ipc, &pm_core_config, sizeof(pm_core_config),
- &pm_core_config, sizeof(pm_core_config));
+ if (pm_ops->set_core_state)
+ return pm_ops->set_core_state(sdev, core, true);
+
+ return 0;
}
static int tgl_dsp_core_put(struct snd_sof_dev *sdev, int core)
{
- struct sof_ipc_pm_core_config pm_core_config = {
- .hdr = {
- .cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE,
- .size = sizeof(pm_core_config),
- },
- .enable_mask = sdev->enabled_cores_mask & ~BIT(core),
- };
+ const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
/* power down primary core and return */
if (core == SOF_DSP_PRIMARY_CORE)
return hda_dsp_core_reset_power_down(sdev, BIT(core));
- /* notify DSP for secondary cores */
- return sof_ipc_tx_message(sdev->ipc, &pm_core_config, sizeof(pm_core_config),
- &pm_core_config, sizeof(pm_core_config));
+ if (pm_ops->set_core_state)
+ return pm_ops->set_core_state(sdev, core, false);
+
+ return 0;
}
/* Tigerlake ops */
diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c
index c5aef5f..6ed3f9b 100644
--- a/sound/soc/sof/ipc.c
+++ b/sound/soc/sof/ipc.c
@@ -155,12 +155,22 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev)
init_waitqueue_head(&msg->waitq);
- /*
- * Use IPC3 ops as it is the only available version now. With the addition of new IPC
- * versions, this will need to be modified to use the selected version at runtime.
- */
- ipc->ops = &ipc3_ops;
- ops = ipc->ops;
+ switch (sdev->pdata->ipc_type) {
+#if defined(CONFIG_SND_SOC_SOF_IPC3)
+ case SOF_IPC:
+ ops = &ipc3_ops;
+ break;
+#endif
+#if defined(CONFIG_SND_SOC_SOF_INTEL_IPC4)
+ case SOF_INTEL_IPC4:
+ ops = &ipc4_ops;
+ break;
+#endif
+ default:
+ dev_err(sdev->dev, "Not supported IPC version: %d\n",
+ sdev->pdata->ipc_type);
+ return NULL;
+ }
/* check for mandatory ops */
if (!ops->tx_msg || !ops->rx_msg || !ops->set_get_data || !ops->get_reply) {
@@ -190,6 +200,8 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev)
return NULL;
}
+ ipc->ops = ops;
+
return ipc;
}
EXPORT_SYMBOL(snd_sof_ipc_init);
diff --git a/sound/soc/sof/ipc3-dtrace.c b/sound/soc/sof/ipc3-dtrace.c
index b4e1343..ecca6dc 100644
--- a/sound/soc/sof/ipc3-dtrace.c
+++ b/sound/soc/sof/ipc3-dtrace.c
@@ -18,6 +18,7 @@
enum sof_dtrace_state {
SOF_DTRACE_DISABLED,
SOF_DTRACE_STOPPED,
+ SOF_DTRACE_INITIALIZING,
SOF_DTRACE_ENABLED,
};
@@ -32,6 +33,15 @@ struct sof_dtrace_priv {
enum sof_dtrace_state dtrace_state;
};
+static bool trace_pos_update_expected(struct sof_dtrace_priv *priv)
+{
+ if (priv->dtrace_state == SOF_DTRACE_ENABLED ||
+ priv->dtrace_state == SOF_DTRACE_INITIALIZING)
+ return true;
+
+ return false;
+}
+
static int trace_filter_append_elem(struct snd_sof_dev *sdev, u32 key, u32 value,
struct sof_ipc_trace_filter_elem *elem_list,
int capacity, int *counter)
@@ -157,9 +167,8 @@ static int ipc3_trace_update_filter(struct snd_sof_dev *sdev, int num_elems,
msg->elem_cnt = num_elems;
memcpy(&msg->elems[0], elems, num_elems * sizeof(*elems));
- ret = pm_runtime_get_sync(sdev->dev);
+ ret = pm_runtime_resume_and_get(sdev->dev);
if (ret < 0 && ret != -EACCES) {
- pm_runtime_put_noidle(sdev->dev);
dev_err(sdev->dev, "enabling device failed: %d\n", ret);
goto error;
}
@@ -242,6 +251,21 @@ static int debugfs_create_trace_filter(struct snd_sof_dev *sdev)
return 0;
}
+static bool sof_dtrace_set_host_offset(struct sof_dtrace_priv *priv, u32 new_offset)
+{
+ u32 host_offset = READ_ONCE(priv->host_offset);
+
+ if (host_offset != new_offset) {
+ /* This is a bit paranoid and unlikely that it is needed */
+ u32 ret = cmpxchg(&priv->host_offset, host_offset, new_offset);
+
+ if (ret == host_offset)
+ return true;
+ }
+
+ return false;
+}
+
static size_t sof_dtrace_avail(struct snd_sof_dev *sdev,
loff_t pos, size_t buffer_size)
{
@@ -274,7 +298,7 @@ static size_t sof_wait_dtrace_avail(struct snd_sof_dev *sdev, loff_t pos,
if (ret)
return ret;
- if (priv->dtrace_state != SOF_DTRACE_ENABLED && priv->dtrace_draining) {
+ if (priv->dtrace_draining && !trace_pos_update_expected(priv)) {
/*
* tracing has ended and all traces have been
* read by client, return EOF
@@ -328,6 +352,10 @@ static ssize_t dfsentry_dtrace_read(struct file *file, char __user *buffer,
return -EIO;
}
+ /* no new trace data */
+ if (!avail)
+ return 0;
+
/* make sure count is <= avail */
if (count > avail)
count = avail;
@@ -358,7 +386,7 @@ static int dfsentry_dtrace_release(struct inode *inode, struct file *file)
/* avoid duplicate traces at next open */
if (priv->dtrace_state != SOF_DTRACE_ENABLED)
- priv->host_offset = 0;
+ sof_dtrace_set_host_offset(priv, 0);
return 0;
}
@@ -434,7 +462,7 @@ static int ipc3_dtrace_enable(struct snd_sof_dev *sdev)
params.buffer.pages = priv->dma_trace_pages;
params.stream_tag = 0;
- priv->host_offset = 0;
+ sof_dtrace_set_host_offset(priv, 0);
priv->dtrace_draining = false;
ret = sof_dtrace_host_init(sdev, &priv->dmatb, ¶ms);
@@ -445,6 +473,7 @@ static int ipc3_dtrace_enable(struct snd_sof_dev *sdev)
dev_dbg(sdev->dev, "%s: stream_tag: %d\n", __func__, params.stream_tag);
/* send IPC to the DSP */
+ priv->dtrace_state = SOF_DTRACE_INITIALIZING;
ret = sof_ipc_tx_message(sdev->ipc, ¶ms, sizeof(params), &ipc_reply, sizeof(ipc_reply));
if (ret < 0) {
dev_err(sdev->dev, "can't set params for DMA for trace %d\n", ret);
@@ -452,17 +481,18 @@ static int ipc3_dtrace_enable(struct snd_sof_dev *sdev)
}
start:
+ priv->dtrace_state = SOF_DTRACE_ENABLED;
+
ret = sof_dtrace_host_trigger(sdev, SNDRV_PCM_TRIGGER_START);
if (ret < 0) {
dev_err(sdev->dev, "Host dtrace trigger start failed: %d\n", ret);
goto trace_release;
}
- priv->dtrace_state = SOF_DTRACE_ENABLED;
-
return 0;
trace_release:
+ priv->dtrace_state = SOF_DTRACE_DISABLED;
sof_dtrace_host_release(sdev);
return ret;
}
@@ -546,11 +576,9 @@ int ipc3_dtrace_posn_update(struct snd_sof_dev *sdev,
if (!sdev->fw_trace_is_supported)
return 0;
- if (priv->dtrace_state == SOF_DTRACE_ENABLED &&
- priv->host_offset != posn->host_offset) {
- priv->host_offset = posn->host_offset;
+ if (trace_pos_update_expected(priv) &&
+ sof_dtrace_set_host_offset(priv, posn->host_offset))
wake_up(&priv->trace_sleep);
- }
if (posn->overflow != 0)
dev_err(sdev->dev,
diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c
index c8774a8..b97e63d 100644
--- a/sound/soc/sof/ipc3-pcm.c
+++ b/sound/soc/sof/ipc3-pcm.c
@@ -344,10 +344,10 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
channels->min, channels->max);
break;
case SOF_DAI_AMD_DMIC:
- rate->min = private->dai_config->acpdmic.fsync_rate;
- rate->max = private->dai_config->acpdmic.fsync_rate;
- channels->min = private->dai_config->acpdmic.tdm_slots;
- channels->max = private->dai_config->acpdmic.tdm_slots;
+ rate->min = private->dai_config->acpdmic.pdm_rate;
+ rate->max = private->dai_config->acpdmic.pdm_rate;
+ channels->min = private->dai_config->acpdmic.pdm_ch;
+ channels->max = private->dai_config->acpdmic.pdm_ch;
dev_dbg(component->dev,
"AMD_DMIC rate_min: %d rate_max: %d\n", rate->min, rate->max);
diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c
index 10740c5..28d3c14 100644
--- a/sound/soc/sof/ipc3-topology.c
+++ b/sound/soc/sof/ipc3-topology.c
@@ -17,6 +17,9 @@
/* Full volume for default values */
#define VOL_ZERO_DB BIT(VOLUME_FWL)
+/* size of tplg ABI in bytes */
+#define SOF_IPC3_TPLG_ABI_SIZE 3
+
struct sof_widget_data {
int ctrl_type;
int ipc_cmd;
@@ -263,6 +266,16 @@ static const struct sof_topology_token afe_tokens[] = {
offsetof(struct sof_ipc_dai_mtk_afe_params, format)},
};
+/* ACPDMIC */
+static const struct sof_topology_token acpdmic_tokens[] = {
+ {SOF_TKN_AMD_ACPDMIC_RATE,
+ SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc_dai_acpdmic_params, pdm_rate)},
+ {SOF_TKN_AMD_ACPDMIC_CH,
+ SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc_dai_acpdmic_params, pdm_ch)},
+};
+
/* Core tokens */
static const struct sof_topology_token core_tokens[] = {
{SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
@@ -297,6 +310,7 @@ static const struct sof_token_info ipc3_token_list[SOF_TOKEN_COUNT] = {
[SOF_ESAI_TOKENS] = {"ESAI tokens", esai_tokens, ARRAY_SIZE(esai_tokens)},
[SOF_SAI_TOKENS] = {"SAI tokens", sai_tokens, ARRAY_SIZE(sai_tokens)},
[SOF_AFE_TOKENS] = {"AFE tokens", afe_tokens, ARRAY_SIZE(afe_tokens)},
+ [SOF_ACPDMIC_TOKENS] = {"ACPDMIC tokens", acpdmic_tokens, ARRAY_SIZE(acpdmic_tokens)},
};
/**
@@ -1117,20 +1131,22 @@ static int sof_link_acp_dmic_load(struct snd_soc_component *scomp, struct snd_so
struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
struct sof_dai_private_data *private = dai->private;
u32 size = sizeof(*config);
+ int ret;
/* handle master/slave and inverted clocks */
sof_dai_set_format(hw_config, config);
- /* init IPC */
- memset(&config->acpdmic, 0, sizeof(config->acpdmic));
config->hdr.size = size;
- config->acpdmic.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
- config->acpdmic.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
+ /* parse the required set of ACPDMIC tokens based on num_hw_cfgs */
+ ret = sof_update_ipc_object(scomp, &config->acpdmic, SOF_ACPDMIC_TOKENS, slink->tuples,
+ slink->num_tuples, size, slink->num_hw_configs);
+ if (ret < 0)
+ return ret;
dev_info(scomp->dev, "ACP_DMIC config ACP%d channel %d rate %d\n",
- config->dai_index, config->acpdmic.tdm_slots,
- config->acpdmic.fsync_rate);
+ config->dai_index, config->acpdmic.pdm_ch,
+ config->acpdmic.pdm_rate);
dai->number_configs = 1;
dai->current_config = 0;
@@ -2302,6 +2318,50 @@ static int sof_ipc3_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *da
return -EINVAL;
}
+static int sof_ipc3_parse_manifest(struct snd_soc_component *scomp, int index,
+ struct snd_soc_tplg_manifest *man)
+{
+ u32 size = le32_to_cpu(man->priv.size);
+ u32 abi_version;
+
+ /* backward compatible with tplg without ABI info */
+ if (!size) {
+ dev_dbg(scomp->dev, "No topology ABI info\n");
+ return 0;
+ }
+
+ if (size != SOF_IPC3_TPLG_ABI_SIZE) {
+ dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n",
+ __func__, size);
+ return -EINVAL;
+ }
+
+ dev_info(scomp->dev,
+ "Topology: ABI %d:%d:%d Kernel ABI %hhu:%hhu:%hhu\n",
+ man->priv.data[0], man->priv.data[1], man->priv.data[2],
+ SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
+
+ abi_version = SOF_ABI_VER(man->priv.data[0], man->priv.data[1], man->priv.data[2]);
+
+ if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, abi_version)) {
+ dev_err(scomp->dev, "%s: Incompatible topology ABI version\n", __func__);
+ return -EINVAL;
+ }
+
+ if (SOF_ABI_VERSION_MINOR(abi_version) > SOF_ABI_MINOR) {
+ if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS)) {
+ dev_warn(scomp->dev, "%s: Topology ABI is more recent than kernel\n",
+ __func__);
+ } else {
+ dev_err(scomp->dev, "%s: Topology ABI is more recent than kernel\n",
+ __func__);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
/* token list for each topology object */
static enum sof_tokens host_token_list[] = {
SOF_CORE_TOKENS,
@@ -2412,4 +2472,5 @@ const struct sof_ipc_tplg_ops ipc3_tplg_ops = {
.dai_get_clk = sof_ipc3_dai_get_clk,
.set_up_all_pipelines = sof_ipc3_set_up_all_pipelines,
.tear_down_all_pipelines = sof_ipc3_tear_down_all_pipelines,
+ .parse_manifest = sof_ipc3_parse_manifest,
};
diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c
index dff5feaa..1fb132b 100644
--- a/sound/soc/sof/ipc3.c
+++ b/sound/soc/sof/ipc3.c
@@ -147,6 +147,8 @@ static void ipc3_log_header(struct device *dev, u8 *text, u32 cmd)
case SOF_IPC_TRACE_DMA_PARAMS:
str2 = "DMA_PARAMS"; break;
case SOF_IPC_TRACE_DMA_POSITION:
+ if (!sof_debug_check_flag(SOF_DBG_PRINT_DMA_POSITION_UPDATE_LOGS))
+ return;
str2 = "DMA_POSITION"; break;
case SOF_IPC_TRACE_DMA_PARAMS_EXT:
str2 = "DMA_PARAMS_EXT"; break;
@@ -290,7 +292,7 @@ static int ipc3_wait_tx_done(struct snd_sof_ipc *ipc, void *reply_data)
dev_err(sdev->dev,
"ipc tx timed out for %#x (msg/reply size: %d/%zu)\n",
hdr->cmd, hdr->size, msg->reply_size);
- snd_sof_handle_fw_exception(ipc->sdev);
+ snd_sof_handle_fw_exception(ipc->sdev, "IPC timeout");
ret = -ETIMEDOUT;
} else {
ret = msg->reply_error;
@@ -299,7 +301,8 @@ static int ipc3_wait_tx_done(struct snd_sof_ipc *ipc, void *reply_data)
"ipc tx error for %#x (msg/reply size: %d/%zu): %d\n",
hdr->cmd, hdr->size, msg->reply_size, ret);
} else {
- ipc3_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd);
+ if (sof_debug_check_flag(SOF_DBG_PRINT_IPC_SUCCESS_LOGS))
+ ipc3_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd);
if (msg->reply_size)
/* copy the data returned from DSP */
memcpy(reply_data, msg->reply_data,
@@ -1037,6 +1040,23 @@ static void sof_ipc3_rx_msg(struct snd_sof_dev *sdev)
ipc3_log_header(sdev->dev, "ipc rx done", hdr.cmd);
}
+static int sof_ipc3_set_core_state(struct snd_sof_dev *sdev, int core_idx, bool on)
+{
+ struct sof_ipc_pm_core_config core_cfg = {
+ .hdr.size = sizeof(core_cfg),
+ .hdr.cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE,
+ };
+ struct sof_ipc_reply reply;
+
+ if (on)
+ core_cfg.enable_mask = sdev->enabled_cores_mask | BIT(core_idx);
+ else
+ core_cfg.enable_mask = sdev->enabled_cores_mask & ~BIT(core_idx);
+
+ return sof_ipc3_tx_msg(sdev, &core_cfg, sizeof(core_cfg),
+ &reply, sizeof(reply), false);
+}
+
static int sof_ipc3_ctx_ipc(struct snd_sof_dev *sdev, int cmd)
{
struct sof_ipc_pm_ctx pm_ctx = {
@@ -1063,6 +1083,7 @@ static int sof_ipc3_ctx_restore(struct snd_sof_dev *sdev)
static const struct sof_ipc_pm_ops ipc3_pm_ops = {
.ctx_save = sof_ipc3_ctx_save,
.ctx_restore = sof_ipc3_ctx_restore,
+ .set_core_state = sof_ipc3_set_core_state,
};
const struct sof_ipc_ops ipc3_ops = {
diff --git a/sound/soc/sof/ipc4-control.c b/sound/soc/sof/ipc4-control.c
new file mode 100644
index 0000000..95ee121
--- /dev/null
+++ b/sound/soc/sof/ipc4-control.c
@@ -0,0 +1,216 @@
+// 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 Intel Corporation. All rights reserved.
+//
+//
+
+#include "sof-priv.h"
+#include "sof-audio.h"
+#include "ipc4-priv.h"
+#include "ipc4-topology.h"
+
+static int sof_ipc4_set_get_kcontrol_data(struct snd_sof_control *scontrol, bool set)
+{
+ struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
+ struct snd_soc_component *scomp = scontrol->scomp;
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+ const struct sof_ipc_ops *iops = sdev->ipc->ops;
+ struct sof_ipc4_msg *msg = &cdata->msg;
+ struct snd_sof_widget *swidget;
+ bool widget_found = false;
+
+ /* find widget associated with the control */
+ list_for_each_entry(swidget, &sdev->widget_list, list) {
+ if (swidget->comp_id == scontrol->comp_id) {
+ widget_found = true;
+ break;
+ }
+ }
+
+ if (!widget_found) {
+ dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name);
+ return -ENOENT;
+ }
+
+ /*
+ * Volatile controls should always be part of static pipelines and the widget use_count
+ * would always be > 0 in this case. For the others, just return the cached value if the
+ * widget is not set up.
+ */
+ if (!swidget->use_count)
+ return 0;
+
+ msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK;
+ msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id);
+
+ return iops->set_get_data(sdev, msg, msg->data_size, set);
+}
+
+static int
+sof_ipc4_set_volume_data(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
+ struct snd_sof_control *scontrol)
+{
+ struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
+ struct sof_ipc4_gain *gain = swidget->private;
+ struct sof_ipc4_msg *msg = &cdata->msg;
+ struct sof_ipc4_gain_data data;
+ bool all_channels_equal = true;
+ u32 value;
+ int ret, i;
+
+ /* check if all channel values are equal */
+ value = cdata->chanv[0].value;
+ for (i = 1; i < scontrol->num_channels; i++) {
+ if (cdata->chanv[i].value != value) {
+ all_channels_equal = false;
+ break;
+ }
+ }
+
+ /*
+ * notify DSP with a single IPC message if all channel values are equal. Otherwise send
+ * a separate IPC for each channel.
+ */
+ for (i = 0; i < scontrol->num_channels; i++) {
+ if (all_channels_equal) {
+ data.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK;
+ data.init_val = cdata->chanv[0].value;
+ } else {
+ data.channels = cdata->chanv[i].channel;
+ data.init_val = cdata->chanv[i].value;
+ }
+
+ /* set curve type and duration from topology */
+ data.curve_duration = gain->data.curve_duration;
+ data.curve_type = gain->data.curve_type;
+
+ msg->data_ptr = &data;
+ msg->data_size = sizeof(data);
+
+ ret = sof_ipc4_set_get_kcontrol_data(scontrol, true);
+ msg->data_ptr = NULL;
+ msg->data_size = 0;
+ if (ret < 0) {
+ dev_err(sdev->dev, "Failed to set volume update for %s\n",
+ scontrol->name);
+ return ret;
+ }
+
+ if (all_channels_equal)
+ break;
+ }
+
+ return 0;
+}
+
+static bool sof_ipc4_volume_put(struct snd_sof_control *scontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
+ struct snd_soc_component *scomp = scontrol->scomp;
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+ unsigned int channels = scontrol->num_channels;
+ struct snd_sof_widget *swidget;
+ bool widget_found = false;
+ bool change = false;
+ unsigned int i;
+ int ret;
+
+ /* update each channel */
+ for (i = 0; i < channels; i++) {
+ u32 value = mixer_to_ipc(ucontrol->value.integer.value[i],
+ scontrol->volume_table, scontrol->max + 1);
+
+ change = change || (value != cdata->chanv[i].value);
+ cdata->chanv[i].channel = i;
+ cdata->chanv[i].value = value;
+ }
+
+ if (!pm_runtime_active(scomp->dev))
+ return change;
+
+ /* find widget associated with the control */
+ list_for_each_entry(swidget, &sdev->widget_list, list) {
+ if (swidget->comp_id == scontrol->comp_id) {
+ widget_found = true;
+ break;
+ }
+ }
+
+ if (!widget_found) {
+ dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name);
+ return -ENOENT;
+ }
+
+ ret = sof_ipc4_set_volume_data(sdev, swidget, scontrol);
+ if (ret < 0)
+ return false;
+
+ return change;
+}
+
+static int sof_ipc4_volume_get(struct snd_sof_control *scontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
+ unsigned int channels = scontrol->num_channels;
+ unsigned int i;
+
+ for (i = 0; i < channels; i++)
+ ucontrol->value.integer.value[i] = ipc_to_mixer(cdata->chanv[i].value,
+ scontrol->volume_table,
+ scontrol->max + 1);
+
+ return 0;
+}
+
+/* set up all controls for the widget */
+static int sof_ipc4_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
+{
+ struct snd_sof_control *scontrol;
+ int ret;
+
+ list_for_each_entry(scontrol, &sdev->kcontrol_list, list)
+ if (scontrol->comp_id == swidget->comp_id) {
+ ret = sof_ipc4_set_volume_data(sdev, swidget, scontrol);
+ if (ret < 0) {
+ dev_err(sdev->dev, "%s: kcontrol %d set up failed for widget %s\n",
+ __func__, scontrol->comp_id, swidget->widget->name);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int
+sof_ipc4_set_up_volume_table(struct snd_sof_control *scontrol, int tlv[SOF_TLV_ITEMS], int size)
+{
+ int i;
+
+ /* init the volume table */
+ scontrol->volume_table = kcalloc(size, sizeof(u32), GFP_KERNEL);
+ if (!scontrol->volume_table)
+ return -ENOMEM;
+
+ /* populate the volume table */
+ for (i = 0; i < size ; i++) {
+ u32 val = vol_compute_gain(i, tlv);
+ u64 q31val = ((u64)val) << 15; /* Can be over Q1.31, need to saturate */
+
+ scontrol->volume_table[i] = q31val > SOF_IPC4_VOL_ZERO_DB ?
+ SOF_IPC4_VOL_ZERO_DB : q31val;
+ }
+
+ return 0;
+}
+
+const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops = {
+ .volume_put = sof_ipc4_volume_put,
+ .volume_get = sof_ipc4_volume_get,
+ .widget_kcontrol_setup = sof_ipc4_widget_kcontrol_setup,
+ .set_up_volume_table = sof_ipc4_set_up_volume_table,
+};
diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c
new file mode 100644
index 0000000..6a702f9
--- /dev/null
+++ b/sound/soc/sof/ipc4-pcm.c
@@ -0,0 +1,230 @@
+// 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 Intel Corporation. All rights reserved.
+//
+
+#include <sound/pcm_params.h>
+#include <sound/sof/ipc4/header.h>
+#include "sof-audio.h"
+#include "sof-priv.h"
+#include "ipc4-priv.h"
+#include "ipc4-topology.h"
+
+int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state)
+{
+ struct sof_ipc4_msg msg = {{ 0 }};
+ u32 primary;
+
+ dev_dbg(sdev->dev, "ipc4 set pipeline %d state %d", id, state);
+
+ primary = state;
+ primary |= SOF_IPC4_GLB_PIPE_STATE_ID(id);
+ primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE);
+ primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+ primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
+
+ msg.primary = primary;
+
+ return sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
+}
+EXPORT_SYMBOL(sof_ipc4_set_pipeline_state);
+
+static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream, int state)
+{
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_sof_widget *pipeline_widget;
+ struct snd_soc_dapm_widget_list *list;
+ struct snd_soc_dapm_widget *widget;
+ struct sof_ipc4_pipeline *pipeline;
+ struct snd_sof_widget *swidget;
+ struct snd_sof_pcm *spcm;
+ int ret = 0;
+ int num_widgets;
+
+ spcm = snd_sof_find_spcm_dai(component, rtd);
+ if (!spcm)
+ return -EINVAL;
+
+ list = spcm->stream[substream->stream].list;
+
+ for_each_dapm_widgets(list, num_widgets, widget) {
+ swidget = widget->dobj.private;
+
+ if (!swidget)
+ continue;
+
+ /*
+ * set pipeline state for both FE and BE pipelines for RUNNING state.
+ * For PAUSE/RESET, set the pipeline state only for the FE pipeline.
+ */
+ switch (state) {
+ case SOF_IPC4_PIPE_PAUSED:
+ case SOF_IPC4_PIPE_RESET:
+ if (!WIDGET_IS_AIF(swidget->id))
+ continue;
+ break;
+ default:
+ break;
+ }
+
+ /* find pipeline widget for the pipeline that this widget belongs to */
+ pipeline_widget = swidget->pipe_widget;
+ pipeline = (struct sof_ipc4_pipeline *)pipeline_widget->private;
+
+ if (pipeline->state == state)
+ continue;
+
+ /* first set the pipeline to PAUSED state */
+ if (pipeline->state != SOF_IPC4_PIPE_PAUSED) {
+ ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+ SOF_IPC4_PIPE_PAUSED);
+ if (ret < 0) {
+ dev_err(sdev->dev, "failed to pause pipeline %d\n",
+ swidget->pipeline_id);
+ return ret;
+ }
+ }
+
+ pipeline->state = SOF_IPC4_PIPE_PAUSED;
+
+ if (pipeline->state == state)
+ continue;
+
+ /* then set the final state */
+ ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id, state);
+ if (ret < 0) {
+ dev_err(sdev->dev, "failed to set state %d for pipeline %d\n",
+ state, swidget->pipeline_id);
+ break;
+ }
+
+ pipeline->state = state;
+ }
+
+ return ret;
+}
+
+static int sof_ipc4_pcm_trigger(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream, int cmd)
+{
+ int state;
+
+ /* determine the pipeline state */
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ state = SOF_IPC4_PIPE_PAUSED;
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_START:
+ state = SOF_IPC4_PIPE_RUNNING;
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_STOP:
+ state = SOF_IPC4_PIPE_PAUSED;
+ break;
+ default:
+ dev_err(component->dev, "%s: unhandled trigger cmd %d\n", __func__, cmd);
+ return -EINVAL;
+ }
+
+ /* set the pipeline state */
+ return sof_ipc4_trigger_pipelines(component, substream, state);
+}
+
+static int sof_ipc4_pcm_hw_free(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ return sof_ipc4_trigger_pipelines(component, substream, SOF_IPC4_PIPE_RESET);
+}
+
+static void ipc4_ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, const char *link_name,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_sof_dai_link *slink;
+ struct snd_sof_dai *dai;
+ bool dai_link_found = false;
+ int i;
+
+ list_for_each_entry(slink, &sdev->dai_link_list, list) {
+ if (!strcmp(slink->link->name, link_name)) {
+ dai_link_found = true;
+ break;
+ }
+ }
+
+ if (!dai_link_found)
+ return;
+
+ for (i = 0; i < slink->num_hw_configs; i++) {
+ struct snd_soc_tplg_hw_config *hw_config = &slink->hw_configs[i];
+
+ if (params_rate(params) == le32_to_cpu(hw_config->fsync_rate)) {
+ /* set current config for all DAI's with matching name */
+ list_for_each_entry(dai, &sdev->dai_list, list)
+ if (!strcmp(slink->link->name, dai->name))
+ dai->current_config = le32_to_cpu(hw_config->id);
+ break;
+ }
+ }
+}
+
+static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME);
+ struct snd_sof_dai *dai = snd_sof_find_dai(component, rtd->dai_link->name);
+ struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
+ struct sof_ipc4_copier *ipc4_copier;
+ struct snd_soc_dpcm *dpcm;
+
+ if (!dai) {
+ dev_err(component->dev, "%s: No DAI found with name %s\n", __func__,
+ rtd->dai_link->name);
+ return -EINVAL;
+ }
+
+ ipc4_copier = dai->private;
+ if (!ipc4_copier) {
+ dev_err(component->dev, "%s: No private data found for DAI %s\n",
+ __func__, rtd->dai_link->name);
+ return -EINVAL;
+ }
+
+ /* always set BE format to 32-bits for both playback and capture */
+ snd_mask_none(fmt);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
+
+ /*
+ * Set trigger order for capture to SND_SOC_DPCM_TRIGGER_PRE. This is required
+ * to ensure that the BE DAI pipeline gets stopped/suspended before the FE DAI
+ * pipeline gets triggered and the pipeline widgets are freed.
+ */
+ for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_CAPTURE, dpcm) {
+ struct snd_soc_pcm_runtime *fe = dpcm->fe;
+
+ fe->dai_link->trigger[SNDRV_PCM_STREAM_CAPTURE] = SND_SOC_DPCM_TRIGGER_PRE;
+ }
+
+ switch (ipc4_copier->dai_type) {
+ case SOF_DAI_INTEL_SSP:
+ ipc4_ssp_dai_config_pcm_params_match(sdev, (char *)rtd->dai_link->name, params);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+const struct sof_ipc_pcm_ops ipc4_pcm_ops = {
+ .trigger = sof_ipc4_pcm_trigger,
+ .hw_free = sof_ipc4_pcm_hw_free,
+ .dai_link_fixup = sof_ipc4_pcm_dai_link_fixup,
+};
diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h
index 2b71d56..9492fe1 100644
--- a/sound/soc/sof/ipc4-priv.h
+++ b/sound/soc/sof/ipc4-priv.h
@@ -18,11 +18,13 @@
* @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
*/
struct sof_ipc4_fw_data {
u32 manifest_fw_hdr_offset;
int num_fw_modules;
void *fw_modules;
+ void *nhlt;
};
/**
@@ -40,5 +42,10 @@ struct sof_ipc4_fw_module {
};
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;
+
+int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state);
#endif
diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
new file mode 100644
index 0000000..cb0f082
--- /dev/null
+++ b/sound/soc/sof/ipc4-topology.c
@@ -0,0 +1,1702 @@
+// 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 Intel Corporation. All rights reserved.
+//
+//
+#include <uapi/sound/sof/tokens.h>
+#include <sound/pcm_params.h>
+#include <sound/sof/ext_manifest4.h>
+#include <sound/intel-nhlt.h>
+#include "sof-priv.h"
+#include "sof-audio.h"
+#include "ipc4-priv.h"
+#include "ipc4-topology.h"
+#include "ops.h"
+
+#define SOF_IPC4_GAIN_PARAM_ID 0
+#define SOF_IPC4_TPLG_ABI_SIZE 6
+
+static const struct sof_topology_token ipc4_sched_tokens[] = {
+ {SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc4_pipeline, lp_mode)}
+};
+
+static const struct sof_topology_token pipeline_tokens[] = {
+ {SOF_TKN_SCHED_DYNAMIC_PIPELINE, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16,
+ offsetof(struct snd_sof_widget, dynamic_pipeline_widget)},
+};
+
+static const struct sof_topology_token ipc4_comp_tokens[] = {
+ {SOF_TKN_COMP_CPC, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc4_base_module_cfg, cpc)},
+ {SOF_TKN_COMP_IS_PAGES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc4_base_module_cfg, is_pages)},
+};
+
+static const struct sof_topology_token ipc4_audio_format_buffer_size_tokens[] = {
+ {SOF_TKN_CAVS_AUDIO_FORMAT_IBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc4_base_module_cfg, ibs)},
+ {SOF_TKN_CAVS_AUDIO_FORMAT_OBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc4_base_module_cfg, obs)},
+};
+
+static const struct sof_topology_token ipc4_in_audio_format_tokens[] = {
+ {SOF_TKN_CAVS_AUDIO_FORMAT_IN_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc4_audio_format, sampling_frequency)},
+ {SOF_TKN_CAVS_AUDIO_FORMAT_IN_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc4_audio_format, bit_depth)},
+ {SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc4_audio_format, ch_map)},
+ {SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc4_audio_format, ch_cfg)},
+ {SOF_TKN_CAVS_AUDIO_FORMAT_IN_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ get_token_u32, offsetof(struct sof_ipc4_audio_format, interleaving_style)},
+ {SOF_TKN_CAVS_AUDIO_FORMAT_IN_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc4_audio_format, fmt_cfg)},
+};
+
+static const struct sof_topology_token ipc4_out_audio_format_tokens[] = {
+ {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc4_audio_format, sampling_frequency)},
+ {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc4_audio_format, bit_depth)},
+ {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc4_audio_format, ch_map)},
+ {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc4_audio_format, ch_cfg)},
+ {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ get_token_u32, offsetof(struct sof_ipc4_audio_format, interleaving_style)},
+ {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc4_audio_format, fmt_cfg)},
+};
+
+static const struct sof_topology_token ipc4_copier_gateway_cfg_tokens[] = {
+ {SOF_TKN_CAVS_AUDIO_FORMAT_DMA_BUFFER_SIZE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0},
+};
+
+static const struct sof_topology_token ipc4_copier_tokens[] = {
+ {SOF_TKN_INTEL_COPIER_NODE_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0},
+};
+
+static const struct sof_topology_token ipc4_audio_fmt_num_tokens[] = {
+ {SOF_TKN_COMP_NUM_AUDIO_FORMATS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ 0},
+};
+
+static const struct sof_topology_token dai_tokens[] = {
+ {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type,
+ offsetof(struct sof_ipc4_copier, dai_type)},
+ {SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc4_copier, dai_index)},
+};
+
+/* Component extended tokens */
+static const struct sof_topology_token comp_ext_tokens[] = {
+ {SOF_TKN_COMP_UUID, SND_SOC_TPLG_TUPLE_TYPE_UUID, get_token_uuid,
+ offsetof(struct snd_sof_widget, uuid)},
+};
+
+static const struct sof_topology_token gain_tokens[] = {
+ {SOF_TKN_GAIN_RAMP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ get_token_u32, offsetof(struct sof_ipc4_gain_data, curve_type)},
+ {SOF_TKN_GAIN_RAMP_DURATION,
+ SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc4_gain_data, curve_duration)},
+ {SOF_TKN_GAIN_VAL, SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ get_token_u32, offsetof(struct sof_ipc4_gain_data, init_val)},
+};
+
+static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = {
+ [SOF_DAI_TOKENS] = {"DAI tokens", dai_tokens, ARRAY_SIZE(dai_tokens)},
+ [SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_tokens)},
+ [SOF_SCHED_TOKENS] = {"Scheduler tokens", ipc4_sched_tokens,
+ ARRAY_SIZE(ipc4_sched_tokens)},
+ [SOF_COMP_EXT_TOKENS] = {"Comp extended tokens", comp_ext_tokens,
+ ARRAY_SIZE(comp_ext_tokens)},
+ [SOF_COMP_TOKENS] = {"IPC4 Component tokens",
+ ipc4_comp_tokens, ARRAY_SIZE(ipc4_comp_tokens)},
+ [SOF_IN_AUDIO_FORMAT_TOKENS] = {"IPC4 Input Audio format tokens",
+ ipc4_in_audio_format_tokens, ARRAY_SIZE(ipc4_in_audio_format_tokens)},
+ [SOF_OUT_AUDIO_FORMAT_TOKENS] = {"IPC4 Output Audio format tokens",
+ ipc4_out_audio_format_tokens, ARRAY_SIZE(ipc4_out_audio_format_tokens)},
+ [SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS] = {"IPC4 Audio format buffer size tokens",
+ ipc4_audio_format_buffer_size_tokens,
+ ARRAY_SIZE(ipc4_audio_format_buffer_size_tokens)},
+ [SOF_COPIER_GATEWAY_CFG_TOKENS] = {"IPC4 Copier gateway config tokens",
+ ipc4_copier_gateway_cfg_tokens, ARRAY_SIZE(ipc4_copier_gateway_cfg_tokens)},
+ [SOF_COPIER_TOKENS] = {"IPC4 Copier tokens", ipc4_copier_tokens,
+ ARRAY_SIZE(ipc4_copier_tokens)},
+ [SOF_AUDIO_FMT_NUM_TOKENS] = {"IPC4 Audio format number tokens",
+ ipc4_audio_fmt_num_tokens, ARRAY_SIZE(ipc4_audio_fmt_num_tokens)},
+ [SOF_GAIN_TOKENS] = {"Gain tokens", gain_tokens, ARRAY_SIZE(gain_tokens)},
+};
+
+static void sof_ipc4_dbg_audio_format(struct device *dev,
+ struct sof_ipc4_audio_format *format,
+ size_t object_size, int num_format)
+{
+ struct sof_ipc4_audio_format *fmt;
+ void *ptr = format;
+ int i;
+
+ for (i = 0; i < num_format; i++, ptr = (u8 *)ptr + object_size) {
+ fmt = ptr;
+ dev_dbg(dev,
+ " #%d: %uKHz, %ubit (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x)\n",
+ i, fmt->sampling_frequency, fmt->bit_depth, fmt->ch_map,
+ fmt->ch_cfg, fmt->interleaving_style, fmt->fmt_cfg);
+ }
+}
+
+/**
+ * sof_ipc4_get_audio_fmt - get available audio formats from swidget->tuples
+ * @scomp: pointer to pointer to SOC component
+ * @swidget: pointer to struct snd_sof_widget containing tuples
+ * @available_fmt: pointer to struct sof_ipc4_available_audio_format being filling in
+ * @has_out_format: true if available_fmt contains output format
+ *
+ * Return: 0 if successful
+ */
+static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp,
+ struct snd_sof_widget *swidget,
+ struct sof_ipc4_available_audio_format *available_fmt,
+ bool has_out_format)
+{
+ struct sof_ipc4_base_module_cfg *base_config;
+ struct sof_ipc4_audio_format *out_format;
+ int audio_fmt_num = 0;
+ int ret, i;
+
+ ret = sof_update_ipc_object(scomp, &audio_fmt_num,
+ SOF_AUDIO_FMT_NUM_TOKENS, swidget->tuples,
+ swidget->num_tuples, sizeof(audio_fmt_num), 1);
+ if (ret || audio_fmt_num <= 0) {
+ dev_err(scomp->dev, "Invalid number of audio formats: %d\n", audio_fmt_num);
+ return -EINVAL;
+ }
+ available_fmt->audio_fmt_num = audio_fmt_num;
+
+ dev_dbg(scomp->dev, "Number of audio formats: %d\n", available_fmt->audio_fmt_num);
+
+ base_config = kcalloc(available_fmt->audio_fmt_num, sizeof(*base_config), GFP_KERNEL);
+ if (!base_config)
+ return -ENOMEM;
+
+ /* set cpc and is_pages for all base_cfg */
+ for (i = 0; i < available_fmt->audio_fmt_num; i++) {
+ ret = sof_update_ipc_object(scomp, &base_config[i],
+ SOF_COMP_TOKENS, swidget->tuples,
+ swidget->num_tuples, sizeof(*base_config), 1);
+ if (ret) {
+ dev_err(scomp->dev, "parse comp tokens failed %d\n", ret);
+ goto err_in;
+ }
+ }
+
+ /* copy the ibs/obs for each base_cfg */
+ ret = sof_update_ipc_object(scomp, base_config,
+ SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, swidget->tuples,
+ swidget->num_tuples, sizeof(*base_config),
+ available_fmt->audio_fmt_num);
+ if (ret) {
+ dev_err(scomp->dev, "parse buffer size tokens failed %d\n", ret);
+ goto err_in;
+ }
+
+ for (i = 0; i < available_fmt->audio_fmt_num; i++)
+ dev_dbg(scomp->dev, "%d: ibs: %d obs: %d cpc: %d is_pages: %d\n", i,
+ base_config[i].ibs, base_config[i].obs,
+ base_config[i].cpc, base_config[i].is_pages);
+
+ ret = sof_update_ipc_object(scomp, &base_config->audio_fmt,
+ SOF_IN_AUDIO_FORMAT_TOKENS, swidget->tuples,
+ swidget->num_tuples, sizeof(*base_config),
+ available_fmt->audio_fmt_num);
+ if (ret) {
+ dev_err(scomp->dev, "parse base_config audio_fmt tokens failed %d\n", ret);
+ goto err_in;
+ }
+
+ dev_dbg(scomp->dev, "Get input audio formats for %s\n", swidget->widget->name);
+ sof_ipc4_dbg_audio_format(scomp->dev, &base_config->audio_fmt,
+ sizeof(*base_config),
+ available_fmt->audio_fmt_num);
+
+ available_fmt->base_config = base_config;
+
+ if (!has_out_format)
+ return 0;
+
+ out_format = kcalloc(available_fmt->audio_fmt_num, sizeof(*out_format), GFP_KERNEL);
+ if (!out_format) {
+ ret = -ENOMEM;
+ goto err_in;
+ }
+
+ ret = sof_update_ipc_object(scomp, out_format,
+ SOF_OUT_AUDIO_FORMAT_TOKENS, swidget->tuples,
+ swidget->num_tuples, sizeof(*out_format),
+ available_fmt->audio_fmt_num);
+
+ if (ret) {
+ dev_err(scomp->dev, "parse output audio_fmt tokens failed\n");
+ goto err_out;
+ }
+
+ available_fmt->out_audio_fmt = out_format;
+ dev_dbg(scomp->dev, "Get output audio formats for %s\n", swidget->widget->name);
+ sof_ipc4_dbg_audio_format(scomp->dev, out_format, sizeof(*out_format),
+ available_fmt->audio_fmt_num);
+
+ return 0;
+
+err_out:
+ kfree(out_format);
+err_in:
+ kfree(base_config);
+
+ return ret;
+}
+
+static void sof_ipc4_widget_free_comp(struct snd_sof_widget *swidget)
+{
+ kfree(swidget->private);
+}
+
+static int sof_ipc4_widget_set_module_info(struct snd_sof_widget *swidget)
+{
+ struct snd_soc_component *scomp = swidget->scomp;
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+ struct sof_ipc4_fw_module *fw_modules = ipc4_data->fw_modules;
+ int i;
+
+ if (!fw_modules) {
+ dev_err(sdev->dev, "no fw_module information\n");
+ return -EINVAL;
+ }
+
+ /* set module info */
+ for (i = 0; i < ipc4_data->num_fw_modules; i++) {
+ if (guid_equal(&swidget->uuid, &fw_modules[i].man4_module_entry.uuid)) {
+ swidget->module_info = &fw_modules[i];
+ return 0;
+ }
+ }
+
+ dev_err(sdev->dev, "failed to find module info for widget %s with UUID %pUL\n",
+ swidget->widget->name, &swidget->uuid);
+ return -EINVAL;
+}
+
+static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_ipc4_msg *msg)
+{
+ struct sof_ipc4_fw_module *fw_module;
+ int ret;
+
+ ret = sof_ipc4_widget_set_module_info(swidget);
+ if (ret)
+ return ret;
+
+ fw_module = swidget->module_info;
+
+ msg->primary = fw_module->man4_module_entry.id;
+ msg->primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_INIT_INSTANCE);
+ msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+ msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
+
+ msg->extension = SOF_IPC4_MOD_EXT_PPL_ID(swidget->pipeline_id);
+ msg->extension |= SOF_IPC4_MOD_EXT_CORE_ID(swidget->core);
+
+ return 0;
+}
+
+static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget)
+{
+ struct sof_ipc4_available_audio_format *available_fmt;
+ struct snd_soc_component *scomp = swidget->scomp;
+ struct sof_ipc4_copier *ipc4_copier;
+ int node_type = 0;
+ int ret, i;
+
+ ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL);
+ if (!ipc4_copier)
+ return -ENOMEM;
+
+ swidget->private = ipc4_copier;
+ available_fmt = &ipc4_copier->available_fmt;
+
+ dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
+
+ ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt, true);
+ if (ret)
+ goto free_copier;
+
+ available_fmt->dma_buffer_size = kcalloc(available_fmt->audio_fmt_num, sizeof(u32),
+ GFP_KERNEL);
+ if (!available_fmt->dma_buffer_size) {
+ ret = -ENOMEM;
+ goto free_copier;
+ }
+
+ ret = sof_update_ipc_object(scomp, available_fmt->dma_buffer_size,
+ SOF_COPIER_GATEWAY_CFG_TOKENS, swidget->tuples,
+ swidget->num_tuples, sizeof(u32),
+ available_fmt->audio_fmt_num);
+ if (ret) {
+ dev_err(scomp->dev, "Failed to parse dma buffer size in audio format for %s\n",
+ swidget->widget->name);
+ goto err;
+ }
+
+ dev_dbg(scomp->dev, "dma buffer size:\n");
+ for (i = 0; i < available_fmt->audio_fmt_num; i++)
+ dev_dbg(scomp->dev, "%d: %u\n", i,
+ available_fmt->dma_buffer_size[i]);
+
+ ret = sof_update_ipc_object(scomp, &node_type,
+ SOF_COPIER_TOKENS, swidget->tuples,
+ swidget->num_tuples, sizeof(node_type), 1);
+
+ if (ret) {
+ dev_err(scomp->dev, "parse host copier node type token failed %d\n",
+ ret);
+ goto err;
+ }
+ dev_dbg(scomp->dev, "host copier '%s' node_type %u\n", swidget->widget->name, node_type);
+
+ ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type);
+ ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL);
+ if (!ipc4_copier->gtw_attr) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr;
+ ipc4_copier->data.gtw_cfg.config_length =
+ sizeof(struct sof_ipc4_gtw_attributes) >> 2;
+
+ /* set up module info and message header */
+ ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg);
+ if (ret)
+ goto free_gtw_attr;
+
+ return 0;
+
+free_gtw_attr:
+ kfree(ipc4_copier->gtw_attr);
+err:
+ kfree(available_fmt->dma_buffer_size);
+free_copier:
+ kfree(ipc4_copier);
+ return ret;
+}
+
+static void sof_ipc4_widget_free_comp_pcm(struct snd_sof_widget *swidget)
+{
+ struct sof_ipc4_copier *ipc4_copier = swidget->private;
+ struct sof_ipc4_available_audio_format *available_fmt;
+
+ if (!ipc4_copier)
+ return;
+
+ available_fmt = &ipc4_copier->available_fmt;
+ kfree(available_fmt->dma_buffer_size);
+ kfree(available_fmt->base_config);
+ kfree(available_fmt->out_audio_fmt);
+ kfree(ipc4_copier->gtw_attr);
+ kfree(ipc4_copier);
+ swidget->private = NULL;
+}
+
+static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
+{
+ struct sof_ipc4_available_audio_format *available_fmt;
+ struct snd_soc_component *scomp = swidget->scomp;
+ struct snd_sof_dai *dai = swidget->private;
+ struct sof_ipc4_copier *ipc4_copier;
+ int node_type = 0;
+ int ret, i;
+
+ ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL);
+ if (!ipc4_copier)
+ return -ENOMEM;
+
+ available_fmt = &ipc4_copier->available_fmt;
+
+ dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
+
+ ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt, true);
+ if (ret)
+ goto free_copier;
+
+ available_fmt->dma_buffer_size = kcalloc(available_fmt->audio_fmt_num, sizeof(u32),
+ GFP_KERNEL);
+ if (!available_fmt->dma_buffer_size) {
+ ret = -ENOMEM;
+ goto free_copier;
+ }
+
+ ret = sof_update_ipc_object(scomp, available_fmt->dma_buffer_size,
+ SOF_COPIER_GATEWAY_CFG_TOKENS, swidget->tuples,
+ swidget->num_tuples, sizeof(u32),
+ available_fmt->audio_fmt_num);
+ if (ret) {
+ dev_err(scomp->dev, "Failed to parse dma buffer size in audio format for %s\n",
+ swidget->widget->name);
+ goto err;
+ }
+
+ for (i = 0; i < available_fmt->audio_fmt_num; i++)
+ dev_dbg(scomp->dev, "%d: dma buffer size: %u\n", i,
+ available_fmt->dma_buffer_size[i]);
+
+ ret = sof_update_ipc_object(scomp, &node_type,
+ SOF_COPIER_TOKENS, swidget->tuples,
+ swidget->num_tuples, sizeof(node_type), 1);
+ if (ret) {
+ dev_err(scomp->dev, "parse dai node type failed %d\n", ret);
+ goto err;
+ }
+
+ ret = sof_update_ipc_object(scomp, ipc4_copier,
+ SOF_DAI_TOKENS, swidget->tuples,
+ swidget->num_tuples, sizeof(u32), 1);
+ if (ret) {
+ dev_err(scomp->dev, "parse dai copier node token failed %d\n", ret);
+ goto err;
+ }
+
+ dev_dbg(scomp->dev, "dai %s node_type %u dai_type %u dai_index %d\n", swidget->widget->name,
+ node_type, ipc4_copier->dai_type, ipc4_copier->dai_index);
+
+ ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type);
+
+ switch (ipc4_copier->dai_type) {
+ case SOF_DAI_INTEL_ALH:
+ {
+ struct sof_ipc4_alh_configuration_blob *blob;
+
+ blob = kzalloc(sizeof(*blob), GFP_KERNEL);
+ if (!blob) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ipc4_copier->copier_config = (uint32_t *)blob;
+ ipc4_copier->data.gtw_cfg.config_length = sizeof(*blob) >> 2;
+ break;
+ }
+ case SOF_DAI_INTEL_SSP:
+ /* set SSP DAI index as the node_id */
+ ipc4_copier->data.gtw_cfg.node_id |=
+ SOF_IPC4_NODE_INDEX_INTEL_SSP(ipc4_copier->dai_index);
+ break;
+ case SOF_DAI_INTEL_DMIC:
+ /* set DMIC DAI index as the node_id */
+ ipc4_copier->data.gtw_cfg.node_id |=
+ SOF_IPC4_NODE_INDEX_INTEL_DMIC(ipc4_copier->dai_index);
+ break;
+ default:
+ ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL);
+ if (!ipc4_copier->gtw_attr) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr;
+ ipc4_copier->data.gtw_cfg.config_length =
+ sizeof(struct sof_ipc4_gtw_attributes) >> 2;
+ break;
+ }
+
+ dai->scomp = scomp;
+ dai->private = ipc4_copier;
+
+ /* set up module info and message header */
+ ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg);
+ if (ret)
+ goto free_copier_config;
+
+ return 0;
+
+free_copier_config:
+ kfree(ipc4_copier->copier_config);
+err:
+ kfree(available_fmt->dma_buffer_size);
+free_copier:
+ kfree(ipc4_copier);
+ return ret;
+}
+
+static void sof_ipc4_widget_free_comp_dai(struct snd_sof_widget *swidget)
+{
+ struct sof_ipc4_available_audio_format *available_fmt;
+ struct snd_sof_dai *dai = swidget->private;
+ struct sof_ipc4_copier *ipc4_copier;
+
+ if (!dai)
+ return;
+
+ ipc4_copier = dai->private;
+ available_fmt = &ipc4_copier->available_fmt;
+
+ kfree(available_fmt->dma_buffer_size);
+ kfree(available_fmt->base_config);
+ kfree(available_fmt->out_audio_fmt);
+ if (ipc4_copier->dai_type != SOF_DAI_INTEL_SSP &&
+ ipc4_copier->dai_type != SOF_DAI_INTEL_DMIC)
+ kfree(ipc4_copier->copier_config);
+ kfree(dai->private);
+ kfree(dai);
+ swidget->private = NULL;
+}
+
+static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
+{
+ struct snd_soc_component *scomp = swidget->scomp;
+ struct sof_ipc4_pipeline *pipeline;
+ int ret;
+
+ pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL);
+ if (!pipeline)
+ return -ENOMEM;
+
+ ret = sof_update_ipc_object(scomp, pipeline, SOF_SCHED_TOKENS, swidget->tuples,
+ swidget->num_tuples, sizeof(*pipeline), 1);
+ if (ret) {
+ dev_err(scomp->dev, "parsing scheduler tokens failed\n");
+ goto err;
+ }
+
+ /* parse one set of pipeline tokens */
+ ret = sof_update_ipc_object(scomp, swidget, SOF_PIPELINE_TOKENS, swidget->tuples,
+ swidget->num_tuples, sizeof(*swidget), 1);
+ if (ret) {
+ dev_err(scomp->dev, "parsing pipeline tokens failed\n");
+ goto err;
+ }
+
+ /* TODO: Get priority from topology */
+ pipeline->priority = 0;
+
+ dev_dbg(scomp->dev, "pipeline '%s': id %d pri %d lp mode %d\n",
+ swidget->widget->name, swidget->pipeline_id,
+ pipeline->priority, pipeline->lp_mode);
+
+ swidget->private = pipeline;
+
+ pipeline->msg.primary = SOF_IPC4_GLB_PIPE_PRIORITY(pipeline->priority);
+ pipeline->msg.primary |= SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->pipeline_id);
+ pipeline->msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_CREATE_PIPELINE);
+ pipeline->msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+ pipeline->msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
+
+ pipeline->msg.extension = pipeline->lp_mode;
+ pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
+
+ return 0;
+err:
+ kfree(pipeline);
+ return ret;
+}
+
+static int sof_ipc4_widget_setup_comp_pga(struct snd_sof_widget *swidget)
+{
+ struct snd_soc_component *scomp = swidget->scomp;
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+ struct sof_ipc4_fw_module *fw_module;
+ struct snd_sof_control *scontrol;
+ struct sof_ipc4_gain *gain;
+ int ret;
+
+ gain = kzalloc(sizeof(*gain), GFP_KERNEL);
+ if (!gain)
+ return -ENOMEM;
+
+ swidget->private = gain;
+
+ gain->data.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK;
+ gain->data.init_val = SOF_IPC4_VOL_ZERO_DB;
+
+ /* The out_audio_fmt in topology is ignored as it is not required to be sent to the FW */
+ ret = sof_ipc4_get_audio_fmt(scomp, swidget, &gain->available_fmt, false);
+ if (ret)
+ goto err;
+
+ ret = sof_update_ipc_object(scomp, &gain->data, SOF_GAIN_TOKENS, swidget->tuples,
+ swidget->num_tuples, sizeof(gain->data), 1);
+ if (ret) {
+ dev_err(scomp->dev, "Parsing gain tokens failed\n");
+ goto err;
+ }
+
+ dev_dbg(scomp->dev,
+ "pga widget %s: ramp type: %d, ramp duration %d, initial gain value: %#x, cpc %d\n",
+ swidget->widget->name, gain->data.curve_type, gain->data.curve_duration,
+ gain->data.init_val, gain->base_config.cpc);
+
+ ret = sof_ipc4_widget_setup_msg(swidget, &gain->msg);
+ if (ret)
+ goto err;
+
+ fw_module = swidget->module_info;
+
+ /* update module ID for all kcontrols for this widget */
+ list_for_each_entry(scontrol, &sdev->kcontrol_list, list)
+ if (scontrol->comp_id == swidget->comp_id) {
+ struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
+ struct sof_ipc4_msg *msg = &cdata->msg;
+
+ msg->primary |= fw_module->man4_module_entry.id;
+ }
+
+ return 0;
+err:
+ kfree(gain);
+ return ret;
+}
+
+static int sof_ipc4_widget_setup_comp_mixer(struct snd_sof_widget *swidget)
+{
+ struct snd_soc_component *scomp = swidget->scomp;
+ struct sof_ipc4_mixer *mixer;
+ int ret;
+
+ dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
+
+ mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);
+ if (!mixer)
+ return -ENOMEM;
+
+ swidget->private = mixer;
+
+ /* The out_audio_fmt in topology is ignored as it is not required to be sent to the FW */
+ ret = sof_ipc4_get_audio_fmt(scomp, swidget, &mixer->available_fmt, false);
+ if (ret)
+ goto err;
+
+ ret = sof_ipc4_widget_setup_msg(swidget, &mixer->msg);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ kfree(mixer);
+ return ret;
+}
+
+static void
+sof_ipc4_update_pipeline_mem_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
+ struct sof_ipc4_base_module_cfg *base_config)
+{
+ struct sof_ipc4_fw_module *fw_module = swidget->module_info;
+ struct snd_sof_widget *pipe_widget;
+ struct sof_ipc4_pipeline *pipeline;
+ int task_mem, queue_mem;
+ int ibs, bss, total;
+
+ ibs = base_config->ibs;
+ bss = base_config->is_pages;
+
+ task_mem = SOF_IPC4_PIPELINE_OBJECT_SIZE;
+ task_mem += SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE + bss;
+
+ if (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_LL) {
+ task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_LL_TASK_OBJECT_SIZE);
+ task_mem += SOF_IPC4_FW_MAX_QUEUE_COUNT * SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE;
+ task_mem += SOF_IPC4_LL_TASK_LIST_ITEM_SIZE;
+ } else {
+ task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_DP_TASK_OBJECT_SIZE);
+ task_mem += SOF_IPC4_DP_TASK_LIST_SIZE;
+ }
+
+ ibs = SOF_IPC4_FW_ROUNDUP(ibs);
+ queue_mem = SOF_IPC4_FW_MAX_QUEUE_COUNT * (SOF_IPC4_DATA_QUEUE_OBJECT_SIZE + ibs);
+
+ total = SOF_IPC4_FW_PAGE(task_mem + queue_mem);
+
+ pipe_widget = swidget->pipe_widget;
+ pipeline = pipe_widget->private;
+ pipeline->mem_usage += total;
+}
+
+static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev,
+ struct snd_sof_widget *swidget)
+{
+ struct sof_ipc4_fw_module *fw_module = swidget->module_info;
+ int max_instances = fw_module->man4_module_entry.instance_max_count;
+
+ swidget->instance_id = ida_alloc_max(&fw_module->m_ida, max_instances, GFP_KERNEL);
+ if (swidget->instance_id < 0) {
+ dev_err(sdev->dev, "failed to assign instance id for widget %s",
+ swidget->widget->name);
+ return swidget->instance_id;
+ }
+
+ return 0;
+}
+
+static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev,
+ struct snd_sof_widget *swidget,
+ struct sof_ipc4_base_module_cfg *base_config,
+ struct sof_ipc4_audio_format *out_format,
+ struct snd_pcm_hw_params *params,
+ struct sof_ipc4_available_audio_format *available_fmt,
+ size_t object_offset)
+{
+ void *ptr = available_fmt->ref_audio_fmt;
+ u32 valid_bits;
+ u32 channels;
+ u32 rate;
+ int sample_valid_bits;
+ int i;
+
+ if (!ptr) {
+ dev_err(sdev->dev, "no reference formats for %s\n", swidget->widget->name);
+ return -EINVAL;
+ }
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ sample_valid_bits = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ sample_valid_bits = 24;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ sample_valid_bits = 32;
+ break;
+ default:
+ dev_err(sdev->dev, "invalid pcm frame format %d\n", params_format(params));
+ return -EINVAL;
+ }
+
+ if (!available_fmt->audio_fmt_num) {
+ dev_err(sdev->dev, "no formats available for %s\n", swidget->widget->name);
+ return -EINVAL;
+ }
+
+ /*
+ * Search supported audio formats to match rate, channels ,and
+ * sample_valid_bytes from runtime params
+ */
+ for (i = 0; i < available_fmt->audio_fmt_num; i++, ptr = (u8 *)ptr + object_offset) {
+ struct sof_ipc4_audio_format *fmt = ptr;
+
+ rate = fmt->sampling_frequency;
+ channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
+ valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
+ if (params_rate(params) == rate && params_channels(params) == channels &&
+ sample_valid_bits == valid_bits) {
+ dev_dbg(sdev->dev, "%s: matching audio format index for %uHz, %ubit, %u channels: %d\n",
+ __func__, rate, valid_bits, channels, i);
+
+ /* copy ibs/obs and input format */
+ memcpy(base_config, &available_fmt->base_config[i],
+ sizeof(struct sof_ipc4_base_module_cfg));
+
+ /* copy output format */
+ if (out_format)
+ memcpy(out_format, &available_fmt->out_audio_fmt[i],
+ sizeof(struct sof_ipc4_audio_format));
+ break;
+ }
+ }
+
+ if (i == available_fmt->audio_fmt_num) {
+ dev_err(sdev->dev, "%s: Unsupported audio format: %uHz, %ubit, %u channels\n",
+ __func__, params_rate(params), sample_valid_bits, params_channels(params));
+ return -EINVAL;
+ }
+
+ dev_dbg(sdev->dev, "Init input audio formats for %s\n", swidget->widget->name);
+ sof_ipc4_dbg_audio_format(sdev->dev, &base_config->audio_fmt,
+ sizeof(*base_config), 1);
+ if (out_format) {
+ dev_dbg(sdev->dev, "Init output audio formats for %s\n", swidget->widget->name);
+ sof_ipc4_dbg_audio_format(sdev->dev, out_format,
+ sizeof(*out_format), 1);
+ }
+
+ /* Return the index of the matched format */
+ return i;
+}
+
+static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
+{
+ struct sof_ipc4_fw_module *fw_module = swidget->module_info;
+ struct sof_ipc4_copier *ipc4_copier = NULL;
+ struct snd_sof_widget *pipe_widget;
+ struct sof_ipc4_pipeline *pipeline;
+
+ /* reset pipeline memory usage */
+ pipe_widget = swidget->pipe_widget;
+ pipeline = pipe_widget->private;
+ pipeline->mem_usage = 0;
+
+ if (WIDGET_IS_AIF(swidget->id)) {
+ ipc4_copier = swidget->private;
+ } else if (WIDGET_IS_DAI(swidget->id)) {
+ struct snd_sof_dai *dai = swidget->private;
+
+ ipc4_copier = dai->private;
+ }
+
+ if (ipc4_copier) {
+ kfree(ipc4_copier->ipc_config_data);
+ ipc4_copier->ipc_config_data = NULL;
+ ipc4_copier->ipc_config_size = 0;
+ }
+
+ ida_free(&fw_module->m_ida, swidget->instance_id);
+}
+
+#if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_INTEL_NHLT)
+static int snd_sof_get_hw_config_params(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
+ int *sample_rate, int *channel_count, int *bit_depth)
+{
+ struct snd_soc_tplg_hw_config *hw_config;
+ struct snd_sof_dai_link *slink;
+ bool dai_link_found = false;
+ bool hw_cfg_found = false;
+ int i;
+
+ /* get current hw_config from link */
+ list_for_each_entry(slink, &sdev->dai_link_list, list) {
+ if (!strcmp(slink->link->name, dai->name)) {
+ dai_link_found = true;
+ break;
+ }
+ }
+
+ if (!dai_link_found) {
+ dev_err(sdev->dev, "%s: no DAI link found for DAI %s\n", __func__, dai->name);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < slink->num_hw_configs; i++) {
+ hw_config = &slink->hw_configs[i];
+ if (dai->current_config == le32_to_cpu(hw_config->id)) {
+ hw_cfg_found = true;
+ break;
+ }
+ }
+
+ if (!hw_cfg_found) {
+ dev_err(sdev->dev, "%s: no matching hw_config found for DAI %s\n", __func__,
+ dai->name);
+ return -EINVAL;
+ }
+
+ *bit_depth = le32_to_cpu(hw_config->tdm_slot_width);
+ *channel_count = le32_to_cpu(hw_config->tdm_slots);
+ *sample_rate = le32_to_cpu(hw_config->fsync_rate);
+
+ dev_dbg(sdev->dev, "%s: sample rate: %d sample width: %d channels: %d\n",
+ __func__, *sample_rate, *bit_depth, *channel_count);
+
+ return 0;
+}
+
+static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
+ struct snd_pcm_hw_params *params, u32 dai_index,
+ u32 linktype, u8 dir, u32 **dst, u32 *len)
+{
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+ struct nhlt_specific_cfg *cfg;
+ int sample_rate, channel_count;
+ int bit_depth, ret;
+ u32 nhlt_type;
+
+ /* convert to NHLT type */
+ switch (linktype) {
+ case SOF_DAI_INTEL_DMIC:
+ nhlt_type = NHLT_LINK_DMIC;
+ bit_depth = params_width(params);
+ channel_count = params_channels(params);
+ sample_rate = params_rate(params);
+ break;
+ case SOF_DAI_INTEL_SSP:
+ nhlt_type = NHLT_LINK_SSP;
+ ret = snd_sof_get_hw_config_params(sdev, dai, &sample_rate, &channel_count,
+ &bit_depth);
+ if (ret < 0)
+ return ret;
+ break;
+ default:
+ return 0;
+ }
+
+ dev_dbg(sdev->dev, "%s: dai index %d nhlt type %d direction %d\n",
+ __func__, dai_index, nhlt_type, dir);
+
+ /* find NHLT blob with matching params */
+ cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt, dai_index, nhlt_type,
+ bit_depth, bit_depth, channel_count, sample_rate,
+ dir, 0);
+
+ if (!cfg) {
+ dev_err(sdev->dev,
+ "no matching blob for sample rate: %d sample width: %d channels: %d\n",
+ sample_rate, bit_depth, channel_count);
+ return -EINVAL;
+ }
+
+ /* config length should be in dwords */
+ *len = cfg->size >> 2;
+ *dst = (u32 *)cfg->caps;
+
+ return 0;
+}
+#else
+static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
+ struct snd_pcm_hw_params *params, u32 dai_index,
+ u32 linktype, u8 dir, u32 **dst, u32 *len)
+{
+ return 0;
+}
+#endif
+
+static int
+sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
+ struct snd_pcm_hw_params *fe_params,
+ struct snd_sof_platform_stream_params *platform_params,
+ struct snd_pcm_hw_params *pipeline_params, int dir)
+{
+ struct sof_ipc4_available_audio_format *available_fmt;
+ struct snd_soc_component *scomp = swidget->scomp;
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+ struct sof_ipc4_copier_data *copier_data;
+ struct snd_pcm_hw_params *ref_params;
+ struct sof_ipc4_copier *ipc4_copier;
+ struct snd_mask *fmt;
+ int out_sample_valid_bits;
+ size_t ref_audio_fmt_size;
+ void **ipc_config_data;
+ int *ipc_config_size;
+ u32 **data;
+ int ipc_size, ret;
+
+ dev_dbg(sdev->dev, "%s: copier %s, type %d", __func__, swidget->widget->name, swidget->id);
+
+ switch (swidget->id) {
+ case snd_soc_dapm_aif_in:
+ case snd_soc_dapm_aif_out:
+ {
+ struct sof_ipc4_gtw_attributes *gtw_attr;
+ struct snd_sof_widget *pipe_widget;
+ struct sof_ipc4_pipeline *pipeline;
+
+ pipe_widget = swidget->pipe_widget;
+ pipeline = pipe_widget->private;
+ ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
+ gtw_attr = ipc4_copier->gtw_attr;
+ copier_data = &ipc4_copier->data;
+ available_fmt = &ipc4_copier->available_fmt;
+
+ /*
+ * base_config->audio_fmt and out_audio_fmt represent the input and output audio
+ * formats. Use the input format as the reference to match pcm params for playback
+ * and the output format as reference for capture.
+ */
+ if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
+ available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt;
+ ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg);
+ } else {
+ available_fmt->ref_audio_fmt = available_fmt->out_audio_fmt;
+ ref_audio_fmt_size = sizeof(struct sof_ipc4_audio_format);
+ }
+ copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
+ copier_data->gtw_cfg.node_id |=
+ SOF_IPC4_NODE_INDEX(platform_params->stream_tag - 1);
+
+ /* set gateway attributes */
+ gtw_attr->lp_buffer_alloc = pipeline->lp_mode;
+ ref_params = fe_params;
+ break;
+ }
+ case snd_soc_dapm_dai_in:
+ case snd_soc_dapm_dai_out:
+ {
+ struct snd_sof_dai *dai = swidget->private;
+
+ ipc4_copier = (struct sof_ipc4_copier *)dai->private;
+ copier_data = &ipc4_copier->data;
+ available_fmt = &ipc4_copier->available_fmt;
+ if (dir == SNDRV_PCM_STREAM_CAPTURE) {
+ available_fmt->ref_audio_fmt = available_fmt->out_audio_fmt;
+ ref_audio_fmt_size = sizeof(struct sof_ipc4_audio_format);
+
+ /*
+ * modify the input params for the dai copier as it only supports
+ * 32-bit always
+ */
+ fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT);
+ snd_mask_none(fmt);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
+ } else {
+ available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt;
+ ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg);
+ }
+
+ ref_params = pipeline_params;
+
+ ret = snd_sof_get_nhlt_endpoint_data(sdev, dai, fe_params, ipc4_copier->dai_index,
+ ipc4_copier->dai_type, dir,
+ &ipc4_copier->copier_config,
+ &copier_data->gtw_cfg.config_length);
+ if (ret < 0)
+ return ret;
+
+ break;
+ }
+ default:
+ dev_err(sdev->dev, "unsupported type %d for copier %s",
+ swidget->id, swidget->widget->name);
+ return -EINVAL;
+ }
+
+ /* set input and output audio formats */
+ ret = sof_ipc4_init_audio_fmt(sdev, swidget, &copier_data->base_config,
+ &copier_data->out_format, ref_params,
+ available_fmt, ref_audio_fmt_size);
+ if (ret < 0)
+ return ret;
+
+ switch (swidget->id) {
+ case snd_soc_dapm_dai_in:
+ case snd_soc_dapm_dai_out:
+ {
+ /*
+ * Only SOF_DAI_INTEL_ALH needs copier_data to set blob.
+ * That's why only ALH dai's blob is set after sof_ipc4_init_audio_fmt
+ */
+ if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
+ struct sof_ipc4_alh_configuration_blob *blob;
+ u32 ch_map;
+ int i;
+
+ blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
+ /* TODO: add aggregation mode support */
+ blob->alh_cfg.count = 1;
+ blob->alh_cfg.mapping[0].alh_id = copier_data->gtw_cfg.node_id;
+ blob->gw_attr.lp_buffer_alloc = 0;
+
+ /* Get channel_mask from ch_map */
+ ch_map = copier_data->base_config.audio_fmt.ch_map;
+ for (i = 0; ch_map; i++) {
+ if ((ch_map & 0xf) != 0xf)
+ blob->alh_cfg.mapping[0].channel_mask |= BIT(i);
+ ch_map >>= 4;
+ }
+ }
+ }
+ }
+
+ /* modify the input params for the next widget */
+ fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT);
+ out_sample_valid_bits =
+ SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(copier_data->out_format.fmt_cfg);
+ snd_mask_none(fmt);
+ switch (out_sample_valid_bits) {
+ case 16:
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
+ break;
+ case 24:
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+ break;
+ case 32:
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
+ break;
+ default:
+ dev_err(sdev->dev, "invalid sample frame format %d\n",
+ params_format(pipeline_params));
+ return -EINVAL;
+ }
+
+ /* set the gateway dma_buffer_size using the matched ID returned above */
+ copier_data->gtw_cfg.dma_buffer_size = available_fmt->dma_buffer_size[ret];
+
+ data = &ipc4_copier->copier_config;
+ ipc_config_size = &ipc4_copier->ipc_config_size;
+ ipc_config_data = &ipc4_copier->ipc_config_data;
+
+ /* config_length is DWORD based */
+ ipc_size = sizeof(*copier_data) + copier_data->gtw_cfg.config_length * 4;
+
+ dev_dbg(sdev->dev, "copier %s, IPC size is %d", swidget->widget->name, ipc_size);
+
+ *ipc_config_data = kzalloc(ipc_size, GFP_KERNEL);
+ if (!*ipc_config_data)
+ return -ENOMEM;
+
+ *ipc_config_size = ipc_size;
+
+ /* copy IPC data */
+ memcpy(*ipc_config_data, (void *)copier_data, sizeof(*copier_data));
+ if (copier_data->gtw_cfg.config_length)
+ memcpy(*ipc_config_data + sizeof(*copier_data),
+ *data, copier_data->gtw_cfg.config_length * 4);
+
+ /* update pipeline memory usage */
+ sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &copier_data->base_config);
+
+ /* assign instance ID */
+ return sof_ipc4_widget_assign_instance_id(sdev, swidget);
+}
+
+static void sof_ipc4_unprepare_generic_module(struct snd_sof_widget *swidget)
+{
+ struct sof_ipc4_fw_module *fw_module = swidget->module_info;
+
+ ida_free(&fw_module->m_ida, swidget->instance_id);
+}
+
+static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget,
+ struct snd_pcm_hw_params *fe_params,
+ struct snd_sof_platform_stream_params *platform_params,
+ struct snd_pcm_hw_params *pipeline_params, int dir)
+{
+ struct snd_soc_component *scomp = swidget->scomp;
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+ struct sof_ipc4_gain *gain = swidget->private;
+ int ret;
+
+ gain->available_fmt.ref_audio_fmt = &gain->available_fmt.base_config->audio_fmt;
+
+ /* output format is not required to be sent to the FW for gain */
+ ret = sof_ipc4_init_audio_fmt(sdev, swidget, &gain->base_config,
+ NULL, pipeline_params, &gain->available_fmt,
+ sizeof(gain->base_config));
+ if (ret < 0)
+ return ret;
+
+ /* update pipeline memory usage */
+ sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &gain->base_config);
+
+ /* assign instance ID */
+ return sof_ipc4_widget_assign_instance_id(sdev, swidget);
+}
+
+static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget,
+ struct snd_pcm_hw_params *fe_params,
+ struct snd_sof_platform_stream_params *platform_params,
+ struct snd_pcm_hw_params *pipeline_params, int dir)
+{
+ struct snd_soc_component *scomp = swidget->scomp;
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+ struct sof_ipc4_mixer *mixer = swidget->private;
+ int ret;
+
+ /* only 32bit is supported by mixer */
+ mixer->available_fmt.ref_audio_fmt = &mixer->available_fmt.base_config->audio_fmt;
+
+ /* output format is not required to be sent to the FW for mixer */
+ ret = sof_ipc4_init_audio_fmt(sdev, swidget, &mixer->base_config,
+ NULL, pipeline_params, &mixer->available_fmt,
+ sizeof(mixer->base_config));
+ if (ret < 0)
+ return ret;
+
+ /* update pipeline memory usage */
+ sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &mixer->base_config);
+
+ /* assign instance ID */
+ return sof_ipc4_widget_assign_instance_id(sdev, swidget);
+}
+
+static int sof_ipc4_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
+{
+ struct sof_ipc4_control_data *control_data;
+ struct sof_ipc4_msg *msg;
+ int i;
+
+ scontrol->size = struct_size(control_data, chanv, scontrol->num_channels);
+
+ /* scontrol->ipc_control_data will be freed in sof_control_unload */
+ scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL);
+ if (!scontrol->ipc_control_data)
+ return -ENOMEM;
+
+ control_data = scontrol->ipc_control_data;
+ control_data->index = scontrol->index;
+
+ msg = &control_data->msg;
+ msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET);
+ msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+ msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
+
+ msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_GAIN_PARAM_ID);
+
+ /* set default volume values to 0dB in control */
+ for (i = 0; i < scontrol->num_channels; i++) {
+ control_data->chanv[i].channel = i;
+ control_data->chanv[i].value = SOF_IPC4_VOL_ZERO_DB;
+ }
+
+ return 0;
+}
+
+static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
+{
+ switch (scontrol->info_type) {
+ case SND_SOC_TPLG_CTL_VOLSW:
+ case SND_SOC_TPLG_CTL_VOLSW_SX:
+ case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
+ return sof_ipc4_control_load_volume(sdev, scontrol);
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+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;
+ u32 ipc_size = 0;
+ int ret;
+
+ dev_dbg(sdev->dev, "Create widget %s instance %d - pipe %d - core %d\n",
+ swidget->widget->name, swidget->instance_id, swidget->pipeline_id, swidget->core);
+
+ switch (swidget->id) {
+ case snd_soc_dapm_scheduler:
+ pipeline = swidget->private;
+
+ dev_dbg(sdev->dev, "pipeline: %d memory pages: %d\n", swidget->pipeline_id,
+ pipeline->mem_usage);
+
+ msg = &pipeline->msg;
+ msg->primary |= pipeline->mem_usage;
+ break;
+ case snd_soc_dapm_aif_in:
+ case snd_soc_dapm_aif_out:
+ {
+ struct sof_ipc4_copier *ipc4_copier = swidget->private;
+
+ ipc_size = ipc4_copier->ipc_config_size;
+ ipc_data = ipc4_copier->ipc_config_data;
+
+ msg = &ipc4_copier->msg;
+ break;
+ }
+ case snd_soc_dapm_dai_in:
+ case snd_soc_dapm_dai_out:
+ {
+ struct snd_sof_dai *dai = swidget->private;
+ struct sof_ipc4_copier *ipc4_copier = dai->private;
+
+ ipc_size = ipc4_copier->ipc_config_size;
+ ipc_data = ipc4_copier->ipc_config_data;
+
+ msg = &ipc4_copier->msg;
+ break;
+ }
+ case snd_soc_dapm_pga:
+ {
+ struct sof_ipc4_gain *gain = swidget->private;
+
+ ipc_size = sizeof(struct sof_ipc4_base_module_cfg) +
+ sizeof(struct sof_ipc4_gain_data);
+ ipc_data = gain;
+
+ msg = &gain->msg;
+ break;
+ }
+ case snd_soc_dapm_mixer:
+ {
+ struct sof_ipc4_mixer *mixer = swidget->private;
+
+ ipc_size = sizeof(mixer->base_config);
+ ipc_data = &mixer->base_config;
+
+ msg = &mixer->msg;
+ break;
+ }
+ default:
+ dev_err(sdev->dev, "widget type %d not supported", swidget->id);
+ return -EINVAL;
+ }
+
+ if (swidget->id != snd_soc_dapm_scheduler) {
+ pipeline = pipe_widget->private;
+ msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK;
+ msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id);
+
+ msg->extension &= ~SOF_IPC4_MOD_EXT_PARAM_SIZE_MASK;
+ msg->extension |= ipc_size >> 2;
+ msg->extension &= ~SOF_IPC4_MOD_EXT_DOMAIN_MASK;
+ msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(pipeline->lp_mode);
+ }
+
+ msg->data_size = ipc_size;
+ msg->data_ptr = ipc_data;
+
+ ret = sof_ipc_tx_message(sdev->ipc, msg, ipc_size, NULL, 0);
+ if (ret < 0)
+ dev_err(sdev->dev, "failed to create module %s\n", swidget->widget->name);
+
+ return ret;
+}
+
+static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
+{
+ int ret = 0;
+
+ /* freeing a pipeline frees all the widgets associated with it */
+ if (swidget->id == snd_soc_dapm_scheduler) {
+ struct sof_ipc4_pipeline *pipeline = swidget->private;
+ struct sof_ipc4_msg msg = {{ 0 }};
+ u32 header;
+
+ header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->pipeline_id);
+ header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_DELETE_PIPELINE);
+ header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+ header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
+
+ msg.primary = header;
+
+ ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
+ if (ret < 0)
+ dev_err(sdev->dev, "failed to free pipeline widget %s\n",
+ swidget->widget->name);
+
+ pipeline->mem_usage = 0;
+ pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
+ }
+
+ return ret;
+}
+
+static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
+{
+ struct snd_sof_widget *src_widget = sroute->src_widget;
+ struct snd_sof_widget *sink_widget = sroute->sink_widget;
+ struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;
+ struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
+ struct sof_ipc4_msg msg = {{ 0 }};
+ u32 header, extension;
+ int src_queue = 0;
+ int dst_queue = 0;
+ int ret;
+
+ dev_dbg(sdev->dev, "%s: bind %s -> %s\n", __func__,
+ src_widget->widget->name, sink_widget->widget->name);
+
+ header = src_fw_module->man4_module_entry.id;
+ header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
+ header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_BIND);
+ header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+ header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
+
+ extension = sink_fw_module->man4_module_entry.id;
+ extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id);
+ extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(dst_queue);
+ extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(src_queue);
+
+ msg.primary = header;
+ msg.extension = extension;
+
+ ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
+ if (ret < 0)
+ dev_err(sdev->dev, "%s: failed to bind modules %s -> %s\n",
+ __func__, src_widget->widget->name, sink_widget->widget->name);
+
+ return ret;
+}
+
+static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
+{
+ struct snd_sof_widget *src_widget = sroute->src_widget;
+ struct snd_sof_widget *sink_widget = sroute->sink_widget;
+ struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;
+ struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
+ struct sof_ipc4_msg msg = {{ 0 }};
+ u32 header, extension;
+ int src_queue = 0;
+ int dst_queue = 0;
+ int ret;
+
+ dev_dbg(sdev->dev, "%s: unbind modules %s -> %s\n", __func__,
+ src_widget->widget->name, sink_widget->widget->name);
+
+ header = src_fw_module->man4_module_entry.id;
+ header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
+ header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_UNBIND);
+ header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+ header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
+
+ extension = sink_fw_module->man4_module_entry.id;
+ extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id);
+ extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(dst_queue);
+ extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(src_queue);
+
+ msg.primary = header;
+ msg.extension = extension;
+
+ ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
+ if (ret < 0)
+ dev_err(sdev->dev, "failed to unbind modules %s -> %s\n",
+ src_widget->widget->name, sink_widget->widget->name);
+
+ return ret;
+}
+
+static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
+ unsigned int flags, struct snd_sof_dai_config_data *data)
+{
+ struct snd_sof_widget *pipe_widget = swidget->pipe_widget;
+ struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
+ struct snd_sof_dai *dai = swidget->private;
+ struct sof_ipc4_gtw_attributes *gtw_attr;
+ struct sof_ipc4_copier_data *copier_data;
+ struct sof_ipc4_copier *ipc4_copier;
+
+ if (!dai || !dai->private) {
+ dev_err(sdev->dev, "Invalid DAI or DAI private data for %s\n",
+ swidget->widget->name);
+ return -EINVAL;
+ }
+
+ ipc4_copier = (struct sof_ipc4_copier *)dai->private;
+ copier_data = &ipc4_copier->data;
+
+ if (!data)
+ return 0;
+
+ switch (ipc4_copier->dai_type) {
+ case SOF_DAI_INTEL_HDA:
+ gtw_attr = ipc4_copier->gtw_attr;
+ gtw_attr->lp_buffer_alloc = pipeline->lp_mode;
+ fallthrough;
+ case SOF_DAI_INTEL_ALH:
+ copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
+ copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_data);
+ break;
+ case SOF_DAI_INTEL_DMIC:
+ case SOF_DAI_INTEL_SSP:
+ /* nothing to do for SSP/DMIC */
+ break;
+ default:
+ dev_err(sdev->dev, "%s: unsupported dai type %d\n", __func__,
+ ipc4_copier->dai_type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index,
+ struct snd_soc_tplg_manifest *man)
+{
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+ struct sof_manifest_tlv *manifest_tlv;
+ struct sof_manifest *manifest;
+ u32 size = le32_to_cpu(man->priv.size);
+ u8 *man_ptr = man->priv.data;
+ u32 len_check;
+ int i;
+
+ if (!size || size < SOF_IPC4_TPLG_ABI_SIZE) {
+ dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n",
+ __func__, size);
+ return -EINVAL;
+ }
+
+ manifest = (struct sof_manifest *)man_ptr;
+
+ dev_info(scomp->dev,
+ "Topology: ABI %d:%d:%d Kernel ABI %u:%u:%u\n",
+ le16_to_cpu(manifest->abi_major), le16_to_cpu(manifest->abi_minor),
+ le16_to_cpu(manifest->abi_patch),
+ SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
+
+ /* TODO: Add ABI compatibility check */
+
+ /* no more data after the ABI version */
+ if (size <= SOF_IPC4_TPLG_ABI_SIZE)
+ return 0;
+
+ manifest_tlv = manifest->items;
+ len_check = sizeof(struct sof_manifest);
+ for (i = 0; i < le16_to_cpu(manifest->count); i++) {
+ len_check += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size);
+ if (len_check > size)
+ return -EINVAL;
+
+ switch (le32_to_cpu(manifest_tlv->type)) {
+ case SOF_MANIFEST_DATA_TYPE_NHLT:
+ /* no NHLT in BIOS, so use the one from topology manifest */
+ if (ipc4_data->nhlt)
+ break;
+ ipc4_data->nhlt = devm_kmemdup(sdev->dev, manifest_tlv->data,
+ le32_to_cpu(manifest_tlv->size), GFP_KERNEL);
+ if (!ipc4_data->nhlt)
+ return -ENOMEM;
+ break;
+ default:
+ dev_warn(scomp->dev, "Skipping unknown manifest data type %d\n",
+ manifest_tlv->type);
+ break;
+ }
+ man_ptr += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size);
+ manifest_tlv = (struct sof_manifest_tlv *)man_ptr;
+ }
+
+ return 0;
+}
+
+static int sof_ipc4_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type)
+{
+ struct sof_ipc4_copier *ipc4_copier = dai->private;
+ struct snd_soc_tplg_hw_config *hw_config;
+ struct snd_sof_dai_link *slink;
+ bool dai_link_found = false;
+ bool hw_cfg_found = false;
+ int i;
+
+ if (!ipc4_copier)
+ return 0;
+
+ list_for_each_entry(slink, &sdev->dai_link_list, list) {
+ if (!strcmp(slink->link->name, dai->name)) {
+ dai_link_found = true;
+ break;
+ }
+ }
+
+ if (!dai_link_found) {
+ dev_err(sdev->dev, "no DAI link found for DAI %s\n", dai->name);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < slink->num_hw_configs; i++) {
+ hw_config = &slink->hw_configs[i];
+ if (dai->current_config == le32_to_cpu(hw_config->id)) {
+ hw_cfg_found = true;
+ break;
+ }
+ }
+
+ if (!hw_cfg_found) {
+ dev_err(sdev->dev, "no matching hw_config found for DAI %s\n", dai->name);
+ return -EINVAL;
+ }
+
+ switch (ipc4_copier->dai_type) {
+ case SOF_DAI_INTEL_SSP:
+ switch (clk_type) {
+ case SOF_DAI_CLK_INTEL_SSP_MCLK:
+ return le32_to_cpu(hw_config->mclk_rate);
+ case SOF_DAI_CLK_INTEL_SSP_BCLK:
+ return le32_to_cpu(hw_config->bclk_rate);
+ default:
+ dev_err(sdev->dev, "Invalid clk type for SSP %d\n", clk_type);
+ break;
+ }
+ break;
+ default:
+ dev_err(sdev->dev, "DAI type %d not supported yet!\n", ipc4_copier->dai_type);
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static enum sof_tokens host_token_list[] = {
+ SOF_COMP_TOKENS,
+ SOF_AUDIO_FMT_NUM_TOKENS,
+ SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
+ SOF_IN_AUDIO_FORMAT_TOKENS,
+ SOF_OUT_AUDIO_FORMAT_TOKENS,
+ SOF_COPIER_GATEWAY_CFG_TOKENS,
+ SOF_COPIER_TOKENS,
+ SOF_COMP_EXT_TOKENS,
+};
+
+static enum sof_tokens pipeline_token_list[] = {
+ SOF_SCHED_TOKENS,
+ SOF_PIPELINE_TOKENS,
+};
+
+static enum sof_tokens dai_token_list[] = {
+ SOF_COMP_TOKENS,
+ SOF_AUDIO_FMT_NUM_TOKENS,
+ SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
+ SOF_IN_AUDIO_FORMAT_TOKENS,
+ SOF_OUT_AUDIO_FORMAT_TOKENS,
+ SOF_COPIER_GATEWAY_CFG_TOKENS,
+ SOF_COPIER_TOKENS,
+ SOF_DAI_TOKENS,
+ SOF_COMP_EXT_TOKENS,
+};
+
+static enum sof_tokens pga_token_list[] = {
+ SOF_COMP_TOKENS,
+ SOF_GAIN_TOKENS,
+ SOF_AUDIO_FMT_NUM_TOKENS,
+ SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
+ SOF_IN_AUDIO_FORMAT_TOKENS,
+ SOF_COMP_EXT_TOKENS,
+};
+
+static enum sof_tokens mixer_token_list[] = {
+ SOF_COMP_TOKENS,
+ SOF_AUDIO_FMT_NUM_TOKENS,
+ SOF_IN_AUDIO_FORMAT_TOKENS,
+ SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
+ SOF_COMP_EXT_TOKENS,
+};
+
+static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = {
+ [snd_soc_dapm_aif_in] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
+ host_token_list, ARRAY_SIZE(host_token_list), NULL,
+ sof_ipc4_prepare_copier_module,
+ sof_ipc4_unprepare_copier_module},
+ [snd_soc_dapm_aif_out] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
+ host_token_list, ARRAY_SIZE(host_token_list), NULL,
+ sof_ipc4_prepare_copier_module,
+ sof_ipc4_unprepare_copier_module},
+ [snd_soc_dapm_dai_in] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai,
+ dai_token_list, ARRAY_SIZE(dai_token_list), NULL,
+ sof_ipc4_prepare_copier_module,
+ sof_ipc4_unprepare_copier_module},
+ [snd_soc_dapm_dai_out] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai,
+ dai_token_list, ARRAY_SIZE(dai_token_list), NULL,
+ sof_ipc4_prepare_copier_module,
+ sof_ipc4_unprepare_copier_module},
+ [snd_soc_dapm_scheduler] = {sof_ipc4_widget_setup_comp_pipeline, sof_ipc4_widget_free_comp,
+ pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL,
+ NULL, NULL},
+ [snd_soc_dapm_pga] = {sof_ipc4_widget_setup_comp_pga, sof_ipc4_widget_free_comp,
+ pga_token_list, ARRAY_SIZE(pga_token_list), NULL,
+ sof_ipc4_prepare_gain_module,
+ sof_ipc4_unprepare_generic_module},
+ [snd_soc_dapm_mixer] = {sof_ipc4_widget_setup_comp_mixer, sof_ipc4_widget_free_comp,
+ mixer_token_list, ARRAY_SIZE(mixer_token_list),
+ NULL, sof_ipc4_prepare_mixer_module,
+ sof_ipc4_unprepare_generic_module},
+};
+
+const struct sof_ipc_tplg_ops ipc4_tplg_ops = {
+ .widget = tplg_ipc4_widget_ops,
+ .token_list = ipc4_token_list,
+ .control_setup = sof_ipc4_control_setup,
+ .control = &tplg_ipc4_control_ops,
+ .widget_setup = sof_ipc4_widget_setup,
+ .widget_free = sof_ipc4_widget_free,
+ .route_setup = sof_ipc4_route_setup,
+ .route_free = sof_ipc4_route_free,
+ .dai_config = sof_ipc4_dai_config,
+ .parse_manifest = sof_ipc4_parse_manifest,
+ .dai_get_clk = sof_ipc4_dai_get_clk,
+};
diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h
new file mode 100644
index 0000000..1a9c062
--- /dev/null
+++ b/sound/soc/sof/ipc4-topology.h
@@ -0,0 +1,234 @@
+/* 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 Intel Corporation. All rights reserved.
+ */
+
+#ifndef __INCLUDE_SOUND_SOF_IPC4_TOPOLOGY_H__
+#define __INCLUDE_SOUND_SOF_IPC4_TOPOLOGY_H__
+
+#include <sound/sof/ipc4/header.h>
+
+#define SOF_IPC4_FW_PAGE_SIZE BIT(12)
+#define SOF_IPC4_FW_PAGE(x) ((((x) + BIT(12) - 1) & ~(BIT(12) - 1)) >> 12)
+#define SOF_IPC4_FW_ROUNDUP(x) (((x) + BIT(6) - 1) & (~(BIT(6) - 1)))
+
+#define SOF_IPC4_MODULE_LL BIT(5)
+#define SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE 12
+#define SOF_IPC4_PIPELINE_OBJECT_SIZE 448
+#define SOF_IPC4_DATA_QUEUE_OBJECT_SIZE 128
+#define SOF_IPC4_LL_TASK_OBJECT_SIZE 72
+#define SOF_IPC4_DP_TASK_OBJECT_SIZE 104
+#define SOF_IPC4_DP_TASK_LIST_SIZE (12 + 8)
+#define SOF_IPC4_LL_TASK_LIST_ITEM_SIZE 12
+#define SOF_IPC4_FW_MAX_PAGE_COUNT 20
+#define SOF_IPC4_FW_MAX_QUEUE_COUNT 8
+
+/* Node index and mask applicable for host copier and ALH/HDA type DAI copiers */
+#define SOF_IPC4_NODE_INDEX_MASK 0xFF
+#define SOF_IPC4_NODE_INDEX(x) ((x) & SOF_IPC4_NODE_INDEX_MASK)
+#define SOF_IPC4_NODE_TYPE(x) ((x) << 8)
+
+/* Node ID for SSP type DAI copiers */
+#define SOF_IPC4_NODE_INDEX_INTEL_SSP(x) (((x) & 0xf) << 4)
+
+/* Node ID for DMIC type DAI copiers */
+#define SOF_IPC4_NODE_INDEX_INTEL_DMIC(x) (((x) & 0x7) << 5)
+
+#define SOF_IPC4_GAIN_ALL_CHANNELS_MASK 0xffffffff
+#define SOF_IPC4_VOL_ZERO_DB 0x7fffffff
+
+#define ALH_MAX_NUMBER_OF_GTW 16
+
+/**
+ * struct sof_ipc4_pipeline - pipeline config data
+ * @priority: Priority of this pipeline
+ * @lp_mode: Low power mode
+ * @mem_usage: Memory usage
+ * @state: Pipeline state
+ * @msg: message structure for pipeline
+ */
+struct sof_ipc4_pipeline {
+ uint32_t priority;
+ uint32_t lp_mode;
+ uint32_t mem_usage;
+ int state;
+ struct sof_ipc4_msg msg;
+};
+
+/**
+ * struct sof_ipc4_available_audio_format - Available audio formats
+ * @base_config: Available base config
+ * @out_audio_fmt: Available output audio format
+ * @ref_audio_fmt: Reference audio format to match runtime audio format
+ * @dma_buffer_size: Available Gateway DMA buffer size (in bytes)
+ * @audio_fmt_num: Number of available audio formats
+ */
+struct sof_ipc4_available_audio_format {
+ struct sof_ipc4_base_module_cfg *base_config;
+ struct sof_ipc4_audio_format *out_audio_fmt;
+ struct sof_ipc4_audio_format *ref_audio_fmt;
+ u32 *dma_buffer_size;
+ int audio_fmt_num;
+};
+
+/**
+ * struct sof_copier_gateway_cfg - IPC gateway configuration
+ * @node_id: ID of Gateway Node
+ * @dma_buffer_size: Preferred Gateway DMA buffer size (in bytes)
+ * @config_length: Length of gateway node configuration blob specified in #config_data
+ * config_data: Gateway node configuration blob
+ */
+struct sof_copier_gateway_cfg {
+ uint32_t node_id;
+ uint32_t dma_buffer_size;
+ uint32_t config_length;
+ uint32_t config_data[];
+};
+
+/**
+ * struct sof_ipc4_copier_data - IPC data for copier
+ * @base_config: Base configuration including input audio format
+ * @out_format: Output audio format
+ * @copier_feature_mask: Copier feature mask
+ * @gtw_cfg: Gateway configuration
+ */
+struct sof_ipc4_copier_data {
+ struct sof_ipc4_base_module_cfg base_config;
+ struct sof_ipc4_audio_format out_format;
+ uint32_t copier_feature_mask;
+ struct sof_copier_gateway_cfg gtw_cfg;
+};
+
+/**
+ * struct sof_ipc4_gtw_attributes: Gateway attributes
+ * @lp_buffer_alloc: Gateway data requested in low power memory
+ * @alloc_from_reg_file: Gateway data requested in register file memory
+ * @rsvd: reserved for future use
+ */
+struct sof_ipc4_gtw_attributes {
+ uint32_t lp_buffer_alloc : 1;
+ uint32_t alloc_from_reg_file : 1;
+ uint32_t rsvd : 30;
+};
+
+/** struct sof_ipc4_alh_multi_gtw_cfg: ALH gateway cfg data
+ * @count: Number of streams (valid items in mapping array)
+ * @alh_id: ALH stream id of a single ALH stream aggregated
+ * @channel_mask: Channel mask
+ * @mapping: ALH streams
+ */
+struct sof_ipc4_alh_multi_gtw_cfg {
+ uint32_t count;
+ struct {
+ uint32_t alh_id;
+ uint32_t channel_mask;
+ } mapping[ALH_MAX_NUMBER_OF_GTW];
+} __packed;
+
+/** struct sof_ipc4_alh_configuration_blob: ALH blob
+ * @gw_attr: Gateway attributes
+ * @alh_cfg: ALH configuration data
+ */
+struct sof_ipc4_alh_configuration_blob {
+ struct sof_ipc4_gtw_attributes gw_attr;
+ struct sof_ipc4_alh_multi_gtw_cfg alh_cfg;
+};
+
+/**
+ * struct sof_ipc4_copier - copier config data
+ * @data: IPC copier data
+ * @copier_config: Copier + blob
+ * @ipc_config_size: Size of copier_config
+ * @available_fmt: Available audio format
+ * @frame_fmt: frame format
+ * @msg: message structure for copier
+ * @gtw_attr: Gateway attributes for copier blob
+ * @dai_type: DAI type
+ * @dai_index: DAI index
+ */
+struct sof_ipc4_copier {
+ struct sof_ipc4_copier_data data;
+ u32 *copier_config;
+ uint32_t ipc_config_size;
+ void *ipc_config_data;
+ struct sof_ipc4_available_audio_format available_fmt;
+ u32 frame_fmt;
+ struct sof_ipc4_msg msg;
+ struct sof_ipc4_gtw_attributes *gtw_attr;
+ u32 dai_type;
+ int dai_index;
+};
+
+/**
+ * struct sof_ipc4_ctrl_value_chan: generic channel mapped value data
+ * @channel: Channel ID
+ * @value: gain value
+ */
+struct sof_ipc4_ctrl_value_chan {
+ u32 channel;
+ u32 value;
+};
+
+/**
+ * struct sof_ipc4_control_data - IPC data for kcontrol IO
+ * @msg: message structure for kcontrol IO
+ * @index: pipeline ID
+ * @chanv: channel ID and value array used by volume type controls
+ * @data: data for binary kcontrols
+ */
+struct sof_ipc4_control_data {
+ struct sof_ipc4_msg msg;
+ int index;
+
+ union {
+ struct sof_ipc4_ctrl_value_chan chanv[0];
+ struct sof_abi_hdr data[0];
+ };
+};
+
+/**
+ * struct sof_ipc4_gain_data - IPC gain blob
+ * @channels: Channels
+ * @init_val: Initial value
+ * @curve_type: Curve type
+ * @reserved: reserved for future use
+ * @curve_duration: Curve duration
+ */
+struct sof_ipc4_gain_data {
+ uint32_t channels;
+ uint32_t init_val;
+ uint32_t curve_type;
+ uint32_t reserved;
+ uint32_t curve_duration;
+} __aligned(8);
+
+/**
+ * struct sof_ipc4_gain - gain config data
+ * @base_config: IPC base config data
+ * @data: IPC gain blob
+ * @available_fmt: Available audio format
+ * @msg: message structure for gain
+ */
+struct sof_ipc4_gain {
+ struct sof_ipc4_base_module_cfg base_config;
+ struct sof_ipc4_gain_data data;
+ struct sof_ipc4_available_audio_format available_fmt;
+ struct sof_ipc4_msg msg;
+};
+
+/**
+ * struct sof_ipc4_mixer - mixer config data
+ * @base_config: IPC base config data
+ * @available_fmt: Available audio format
+ * @msg: IPC4 message struct containing header and data info
+ */
+struct sof_ipc4_mixer {
+ struct sof_ipc4_base_module_cfg base_config;
+ struct sof_ipc4_available_audio_format available_fmt;
+ struct sof_ipc4_msg msg;
+};
+
+#endif
diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c
index 658802c8..a8dea5a 100644
--- a/sound/soc/sof/ipc4.c
+++ b/sound/soc/sof/ipc4.c
@@ -597,10 +597,53 @@ static void sof_ipc4_rx_msg(struct snd_sof_dev *sdev)
}
}
+static int sof_ipc4_set_core_state(struct snd_sof_dev *sdev, int core_idx, bool on)
+{
+ struct sof_ipc4_dx_state_info dx_state;
+ struct sof_ipc4_msg msg;
+
+ dx_state.core_mask = BIT(core_idx);
+ if (on)
+ dx_state.dx_mask = BIT(core_idx);
+ else
+ dx_state.dx_mask = 0;
+
+ msg.primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_SET_DX);
+ msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+ msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
+ msg.extension = 0;
+ msg.data_ptr = &dx_state;
+ msg.data_size = sizeof(dx_state);
+
+ return sof_ipc4_tx_msg(sdev, &msg, msg.data_size, NULL, 0, false);
+}
+
+/*
+ * The context save callback is used to send a message to the firmware notifying
+ * it that the primary core is going to be turned off, which is used as an
+ * indication to prepare for a full power down, thus preparing for IMR boot
+ * (when supported)
+ *
+ * Note: in IPC4 there is no message used to restore context, thus no context
+ * restore callback is implemented
+ */
+static int sof_ipc4_ctx_save(struct snd_sof_dev *sdev)
+{
+ return sof_ipc4_set_core_state(sdev, SOF_DSP_PRIMARY_CORE, false);
+}
+
+static const struct sof_ipc_pm_ops ipc4_pm_ops = {
+ .ctx_save = sof_ipc4_ctx_save,
+ .set_core_state = sof_ipc4_set_core_state,
+};
+
const struct sof_ipc_ops ipc4_ops = {
.tx_msg = sof_ipc4_tx_msg,
.rx_msg = sof_ipc4_rx_msg,
.set_get_data = sof_ipc4_set_get_data,
.get_reply = sof_ipc4_get_reply,
+ .pm = &ipc4_pm_ops,
.fw_loader = &ipc4_loader_ops,
+ .tplg = &ipc4_tplg_ops,
+ .pcm = &ipc4_pcm_ops,
};
diff --git a/sound/soc/sof/mediatek/Kconfig b/sound/soc/sof/mediatek/Kconfig
index a149dd1..4a2eddf 100644
--- a/sound/soc/sof/mediatek/Kconfig
+++ b/sound/soc/sof/mediatek/Kconfig
@@ -15,6 +15,7 @@
tristate
select SND_SOC_SOF_OF_DEV
select SND_SOC_SOF
+ select SND_SOC_SOF_IPC3
select SND_SOC_SOF_XTENSA
select SND_SOC_SOF_COMPRESS
help
diff --git a/sound/soc/sof/mediatek/adsp_helper.h b/sound/soc/sof/mediatek/adsp_helper.h
index 4ab9987..d41e904 100644
--- a/sound/soc/sof/mediatek/adsp_helper.h
+++ b/sound/soc/sof/mediatek/adsp_helper.h
@@ -20,6 +20,7 @@ struct mtk_adsp_chip_info {
u32 sramsize;
u32 dramsize;
u32 cfgregsize;
+ u32 shared_size;
void __iomem *va_sram; /* corresponding to pa_sram */
void __iomem *va_dram; /* corresponding to pa_dram */
void __iomem *va_cfgreg;
diff --git a/sound/soc/sof/mediatek/mt8195/mt8195-clk.c b/sound/soc/sof/mediatek/mt8195/mt8195-clk.c
index 6bcb4b9..9ef08e4 100644
--- a/sound/soc/sof/mediatek/mt8195/mt8195-clk.c
+++ b/sound/soc/sof/mediatek/mt8195/mt8195-clk.c
@@ -132,6 +132,13 @@ static int adsp_default_clk_init(struct snd_sof_dev *sdev, bool enable)
return ret;
}
+ ret = clk_set_parent(priv->clk[CLK_TOP_AUDIO_H],
+ priv->clk[CLK_TOP_CLK26M]);
+ if (ret) {
+ dev_err(dev, "set audio_h_sel failed %d\n", ret);
+ return ret;
+ }
+
ret = adsp_enable_all_clock(sdev);
if (ret) {
dev_err(dev, "failed to adsp_enable_clock: %d\n", ret);
diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c
index 30111ab..9c14601 100644
--- a/sound/soc/sof/mediatek/mt8195/mt8195.c
+++ b/sound/soc/sof/mediatek/mt8195/mt8195.c
@@ -145,6 +145,14 @@ static int platform_parse_resource(struct platform_device *pdev, void *data)
dev_dbg(dev, "DMA %pR\n", &res);
+ adsp->pa_shared_dram = (phys_addr_t)res.start;
+ adsp->shared_size = resource_size(&res);
+ if (adsp->pa_shared_dram & DRAM_REMAP_MASK) {
+ dev_err(dev, "adsp shared dma memory(%#x) is not 4K-aligned\n",
+ (u32)adsp->pa_shared_dram);
+ return -EINVAL;
+ }
+
ret = of_reserved_mem_device_init(dev);
if (ret) {
dev_err(dev, "of_reserved_mem_device_init failed\n");
@@ -273,23 +281,18 @@ static int adsp_shared_base_ioremap(struct platform_device *pdev, void *data)
{
struct device *dev = &pdev->dev;
struct mtk_adsp_chip_info *adsp = data;
- u32 shared_size;
/* remap shared-dram base to be non-cachable */
- shared_size = TOTAL_SIZE_SHARED_DRAM_FROM_TAIL;
- adsp->pa_shared_dram = adsp->pa_dram + adsp->dramsize - shared_size;
- if (adsp->va_dram) {
- adsp->shared_dram = adsp->va_dram + DSP_DRAM_SIZE - shared_size;
- } else {
- adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram,
- shared_size);
- if (!adsp->shared_dram) {
- dev_err(dev, "ioremap failed for shared DRAM\n");
- return -ENOMEM;
- }
+ adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram,
+ adsp->shared_size);
+ if (!adsp->shared_dram) {
+ dev_err(dev, "failed to ioremap base %pa size %#x\n",
+ adsp->shared_dram, adsp->shared_size);
+ return -ENOMEM;
}
+
dev_dbg(dev, "shared-dram vbase=%p, phy addr :%pa, size=%#x\n",
- adsp->shared_dram, &adsp->pa_shared_dram, shared_size);
+ adsp->shared_dram, &adsp->pa_shared_dram, adsp->shared_size);
return 0;
}
@@ -361,9 +364,11 @@ static int mt8195_dsp_probe(struct snd_sof_dev *sdev)
goto err_adsp_sram_power_off;
}
- sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev,
- priv->adsp->pa_dram,
- priv->adsp->dramsize);
+ priv->adsp->va_sram = sdev->bar[SOF_FW_BLK_TYPE_IRAM];
+
+ sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap(sdev->dev,
+ priv->adsp->pa_dram,
+ priv->adsp->dramsize);
if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) {
dev_err(sdev->dev, "failed to ioremap base %pa size %#x\n",
&priv->adsp->pa_dram, priv->adsp->dramsize);
@@ -438,6 +443,19 @@ static int mt8195_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state)
{
struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev);
int ret;
+ u32 reset_sw, dbg_pc;
+
+ /* wait dsp enter idle, timeout is 1 second */
+ ret = snd_sof_dsp_read_poll_timeout(sdev, DSP_REG_BAR,
+ DSP_RESET_SW, reset_sw,
+ ((reset_sw & ADSP_PWAIT) == ADSP_PWAIT),
+ SUSPEND_DSP_IDLE_POLL_INTERVAL_US,
+ SUSPEND_DSP_IDLE_TIMEOUT_US);
+ if (ret < 0) {
+ dbg_pc = snd_sof_dsp_read(sdev, DSP_REG_BAR, DSP_PDEBUGPC);
+ dev_warn(sdev->dev, "dsp not idle, powering off anyway : swrest %#x, pc %#x, ret %d\n",
+ reset_sw, dbg_pc, ret);
+ }
/* stall and reset dsp */
sof_hifixdsp_shutdown(sdev);
diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.h b/sound/soc/sof/mediatek/mt8195/mt8195.h
index 9294241..7ffd523 100644
--- a/sound/soc/sof/mediatek/mt8195/mt8195.h
+++ b/sound/soc/sof/mediatek/mt8195/mt8195.h
@@ -34,6 +34,7 @@ struct snd_sof_dev;
#define ADSP_DRESET_SW BIT(1)
#define ADSP_RUNSTALL BIT(3)
#define STATVECTOR_SEL BIT(4)
+#define ADSP_PWAIT BIT(16)
#define DSP_PFAULTBUS 0x0028
#define DSP_PFAULTINFO 0x002c
#define DSP_GPR00 0x0030
@@ -153,6 +154,10 @@ struct snd_sof_dev;
#define DRAM_REMAP_SHIFT 12
#define DRAM_REMAP_MASK (BIT(DRAM_REMAP_SHIFT) - 1)
+/* suspend dsp idle check interval and timeout */
+#define SUSPEND_DSP_IDLE_TIMEOUT_US 1000000 /* timeout to wait dsp idle, 1 sec */
+#define SUSPEND_DSP_IDLE_POLL_INTERVAL_US 500 /* 0.5 msec */
+
void sof_hifixdsp_boot_sequence(struct snd_sof_dev *sdev, u32 boot_addr);
void sof_hifixdsp_shutdown(struct snd_sof_dev *sdev);
#endif
diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h
index b79ae4f..55d43adb 100644
--- a/sound/soc/sof/ops.h
+++ b/sound/soc/sof/ops.h
@@ -29,6 +29,12 @@ static inline int sof_ops_init(struct snd_sof_dev *sdev)
return 0;
}
+static inline void sof_ops_free(struct snd_sof_dev *sdev)
+{
+ if (sdev->pdata->desc->ops_free)
+ sdev->pdata->desc->ops_free(sdev);
+}
+
/* Mandatory operations are verified during probing */
/* init */
diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h
index 27cc5fb..4284ea2f 100644
--- a/sound/soc/sof/sof-audio.h
+++ b/sound/soc/sof/sof-audio.h
@@ -168,6 +168,7 @@ struct sof_ipc_tplg_widget_ops {
* @dai_get_clk: Function pointer for getting the DAI clock setting
* @set_up_all_pipelines: Function pointer for setting up all topology pipelines
* @tear_down_all_pipelines: Function pointer for tearing down all topology pipelines
+ * @parse_manifest: Optional function pointer for ipc4 specific parsing of topology manifest
*/
struct sof_ipc_tplg_ops {
const struct sof_ipc_tplg_widget_ops *widget;
@@ -185,6 +186,8 @@ struct sof_ipc_tplg_ops {
int (*dai_get_clk)(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type);
int (*set_up_all_pipelines)(struct snd_sof_dev *sdev, bool verify);
int (*tear_down_all_pipelines)(struct snd_sof_dev *sdev, bool verify);
+ int (*parse_manifest)(struct snd_soc_component *scomp, int index,
+ struct snd_soc_tplg_manifest *man);
};
/** struct snd_sof_tuple - Tuple info
@@ -225,6 +228,15 @@ enum sof_tokens {
SOF_AFE_TOKENS,
SOF_CORE_TOKENS,
SOF_COMP_EXT_TOKENS,
+ SOF_IN_AUDIO_FORMAT_TOKENS,
+ SOF_OUT_AUDIO_FORMAT_TOKENS,
+ SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
+ SOF_COPIER_GATEWAY_CFG_TOKENS,
+ SOF_COPIER_TOKENS,
+ SOF_AUDIO_FMT_NUM_TOKENS,
+ SOF_COPIER_FORMAT_TOKENS,
+ SOF_GAIN_TOKENS,
+ SOF_ACPDMIC_TOKENS,
/* this should be the last */
SOF_TOKEN_COUNT,
diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h
index 9d7f53f..52396f3 100644
--- a/sound/soc/sof/sof-priv.h
+++ b/sound/soc/sof/sof-priv.h
@@ -37,6 +37,12 @@
#define SOF_DBG_IGNORE_D3_PERSISTENT BIT(7) /* ignore the DSP D3 persistent capability
* and always download firmware upon D3 exit
*/
+#define SOF_DBG_PRINT_DMA_POSITION_UPDATE_LOGS BIT(8) /* print DMA position updates
+ * in dmesg logs
+ */
+#define SOF_DBG_PRINT_IPC_SUCCESS_LOGS BIT(9) /* print IPC success
+ * in dmesg logs
+ */
/* Flag definitions used for controlling the DSP dump behavior */
#define SOF_DBG_DUMP_REGS BIT(0)
@@ -376,12 +382,14 @@ struct sof_ipc_fw_tracing_ops {
/**
* struct sof_ipc_pm_ops - IPC-specific PM ops
- * @ctx_save: Function pointer for context save
- * @ctx_restore: Function pointer for context restore
+ * @ctx_save: Optional function pointer for context save
+ * @ctx_restore: Optional function pointer for context restore
+ * @set_core_state: Optional function pointer for turning on/off a DSP core
*/
struct sof_ipc_pm_ops {
int (*ctx_save)(struct snd_sof_dev *sdev);
int (*ctx_restore)(struct snd_sof_dev *sdev);
+ int (*set_core_state)(struct snd_sof_dev *sdev, int core_idx, bool on);
};
/**
@@ -655,7 +663,7 @@ void sof_print_oops_and_stack(struct snd_sof_dev *sdev, const char *level,
u32 panic_code, u32 tracep_code, void *oops,
struct sof_ipc_panic_info *panic_info,
void *stack, size_t stack_words);
-void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev);
+void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev, const char *msg);
int snd_sof_dbg_memory_info_init(struct snd_sof_dev *sdev);
int snd_sof_debugfs_add_region_item_iomem(struct snd_sof_dev *sdev,
enum snd_sof_fw_blk_type blk_type, u32 offset, size_t size,
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index b1fcab7..7e54eb1 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -36,9 +36,6 @@
#define TLV_STEP 1
#define TLV_MUTE 2
-/* size of tplg abi in byte */
-#define SOF_TPLG_ABI_SIZE 3
-
/**
* sof_update_ipc_object - Parse multiple sets of tokens within the token array associated with the
* token ID.
@@ -1141,6 +1138,21 @@ static int spcm_bind(struct snd_soc_component *scomp, struct snd_sof_pcm *spcm,
return 0;
}
+static int sof_get_token_value(u32 token_id, struct snd_sof_tuple *tuples, int num_tuples)
+{
+ int i;
+
+ if (!tuples)
+ return -EINVAL;
+
+ for (i = 0; i < num_tuples; i++) {
+ if (tuples[i].token == token_id)
+ return tuples[i].value.v;
+ }
+
+ return -EINVAL;
+}
+
static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_sof_widget *swidget,
struct snd_soc_tplg_dapm_widget *tw,
enum sof_tokens *object_token_list, int count)
@@ -1168,6 +1180,8 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s
/* parse token list for widget */
for (i = 0; i < count; i++) {
+ int num_sets = 1;
+
if (object_token_list[i] >= SOF_TOKEN_COUNT) {
dev_err(scomp->dev, "Invalid token id %d for widget %s\n",
object_token_list[i], swidget->widget->name);
@@ -1175,8 +1189,9 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s
goto err;
}
- /* parse and save UUID in swidget */
- if (object_token_list[i] == SOF_COMP_EXT_TOKENS) {
+ switch (object_token_list[i]) {
+ case SOF_COMP_EXT_TOKENS:
+ /* parse and save UUID in swidget */
ret = sof_parse_tokens(scomp, swidget,
token_list[object_token_list[i]].tokens,
token_list[object_token_list[i]].count,
@@ -1189,11 +1204,41 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s
}
continue;
+ case SOF_IN_AUDIO_FORMAT_TOKENS:
+ case SOF_OUT_AUDIO_FORMAT_TOKENS:
+ case SOF_COPIER_GATEWAY_CFG_TOKENS:
+ case SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS:
+ num_sets = sof_get_token_value(SOF_TKN_COMP_NUM_AUDIO_FORMATS,
+ swidget->tuples, swidget->num_tuples);
+
+ if (num_sets < 0) {
+ dev_err(sdev->dev, "Invalid audio format count for %s\n",
+ swidget->widget->name);
+ ret = num_sets;
+ goto err;
+ }
+
+ if (num_sets > 1) {
+ struct snd_sof_tuple *new_tuples;
+
+ num_tuples += token_list[object_token_list[i]].count * num_sets;
+ new_tuples = krealloc(swidget->tuples,
+ sizeof(*new_tuples) * num_tuples, GFP_KERNEL);
+ if (!new_tuples) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ swidget->tuples = new_tuples;
+ }
+ break;
+ default:
+ break;
}
/* copy one set of tuples per token ID into swidget->tuples */
ret = sof_copy_tuples(sdev, private->array, le32_to_cpu(private->size),
- object_token_list[i], 1, swidget->tuples,
+ object_token_list[i], num_sets, swidget->tuples,
num_tuples, &swidget->num_tuples);
if (ret < 0) {
dev_err(scomp->dev, "Failed parsing %s for widget %s err: %d\n",
@@ -1208,21 +1253,6 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s
return ret;
}
-static int sof_get_token_value(u32 token_id, struct snd_sof_tuple *tuples, int num_tuples)
-{
- int i;
-
- if (!tuples)
- return -EINVAL;
-
- for (i = 0; i < num_tuples; i++) {
- if (tuples[i].token == token_id)
- return tuples[i].value.v;
- }
-
- return -EINVAL;
-}
-
/* external widget init - used for any driver specific init */
static int sof_widget_ready(struct snd_soc_component *scomp, int index,
struct snd_soc_dapm_widget *w,
@@ -1709,6 +1739,10 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_
token_id = SOF_AFE_TOKENS;
num_tuples += token_list[SOF_AFE_TOKENS].count;
break;
+ case SOF_DAI_AMD_DMIC:
+ token_id = SOF_ACPDMIC_TOKENS;
+ num_tuples += token_list[SOF_ACPDMIC_TOKENS].count;
+ break;
default:
break;
}
@@ -1987,45 +2021,11 @@ static int sof_complete(struct snd_soc_component *scomp)
static int sof_manifest(struct snd_soc_component *scomp, int index,
struct snd_soc_tplg_manifest *man)
{
- u32 size;
- u32 abi_version;
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+ const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg;
- size = le32_to_cpu(man->priv.size);
-
- /* backward compatible with tplg without ABI info */
- if (!size) {
- dev_dbg(scomp->dev, "No topology ABI info\n");
- return 0;
- }
-
- if (size != SOF_TPLG_ABI_SIZE) {
- dev_err(scomp->dev, "error: invalid topology ABI size\n");
- return -EINVAL;
- }
-
- dev_info(scomp->dev,
- "Topology: ABI %d:%d:%d Kernel ABI %d:%d:%d\n",
- man->priv.data[0], man->priv.data[1],
- man->priv.data[2], SOF_ABI_MAJOR, SOF_ABI_MINOR,
- SOF_ABI_PATCH);
-
- abi_version = SOF_ABI_VER(man->priv.data[0],
- man->priv.data[1],
- man->priv.data[2]);
-
- if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, abi_version)) {
- dev_err(scomp->dev, "error: incompatible topology ABI version\n");
- return -EINVAL;
- }
-
- if (SOF_ABI_VERSION_MINOR(abi_version) > SOF_ABI_MINOR) {
- if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS)) {
- dev_warn(scomp->dev, "warn: topology ABI is more recent than kernel\n");
- } else {
- dev_err(scomp->dev, "error: topology ABI is more recent than kernel\n");
- return -EINVAL;
- }
- }
+ if (ipc_tplg_ops->parse_manifest)
+ return ipc_tplg_ops->parse_manifest(scomp, index, man);
return 0;
}
diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c
index 6ee7145..1228051 100644
--- a/sound/soc/stm/stm32_adfsdm.c
+++ b/sound/soc/stm/stm32_adfsdm.c
@@ -296,7 +296,7 @@ static int stm32_adfsdm_pcm_new(struct snd_soc_component *component,
static int stm32_adfsdm_dummy_cb(const void *data, void *private)
{
/*
- * This dummmy callback is requested by iio_channel_get_all_cb() API,
+ * This dummy callback is requested by iio_channel_get_all_cb() API,
* but the stm32_dfsdm_get_buff_cb() API is used instead, to optimize
* DMA transfers.
*/
diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c
index ac5dff4d..32d885f 100644
--- a/sound/soc/stm/stm32_i2s.c
+++ b/sound/soc/stm/stm32_i2s.c
@@ -593,16 +593,16 @@ static int stm32_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
}
/* DAI clock master masks */
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BC_FC:
i2s->ms_flg = I2S_MS_SLAVE;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_BP_FP:
i2s->ms_flg = I2S_MS_MASTER;
break;
default:
dev_err(cpu_dai->dev, "Unsupported mode %#x\n",
- fmt & SND_SOC_DAIFMT_MASTER_MASK);
+ fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK);
return -EINVAL;
}
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index dd636af..03cc6d1 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -45,8 +45,6 @@
#define STM_SAI_B_ID 0x1
#define STM_SAI_IS_SUB_A(x) ((x)->id == STM_SAI_A_ID)
-#define STM_SAI_IS_SUB_B(x) ((x)->id == STM_SAI_B_ID)
-#define STM_SAI_BLOCK_NAME(x) (((x)->id == STM_SAI_A_ID) ? "A" : "B")
#define SAI_SYNC_NONE 0x0
#define SAI_SYNC_INTERNAL 0x1
@@ -719,18 +717,18 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
stm32_sai_sub_reg_up(sai, STM_SAI_FRCR_REGX, frcr_mask, frcr);
/* DAI clock master masks */
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BC_FC:
/* codec is master */
cr1 |= SAI_XCR1_SLAVE;
sai->master = false;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_BP_FP:
sai->master = true;
break;
default:
dev_err(cpu_dai->dev, "Unsupported mode %#x\n",
- fmt & SND_SOC_DAIFMT_MASTER_MASK);
+ fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK);
return -EINVAL;
}
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 7047f71..f58aa64 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -702,13 +702,13 @@ static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
SUN4I_I2S_FMT0_FMT_MASK, val);
/* DAI clock master masks */
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BP_FP:
/* BCLK and LRCLK master */
val = SUN4I_I2S_CTRL_MODE_MASTER;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_BC_FC:
/* BCLK and LRCLK slave */
val = SUN4I_I2S_CTRL_MODE_SLAVE;
break;
@@ -802,13 +802,13 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
SUN8I_I2S_TX_CHAN_OFFSET(offset));
/* DAI clock master masks */
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BP_FP:
/* BCLK and LRCLK master */
val = SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_BC_FC:
/* BCLK and LRCLK slave */
val = 0;
break;
@@ -909,13 +909,13 @@ static int sun50i_h6_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset));
/* DAI clock master masks */
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BP_FP:
/* BCLK and LRCLK master */
val = SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_BC_FC:
/* BCLK and LRCLK slave */
val = 0;
break;
diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 0bea216..f797c53 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -286,11 +286,11 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
u32 dsp_format, format, invert, value;
/* clock masters */
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBC_CFC: /* Codec slave, DAI master */
value = 0x1;
break;
- case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
+ case SND_SOC_DAIFMT_CBP_CFP: /* Codec Master, DAI slave */
value = 0x0;
break;
default:
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index 2482d98..b6712a3 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -85,6 +85,15 @@
compatible devices.
Say Y or M if you want to add support for Tegra210 I2S module.
+config SND_SOC_TEGRA210_OPE
+ tristate "Tegra210 OPE module"
+ help
+ Config to enable the Output Processing Engine (OPE) which includes
+ Parametric Equalizer (PEQ) and Multi Band Dynamic Range Compressor
+ (MBDRC) sub blocks for data processing. It can support up to 8
+ channels.
+ Say Y or M if you want to add support for Tegra210 OPE module.
+
config SND_SOC_TEGRA186_ASRC
tristate "Tegra186 ASRC module"
help
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index 70a498d..b723c78 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -19,6 +19,7 @@
snd-soc-tegra210-amx-objs := tegra210_amx.o
snd-soc-tegra210-adx-objs := tegra210_adx.o
snd-soc-tegra210-mixer-objs := tegra210_mixer.o
+snd-soc-tegra210-ope-objs := tegra210_ope.o tegra210_mbdrc.o tegra210_peq.o
obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
obj-$(CONFIG_SND_SOC_TEGRA20_AC97) += snd-soc-tegra20-ac97.o
@@ -38,6 +39,7 @@
obj-$(CONFIG_SND_SOC_TEGRA210_AMX) += snd-soc-tegra210-amx.o
obj-$(CONFIG_SND_SOC_TEGRA210_ADX) += snd-soc-tegra210-adx.o
obj-$(CONFIG_SND_SOC_TEGRA210_MIXER) += snd-soc-tegra210-mixer.o
+obj-$(CONFIG_SND_SOC_TEGRA210_OPE) += snd-soc-tegra210-ope.o
# Tegra machine Support
snd-soc-tegra-wm8903-objs := tegra_wm8903.o
diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c
index 27365a8..2e1a726 100644
--- a/sound/soc/tegra/tegra20_i2s.c
+++ b/sound/soc/tegra/tegra20_i2s.c
@@ -95,11 +95,11 @@ static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai,
}
mask |= TEGRA20_I2S_CTRL_MASTER_ENABLE;
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BP_FP:
val |= TEGRA20_I2S_CTRL_MASTER_ENABLE;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_BC_FC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/tegra/tegra210_ahub.c b/sound/soc/tegra/tegra210_ahub.c
index e1f90da..b38d205 100644
--- a/sound/soc/tegra/tegra210_ahub.c
+++ b/sound/soc/tegra/tegra210_ahub.c
@@ -170,6 +170,11 @@ static struct snd_soc_dai_driver tegra210_ahub_dais[] = {
DAI(MIXER1 TX3),
DAI(MIXER1 TX4),
DAI(MIXER1 TX5),
+ /* XBAR -> OPE -> XBAR */
+ DAI(OPE1 RX),
+ DAI(OPE1 TX),
+ DAI(OPE2 RX),
+ DAI(OPE2 TX),
};
static struct snd_soc_dai_driver tegra186_ahub_dais[] = {
@@ -294,6 +299,9 @@ static struct snd_soc_dai_driver tegra186_ahub_dais[] = {
DAI(ASRC1 RX6),
DAI(ASRC1 TX6),
DAI(ASRC1 RX7),
+ /* XBAR -> OPE -> XBAR */
+ DAI(OPE1 RX),
+ DAI(OPE1 TX),
};
static const char * const tegra210_ahub_mux_texts[] = {
@@ -337,6 +345,8 @@ static const char * const tegra210_ahub_mux_texts[] = {
"MIXER1 TX3",
"MIXER1 TX4",
"MIXER1 TX5",
+ "OPE1",
+ "OPE2",
};
static const char * const tegra186_ahub_mux_texts[] = {
@@ -408,6 +418,7 @@ static const char * const tegra186_ahub_mux_texts[] = {
"ASRC1 TX4",
"ASRC1 TX5",
"ASRC1 TX6",
+ "OPE1",
};
static const unsigned int tegra210_ahub_mux_values[] = {
@@ -459,6 +470,9 @@ static const unsigned int tegra210_ahub_mux_values[] = {
MUX_VALUE(1, 2),
MUX_VALUE(1, 3),
MUX_VALUE(1, 4),
+ /* OPE */
+ MUX_VALUE(2, 0),
+ MUX_VALUE(2, 1),
};
static const unsigned int tegra186_ahub_mux_values[] = {
@@ -540,6 +554,8 @@ static const unsigned int tegra186_ahub_mux_values[] = {
MUX_VALUE(3, 27),
MUX_VALUE(3, 28),
MUX_VALUE(3, 29),
+ /* OPE */
+ MUX_VALUE(2, 0),
};
/* Controls for t210 */
@@ -584,6 +600,8 @@ MUX_ENUM_CTRL_DECL(t210_mixer17_tx, 0x26);
MUX_ENUM_CTRL_DECL(t210_mixer18_tx, 0x27);
MUX_ENUM_CTRL_DECL(t210_mixer19_tx, 0x28);
MUX_ENUM_CTRL_DECL(t210_mixer110_tx, 0x29);
+MUX_ENUM_CTRL_DECL(t210_ope1_tx, 0x40);
+MUX_ENUM_CTRL_DECL(t210_ope2_tx, 0x41);
/* Controls for t186 */
MUX_ENUM_CTRL_DECL_186(t186_admaif1_tx, 0x00);
@@ -657,6 +675,7 @@ MUX_ENUM_CTRL_DECL_186(t186_asrc14_tx, 0x6f);
MUX_ENUM_CTRL_DECL_186(t186_asrc15_tx, 0x70);
MUX_ENUM_CTRL_DECL_186(t186_asrc16_tx, 0x71);
MUX_ENUM_CTRL_DECL_186(t186_asrc17_tx, 0x72);
+MUX_ENUM_CTRL_DECL_186(t186_ope1_tx, 0x40);
/* Controls for t234 */
MUX_ENUM_CTRL_DECL_234(t234_mvc1_tx, 0x44);
@@ -758,6 +777,8 @@ static const struct snd_soc_dapm_widget tegra210_ahub_widgets[] = {
TX_WIDGETS("MIXER1 TX3"),
TX_WIDGETS("MIXER1 TX4"),
TX_WIDGETS("MIXER1 TX5"),
+ WIDGETS("OPE1", t210_ope1_tx),
+ WIDGETS("OPE2", t210_ope2_tx),
};
static const struct snd_soc_dapm_widget tegra186_ahub_widgets[] = {
@@ -867,6 +888,7 @@ static const struct snd_soc_dapm_widget tegra186_ahub_widgets[] = {
TX_WIDGETS("ASRC1 TX4"),
TX_WIDGETS("ASRC1 TX5"),
TX_WIDGETS("ASRC1 TX6"),
+ WIDGETS("OPE1", t186_ope1_tx),
};
static const struct snd_soc_dapm_widget tegra234_ahub_widgets[] = {
@@ -976,6 +998,7 @@ static const struct snd_soc_dapm_widget tegra234_ahub_widgets[] = {
TX_WIDGETS("ASRC1 TX4"),
TX_WIDGETS("ASRC1 TX5"),
TX_WIDGETS("ASRC1 TX6"),
+ WIDGETS("OPE1", t186_ope1_tx),
};
#define TEGRA_COMMON_MUX_ROUTES(name) \
@@ -1018,7 +1041,11 @@ static const struct snd_soc_dapm_widget tegra234_ahub_widgets[] = {
{ name " Mux", "MIXER1 TX2", "MIXER1 TX2 XBAR-RX" }, \
{ name " Mux", "MIXER1 TX3", "MIXER1 TX3 XBAR-RX" }, \
{ name " Mux", "MIXER1 TX4", "MIXER1 TX4 XBAR-RX" }, \
- { name " Mux", "MIXER1 TX5", "MIXER1 TX5 XBAR-RX" },
+ { name " Mux", "MIXER1 TX5", "MIXER1 TX5 XBAR-RX" }, \
+ { name " Mux", "OPE1", "OPE1 XBAR-RX" },
+
+#define TEGRA210_ONLY_MUX_ROUTES(name) \
+ { name " Mux", "OPE2", "OPE2 XBAR-RX" },
#define TEGRA186_ONLY_MUX_ROUTES(name) \
{ name " Mux", "ADMAIF11", "ADMAIF11 XBAR-RX" }, \
@@ -1050,10 +1077,11 @@ static const struct snd_soc_dapm_widget tegra234_ahub_widgets[] = {
{ name " Mux", "ASRC1 TX5", "ASRC1 TX5 XBAR-RX" }, \
{ name " Mux", "ASRC1 TX6", "ASRC1 TX6 XBAR-RX" },
-#define TEGRA210_MUX_ROUTES(name) \
- TEGRA_COMMON_MUX_ROUTES(name)
+#define TEGRA210_MUX_ROUTES(name) \
+ TEGRA_COMMON_MUX_ROUTES(name) \
+ TEGRA210_ONLY_MUX_ROUTES(name)
-#define TEGRA186_MUX_ROUTES(name) \
+#define TEGRA186_MUX_ROUTES(name) \
TEGRA_COMMON_MUX_ROUTES(name) \
TEGRA186_ONLY_MUX_ROUTES(name)
@@ -1121,6 +1149,8 @@ static const struct snd_soc_dapm_route tegra210_ahub_routes[] = {
TEGRA210_MUX_ROUTES("MIXER1 RX8")
TEGRA210_MUX_ROUTES("MIXER1 RX9")
TEGRA210_MUX_ROUTES("MIXER1 RX10")
+ TEGRA210_MUX_ROUTES("OPE1")
+ TEGRA210_MUX_ROUTES("OPE2")
};
static const struct snd_soc_dapm_route tegra186_ahub_routes[] = {
@@ -1215,6 +1245,7 @@ static const struct snd_soc_dapm_route tegra186_ahub_routes[] = {
TEGRA186_MUX_ROUTES("ASRC1 RX5")
TEGRA186_MUX_ROUTES("ASRC1 RX6")
TEGRA186_MUX_ROUTES("ASRC1 RX7")
+ TEGRA186_MUX_ROUTES("OPE1")
};
static const struct snd_soc_component_driver tegra210_ahub_component = {
diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c
index 9552bbb..a289458 100644
--- a/sound/soc/tegra/tegra210_i2s.c
+++ b/sound/soc/tegra/tegra210_i2s.c
@@ -214,11 +214,11 @@ static int tegra210_i2s_set_fmt(struct snd_soc_dai *dai,
unsigned int mask, val;
mask = I2S_CTRL_MASTER_EN_MASK;
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BP_FP:
val = 0;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_BC_FC:
val = I2S_CTRL_MASTER_EN;
break;
default:
diff --git a/sound/soc/tegra/tegra210_mbdrc.c b/sound/soc/tegra/tegra210_mbdrc.c
new file mode 100644
index 0000000..7d9da33
--- /dev/null
+++ b/sound/soc/tegra/tegra210_mbdrc.c
@@ -0,0 +1,1012 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra210_mbdrc.c - Tegra210 MBDRC driver
+//
+// Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "tegra210_mbdrc.h"
+#include "tegra210_ope.h"
+
+#define MBDRC_FILTER_REG(reg, id) \
+ ((reg) + ((id) * TEGRA210_MBDRC_FILTER_PARAM_STRIDE))
+
+#define MBDRC_FILTER_REG_DEFAULTS(id) \
+ { MBDRC_FILTER_REG(TEGRA210_MBDRC_IIR_CFG, id), 0x00000005}, \
+ { MBDRC_FILTER_REG(TEGRA210_MBDRC_IN_ATTACK, id), 0x3e48590c}, \
+ { MBDRC_FILTER_REG(TEGRA210_MBDRC_IN_RELEASE, id), 0x08414e9f}, \
+ { MBDRC_FILTER_REG(TEGRA210_MBDRC_FAST_ATTACK, id), 0x7fffffff}, \
+ { MBDRC_FILTER_REG(TEGRA210_MBDRC_IN_THRESHOLD, id), 0x06145082}, \
+ { MBDRC_FILTER_REG(TEGRA210_MBDRC_OUT_THRESHOLD, id), 0x060d379b}, \
+ { MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_1ST, id), 0x0000a000}, \
+ { MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_2ND, id), 0x00002000}, \
+ { MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_3RD, id), 0x00000b33}, \
+ { MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_4TH, id), 0x00000800}, \
+ { MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_5TH, id), 0x0000019a}, \
+ { MBDRC_FILTER_REG(TEGRA210_MBDRC_MAKEUP_GAIN, id), 0x00000002}, \
+ { MBDRC_FILTER_REG(TEGRA210_MBDRC_INIT_GAIN, id), 0x00066666}, \
+ { MBDRC_FILTER_REG(TEGRA210_MBDRC_GAIN_ATTACK, id), 0x00d9ba0e}, \
+ { MBDRC_FILTER_REG(TEGRA210_MBDRC_GAIN_RELEASE, id), 0x3e48590c}, \
+ { MBDRC_FILTER_REG(TEGRA210_MBDRC_FAST_RELEASE, id), 0x7ffff26a}, \
+ { MBDRC_FILTER_REG(TEGRA210_MBDRC_CFG_RAM_CTRL, id), 0x4000}
+
+static const struct reg_default tegra210_mbdrc_reg_defaults[] = {
+ { TEGRA210_MBDRC_CFG, 0x0030de51},
+ { TEGRA210_MBDRC_CHANNEL_MASK, 0x00000003},
+ { TEGRA210_MBDRC_FAST_FACTOR, 0x30000800},
+
+ MBDRC_FILTER_REG_DEFAULTS(0),
+ MBDRC_FILTER_REG_DEFAULTS(1),
+ MBDRC_FILTER_REG_DEFAULTS(2),
+};
+
+/* Default MBDRC parameters */
+static const struct tegra210_mbdrc_config mbdrc_init_config = {
+ .mode = 0, /* Bypass */
+ .rms_off = 48,
+ .peak_rms_mode = 1, /* PEAK */
+ .fliter_structure = 0, /* All-pass tree */
+ .shift_ctrl = 30,
+ .frame_size = 32,
+ .channel_mask = 0x3,
+ .fa_factor = 2048,
+ .fr_factor = 14747,
+
+ .band_params[MBDRC_LOW_BAND] = {
+ .band = MBDRC_LOW_BAND,
+ .iir_stages = 5,
+ .in_attack_tc = 1044928780,
+ .in_release_tc = 138497695,
+ .fast_attack_tc = 2147483647,
+ .in_threshold = {130, 80, 20, 6},
+ .out_threshold = {155, 55, 13, 6},
+ .ratio = {40960, 8192, 2867, 2048, 410},
+ .makeup_gain = 4,
+ .gain_init = 419430,
+ .gain_attack_tc = 14268942,
+ .gain_release_tc = 1440547090,
+ .fast_release_tc = 2147480170,
+
+ .biquad_params = {
+ /*
+ * Gains:
+ *
+ * b0, b1, a0,
+ * a1, a2,
+ */
+
+ /* Band-0 */
+ 961046798, -2030431983, 1073741824,
+ 2030431983, -961046798,
+ /* Band-1 */
+ 1030244425, -2099481453, 1073741824,
+ 2099481453, -1030244425,
+ /* Band-2 */
+ 1067169294, -2136327263, 1073741824,
+ 2136327263, -1067169294,
+ /* Band-3 */
+ 434951949, -1306567134, 1073741824,
+ 1306567134, -434951949,
+ /* Band-4 */
+ 780656019, -1605955641, 1073741824,
+ 1605955641, -780656019,
+ /* Band-5 */
+ 1024497031, -1817128152, 1073741824,
+ 1817128152, -1024497031,
+ /* Band-6 */
+ 1073741824, 0, 0,
+ 0, 0,
+ /* Band-7 */
+ 1073741824, 0, 0,
+ 0, 0,
+ }
+ },
+
+ .band_params[MBDRC_MID_BAND] = {
+ .band = MBDRC_MID_BAND,
+ .iir_stages = 5,
+ .in_attack_tc = 1581413104,
+ .in_release_tc = 35494783,
+ .fast_attack_tc = 2147483647,
+ .in_threshold = {130, 50, 30, 6},
+ .out_threshold = {106, 50, 30, 13},
+ .ratio = {40960, 2867, 4096, 2867, 410},
+ .makeup_gain = 6,
+ .gain_init = 419430,
+ .gain_attack_tc = 4766887,
+ .gain_release_tc = 1044928780,
+ .fast_release_tc = 2147480170,
+
+ .biquad_params = {
+ /*
+ * Gains:
+ *
+ * b0, b1, a0,
+ * a1, a2,
+ */
+
+ /* Band-0 */
+ -1005668963, 1073741824, 0,
+ 1005668963, 0,
+ /* Band-1 */
+ 998437058, -2067742187, 1073741824,
+ 2067742187, -998437058,
+ /* Band-2 */
+ 1051963422, -2121153948, 1073741824,
+ 2121153948, -1051963422,
+ /* Band-3 */
+ 434951949, -1306567134, 1073741824,
+ 1306567134, -434951949,
+ /* Band-4 */
+ 780656019, -1605955641, 1073741824,
+ 1605955641, -780656019,
+ /* Band-5 */
+ 1024497031, -1817128152, 1073741824,
+ 1817128152, -1024497031,
+ /* Band-6 */
+ 1073741824, 0, 0,
+ 0, 0,
+ /* Band-7 */
+ 1073741824, 0, 0,
+ 0, 0,
+ }
+ },
+
+ .band_params[MBDRC_HIGH_BAND] = {
+ .band = MBDRC_HIGH_BAND,
+ .iir_stages = 5,
+ .in_attack_tc = 2144750688,
+ .in_release_tc = 70402888,
+ .fast_attack_tc = 2147483647,
+ .in_threshold = {130, 50, 30, 6},
+ .out_threshold = {106, 50, 30, 13},
+ .ratio = {40960, 2867, 4096, 2867, 410},
+ .makeup_gain = 6,
+ .gain_init = 419430,
+ .gain_attack_tc = 4766887,
+ .gain_release_tc = 1044928780,
+ .fast_release_tc = 2147480170,
+
+ .biquad_params = {
+ /*
+ * Gains:
+ *
+ * b0, b1, a0,
+ * a1, a2,
+ */
+
+ /* Band-0 */
+ 1073741824, 0, 0,
+ 0, 0,
+ /* Band-1 */
+ 1073741824, 0, 0,
+ 0, 0,
+ /* Band-2 */
+ 1073741824, 0, 0,
+ 0, 0,
+ /* Band-3 */
+ -619925131, 1073741824, 0,
+ 619925131, 0,
+ /* Band-4 */
+ 606839335, -1455425976, 1073741824,
+ 1455425976, -606839335,
+ /* Band-5 */
+ 917759617, -1724690840, 1073741824,
+ 1724690840, -917759617,
+ /* Band-6 */
+ 1073741824, 0, 0,
+ 0, 0,
+ /* Band-7 */
+ 1073741824, 0, 0,
+ 0, 0,
+ }
+ }
+};
+
+static void tegra210_mbdrc_write_ram(struct regmap *regmap, unsigned int reg_ctrl,
+ unsigned int reg_data, unsigned int ram_offset,
+ unsigned int *data, size_t size)
+{
+ unsigned int val;
+ unsigned int i;
+
+ val = ram_offset & TEGRA210_MBDRC_RAM_CTRL_RAM_ADDR_MASK;
+ val |= TEGRA210_MBDRC_RAM_CTRL_ADDR_INIT_EN;
+ val |= TEGRA210_MBDRC_RAM_CTRL_SEQ_ACCESS_EN;
+ val |= TEGRA210_MBDRC_RAM_CTRL_RW_WRITE;
+
+ regmap_write(regmap, reg_ctrl, val);
+
+ for (i = 0; i < size; i++)
+ regmap_write(regmap, reg_data, data[i]);
+}
+
+static int tegra210_mbdrc_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+ unsigned int val;
+
+ regmap_read(ope->mbdrc_regmap, mc->reg, &val);
+
+ ucontrol->value.integer.value[0] = (val >> mc->shift) & mc->max;
+
+ return 0;
+}
+
+static int tegra210_mbdrc_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+ unsigned int val = ucontrol->value.integer.value[0];
+ bool change = false;
+
+ val = val << mc->shift;
+
+ regmap_update_bits_check(ope->mbdrc_regmap, mc->reg,
+ (mc->max << mc->shift), val, &change);
+
+ return change ? 1 : 0;
+}
+
+static int tegra210_mbdrc_get_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int val;
+
+ regmap_read(ope->mbdrc_regmap, e->reg, &val);
+
+ ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & e->mask;
+
+ return 0;
+}
+
+static int tegra210_mbdrc_put_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ bool change = false;
+ unsigned int val;
+ unsigned int mask;
+
+ if (ucontrol->value.enumerated.item[0] > e->items - 1)
+ return -EINVAL;
+
+ val = ucontrol->value.enumerated.item[0] << e->shift_l;
+ mask = e->mask << e->shift_l;
+
+ regmap_update_bits_check(ope->mbdrc_regmap, e->reg, mask, val,
+ &change);
+
+ return change ? 1 : 0;
+}
+
+static int tegra210_mbdrc_band_params_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+ u32 *data = (u32 *)ucontrol->value.bytes.data;
+ u32 regs = params->soc.base;
+ u32 mask = params->soc.mask;
+ u32 shift = params->shift;
+ unsigned int i;
+
+ for (i = 0; i < params->soc.num_regs; i++, regs += cmpnt->val_bytes) {
+ regmap_read(ope->mbdrc_regmap, regs, &data[i]);
+
+ data[i] = ((data[i] & mask) >> shift);
+ }
+
+ return 0;
+}
+
+static int tegra210_mbdrc_band_params_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+ u32 *data = (u32 *)ucontrol->value.bytes.data;
+ u32 regs = params->soc.base;
+ u32 mask = params->soc.mask;
+ u32 shift = params->shift;
+ bool change = false;
+ unsigned int i;
+
+ for (i = 0; i < params->soc.num_regs; i++, regs += cmpnt->val_bytes) {
+ bool update = false;
+
+ regmap_update_bits_check(ope->mbdrc_regmap, regs, mask,
+ data[i] << shift, &update);
+
+ change |= update;
+ }
+
+ return change ? 1 : 0;
+}
+
+static int tegra210_mbdrc_threshold_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+ u32 *data = (u32 *)ucontrol->value.bytes.data;
+ u32 regs = params->soc.base;
+ u32 num_regs = params->soc.num_regs;
+ u32 val;
+ unsigned int i;
+
+ for (i = 0; i < num_regs; i += 4, regs += cmpnt->val_bytes) {
+ regmap_read(ope->mbdrc_regmap, regs, &val);
+
+ data[i] = (val & TEGRA210_MBDRC_THRESH_1ST_MASK) >>
+ TEGRA210_MBDRC_THRESH_1ST_SHIFT;
+ data[i + 1] = (val & TEGRA210_MBDRC_THRESH_2ND_MASK) >>
+ TEGRA210_MBDRC_THRESH_2ND_SHIFT;
+ data[i + 2] = (val & TEGRA210_MBDRC_THRESH_3RD_MASK) >>
+ TEGRA210_MBDRC_THRESH_3RD_SHIFT;
+ data[i + 3] = (val & TEGRA210_MBDRC_THRESH_4TH_MASK) >>
+ TEGRA210_MBDRC_THRESH_4TH_SHIFT;
+ }
+
+ return 0;
+}
+
+static int tegra210_mbdrc_threshold_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+ u32 *data = (u32 *)ucontrol->value.bytes.data;
+ u32 regs = params->soc.base;
+ u32 num_regs = params->soc.num_regs;
+ bool change = false;
+ unsigned int i;
+
+ for (i = 0; i < num_regs; i += 4, regs += cmpnt->val_bytes) {
+ bool update = false;
+
+ data[i] = (((data[i] >> TEGRA210_MBDRC_THRESH_1ST_SHIFT) &
+ TEGRA210_MBDRC_THRESH_1ST_MASK) |
+ ((data[i + 1] >> TEGRA210_MBDRC_THRESH_2ND_SHIFT) &
+ TEGRA210_MBDRC_THRESH_2ND_MASK) |
+ ((data[i + 2] >> TEGRA210_MBDRC_THRESH_3RD_SHIFT) &
+ TEGRA210_MBDRC_THRESH_3RD_MASK) |
+ ((data[i + 3] >> TEGRA210_MBDRC_THRESH_4TH_SHIFT) &
+ TEGRA210_MBDRC_THRESH_4TH_MASK));
+
+ regmap_update_bits_check(ope->mbdrc_regmap, regs, 0xffffffff,
+ data[i], &update);
+
+ change |= update;
+ }
+
+ return change ? 1 : 0;
+}
+
+static int tegra210_mbdrc_biquad_coeffs_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ u32 *data = (u32 *)ucontrol->value.bytes.data;
+
+ memset(data, 0, params->soc.num_regs * cmpnt->val_bytes);
+
+ return 0;
+}
+
+static int tegra210_mbdrc_biquad_coeffs_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+ u32 reg_ctrl = params->soc.base;
+ u32 reg_data = reg_ctrl + cmpnt->val_bytes;
+ u32 *data = (u32 *)ucontrol->value.bytes.data;
+
+ tegra210_mbdrc_write_ram(ope->mbdrc_regmap, reg_ctrl, reg_data,
+ params->shift, data, params->soc.num_regs);
+
+ return 1;
+}
+
+static int tegra210_mbdrc_param_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct soc_bytes *params = (void *)kcontrol->private_value;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ uinfo->count = params->num_regs * sizeof(u32);
+
+ return 0;
+}
+
+static int tegra210_mbdrc_vol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+ int val;
+
+ regmap_read(ope->mbdrc_regmap, mc->reg, &val);
+
+ ucontrol->value.integer.value[0] =
+ ((val >> mc->shift) - TEGRA210_MBDRC_MASTER_VOL_MIN);
+
+ return 0;
+}
+
+static int tegra210_mbdrc_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+ int val = ucontrol->value.integer.value[0];
+ bool change = false;
+
+ val += TEGRA210_MBDRC_MASTER_VOL_MIN;
+
+ regmap_update_bits_check(ope->mbdrc_regmap, mc->reg,
+ mc->max << mc->shift, val << mc->shift,
+ &change);
+
+ regmap_read(ope->mbdrc_regmap, mc->reg, &val);
+
+ return change ? 1 : 0;
+}
+
+static const char * const tegra210_mbdrc_mode_text[] = {
+ "Bypass", "Fullband", "Dualband", "Multiband"
+};
+
+static const struct soc_enum tegra210_mbdrc_mode_enum =
+ SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG, TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT,
+ 4, tegra210_mbdrc_mode_text);
+
+static const char * const tegra210_mbdrc_peak_rms_text[] = {
+ "Peak", "RMS"
+};
+
+static const struct soc_enum tegra210_mbdrc_peak_rms_enum =
+ SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG, TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT,
+ 2, tegra210_mbdrc_peak_rms_text);
+
+static const char * const tegra210_mbdrc_filter_structure_text[] = {
+ "All-pass-tree", "Flexible"
+};
+
+static const struct soc_enum tegra210_mbdrc_filter_structure_enum =
+ SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG,
+ TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT, 2,
+ tegra210_mbdrc_filter_structure_text);
+
+static const char * const tegra210_mbdrc_frame_size_text[] = {
+ "N1", "N2", "N4", "N8", "N16", "N32", "N64"
+};
+
+static const struct soc_enum tegra210_mbdrc_frame_size_enum =
+ SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG, TEGRA210_MBDRC_CFG_FRAME_SIZE_SHIFT,
+ 7, tegra210_mbdrc_frame_size_text);
+
+#define TEGRA_MBDRC_BYTES_EXT(xname, xbase, xregs, xshift, xmask, xinfo) \
+ TEGRA_SOC_BYTES_EXT(xname, xbase, xregs, xshift, xmask, \
+ tegra210_mbdrc_band_params_get, \
+ tegra210_mbdrc_band_params_put, \
+ tegra210_mbdrc_param_info)
+
+#define TEGRA_MBDRC_BAND_BYTES_EXT(xname, xbase, xshift, xmask, xinfo) \
+ TEGRA_MBDRC_BYTES_EXT(xname, xbase, TEGRA210_MBDRC_FILTER_COUNT, \
+ xshift, xmask, xinfo)
+
+static const DECLARE_TLV_DB_MINMAX(mdbrc_vol_tlv, -25600, 25500);
+
+static const struct snd_kcontrol_new tegra210_mbdrc_controls[] = {
+ SOC_ENUM_EXT("MBDRC Peak RMS Mode", tegra210_mbdrc_peak_rms_enum,
+ tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum),
+
+ SOC_ENUM_EXT("MBDRC Filter Structure",
+ tegra210_mbdrc_filter_structure_enum,
+ tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum),
+
+ SOC_ENUM_EXT("MBDRC Frame Size", tegra210_mbdrc_frame_size_enum,
+ tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum),
+
+ SOC_ENUM_EXT("MBDRC Mode", tegra210_mbdrc_mode_enum,
+ tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum),
+
+ SOC_SINGLE_EXT("MBDRC RMS Offset", TEGRA210_MBDRC_CFG,
+ TEGRA210_MBDRC_CFG_RMS_OFFSET_SHIFT, 0x1ff, 0,
+ tegra210_mbdrc_get, tegra210_mbdrc_put),
+
+ SOC_SINGLE_EXT("MBDRC Shift Control", TEGRA210_MBDRC_CFG,
+ TEGRA210_MBDRC_CFG_SHIFT_CTRL_SHIFT, 0x1f, 0,
+ tegra210_mbdrc_get, tegra210_mbdrc_put),
+
+ SOC_SINGLE_EXT("MBDRC Fast Attack Factor", TEGRA210_MBDRC_FAST_FACTOR,
+ TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT, 0xffff, 0,
+ tegra210_mbdrc_get, tegra210_mbdrc_put),
+
+ SOC_SINGLE_EXT("MBDRC Fast Release Factor", TEGRA210_MBDRC_FAST_FACTOR,
+ TEGRA210_MBDRC_FAST_FACTOR_RELEASE_SHIFT, 0xffff, 0,
+ tegra210_mbdrc_get, tegra210_mbdrc_put),
+
+ SOC_SINGLE_RANGE_EXT_TLV("MBDRC Master Volume",
+ TEGRA210_MBDRC_MASTER_VOL,
+ TEGRA210_MBDRC_MASTER_VOL_SHIFT,
+ 0, 0x1ff, 0,
+ tegra210_mbdrc_vol_get, tegra210_mbdrc_vol_put,
+ mdbrc_vol_tlv),
+
+ TEGRA_SOC_BYTES_EXT("MBDRC IIR Stages", TEGRA210_MBDRC_IIR_CFG,
+ TEGRA210_MBDRC_FILTER_COUNT,
+ TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_SHIFT,
+ TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_MASK,
+ tegra210_mbdrc_band_params_get,
+ tegra210_mbdrc_band_params_put,
+ tegra210_mbdrc_param_info),
+
+ TEGRA_SOC_BYTES_EXT("MBDRC In Attack Time Const", TEGRA210_MBDRC_IN_ATTACK,
+ TEGRA210_MBDRC_FILTER_COUNT,
+ TEGRA210_MBDRC_IN_ATTACK_TC_SHIFT,
+ TEGRA210_MBDRC_IN_ATTACK_TC_MASK,
+ tegra210_mbdrc_band_params_get,
+ tegra210_mbdrc_band_params_put,
+ tegra210_mbdrc_param_info),
+
+ TEGRA_SOC_BYTES_EXT("MBDRC In Release Time Const", TEGRA210_MBDRC_IN_RELEASE,
+ TEGRA210_MBDRC_FILTER_COUNT,
+ TEGRA210_MBDRC_IN_RELEASE_TC_SHIFT,
+ TEGRA210_MBDRC_IN_RELEASE_TC_MASK,
+ tegra210_mbdrc_band_params_get,
+ tegra210_mbdrc_band_params_put,
+ tegra210_mbdrc_param_info),
+
+ TEGRA_SOC_BYTES_EXT("MBDRC Fast Attack Time Const", TEGRA210_MBDRC_FAST_ATTACK,
+ TEGRA210_MBDRC_FILTER_COUNT,
+ TEGRA210_MBDRC_FAST_ATTACK_TC_SHIFT,
+ TEGRA210_MBDRC_FAST_ATTACK_TC_MASK,
+ tegra210_mbdrc_band_params_get,
+ tegra210_mbdrc_band_params_put,
+ tegra210_mbdrc_param_info),
+
+ TEGRA_SOC_BYTES_EXT("MBDRC In Threshold", TEGRA210_MBDRC_IN_THRESHOLD,
+ TEGRA210_MBDRC_FILTER_COUNT * 4, 0, 0xffffffff,
+ tegra210_mbdrc_threshold_get,
+ tegra210_mbdrc_threshold_put,
+ tegra210_mbdrc_param_info),
+
+ TEGRA_SOC_BYTES_EXT("MBDRC Out Threshold", TEGRA210_MBDRC_OUT_THRESHOLD,
+ TEGRA210_MBDRC_FILTER_COUNT * 4, 0, 0xffffffff,
+ tegra210_mbdrc_threshold_get,
+ tegra210_mbdrc_threshold_put,
+ tegra210_mbdrc_param_info),
+
+ TEGRA_SOC_BYTES_EXT("MBDRC Ratio", TEGRA210_MBDRC_RATIO_1ST,
+ TEGRA210_MBDRC_FILTER_COUNT * 5,
+ TEGRA210_MBDRC_RATIO_1ST_SHIFT, TEGRA210_MBDRC_RATIO_1ST_MASK,
+ tegra210_mbdrc_band_params_get,
+ tegra210_mbdrc_band_params_put,
+ tegra210_mbdrc_param_info),
+
+ TEGRA_SOC_BYTES_EXT("MBDRC Makeup Gain", TEGRA210_MBDRC_MAKEUP_GAIN,
+ TEGRA210_MBDRC_FILTER_COUNT,
+ TEGRA210_MBDRC_MAKEUP_GAIN_SHIFT,
+ TEGRA210_MBDRC_MAKEUP_GAIN_MASK,
+ tegra210_mbdrc_band_params_get,
+ tegra210_mbdrc_band_params_put,
+ tegra210_mbdrc_param_info),
+
+ TEGRA_SOC_BYTES_EXT("MBDRC Init Gain", TEGRA210_MBDRC_INIT_GAIN,
+ TEGRA210_MBDRC_FILTER_COUNT,
+ TEGRA210_MBDRC_INIT_GAIN_SHIFT,
+ TEGRA210_MBDRC_INIT_GAIN_MASK,
+ tegra210_mbdrc_band_params_get,
+ tegra210_mbdrc_band_params_put,
+ tegra210_mbdrc_param_info),
+
+ TEGRA_SOC_BYTES_EXT("MBDRC Attack Gain", TEGRA210_MBDRC_GAIN_ATTACK,
+ TEGRA210_MBDRC_FILTER_COUNT,
+ TEGRA210_MBDRC_GAIN_ATTACK_SHIFT,
+ TEGRA210_MBDRC_GAIN_ATTACK_MASK,
+ tegra210_mbdrc_band_params_get,
+ tegra210_mbdrc_band_params_put,
+ tegra210_mbdrc_param_info),
+
+ TEGRA_SOC_BYTES_EXT("MBDRC Release Gain", TEGRA210_MBDRC_GAIN_RELEASE,
+ TEGRA210_MBDRC_FILTER_COUNT,
+ TEGRA210_MBDRC_GAIN_RELEASE_SHIFT,
+ TEGRA210_MBDRC_GAIN_RELEASE_MASK,
+ tegra210_mbdrc_band_params_get,
+ tegra210_mbdrc_band_params_put,
+ tegra210_mbdrc_param_info),
+
+ TEGRA_SOC_BYTES_EXT("MBDRC Fast Release Gain",
+ TEGRA210_MBDRC_FAST_RELEASE,
+ TEGRA210_MBDRC_FILTER_COUNT,
+ TEGRA210_MBDRC_FAST_RELEASE_SHIFT,
+ TEGRA210_MBDRC_FAST_RELEASE_MASK,
+ tegra210_mbdrc_band_params_get,
+ tegra210_mbdrc_band_params_put,
+ tegra210_mbdrc_param_info),
+
+ TEGRA_SOC_BYTES_EXT("MBDRC Low Band Biquad Coeffs",
+ TEGRA210_MBDRC_CFG_RAM_CTRL,
+ TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5, 0, 0xffffffff,
+ tegra210_mbdrc_biquad_coeffs_get,
+ tegra210_mbdrc_biquad_coeffs_put,
+ tegra210_mbdrc_param_info),
+
+ TEGRA_SOC_BYTES_EXT("MBDRC Mid Band Biquad Coeffs",
+ TEGRA210_MBDRC_CFG_RAM_CTRL +
+ TEGRA210_MBDRC_FILTER_PARAM_STRIDE,
+ TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5, 0, 0xffffffff,
+ tegra210_mbdrc_biquad_coeffs_get,
+ tegra210_mbdrc_biquad_coeffs_put,
+ tegra210_mbdrc_param_info),
+
+ TEGRA_SOC_BYTES_EXT("MBDRC High Band Biquad Coeffs",
+ TEGRA210_MBDRC_CFG_RAM_CTRL +
+ (TEGRA210_MBDRC_FILTER_PARAM_STRIDE * 2),
+ TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5, 0, 0xffffffff,
+ tegra210_mbdrc_biquad_coeffs_get,
+ tegra210_mbdrc_biquad_coeffs_put,
+ tegra210_mbdrc_param_info),
+};
+
+static bool tegra210_mbdrc_wr_reg(struct device *dev, unsigned int reg)
+{
+ if (reg >= TEGRA210_MBDRC_IIR_CFG)
+ reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) %
+ (TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
+ TEGRA210_MBDRC_FILTER_COUNT));
+
+ switch (reg) {
+ case TEGRA210_MBDRC_SOFT_RESET:
+ case TEGRA210_MBDRC_CG:
+ case TEGRA210_MBDRC_CFG ... TEGRA210_MBDRC_CFG_RAM_DATA:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool tegra210_mbdrc_rd_reg(struct device *dev, unsigned int reg)
+{
+ if (tegra210_mbdrc_wr_reg(dev, reg))
+ return true;
+
+ if (reg >= TEGRA210_MBDRC_IIR_CFG)
+ reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) %
+ (TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
+ TEGRA210_MBDRC_FILTER_COUNT));
+
+ switch (reg) {
+ case TEGRA210_MBDRC_STATUS:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool tegra210_mbdrc_volatile_reg(struct device *dev, unsigned int reg)
+{
+ if (reg >= TEGRA210_MBDRC_IIR_CFG)
+ reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) %
+ (TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
+ TEGRA210_MBDRC_FILTER_COUNT));
+
+ switch (reg) {
+ case TEGRA210_MBDRC_SOFT_RESET:
+ case TEGRA210_MBDRC_STATUS:
+ case TEGRA210_MBDRC_CFG_RAM_CTRL:
+ case TEGRA210_MBDRC_CFG_RAM_DATA:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool tegra210_mbdrc_precious_reg(struct device *dev, unsigned int reg)
+{
+ if (reg >= TEGRA210_MBDRC_IIR_CFG)
+ reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) %
+ (TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
+ TEGRA210_MBDRC_FILTER_COUNT));
+
+ switch (reg) {
+ case TEGRA210_MBDRC_CFG_RAM_DATA:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config tegra210_mbdrc_regmap_cfg = {
+ .name = "mbdrc",
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = TEGRA210_MBDRC_MAX_REG,
+ .writeable_reg = tegra210_mbdrc_wr_reg,
+ .readable_reg = tegra210_mbdrc_rd_reg,
+ .volatile_reg = tegra210_mbdrc_volatile_reg,
+ .precious_reg = tegra210_mbdrc_precious_reg,
+ .reg_defaults = tegra210_mbdrc_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(tegra210_mbdrc_reg_defaults),
+ .cache_type = REGCACHE_FLAT,
+};
+
+int tegra210_mbdrc_hw_params(struct snd_soc_component *cmpnt)
+{
+ struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+ const struct tegra210_mbdrc_config *conf = &mbdrc_init_config;
+ u32 val = 0;
+ unsigned int i;
+
+ regmap_read(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG, &val);
+
+ if (val & TEGRA210_MBDRC_CFG_MBDRC_MODE_BYPASS)
+ return 0;
+
+ for (i = 0; i < MBDRC_NUM_BAND; i++) {
+ const struct tegra210_mbdrc_band_params *params =
+ &conf->band_params[i];
+
+ u32 reg_off = i * TEGRA210_MBDRC_FILTER_PARAM_STRIDE;
+
+ tegra210_mbdrc_write_ram(ope->mbdrc_regmap,
+ reg_off + TEGRA210_MBDRC_CFG_RAM_CTRL,
+ reg_off + TEGRA210_MBDRC_CFG_RAM_DATA,
+ 0, (u32 *)¶ms->biquad_params[0],
+ TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5);
+ }
+ return 0;
+}
+
+int tegra210_mbdrc_component_init(struct snd_soc_component *cmpnt)
+{
+ struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+ const struct tegra210_mbdrc_config *conf = &mbdrc_init_config;
+ unsigned int i;
+ u32 val;
+
+ pm_runtime_get_sync(cmpnt->dev);
+
+ /* Initialize MBDRC registers and AHUB RAM with default params */
+ regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+ TEGRA210_MBDRC_CFG_MBDRC_MODE_MASK,
+ conf->mode << TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT);
+
+ regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+ TEGRA210_MBDRC_CFG_RMS_OFFSET_MASK,
+ conf->rms_off << TEGRA210_MBDRC_CFG_RMS_OFFSET_SHIFT);
+
+ regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+ TEGRA210_MBDRC_CFG_PEAK_RMS_MASK,
+ conf->peak_rms_mode << TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT);
+
+ regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+ TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_MASK,
+ conf->fliter_structure <<
+ TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT);
+
+ regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+ TEGRA210_MBDRC_CFG_SHIFT_CTRL_MASK,
+ conf->shift_ctrl << TEGRA210_MBDRC_CFG_SHIFT_CTRL_SHIFT);
+
+ regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+ TEGRA210_MBDRC_CFG_FRAME_SIZE_MASK,
+ __ffs(conf->frame_size) <<
+ TEGRA210_MBDRC_CFG_FRAME_SIZE_SHIFT);
+
+ regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CHANNEL_MASK,
+ TEGRA210_MBDRC_CHANNEL_MASK_MASK,
+ conf->channel_mask << TEGRA210_MBDRC_CHANNEL_MASK_SHIFT);
+
+ regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_FAST_FACTOR,
+ TEGRA210_MBDRC_FAST_FACTOR_ATTACK_MASK,
+ conf->fa_factor << TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT);
+
+ regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_FAST_FACTOR,
+ TEGRA210_MBDRC_FAST_FACTOR_ATTACK_MASK,
+ conf->fr_factor << TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT);
+
+ for (i = 0; i < MBDRC_NUM_BAND; i++) {
+ const struct tegra210_mbdrc_band_params *params =
+ &conf->band_params[i];
+ u32 reg_off = i * TEGRA210_MBDRC_FILTER_PARAM_STRIDE;
+
+ regmap_update_bits(ope->mbdrc_regmap,
+ reg_off + TEGRA210_MBDRC_IIR_CFG,
+ TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_MASK,
+ params->iir_stages <<
+ TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_SHIFT);
+
+ regmap_update_bits(ope->mbdrc_regmap,
+ reg_off + TEGRA210_MBDRC_IN_ATTACK,
+ TEGRA210_MBDRC_IN_ATTACK_TC_MASK,
+ params->in_attack_tc <<
+ TEGRA210_MBDRC_IN_ATTACK_TC_SHIFT);
+
+ regmap_update_bits(ope->mbdrc_regmap,
+ reg_off + TEGRA210_MBDRC_IN_RELEASE,
+ TEGRA210_MBDRC_IN_RELEASE_TC_MASK,
+ params->in_release_tc <<
+ TEGRA210_MBDRC_IN_RELEASE_TC_SHIFT);
+
+ regmap_update_bits(ope->mbdrc_regmap,
+ reg_off + TEGRA210_MBDRC_FAST_ATTACK,
+ TEGRA210_MBDRC_FAST_ATTACK_TC_MASK,
+ params->fast_attack_tc <<
+ TEGRA210_MBDRC_FAST_ATTACK_TC_SHIFT);
+
+ val = (((params->in_threshold[0] >>
+ TEGRA210_MBDRC_THRESH_1ST_SHIFT) &
+ TEGRA210_MBDRC_THRESH_1ST_MASK) |
+ ((params->in_threshold[1] >>
+ TEGRA210_MBDRC_THRESH_2ND_SHIFT) &
+ TEGRA210_MBDRC_THRESH_2ND_MASK) |
+ ((params->in_threshold[2] >>
+ TEGRA210_MBDRC_THRESH_3RD_SHIFT) &
+ TEGRA210_MBDRC_THRESH_3RD_MASK) |
+ ((params->in_threshold[3] >>
+ TEGRA210_MBDRC_THRESH_4TH_SHIFT) &
+ TEGRA210_MBDRC_THRESH_4TH_MASK));
+
+ regmap_update_bits(ope->mbdrc_regmap,
+ reg_off + TEGRA210_MBDRC_IN_THRESHOLD,
+ 0xffffffff, val);
+
+ val = (((params->out_threshold[0] >>
+ TEGRA210_MBDRC_THRESH_1ST_SHIFT) &
+ TEGRA210_MBDRC_THRESH_1ST_MASK) |
+ ((params->out_threshold[1] >>
+ TEGRA210_MBDRC_THRESH_2ND_SHIFT) &
+ TEGRA210_MBDRC_THRESH_2ND_MASK) |
+ ((params->out_threshold[2] >>
+ TEGRA210_MBDRC_THRESH_3RD_SHIFT) &
+ TEGRA210_MBDRC_THRESH_3RD_MASK) |
+ ((params->out_threshold[3] >>
+ TEGRA210_MBDRC_THRESH_4TH_SHIFT) &
+ TEGRA210_MBDRC_THRESH_4TH_MASK));
+
+ regmap_update_bits(ope->mbdrc_regmap,
+ reg_off + TEGRA210_MBDRC_OUT_THRESHOLD,
+ 0xffffffff, val);
+
+ regmap_update_bits(ope->mbdrc_regmap,
+ reg_off + TEGRA210_MBDRC_RATIO_1ST,
+ TEGRA210_MBDRC_RATIO_1ST_MASK,
+ params->ratio[0] << TEGRA210_MBDRC_RATIO_1ST_SHIFT);
+
+ regmap_update_bits(ope->mbdrc_regmap,
+ reg_off + TEGRA210_MBDRC_RATIO_2ND,
+ TEGRA210_MBDRC_RATIO_2ND_MASK,
+ params->ratio[1] << TEGRA210_MBDRC_RATIO_2ND_SHIFT);
+
+ regmap_update_bits(ope->mbdrc_regmap,
+ reg_off + TEGRA210_MBDRC_RATIO_3RD,
+ TEGRA210_MBDRC_RATIO_3RD_MASK,
+ params->ratio[2] << TEGRA210_MBDRC_RATIO_3RD_SHIFT);
+
+ regmap_update_bits(ope->mbdrc_regmap,
+ reg_off + TEGRA210_MBDRC_RATIO_4TH,
+ TEGRA210_MBDRC_RATIO_4TH_MASK,
+ params->ratio[3] << TEGRA210_MBDRC_RATIO_4TH_SHIFT);
+
+ regmap_update_bits(ope->mbdrc_regmap,
+ reg_off + TEGRA210_MBDRC_RATIO_5TH,
+ TEGRA210_MBDRC_RATIO_5TH_MASK,
+ params->ratio[4] << TEGRA210_MBDRC_RATIO_5TH_SHIFT);
+
+ regmap_update_bits(ope->mbdrc_regmap,
+ reg_off + TEGRA210_MBDRC_MAKEUP_GAIN,
+ TEGRA210_MBDRC_MAKEUP_GAIN_MASK,
+ params->makeup_gain <<
+ TEGRA210_MBDRC_MAKEUP_GAIN_SHIFT);
+
+ regmap_update_bits(ope->mbdrc_regmap,
+ reg_off + TEGRA210_MBDRC_INIT_GAIN,
+ TEGRA210_MBDRC_INIT_GAIN_MASK,
+ params->gain_init <<
+ TEGRA210_MBDRC_INIT_GAIN_SHIFT);
+
+ regmap_update_bits(ope->mbdrc_regmap,
+ reg_off + TEGRA210_MBDRC_GAIN_ATTACK,
+ TEGRA210_MBDRC_GAIN_ATTACK_MASK,
+ params->gain_attack_tc <<
+ TEGRA210_MBDRC_GAIN_ATTACK_SHIFT);
+
+ regmap_update_bits(ope->mbdrc_regmap,
+ reg_off + TEGRA210_MBDRC_GAIN_RELEASE,
+ TEGRA210_MBDRC_GAIN_RELEASE_MASK,
+ params->gain_release_tc <<
+ TEGRA210_MBDRC_GAIN_RELEASE_SHIFT);
+
+ regmap_update_bits(ope->mbdrc_regmap,
+ reg_off + TEGRA210_MBDRC_FAST_RELEASE,
+ TEGRA210_MBDRC_FAST_RELEASE_MASK,
+ params->fast_release_tc <<
+ TEGRA210_MBDRC_FAST_RELEASE_SHIFT);
+
+ tegra210_mbdrc_write_ram(ope->mbdrc_regmap,
+ reg_off + TEGRA210_MBDRC_CFG_RAM_CTRL,
+ reg_off + TEGRA210_MBDRC_CFG_RAM_DATA, 0,
+ (u32 *)¶ms->biquad_params[0],
+ TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5);
+ }
+
+ pm_runtime_put_sync(cmpnt->dev);
+
+ snd_soc_add_component_controls(cmpnt, tegra210_mbdrc_controls,
+ ARRAY_SIZE(tegra210_mbdrc_controls));
+
+ return 0;
+}
+
+int tegra210_mbdrc_regmap_init(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct tegra210_ope *ope = dev_get_drvdata(dev);
+ struct device_node *child;
+ struct resource mem;
+ void __iomem *regs;
+ int err;
+
+ child = of_get_child_by_name(dev->of_node, "dynamic-range-compressor");
+ if (!child)
+ return -ENODEV;
+
+ err = of_address_to_resource(child, 0, &mem);
+ of_node_put(child);
+ if (err < 0) {
+ dev_err(dev, "fail to get MBDRC resource\n");
+ return err;
+ }
+
+ mem.flags = IORESOURCE_MEM;
+ regs = devm_ioremap_resource(dev, &mem);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ ope->mbdrc_regmap = devm_regmap_init_mmio(dev, regs,
+ &tegra210_mbdrc_regmap_cfg);
+ if (IS_ERR(ope->mbdrc_regmap)) {
+ dev_err(dev, "regmap init failed\n");
+ return PTR_ERR(ope->mbdrc_regmap);
+ }
+
+ regcache_cache_only(ope->mbdrc_regmap, true);
+
+ return 0;
+}
diff --git a/sound/soc/tegra/tegra210_mbdrc.h b/sound/soc/tegra/tegra210_mbdrc.h
new file mode 100644
index 0000000..4c48da0
--- /dev/null
+++ b/sound/soc/tegra/tegra210_mbdrc.h
@@ -0,0 +1,215 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_mbdrc.h - Definitions for Tegra210 MBDRC driver
+ *
+ * Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA210_MBDRC_H__
+#define __TEGRA210_MBDRC_H__
+
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+
+/* Register offsets from TEGRA210_MBDRC*_BASE */
+#define TEGRA210_MBDRC_SOFT_RESET 0x4
+#define TEGRA210_MBDRC_CG 0x8
+#define TEGRA210_MBDRC_STATUS 0xc
+#define TEGRA210_MBDRC_CFG 0x28
+#define TEGRA210_MBDRC_CHANNEL_MASK 0x2c
+#define TEGRA210_MBDRC_MASTER_VOL 0x30
+#define TEGRA210_MBDRC_FAST_FACTOR 0x34
+
+#define TEGRA210_MBDRC_FILTER_COUNT 3
+#define TEGRA210_MBDRC_FILTER_PARAM_STRIDE 0x4
+
+#define TEGRA210_MBDRC_IIR_CFG 0x38
+#define TEGRA210_MBDRC_IN_ATTACK 0x44
+#define TEGRA210_MBDRC_IN_RELEASE 0x50
+#define TEGRA210_MBDRC_FAST_ATTACK 0x5c
+#define TEGRA210_MBDRC_IN_THRESHOLD 0x68
+#define TEGRA210_MBDRC_OUT_THRESHOLD 0x74
+#define TEGRA210_MBDRC_RATIO_1ST 0x80
+#define TEGRA210_MBDRC_RATIO_2ND 0x8c
+#define TEGRA210_MBDRC_RATIO_3RD 0x98
+#define TEGRA210_MBDRC_RATIO_4TH 0xa4
+#define TEGRA210_MBDRC_RATIO_5TH 0xb0
+#define TEGRA210_MBDRC_MAKEUP_GAIN 0xbc
+#define TEGRA210_MBDRC_INIT_GAIN 0xc8
+#define TEGRA210_MBDRC_GAIN_ATTACK 0xd4
+#define TEGRA210_MBDRC_GAIN_RELEASE 0xe0
+#define TEGRA210_MBDRC_FAST_RELEASE 0xec
+#define TEGRA210_MBDRC_CFG_RAM_CTRL 0xf8
+#define TEGRA210_MBDRC_CFG_RAM_DATA 0x104
+
+#define TEGRA210_MBDRC_MAX_REG (TEGRA210_MBDRC_CFG_RAM_DATA + \
+ (TEGRA210_MBDRC_FILTER_PARAM_STRIDE * \
+ (TEGRA210_MBDRC_FILTER_COUNT - 1)))
+
+/* Fields for TEGRA210_MBDRC_CFG */
+#define TEGRA210_MBDRC_CFG_RMS_OFFSET_SHIFT 16
+#define TEGRA210_MBDRC_CFG_RMS_OFFSET_MASK (0x1ff << TEGRA210_MBDRC_CFG_RMS_OFFSET_SHIFT)
+
+#define TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT 14
+#define TEGRA210_MBDRC_CFG_PEAK_RMS_MASK (0x1 << TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT)
+#define TEGRA210_MBDRC_CFG_PEAK (1 << TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT)
+
+#define TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT 13
+#define TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_MASK (0x1 << TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT)
+#define TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_FLEX (1 << TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT)
+
+#define TEGRA210_MBDRC_CFG_SHIFT_CTRL_SHIFT 8
+#define TEGRA210_MBDRC_CFG_SHIFT_CTRL_MASK (0x1f << TEGRA210_MBDRC_CFG_SHIFT_CTRL_SHIFT)
+
+#define TEGRA210_MBDRC_CFG_FRAME_SIZE_SHIFT 4
+#define TEGRA210_MBDRC_CFG_FRAME_SIZE_MASK (0xf << TEGRA210_MBDRC_CFG_FRAME_SIZE_SHIFT)
+
+#define TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT 0
+#define TEGRA210_MBDRC_CFG_MBDRC_MODE_MASK (0x3 << TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT)
+#define TEGRA210_MBDRC_CFG_MBDRC_MODE_BYPASS (0 << TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_CHANNEL_MASK */
+#define TEGRA210_MBDRC_CHANNEL_MASK_SHIFT 0
+#define TEGRA210_MBDRC_CHANNEL_MASK_MASK (0xff << TEGRA210_MBDRC_CHANNEL_MASK_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_MASTER_VOL */
+#define TEGRA210_MBDRC_MASTER_VOL_SHIFT 23
+#define TEGRA210_MBDRC_MASTER_VOL_MIN -256
+#define TEGRA210_MBDRC_MASTER_VOL_MAX 256
+
+/* Fields for TEGRA210_MBDRC_FAST_FACTOR */
+#define TEGRA210_MBDRC_FAST_FACTOR_RELEASE_SHIFT 16
+#define TEGRA210_MBDRC_FAST_FACTOR_RELEASE_MASK (0xffff << TEGRA210_MBDRC_FAST_FACTOR_RELEASE_SHIFT)
+
+#define TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT 0
+#define TEGRA210_MBDRC_FAST_FACTOR_ATTACK_MASK (0xffff << TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_IIR_CFG */
+#define TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_SHIFT 0
+#define TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_MASK (0xf << TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_IN_ATTACK */
+#define TEGRA210_MBDRC_IN_ATTACK_TC_SHIFT 0
+#define TEGRA210_MBDRC_IN_ATTACK_TC_MASK (0xffffffff << TEGRA210_MBDRC_IN_ATTACK_TC_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_IN_RELEASE */
+#define TEGRA210_MBDRC_IN_RELEASE_TC_SHIFT 0
+#define TEGRA210_MBDRC_IN_RELEASE_TC_MASK (0xffffffff << TEGRA210_MBDRC_IN_RELEASE_TC_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_FAST_ATTACK */
+#define TEGRA210_MBDRC_FAST_ATTACK_TC_SHIFT 0
+#define TEGRA210_MBDRC_FAST_ATTACK_TC_MASK (0xffffffff << TEGRA210_MBDRC_FAST_ATTACK_TC_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_IN_THRESHOLD / TEGRA210_MBDRC_OUT_THRESHOLD */
+#define TEGRA210_MBDRC_THRESH_4TH_SHIFT 24
+#define TEGRA210_MBDRC_THRESH_4TH_MASK (0xff << TEGRA210_MBDRC_THRESH_4TH_SHIFT)
+
+#define TEGRA210_MBDRC_THRESH_3RD_SHIFT 16
+#define TEGRA210_MBDRC_THRESH_3RD_MASK (0xff << TEGRA210_MBDRC_THRESH_3RD_SHIFT)
+
+#define TEGRA210_MBDRC_THRESH_2ND_SHIFT 8
+#define TEGRA210_MBDRC_THRESH_2ND_MASK (0xff << TEGRA210_MBDRC_THRESH_2ND_SHIFT)
+
+#define TEGRA210_MBDRC_THRESH_1ST_SHIFT 0
+#define TEGRA210_MBDRC_THRESH_1ST_MASK (0xff << TEGRA210_MBDRC_THRESH_1ST_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_RATIO_1ST */
+#define TEGRA210_MBDRC_RATIO_1ST_SHIFT 0
+#define TEGRA210_MBDRC_RATIO_1ST_MASK (0xffff << TEGRA210_MBDRC_RATIO_1ST_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_RATIO_2ND */
+#define TEGRA210_MBDRC_RATIO_2ND_SHIFT 0
+#define TEGRA210_MBDRC_RATIO_2ND_MASK (0xffff << TEGRA210_MBDRC_RATIO_2ND_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_RATIO_3RD */
+#define TEGRA210_MBDRC_RATIO_3RD_SHIFT 0
+#define TEGRA210_MBDRC_RATIO_3RD_MASK (0xffff << TEGRA210_MBDRC_RATIO_3RD_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_RATIO_4TH */
+#define TEGRA210_MBDRC_RATIO_4TH_SHIFT 0
+#define TEGRA210_MBDRC_RATIO_4TH_MASK (0xffff << TEGRA210_MBDRC_RATIO_4TH_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_RATIO_5TH */
+#define TEGRA210_MBDRC_RATIO_5TH_SHIFT 0
+#define TEGRA210_MBDRC_RATIO_5TH_MASK (0xffff << TEGRA210_MBDRC_RATIO_5TH_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_MAKEUP_GAIN */
+#define TEGRA210_MBDRC_MAKEUP_GAIN_SHIFT 0
+#define TEGRA210_MBDRC_MAKEUP_GAIN_MASK (0x3f << TEGRA210_MBDRC_MAKEUP_GAIN_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_INIT_GAIN */
+#define TEGRA210_MBDRC_INIT_GAIN_SHIFT 0
+#define TEGRA210_MBDRC_INIT_GAIN_MASK (0xffffffff << TEGRA210_MBDRC_INIT_GAIN_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_GAIN_ATTACK */
+#define TEGRA210_MBDRC_GAIN_ATTACK_SHIFT 0
+#define TEGRA210_MBDRC_GAIN_ATTACK_MASK (0xffffffff << TEGRA210_MBDRC_GAIN_ATTACK_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_GAIN_RELEASE */
+#define TEGRA210_MBDRC_GAIN_RELEASE_SHIFT 0
+#define TEGRA210_MBDRC_GAIN_RELEASE_MASK (0xffffffff << TEGRA210_MBDRC_GAIN_RELEASE_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_FAST_RELEASE */
+#define TEGRA210_MBDRC_FAST_RELEASE_SHIFT 0
+#define TEGRA210_MBDRC_FAST_RELEASE_MASK (0xffffffff << TEGRA210_MBDRC_FAST_RELEASE_SHIFT)
+
+#define TEGRA210_MBDRC_RAM_CTRL_RW_READ 0
+#define TEGRA210_MBDRC_RAM_CTRL_RW_WRITE (1 << 14)
+#define TEGRA210_MBDRC_RAM_CTRL_ADDR_INIT_EN (1 << 13)
+#define TEGRA210_MBDRC_RAM_CTRL_SEQ_ACCESS_EN (1 << 12)
+#define TEGRA210_MBDRC_RAM_CTRL_RAM_ADDR_MASK 0x1ff
+
+/*
+ * Order and size of each structure element for following structures should not
+ * be altered size order of elements and their size are based on PEQ co-eff ram
+ * and shift ram layout.
+ */
+#define TEGRA210_MBDRC_THRESHOLD_NUM 4
+#define TEGRA210_MBDRC_RATIO_NUM (TEGRA210_MBDRC_THRESHOLD_NUM + 1)
+#define TEGRA210_MBDRC_MAX_BIQUAD_STAGES 8
+
+/* Order of these enums are same as the order of band specific hw registers */
+enum {
+ MBDRC_LOW_BAND,
+ MBDRC_MID_BAND,
+ MBDRC_HIGH_BAND,
+ MBDRC_NUM_BAND,
+};
+
+struct tegra210_mbdrc_band_params {
+ u32 band;
+ u32 iir_stages;
+ u32 in_attack_tc;
+ u32 in_release_tc;
+ u32 fast_attack_tc;
+ u32 in_threshold[TEGRA210_MBDRC_THRESHOLD_NUM];
+ u32 out_threshold[TEGRA210_MBDRC_THRESHOLD_NUM];
+ u32 ratio[TEGRA210_MBDRC_RATIO_NUM];
+ u32 makeup_gain;
+ u32 gain_init;
+ u32 gain_attack_tc;
+ u32 gain_release_tc;
+ u32 fast_release_tc;
+ /* For biquad_params[][5] order of coeff is b0, b1, a0, a1, a2 */
+ u32 biquad_params[TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5];
+};
+
+struct tegra210_mbdrc_config {
+ unsigned int mode;
+ unsigned int rms_off;
+ unsigned int peak_rms_mode;
+ unsigned int fliter_structure;
+ unsigned int shift_ctrl;
+ unsigned int frame_size;
+ unsigned int channel_mask;
+ unsigned int fa_factor; /* Fast attack factor */
+ unsigned int fr_factor; /* Fast release factor */
+ struct tegra210_mbdrc_band_params band_params[MBDRC_NUM_BAND];
+};
+
+int tegra210_mbdrc_regmap_init(struct platform_device *pdev);
+int tegra210_mbdrc_component_init(struct snd_soc_component *cmpnt);
+int tegra210_mbdrc_hw_params(struct snd_soc_component *cmpnt);
+
+#endif
diff --git a/sound/soc/tegra/tegra210_ope.c b/sound/soc/tegra/tegra210_ope.c
new file mode 100644
index 0000000..3dd2bde
--- /dev/null
+++ b/sound/soc/tegra/tegra210_ope.c
@@ -0,0 +1,419 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra210_ope.c - Tegra210 OPE driver
+//
+// Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra210_mbdrc.h"
+#include "tegra210_ope.h"
+#include "tegra210_peq.h"
+#include "tegra_cif.h"
+
+static const struct reg_default tegra210_ope_reg_defaults[] = {
+ { TEGRA210_OPE_RX_INT_MASK, 0x00000001},
+ { TEGRA210_OPE_RX_CIF_CTRL, 0x00007700},
+ { TEGRA210_OPE_TX_INT_MASK, 0x00000001},
+ { TEGRA210_OPE_TX_CIF_CTRL, 0x00007700},
+ { TEGRA210_OPE_CG, 0x1},
+};
+
+static int tegra210_ope_set_audio_cif(struct tegra210_ope *ope,
+ struct snd_pcm_hw_params *params,
+ unsigned int reg)
+{
+ int channels, audio_bits;
+ struct tegra_cif_conf cif_conf;
+
+ memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
+
+ channels = params_channels(params);
+ if (channels < 2)
+ return -EINVAL;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ audio_bits = TEGRA_ACIF_BITS_16;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ audio_bits = TEGRA_ACIF_BITS_32;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ cif_conf.audio_ch = channels;
+ cif_conf.client_ch = channels;
+ cif_conf.audio_bits = audio_bits;
+ cif_conf.client_bits = audio_bits;
+
+ tegra_set_cif(ope->regmap, reg, &cif_conf);
+
+ return 0;
+}
+
+static int tegra210_ope_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct device *dev = dai->dev;
+ struct tegra210_ope *ope = snd_soc_dai_get_drvdata(dai);
+ int err;
+
+ /* Set RX and TX CIF */
+ err = tegra210_ope_set_audio_cif(ope, params,
+ TEGRA210_OPE_RX_CIF_CTRL);
+ if (err) {
+ dev_err(dev, "Can't set OPE RX CIF: %d\n", err);
+ return err;
+ }
+
+ err = tegra210_ope_set_audio_cif(ope, params,
+ TEGRA210_OPE_TX_CIF_CTRL);
+ if (err) {
+ dev_err(dev, "Can't set OPE TX CIF: %d\n", err);
+ return err;
+ }
+
+ tegra210_mbdrc_hw_params(dai->component);
+
+ return err;
+}
+
+static int tegra210_ope_component_probe(struct snd_soc_component *cmpnt)
+{
+ struct tegra210_ope *ope = dev_get_drvdata(cmpnt->dev);
+
+ tegra210_peq_component_init(cmpnt);
+ tegra210_mbdrc_component_init(cmpnt);
+
+ /*
+ * The OPE, PEQ and MBDRC functionalities are combined under one
+ * device registered by OPE driver. In fact OPE HW block includes
+ * sub blocks PEQ and MBDRC. However driver registers separate
+ * regmap interfaces for each of these. ASoC core depends on
+ * dev_get_regmap() to populate the regmap field for a given ASoC
+ * component. A component can have one regmap reference and since
+ * the DAPM routes depend on OPE regmap only, below explicit
+ * assignment is done to highlight this. This is needed for ASoC
+ * core to access correct regmap during DAPM path setup.
+ */
+ snd_soc_component_init_regmap(cmpnt, ope->regmap);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops tegra210_ope_dai_ops = {
+ .hw_params = tegra210_ope_hw_params,
+};
+
+static struct snd_soc_dai_driver tegra210_ope_dais[] = {
+ {
+ .name = "OPE-RX-CIF",
+ .playback = {
+ .stream_name = "RX-CIF-Playback",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .capture = {
+ .stream_name = "RX-CIF-Capture",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ },
+ {
+ .name = "OPE-TX-CIF",
+ .playback = {
+ .stream_name = "TX-CIF-Playback",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .capture = {
+ .stream_name = "TX-CIF-Capture",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &tegra210_ope_dai_ops,
+ }
+};
+
+static const struct snd_soc_dapm_widget tegra210_ope_widgets[] = {
+ SND_SOC_DAPM_AIF_IN("RX", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TX", NULL, 0, TEGRA210_OPE_ENABLE,
+ TEGRA210_OPE_EN_SHIFT, 0),
+};
+
+#define OPE_ROUTES(sname) \
+ { "RX XBAR-" sname, NULL, "XBAR-TX" }, \
+ { "RX-CIF-" sname, NULL, "RX XBAR-" sname }, \
+ { "RX", NULL, "RX-CIF-" sname }, \
+ { "TX-CIF-" sname, NULL, "TX" }, \
+ { "TX XBAR-" sname, NULL, "TX-CIF-" sname }, \
+ { "XBAR-RX", NULL, "TX XBAR-" sname }
+
+static const struct snd_soc_dapm_route tegra210_ope_routes[] = {
+ { "TX", NULL, "RX" },
+ OPE_ROUTES("Playback"),
+ OPE_ROUTES("Capture"),
+};
+
+static const char * const tegra210_ope_data_dir_text[] = {
+ "MBDRC to PEQ",
+ "PEQ to MBDRC"
+};
+
+static const struct soc_enum tegra210_ope_data_dir_enum =
+ SOC_ENUM_SINGLE(TEGRA210_OPE_DIR, TEGRA210_OPE_DIR_SHIFT,
+ 2, tegra210_ope_data_dir_text);
+
+static int tegra210_ope_get_data_dir(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+
+ ucontrol->value.enumerated.item[0] = ope->data_dir;
+
+ return 0;
+}
+
+static int tegra210_ope_put_data_dir(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+ unsigned int value = ucontrol->value.enumerated.item[0];
+
+ if (value == ope->data_dir)
+ return 0;
+
+ ope->data_dir = value;
+
+ return 1;
+}
+
+static const struct snd_kcontrol_new tegra210_ope_controls[] = {
+ SOC_ENUM_EXT("Data Flow Direction", tegra210_ope_data_dir_enum,
+ tegra210_ope_get_data_dir, tegra210_ope_put_data_dir),
+};
+
+static const struct snd_soc_component_driver tegra210_ope_cmpnt = {
+ .probe = tegra210_ope_component_probe,
+ .dapm_widgets = tegra210_ope_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(tegra210_ope_widgets),
+ .dapm_routes = tegra210_ope_routes,
+ .num_dapm_routes = ARRAY_SIZE(tegra210_ope_routes),
+ .controls = tegra210_ope_controls,
+ .num_controls = ARRAY_SIZE(tegra210_ope_controls),
+};
+
+static bool tegra210_ope_wr_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TEGRA210_OPE_RX_INT_MASK ... TEGRA210_OPE_RX_CIF_CTRL:
+ case TEGRA210_OPE_TX_INT_MASK ... TEGRA210_OPE_TX_CIF_CTRL:
+ case TEGRA210_OPE_ENABLE ... TEGRA210_OPE_CG:
+ case TEGRA210_OPE_DIR:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool tegra210_ope_rd_reg(struct device *dev, unsigned int reg)
+{
+ if (tegra210_ope_wr_reg(dev, reg))
+ return true;
+
+ switch (reg) {
+ case TEGRA210_OPE_RX_STATUS:
+ case TEGRA210_OPE_RX_INT_STATUS:
+ case TEGRA210_OPE_TX_STATUS:
+ case TEGRA210_OPE_TX_INT_STATUS:
+ case TEGRA210_OPE_STATUS:
+ case TEGRA210_OPE_INT_STATUS:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool tegra210_ope_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TEGRA210_OPE_RX_STATUS:
+ case TEGRA210_OPE_RX_INT_STATUS:
+ case TEGRA210_OPE_TX_STATUS:
+ case TEGRA210_OPE_TX_INT_STATUS:
+ case TEGRA210_OPE_SOFT_RESET:
+ case TEGRA210_OPE_STATUS:
+ case TEGRA210_OPE_INT_STATUS:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config tegra210_ope_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = TEGRA210_OPE_DIR,
+ .writeable_reg = tegra210_ope_wr_reg,
+ .readable_reg = tegra210_ope_rd_reg,
+ .volatile_reg = tegra210_ope_volatile_reg,
+ .reg_defaults = tegra210_ope_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(tegra210_ope_reg_defaults),
+ .cache_type = REGCACHE_FLAT,
+};
+
+static int tegra210_ope_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct tegra210_ope *ope;
+ void __iomem *regs;
+ int err;
+
+ ope = devm_kzalloc(dev, sizeof(*ope), GFP_KERNEL);
+ if (!ope)
+ return -ENOMEM;
+
+ regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ ope->regmap = devm_regmap_init_mmio(dev, regs,
+ &tegra210_ope_regmap_config);
+ if (IS_ERR(ope->regmap)) {
+ dev_err(dev, "regmap init failed\n");
+ return PTR_ERR(ope->regmap);
+ }
+
+ regcache_cache_only(ope->regmap, true);
+
+ dev_set_drvdata(dev, ope);
+
+ err = tegra210_peq_regmap_init(pdev);
+ if (err < 0) {
+ dev_err(dev, "PEQ init failed\n");
+ return err;
+ }
+
+ err = tegra210_mbdrc_regmap_init(pdev);
+ if (err < 0) {
+ dev_err(dev, "MBDRC init failed\n");
+ return err;
+ }
+
+ err = devm_snd_soc_register_component(dev, &tegra210_ope_cmpnt,
+ tegra210_ope_dais,
+ ARRAY_SIZE(tegra210_ope_dais));
+ if (err) {
+ dev_err(dev, "can't register OPE component, err: %d\n", err);
+ return err;
+ }
+
+ pm_runtime_enable(dev);
+
+ return 0;
+}
+
+static int tegra210_ope_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static int __maybe_unused tegra210_ope_runtime_suspend(struct device *dev)
+{
+ struct tegra210_ope *ope = dev_get_drvdata(dev);
+
+ tegra210_peq_save(ope->peq_regmap, ope->peq_biquad_gains,
+ ope->peq_biquad_shifts);
+
+ regcache_cache_only(ope->mbdrc_regmap, true);
+ regcache_cache_only(ope->peq_regmap, true);
+ regcache_cache_only(ope->regmap, true);
+
+ regcache_mark_dirty(ope->regmap);
+ regcache_mark_dirty(ope->peq_regmap);
+ regcache_mark_dirty(ope->mbdrc_regmap);
+
+ return 0;
+}
+
+static int __maybe_unused tegra210_ope_runtime_resume(struct device *dev)
+{
+ struct tegra210_ope *ope = dev_get_drvdata(dev);
+
+ regcache_cache_only(ope->regmap, false);
+ regcache_cache_only(ope->peq_regmap, false);
+ regcache_cache_only(ope->mbdrc_regmap, false);
+
+ regcache_sync(ope->regmap);
+ regcache_sync(ope->peq_regmap);
+ regcache_sync(ope->mbdrc_regmap);
+
+ tegra210_peq_restore(ope->peq_regmap, ope->peq_biquad_gains,
+ ope->peq_biquad_shifts);
+
+ return 0;
+}
+
+static const struct dev_pm_ops tegra210_ope_pm_ops = {
+ SET_RUNTIME_PM_OPS(tegra210_ope_runtime_suspend,
+ tegra210_ope_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+};
+
+static const struct of_device_id tegra210_ope_of_match[] = {
+ { .compatible = "nvidia,tegra210-ope" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, tegra210_ope_of_match);
+
+static struct platform_driver tegra210_ope_driver = {
+ .driver = {
+ .name = "tegra210-ope",
+ .of_match_table = tegra210_ope_of_match,
+ .pm = &tegra210_ope_pm_ops,
+ },
+ .probe = tegra210_ope_probe,
+ .remove = tegra210_ope_remove,
+};
+module_platform_driver(tegra210_ope_driver)
+
+MODULE_AUTHOR("Sumit Bhattacharya <sumitb@nvidia.com>");
+MODULE_DESCRIPTION("Tegra210 OPE ASoC driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/tegra/tegra210_ope.h b/sound/soc/tegra/tegra210_ope.h
new file mode 100644
index 0000000..2835af6
--- /dev/null
+++ b/sound/soc/tegra/tegra210_ope.h
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_ope.h - Definitions for Tegra210 OPE driver
+ *
+ * Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA210_OPE_H__
+#define __TEGRA210_OPE_H__
+
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "tegra210_peq.h"
+
+/*
+ * OPE_RX registers are with respect to XBAR.
+ * The data comes from XBAR to OPE
+ */
+#define TEGRA210_OPE_RX_STATUS 0xc
+#define TEGRA210_OPE_RX_INT_STATUS 0x10
+#define TEGRA210_OPE_RX_INT_MASK 0x14
+#define TEGRA210_OPE_RX_INT_SET 0x18
+#define TEGRA210_OPE_RX_INT_CLEAR 0x1c
+#define TEGRA210_OPE_RX_CIF_CTRL 0x20
+
+/*
+ * OPE_TX registers are with respect to XBAR.
+ * The data goes out from OPE to XBAR
+ */
+#define TEGRA210_OPE_TX_STATUS 0x4c
+#define TEGRA210_OPE_TX_INT_STATUS 0x50
+#define TEGRA210_OPE_TX_INT_MASK 0x54
+#define TEGRA210_OPE_TX_INT_SET 0x58
+#define TEGRA210_OPE_TX_INT_CLEAR 0x5c
+#define TEGRA210_OPE_TX_CIF_CTRL 0x60
+
+/* OPE Gloabal registers */
+#define TEGRA210_OPE_ENABLE 0x80
+#define TEGRA210_OPE_SOFT_RESET 0x84
+#define TEGRA210_OPE_CG 0x88
+#define TEGRA210_OPE_STATUS 0x8c
+#define TEGRA210_OPE_INT_STATUS 0x90
+#define TEGRA210_OPE_DIR 0x94
+
+/* Fields for TEGRA210_OPE_ENABLE */
+#define TEGRA210_OPE_EN_SHIFT 0
+#define TEGRA210_OPE_EN (1 << TEGRA210_OPE_EN_SHIFT)
+
+/* Fields for TEGRA210_OPE_SOFT_RESET */
+#define TEGRA210_OPE_SOFT_RESET_SHIFT 0
+#define TEGRA210_OPE_SOFT_RESET_EN (1 << TEGRA210_OPE_SOFT_RESET_SHIFT)
+
+#define TEGRA210_OPE_DIR_SHIFT 0
+
+struct tegra210_ope {
+ struct regmap *regmap;
+ struct regmap *peq_regmap;
+ struct regmap *mbdrc_regmap;
+ u32 peq_biquad_gains[TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH];
+ u32 peq_biquad_shifts[TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH];
+ unsigned int data_dir;
+};
+
+/* Extension of soc_bytes structure defined in sound/soc.h */
+struct tegra_soc_bytes {
+ struct soc_bytes soc;
+ u32 shift; /* Used as offset for AHUB RAM related programing */
+};
+
+/* Utility structures for using mixer control of type snd_soc_bytes */
+#define TEGRA_SOC_BYTES_EXT(xname, xbase, xregs, xshift, xmask, \
+ xhandler_get, xhandler_put, xinfo) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .info = xinfo, \
+ .get = xhandler_get, \
+ .put = xhandler_put, \
+ .private_value = ((unsigned long)&(struct tegra_soc_bytes) \
+ { \
+ .soc.base = xbase, \
+ .soc.num_regs = xregs, \
+ .soc.mask = xmask, \
+ .shift = xshift \
+ }) \
+}
+
+#endif
diff --git a/sound/soc/tegra/tegra210_peq.c b/sound/soc/tegra/tegra210_peq.c
new file mode 100644
index 0000000..205d956
--- /dev/null
+++ b/sound/soc/tegra/tegra210_peq.c
@@ -0,0 +1,434 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra210_peq.c - Tegra210 PEQ driver
+//
+// Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra210_ope.h"
+#include "tegra210_peq.h"
+
+static const struct reg_default tegra210_peq_reg_defaults[] = {
+ { TEGRA210_PEQ_CFG, 0x00000013},
+ { TEGRA210_PEQ_CFG_RAM_CTRL, 0x00004000},
+ { TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL, 0x00004000},
+};
+
+static const u32 biquad_init_gains[TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH] = {
+ 1495012349, /* Pre-gain */
+
+ /* Gains : b0, b1, a0, a1, a2 */
+ 536870912, -1073741824, 536870912, 2143508246, -1069773768, /* Band-0 */
+ 134217728, -265414508, 131766272, 2140402222, -1071252997, /* Band-1 */
+ 268435456, -233515765, -33935948, 1839817267, -773826124, /* Band-2 */
+ 536870912, -672537913, 139851540, 1886437554, -824433167, /* Band-3 */
+ 268435456, -114439279, 173723964, 205743566, 278809729, /* Band-4 */
+ 1, 0, 0, 0, 0, /* Band-5 */
+ 1, 0, 0, 0, 0, /* Band-6 */
+ 1, 0, 0, 0, 0, /* Band-7 */
+ 1, 0, 0, 0, 0, /* Band-8 */
+ 1, 0, 0, 0, 0, /* Band-9 */
+ 1, 0, 0, 0, 0, /* Band-10 */
+ 1, 0, 0, 0, 0, /* Band-11 */
+
+ 963423114, /* Post-gain */
+};
+
+static const u32 biquad_init_shifts[TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH] = {
+ 23, /* Pre-shift */
+ 30, 30, 30, 30, 30, 0, 0, 0, 0, 0, 0, 0, /* Shift for bands */
+ 28, /* Post-shift */
+};
+
+static s32 biquad_coeff_buffer[TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH];
+
+static void tegra210_peq_read_ram(struct regmap *regmap, unsigned int reg_ctrl,
+ unsigned int reg_data, unsigned int ram_offset,
+ unsigned int *data, size_t size)
+{
+ unsigned int val;
+ unsigned int i;
+
+ val = ram_offset & TEGRA210_PEQ_RAM_CTRL_RAM_ADDR_MASK;
+ val |= TEGRA210_PEQ_RAM_CTRL_ADDR_INIT_EN;
+ val |= TEGRA210_PEQ_RAM_CTRL_SEQ_ACCESS_EN;
+ val |= TEGRA210_PEQ_RAM_CTRL_RW_READ;
+
+ regmap_write(regmap, reg_ctrl, val);
+
+ /*
+ * Since all ahub non-io modules work under same ahub clock it is not
+ * necessary to check ahub read busy bit after every read.
+ */
+ for (i = 0; i < size; i++)
+ regmap_read(regmap, reg_data, &data[i]);
+}
+
+static void tegra210_peq_write_ram(struct regmap *regmap, unsigned int reg_ctrl,
+ unsigned int reg_data, unsigned int ram_offset,
+ unsigned int *data, size_t size)
+{
+ unsigned int val;
+ unsigned int i;
+
+ val = ram_offset & TEGRA210_PEQ_RAM_CTRL_RAM_ADDR_MASK;
+ val |= TEGRA210_PEQ_RAM_CTRL_ADDR_INIT_EN;
+ val |= TEGRA210_PEQ_RAM_CTRL_SEQ_ACCESS_EN;
+ val |= TEGRA210_PEQ_RAM_CTRL_RW_WRITE;
+
+ regmap_write(regmap, reg_ctrl, val);
+
+ for (i = 0; i < size; i++)
+ regmap_write(regmap, reg_data, data[i]);
+}
+
+static int tegra210_peq_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+ unsigned int mask = (1 << fls(mc->max)) - 1;
+ unsigned int val;
+
+ regmap_read(ope->peq_regmap, mc->reg, &val);
+
+ ucontrol->value.integer.value[0] = (val >> mc->shift) & mask;
+
+ if (!mc->invert)
+ return 0;
+
+ ucontrol->value.integer.value[0] =
+ mc->max - ucontrol->value.integer.value[0];
+
+ return 0;
+}
+
+static int tegra210_peq_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+ unsigned int mask = (1 << fls(mc->max)) - 1;
+ bool change = false;
+ unsigned int val;
+
+ val = (ucontrol->value.integer.value[0] & mask);
+
+ if (mc->invert)
+ val = mc->max - val;
+
+ val = val << mc->shift;
+
+ regmap_update_bits_check(ope->peq_regmap, mc->reg, (mask << mc->shift),
+ val, &change);
+
+ return change ? 1 : 0;
+}
+
+static int tegra210_peq_ram_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+ u32 i, reg_ctrl = params->soc.base;
+ u32 reg_data = reg_ctrl + cmpnt->val_bytes;
+ s32 *data = (s32 *)biquad_coeff_buffer;
+
+ pm_runtime_get_sync(cmpnt->dev);
+
+ tegra210_peq_read_ram(ope->peq_regmap, reg_ctrl, reg_data,
+ params->shift, data, params->soc.num_regs);
+
+ pm_runtime_put_sync(cmpnt->dev);
+
+ for (i = 0; i < params->soc.num_regs; i++)
+ ucontrol->value.integer.value[i] = (long)data[i];
+
+ return 0;
+}
+
+static int tegra210_peq_ram_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+ u32 i, reg_ctrl = params->soc.base;
+ u32 reg_data = reg_ctrl + cmpnt->val_bytes;
+ s32 *data = (s32 *)biquad_coeff_buffer;
+
+ for (i = 0; i < params->soc.num_regs; i++)
+ data[i] = (s32)ucontrol->value.integer.value[i];
+
+ pm_runtime_get_sync(cmpnt->dev);
+
+ tegra210_peq_write_ram(ope->peq_regmap, reg_ctrl, reg_data,
+ params->shift, data, params->soc.num_regs);
+
+ pm_runtime_put_sync(cmpnt->dev);
+
+ return 1;
+}
+
+static int tegra210_peq_param_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct soc_bytes *params = (void *)kcontrol->private_value;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->value.integer.min = INT_MIN;
+ uinfo->value.integer.max = INT_MAX;
+ uinfo->count = params->num_regs;
+
+ return 0;
+}
+
+#define TEGRA210_PEQ_GAIN_PARAMS_CTRL(chan) \
+ TEGRA_SOC_BYTES_EXT("PEQ Channel-" #chan " Biquad Gain Params", \
+ TEGRA210_PEQ_CFG_RAM_CTRL, \
+ TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH, \
+ (TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH * chan), 0xffffffff, \
+ tegra210_peq_ram_get, tegra210_peq_ram_put, \
+ tegra210_peq_param_info)
+
+#define TEGRA210_PEQ_SHIFT_PARAMS_CTRL(chan) \
+ TEGRA_SOC_BYTES_EXT("PEQ Channel-" #chan " Biquad Shift Params", \
+ TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL, \
+ TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH, \
+ (TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH * chan), 0x1f, \
+ tegra210_peq_ram_get, tegra210_peq_ram_put, \
+ tegra210_peq_param_info)
+
+static const struct snd_kcontrol_new tegra210_peq_controls[] = {
+ SOC_SINGLE_EXT("PEQ Active", TEGRA210_PEQ_CFG,
+ TEGRA210_PEQ_CFG_MODE_SHIFT, 1, 0,
+ tegra210_peq_get, tegra210_peq_put),
+
+ SOC_SINGLE_EXT("PEQ Biquad Stages", TEGRA210_PEQ_CFG,
+ TEGRA210_PEQ_CFG_BIQUAD_STAGES_SHIFT,
+ TEGRA210_PEQ_MAX_BIQUAD_STAGES - 1, 0,
+ tegra210_peq_get, tegra210_peq_put),
+
+ TEGRA210_PEQ_GAIN_PARAMS_CTRL(0),
+ TEGRA210_PEQ_GAIN_PARAMS_CTRL(1),
+ TEGRA210_PEQ_GAIN_PARAMS_CTRL(2),
+ TEGRA210_PEQ_GAIN_PARAMS_CTRL(3),
+ TEGRA210_PEQ_GAIN_PARAMS_CTRL(4),
+ TEGRA210_PEQ_GAIN_PARAMS_CTRL(5),
+ TEGRA210_PEQ_GAIN_PARAMS_CTRL(6),
+ TEGRA210_PEQ_GAIN_PARAMS_CTRL(7),
+
+ TEGRA210_PEQ_SHIFT_PARAMS_CTRL(0),
+ TEGRA210_PEQ_SHIFT_PARAMS_CTRL(1),
+ TEGRA210_PEQ_SHIFT_PARAMS_CTRL(2),
+ TEGRA210_PEQ_SHIFT_PARAMS_CTRL(3),
+ TEGRA210_PEQ_SHIFT_PARAMS_CTRL(4),
+ TEGRA210_PEQ_SHIFT_PARAMS_CTRL(5),
+ TEGRA210_PEQ_SHIFT_PARAMS_CTRL(6),
+ TEGRA210_PEQ_SHIFT_PARAMS_CTRL(7),
+};
+
+static bool tegra210_peq_wr_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TEGRA210_PEQ_SOFT_RESET:
+ case TEGRA210_PEQ_CG:
+ case TEGRA210_PEQ_CFG ... TEGRA210_PEQ_CFG_RAM_SHIFT_DATA:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool tegra210_peq_rd_reg(struct device *dev, unsigned int reg)
+{
+ if (tegra210_peq_wr_reg(dev, reg))
+ return true;
+
+ switch (reg) {
+ case TEGRA210_PEQ_STATUS:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool tegra210_peq_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TEGRA210_PEQ_SOFT_RESET:
+ case TEGRA210_PEQ_STATUS:
+ case TEGRA210_PEQ_CFG_RAM_CTRL ... TEGRA210_PEQ_CFG_RAM_SHIFT_DATA:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool tegra210_peq_precious_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TEGRA210_PEQ_CFG_RAM_DATA:
+ case TEGRA210_PEQ_CFG_RAM_SHIFT_DATA:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config tegra210_peq_regmap_config = {
+ .name = "peq",
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = TEGRA210_PEQ_CFG_RAM_SHIFT_DATA,
+ .writeable_reg = tegra210_peq_wr_reg,
+ .readable_reg = tegra210_peq_rd_reg,
+ .volatile_reg = tegra210_peq_volatile_reg,
+ .precious_reg = tegra210_peq_precious_reg,
+ .reg_defaults = tegra210_peq_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(tegra210_peq_reg_defaults),
+ .cache_type = REGCACHE_FLAT,
+};
+
+void tegra210_peq_restore(struct regmap *regmap, u32 *biquad_gains,
+ u32 *biquad_shifts)
+{
+ unsigned int i;
+
+ for (i = 0; i < TEGRA210_PEQ_MAX_CHANNELS; i++) {
+ tegra210_peq_write_ram(regmap, TEGRA210_PEQ_CFG_RAM_CTRL,
+ TEGRA210_PEQ_CFG_RAM_DATA,
+ (i * TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH),
+ biquad_gains,
+ TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH);
+
+ tegra210_peq_write_ram(regmap,
+ TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL,
+ TEGRA210_PEQ_CFG_RAM_SHIFT_DATA,
+ (i * TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH),
+ biquad_shifts,
+ TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH);
+
+ }
+}
+
+void tegra210_peq_save(struct regmap *regmap, u32 *biquad_gains,
+ u32 *biquad_shifts)
+{
+ unsigned int i;
+
+ for (i = 0; i < TEGRA210_PEQ_MAX_CHANNELS; i++) {
+ tegra210_peq_read_ram(regmap,
+ TEGRA210_PEQ_CFG_RAM_CTRL,
+ TEGRA210_PEQ_CFG_RAM_DATA,
+ (i * TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH),
+ biquad_gains,
+ TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH);
+
+ tegra210_peq_read_ram(regmap,
+ TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL,
+ TEGRA210_PEQ_CFG_RAM_SHIFT_DATA,
+ (i * TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH),
+ biquad_shifts,
+ TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH);
+ }
+}
+
+int tegra210_peq_component_init(struct snd_soc_component *cmpnt)
+{
+ struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+ unsigned int i;
+
+ pm_runtime_get_sync(cmpnt->dev);
+ regmap_update_bits(ope->peq_regmap, TEGRA210_PEQ_CFG,
+ TEGRA210_PEQ_CFG_MODE_MASK,
+ 0 << TEGRA210_PEQ_CFG_MODE_SHIFT);
+ regmap_update_bits(ope->peq_regmap, TEGRA210_PEQ_CFG,
+ TEGRA210_PEQ_CFG_BIQUAD_STAGES_MASK,
+ (TEGRA210_PEQ_BIQUAD_INIT_STAGE - 1) <<
+ TEGRA210_PEQ_CFG_BIQUAD_STAGES_SHIFT);
+
+ /* Initialize PEQ AHUB RAM with default params */
+ for (i = 0; i < TEGRA210_PEQ_MAX_CHANNELS; i++) {
+
+ /* Set default gain params */
+ tegra210_peq_write_ram(ope->peq_regmap,
+ TEGRA210_PEQ_CFG_RAM_CTRL,
+ TEGRA210_PEQ_CFG_RAM_DATA,
+ (i * TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH),
+ (u32 *)&biquad_init_gains,
+ TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH);
+
+ /* Set default shift params */
+ tegra210_peq_write_ram(ope->peq_regmap,
+ TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL,
+ TEGRA210_PEQ_CFG_RAM_SHIFT_DATA,
+ (i * TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH),
+ (u32 *)&biquad_init_shifts,
+ TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH);
+
+ }
+
+ pm_runtime_put_sync(cmpnt->dev);
+
+ snd_soc_add_component_controls(cmpnt, tegra210_peq_controls,
+ ARRAY_SIZE(tegra210_peq_controls));
+
+ return 0;
+}
+
+int tegra210_peq_regmap_init(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct tegra210_ope *ope = dev_get_drvdata(dev);
+ struct device_node *child;
+ struct resource mem;
+ void __iomem *regs;
+ int err;
+
+ child = of_get_child_by_name(dev->of_node, "equalizer");
+ if (!child)
+ return -ENODEV;
+
+ err = of_address_to_resource(child, 0, &mem);
+ of_node_put(child);
+ if (err < 0) {
+ dev_err(dev, "fail to get PEQ resource\n");
+ return err;
+ }
+
+ mem.flags = IORESOURCE_MEM;
+ regs = devm_ioremap_resource(dev, &mem);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+ ope->peq_regmap = devm_regmap_init_mmio(dev, regs,
+ &tegra210_peq_regmap_config);
+ if (IS_ERR(ope->peq_regmap)) {
+ dev_err(dev, "regmap init failed\n");
+ return PTR_ERR(ope->peq_regmap);
+ }
+
+ regcache_cache_only(ope->peq_regmap, true);
+
+ return 0;
+}
diff --git a/sound/soc/tegra/tegra210_peq.h b/sound/soc/tegra/tegra210_peq.h
new file mode 100644
index 0000000..6d3de4f
--- /dev/null
+++ b/sound/soc/tegra/tegra210_peq.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_peq.h - Definitions for Tegra210 PEQ driver
+ *
+ * Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA210_PEQ_H__
+#define __TEGRA210_PEQ_H__
+
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+/* Register offsets from PEQ base */
+#define TEGRA210_PEQ_SOFT_RESET 0x0
+#define TEGRA210_PEQ_CG 0x4
+#define TEGRA210_PEQ_STATUS 0x8
+#define TEGRA210_PEQ_CFG 0xc
+#define TEGRA210_PEQ_CFG_RAM_CTRL 0x10
+#define TEGRA210_PEQ_CFG_RAM_DATA 0x14
+#define TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL 0x18
+#define TEGRA210_PEQ_CFG_RAM_SHIFT_DATA 0x1c
+
+/* Fields in TEGRA210_PEQ_CFG */
+#define TEGRA210_PEQ_CFG_BIQUAD_STAGES_SHIFT 2
+#define TEGRA210_PEQ_CFG_BIQUAD_STAGES_MASK (0xf << TEGRA210_PEQ_CFG_BIQUAD_STAGES_SHIFT)
+
+#define TEGRA210_PEQ_CFG_MODE_SHIFT 0
+#define TEGRA210_PEQ_CFG_MODE_MASK (0x1 << TEGRA210_PEQ_CFG_MODE_SHIFT)
+
+#define TEGRA210_PEQ_RAM_CTRL_RW_READ 0
+#define TEGRA210_PEQ_RAM_CTRL_RW_WRITE (1 << 14)
+#define TEGRA210_PEQ_RAM_CTRL_ADDR_INIT_EN (1 << 13)
+#define TEGRA210_PEQ_RAM_CTRL_SEQ_ACCESS_EN (1 << 12)
+#define TEGRA210_PEQ_RAM_CTRL_RAM_ADDR_MASK 0x1ff
+
+/* PEQ register definition ends here */
+#define TEGRA210_PEQ_MAX_BIQUAD_STAGES 12
+
+#define TEGRA210_PEQ_MAX_CHANNELS 8
+
+#define TEGRA210_PEQ_BIQUAD_INIT_STAGE 5
+
+#define TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH (2 + TEGRA210_PEQ_MAX_BIQUAD_STAGES * 5)
+#define TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH (2 + TEGRA210_PEQ_MAX_BIQUAD_STAGES)
+
+int tegra210_peq_regmap_init(struct platform_device *pdev);
+int tegra210_peq_component_init(struct snd_soc_component *cmpnt);
+void tegra210_peq_restore(struct regmap *regmap, u32 *biquad_gains,
+ u32 *biquad_shifts);
+void tegra210_peq_save(struct regmap *regmap, u32 *biquad_gains,
+ u32 *biquad_shifts);
+
+#endif
diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
index 084a533..3aa157c8 100644
--- a/sound/soc/tegra/tegra30_i2s.c
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -87,11 +87,11 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai,
}
mask |= TEGRA30_I2S_CTRL_MASTER_ENABLE;
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BP_FP:
val |= TEGRA30_I2S_CTRL_MASTER_ENABLE;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_BC_FC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/ti/davinci-i2s.c b/sound/soc/ti/davinci-i2s.c
index 0363a08..fe572b7 100644
--- a/sound/soc/ti/davinci-i2s.c
+++ b/sound/soc/ti/davinci-i2s.c
@@ -230,15 +230,15 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
dev->fmt = fmt;
/* set master/slave audio interface */
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BP_FP:
/* cpu is master */
pcr = DAVINCI_MCBSP_PCR_FSXM |
DAVINCI_MCBSP_PCR_FSRM |
DAVINCI_MCBSP_PCR_CLKXM |
DAVINCI_MCBSP_PCR_CLKRM;
break;
- case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_BC_FP:
pcr = DAVINCI_MCBSP_PCR_FSRM | DAVINCI_MCBSP_PCR_FSXM;
/*
* Selection of the clock input pin that is the
@@ -260,7 +260,7 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
}
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_BC_FC:
/* codec is master */
pcr = 0;
break;
@@ -395,12 +395,12 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
}
- master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK;
+ master = dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK;
fmt = params_format(params);
mcbsp_word_length = asp_word_length[fmt];
switch (master) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_BP_FP:
freq = clk_get_rate(dev->clk);
srgr = DAVINCI_MCBSP_SRGR_FSGM |
DAVINCI_MCBSP_SRGR_CLKSM;
@@ -426,7 +426,7 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
clk_div &= 0xFF;
srgr |= clk_div;
break;
- case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_BC_FP:
srgr = DAVINCI_MCBSP_SRGR_FSGM;
clk_div = dev->clk_div - 1;
srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length * 8 - 1);
@@ -434,7 +434,7 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
clk_div &= 0xFF;
srgr |= clk_div;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_BC_FC:
/* Clock and frame sync given from external sources */
i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
srgr = DAVINCI_MCBSP_SRGR_FSGM;
@@ -473,15 +473,15 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
fmt = double_fmt[fmt];
}
switch (master) {
- case SND_SOC_DAIFMT_CBS_CFS:
- case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_BP_FP:
+ case SND_SOC_DAIFMT_BP_FC:
rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(0);
xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(0);
rcr |= DAVINCI_MCBSP_RCR_RPHASE;
xcr |= DAVINCI_MCBSP_XCR_XPHASE;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
- case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_BC_FC:
+ case SND_SOC_DAIFMT_BC_FP:
rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(element_cnt - 1);
xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(element_cnt - 1);
break;
@@ -492,13 +492,13 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
mcbsp_word_length = asp_word_length[fmt];
switch (master) {
- case SND_SOC_DAIFMT_CBS_CFS:
- case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_BP_FP:
+ case SND_SOC_DAIFMT_BP_FC:
rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(0);
xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(0);
break;
- case SND_SOC_DAIFMT_CBM_CFM:
- case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_BC_FC:
+ case SND_SOC_DAIFMT_BC_FP:
rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(element_cnt - 1);
xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(element_cnt - 1);
break;
diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c
index 377be2e..e2aab47 100644
--- a/sound/soc/ti/davinci-mcasp.c
+++ b/sound/soc/ti/davinci-mcasp.c
@@ -492,8 +492,8 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, FSRDLY(data_delay),
FSRDLY(3));
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BP_FP:
/* codec is clock and frame slave */
mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
@@ -510,7 +510,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
mcasp->bclk_master = 1;
break;
- case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_BP_FC:
/* codec is clock slave and frame master */
mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
@@ -527,7 +527,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
mcasp->bclk_master = 1;
break;
- case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_BC_FP:
/* codec is clock master and frame slave */
mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
@@ -544,7 +544,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
mcasp->bclk_master = 0;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_BC_FC:
/* codec is clock and frame master */
mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
diff --git a/sound/soc/ti/omap-mcbsp.c b/sound/soc/ti/omap-mcbsp.c
index 4479d74..58d8e20 100644
--- a/sound/soc/ti/omap-mcbsp.c
+++ b/sound/soc/ti/omap-mcbsp.c
@@ -1036,8 +1036,8 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
/* In McBSP master modes, FRAME (i.e. sample rate) is generated
* by _counting_ BCLKs. Calculate frame size in BCLKs */
- master = mcbsp->fmt & SND_SOC_DAIFMT_MASTER_MASK;
- if (master == SND_SOC_DAIFMT_CBS_CFS) {
+ master = mcbsp->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK;
+ if (master == SND_SOC_DAIFMT_BP_FP) {
div = mcbsp->clk_div ? mcbsp->clk_div : 1;
framesize = (mcbsp->in_freq / div) / params_rate(params);
@@ -1136,20 +1136,20 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
return -EINVAL;
}
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BP_FP:
/* McBSP master. Set FS and bit clocks as outputs */
regs->pcr0 |= FSXM | FSRM |
CLKXM | CLKRM;
/* Sample rate generator drives the FS */
regs->srgr2 |= FSGM;
break;
- case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_BC_FP:
/* McBSP slave. FS clock as output */
regs->srgr2 |= FSGM;
regs->pcr0 |= FSXM | FSRM;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_BC_FC:
/* McBSP slave */
break;
default:
diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c
index 4f41bb0..fdd55d7 100644
--- a/sound/soc/ux500/mop500.c
+++ b/sound/soc/ux500/mop500.c
@@ -4,8 +4,6 @@
*
* Author: Ola Lilja (ola.o.lilja@stericsson.com)
* for ST-Ericsson.
- *
- * License terms:
*/
#include <asm/mach-types.h>
diff --git a/sound/soc/ux500/mop500_ab8500.c b/sound/soc/ux500/mop500_ab8500.c
index 1ea1729..e5e73a2 100644
--- a/sound/soc/ux500/mop500_ab8500.c
+++ b/sound/soc/ux500/mop500_ab8500.c
@@ -5,8 +5,6 @@
* Author: Ola Lilja <ola.o.lilja@stericsson.com>,
* Kristoffer Karlsson <kristoffer.karlsson@stericsson.com>
* for ST-Ericsson.
- *
- * License terms:
*/
#include <linux/module.h>
diff --git a/sound/soc/ux500/mop500_ab8500.h b/sound/soc/ux500/mop500_ab8500.h
index 087ef24..98de80a 100644
--- a/sound/soc/ux500/mop500_ab8500.h
+++ b/sound/soc/ux500/mop500_ab8500.h
@@ -4,8 +4,6 @@
*
* Author: Ola Lilja <ola.o.lilja@stericsson.com>
* for ST-Ericsson.
- *
- * License terms:
*/
#ifndef MOP500_AB8500_H
diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c
index 2105237..e48098f 100644
--- a/sound/soc/ux500/ux500_msp_dai.c
+++ b/sound/soc/ux500/ux500_msp_dai.c
@@ -5,8 +5,6 @@
* Author: Ola Lilja <ola.o.lilja@stericsson.com>,
* Roger Nilsson <roger.xr.nilsson@stericsson.com>
* for ST-Ericsson.
- *
- * License terms:
*/
#include <linux/module.h>
@@ -191,8 +189,8 @@ static int setup_clocking(struct snd_soc_dai *dai,
return -EINVAL;
}
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BC_FC:
dev_dbg(dai->dev, "%s: Codec is master.\n", __func__);
msp_config->iodelay = 0x20;
@@ -204,7 +202,7 @@ static int setup_clocking(struct snd_soc_dai *dai,
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_BP_FP:
dev_dbg(dai->dev, "%s: Codec is slave.\n", __func__);
msp_config->tx_clk_sel = TX_CLK_SEL_SRG;
@@ -328,15 +326,15 @@ static int setup_msp_config(struct snd_pcm_substream *substream,
dev_dbg(dai->dev, "%s: rate: %u, channels: %d.\n", __func__,
runtime->rate, runtime->channels);
switch (fmt &
- (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) {
- case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS:
+ (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK)) {
+ case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_BP_FP:
dev_dbg(dai->dev, "%s: SND_SOC_DAIFMT_I2S.\n", __func__);
msp_config->default_protdesc = 1;
msp_config->protocol = MSP_I2S_PROTOCOL;
break;
- case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_BC_FC:
dev_dbg(dai->dev, "%s: SND_SOC_DAIFMT_I2S.\n", __func__);
msp_config->data_size = MSP_DATA_BITS_16;
@@ -348,10 +346,10 @@ static int setup_msp_config(struct snd_pcm_substream *substream,
break;
- case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:
- case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
- case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBS_CFS:
- case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_BP_FP:
+ case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_BC_FC:
+ case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_BP_FP:
+ case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_BC_FC:
dev_dbg(dai->dev, "%s: PCM format.\n", __func__);
msp_config->data_size = MSP_DATA_BITS_16;
@@ -477,7 +475,7 @@ static int ux500_msp_dai_prepare(struct snd_pcm_substream *substream,
}
/* Set OPP-level */
- if ((drvdata->fmt & SND_SOC_DAIFMT_MASTER_MASK) &&
+ if ((drvdata->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) &&
(drvdata->msp->f_bitclk > 19200000)) {
/* If the bit-clock is higher than 19.2MHz, Vape should be
* run in 100% OPP. Only when bit-clock is used (MSP master)
@@ -544,13 +542,13 @@ static int ux500_msp_dai_set_dai_fmt(struct snd_soc_dai *dai,
dev_dbg(dai->dev, "%s: MSP %d: Enter.\n", __func__, dai->id);
switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK |
- SND_SOC_DAIFMT_MASTER_MASK)) {
- case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS:
- case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
- case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBS_CFS:
- case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM:
- case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:
- case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
+ SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK)) {
+ case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_BP_FP:
+ case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_BC_FC:
+ case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_BP_FP:
+ case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_BC_FC:
+ case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_BP_FP:
+ case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_BC_FC:
break;
default:
diff --git a/sound/soc/ux500/ux500_msp_dai.h b/sound/soc/ux500/ux500_msp_dai.h
index fcd4b26..30bf708 100644
--- a/sound/soc/ux500/ux500_msp_dai.h
+++ b/sound/soc/ux500/ux500_msp_dai.h
@@ -5,8 +5,6 @@
* Author: Ola Lilja <ola.o.lilja@stericsson.com>,
* Roger Nilsson <roger.xr.nilsson@stericsson.com>
* for ST-Ericsson.
- *
- * License terms:
*/
#ifndef UX500_msp_dai_H
diff --git a/sound/soc/ux500/ux500_msp_i2s.c b/sound/soc/ux500/ux500_msp_i2s.c
index fd0b88b..d113411 100644
--- a/sound/soc/ux500/ux500_msp_i2s.c
+++ b/sound/soc/ux500/ux500_msp_i2s.c
@@ -6,8 +6,6 @@
* Roger Nilsson <roger.xr.nilsson@stericsson.com>,
* Sandeep Kaushik <sandeep.kaushik@st.com>
* for ST-Ericsson.
- *
- * License terms:
*/
#include <linux/module.h>
diff --git a/sound/soc/ux500/ux500_msp_i2s.h b/sound/soc/ux500/ux500_msp_i2s.h
index 756b397..d45b5e2 100644
--- a/sound/soc/ux500/ux500_msp_i2s.h
+++ b/sound/soc/ux500/ux500_msp_i2s.h
@@ -4,8 +4,6 @@
*
* Author: Ola Lilja <ola.o.lilja@stericsson.com>,
* for ST-Ericsson.
- *
- * License terms:
*/
diff --git a/sound/soc/ux500/ux500_pcm.c b/sound/soc/ux500/ux500_pcm.c
index 1819108..d3802e5 100644
--- a/sound/soc/ux500/ux500_pcm.c
+++ b/sound/soc/ux500/ux500_pcm.c
@@ -5,8 +5,6 @@
* Author: Ola Lilja <ola.o.lilja@stericsson.com>,
* Roger Nilsson <roger.xr.nilsson@stericsson.com>
* for ST-Ericsson.
- *
- * License terms:
*/
#include <asm/page.h>
diff --git a/sound/soc/ux500/ux500_pcm.h b/sound/soc/ux500/ux500_pcm.h
index ff3ef72..bd4348e 100644
--- a/sound/soc/ux500/ux500_pcm.h
+++ b/sound/soc/ux500/ux500_pcm.h
@@ -5,8 +5,6 @@
* Author: Ola Lilja <ola.o.lilja@stericsson.com>,
* Roger Nilsson <roger.xr.nilsson@stericsson.com>
* for ST-Ericsson.
- *
- * License terms:
*/
#ifndef UX500_PCM_H
#define UX500_PCM_H
diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c
index aeb4b2c..8bd1215 100644
--- a/sound/soc/xtensa/xtfpga-i2s.c
+++ b/sound/soc/xtensa/xtfpga-i2s.c
@@ -339,7 +339,7 @@ static int xtfpga_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
{
if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF)
return -EINVAL;
- if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
+ if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_BP_FP)
return -EINVAL;
if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S)
return -EINVAL;
@@ -487,7 +487,7 @@ static const struct snd_soc_component_driver xtfpga_i2s_component = {
static const struct snd_soc_dai_ops xtfpga_i2s_dai_ops = {
.startup = xtfpga_i2s_startup,
.hw_params = xtfpga_i2s_hw_params,
- .set_fmt = xtfpga_i2s_set_fmt,
+ .set_fmt = xtfpga_i2s_set_fmt,
};
static struct snd_soc_dai_driver xtfpga_i2s_dai[] = {