2024-02-26 14:02:35

by Alexandre Mergnat

[permalink] [raw]
Subject: [PATCH 00/18] Add audio support for the MediaTek Genio 350-evk board

This serie aim to add the following audio support for the Genio 350-evk:
- Playback
- 2ch Headset Jack (Earphone)
- 1ch Line-out Jack (Speaker)
- 8ch HDMI Tx
- Capture
- 1ch DMIC (On-board Digital Microphone)
- 1ch AMIC (On-board Analogic Microphone)
- 1ch Headset Jack (External Analogic Microphone)

Of course, HDMI playback need the MT8365 display patches [1] and a DTS
change documented in "mediatek,mt8365-mt6357.yaml".

[1]: https://lore.kernel.org/all/[email protected]/

Signed-off-by: Alexandre Mergnat <[email protected]>
---
Alexandre Mergnat (15):
ASoC: dt-bindings: mediatek,mt8365-afe: Add audio afe document
ASoC: dt-bindings: mediatek,mt8365-mt6357: Add audio sound card document
dt-bindings: mfd: mediatek: Add codec property for MT6357 PMIC
ASoC: mediatek: mt8365: Add common header
SoC: mediatek: mt8365: support audio clock control
ASoC: mediatek: mt8365: Add I2S DAI support
ASoC: mediatek: mt8365: Add ADDA DAI support
ASoC: mediatek: mt8365: Add DMIC DAI support
ASoC: mediatek: mt8365: Add PCM DAI support
ASoC: mediatek: mt8365: Add platform driver
ASoC: mediatek: Add MT8365 support
arm64: defconfig: enable mt8365 sound
arm64: dts: mediatek: add mt6357 audio codec support
arm64: dts: mediatek: add afe support for mt8365 SoC
arm64: dts: mediatek: add audio support for mt8365-evk

Fabien Parent (1):
mfd: mt6397-core: register mt6357 sound codec

Nicolas Belin (2):
ASoc: mediatek: mt8365: Add a specific soundcard for EVK
ASoC: codecs: mt6357: add MT6357 codec

.../devicetree/bindings/mfd/mediatek,mt6357.yaml | 11 +
.../bindings/sound/mediatek,mt8365-afe.yaml | 164 ++
.../bindings/sound/mediatek,mt8365-mt6357.yaml | 127 ++
arch/arm64/boot/dts/mediatek/mt6357.dtsi | 6 +-
arch/arm64/boot/dts/mediatek/mt8365-evk.dts | 95 +-
arch/arm64/boot/dts/mediatek/mt8365.dtsi | 47 +-
arch/arm64/configs/defconfig | 2 +
drivers/mfd/mt6397-core.c | 3 +
sound/soc/codecs/Kconfig | 7 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/mt6357.c | 1805 +++++++++++++++
sound/soc/codecs/mt6357.h | 674 ++++++
sound/soc/mediatek/Kconfig | 20 +
sound/soc/mediatek/Makefile | 1 +
sound/soc/mediatek/mt8365/Makefile | 15 +
sound/soc/mediatek/mt8365/mt8365-afe-clk.c | 455 ++++
sound/soc/mediatek/mt8365/mt8365-afe-clk.h | 55 +
sound/soc/mediatek/mt8365/mt8365-afe-common.h | 495 +++++
sound/soc/mediatek/mt8365/mt8365-afe-pcm.c | 2347 ++++++++++++++++++++
sound/soc/mediatek/mt8365/mt8365-dai-adda.c | 355 +++
sound/soc/mediatek/mt8365/mt8365-dai-dmic.c | 475 ++++
sound/soc/mediatek/mt8365/mt8365-dai-i2s.c | 901 ++++++++
sound/soc/mediatek/mt8365/mt8365-dai-pcm.c | 298 +++
sound/soc/mediatek/mt8365/mt8365-mt6357.c | 379 ++++
sound/soc/mediatek/mt8365/mt8365-reg.h | 987 ++++++++
25 files changed, 9718 insertions(+), 8 deletions(-)
---
base-commit: 6613476e225e090cc9aad49be7fa504e290dd33d
change-id: 20240226-audio-i350-4e11da088e55

Best regards,
--
Alexandre Mergnat <[email protected]>



2024-02-26 14:02:45

by Alexandre Mergnat

[permalink] [raw]
Subject: [PATCH 01/18] ASoC: dt-bindings: mediatek,mt8365-afe: Add audio afe document

Add MT8365 audio front-end bindings

Signed-off-by: Alexandre Mergnat <[email protected]>
---
.../bindings/sound/mediatek,mt8365-afe.yaml | 164 +++++++++++++++++++++
1 file changed, 164 insertions(+)

diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8365-afe.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8365-afe.yaml
new file mode 100644
index 000000000000..1d7eb2532ad2
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mediatek,mt8365-afe.yaml
@@ -0,0 +1,164 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/mediatek,mt8365-afe.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek AFE PCM controller for MT8365
+
+maintainers:
+ - Alexandre Mergnat <[email protected]>
+
+properties:
+ compatible:
+ const: mediatek,mt8365-afe-pcm
+
+ reg:
+ maxItems: 2
+
+ interrupts:
+ maxItems: 1
+
+ mediatek,topckgen:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: The phandle of the mediatek topckgen controller
+
+ power-domains:
+ maxItems: 1
+
+ "#sound-dai-cells":
+ const: 0
+
+ clocks:
+ items:
+ - description: 26M clock
+ - description: mux for audio clock
+ - description: audio i2s0 mck
+ - description: audio i2s1 mck
+ - description: audio i2s2 mck
+ - description: audio i2s3 mck
+ - description: engen 1 clock
+ - description: engen 2 clock
+ - description: audio 1 clock
+ - description: audio 2 clock
+ - description: mux for i2s0
+ - description: mux for i2s1
+ - description: mux for i2s2
+ - description: mux for i2s3
+
+ clock-names:
+ items:
+ - const: top_clk26m_clk
+ - const: top_audio_sel
+ - const: audio_i2s0_m
+ - const: audio_i2s1_m
+ - const: audio_i2s2_m
+ - const: audio_i2s3_m
+ - const: engen1
+ - const: engen2
+ - const: aud1
+ - const: aud2
+ - const: i2s0_m_sel
+ - const: i2s1_m_sel
+ - const: i2s2_m_sel
+ - const: i2s3_m_sel
+
+ mediatek,i2s-shared-clock:
+ description:
+ i2s modules can share the same external clock pin.
+ If this property is not present the clock mode is separrate.
+ type: boolean
+
+ mediatek,dmic-iir-on:
+ description:
+ Boolean which specifies whether the DMIC IIR is enabled.
+ If this property is not present the IIR is disabled.
+ type: boolean
+
+ mediatek,dmic-irr-mode:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ Selects stop band of IIR DC-removal filter.
+ 0 = Software programmable custom coeff loaded by the driver.
+ 1 = 5Hz if 48KHz mode.
+ 2 = 10Hz if 48KHz mode.
+ 3 = 25Hz if 48KHz mode.
+ 4 = 50Hz if 48KHz mode.
+ 5 = 65Hz if 48KHz mode.
+ enum:
+ - 0
+ - 1
+ - 2
+ - 3
+ - 4
+ - 5
+
+ mediatek,dmic-two-wire-mode:
+ description:
+ Boolean which turns on digital microphone for two wire mode.
+ If this property is not present the two wire mode is disabled.
+ type: boolean
+
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - power-domains
+ - mediatek,topckgen
+ - clocks
+ - clock-names
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/mediatek,mt8365-clk.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/power/mediatek,mt8365-power.h>
+
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ afe@11220000 {
+ compatible = "mediatek,mt8365-afe-pcm";
+ reg = <0 0x11220000 0 0x1000>,
+ <0 0x11221000 0 0xA000>;
+ interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_LOW>;
+ power-domains = <&spm MT8365_POWER_DOMAIN_AUDIO>;
+ mediatek,topckgen = <&topckgen>;
+ #sound-dai-cells = <0>;
+ clocks = <&clk26m>,
+ <&topckgen CLK_TOP_AUDIO_SEL>,
+ <&topckgen CLK_TOP_AUD_I2S0_M>,
+ <&topckgen CLK_TOP_AUD_I2S1_M>,
+ <&topckgen CLK_TOP_AUD_I2S2_M>,
+ <&topckgen CLK_TOP_AUD_I2S3_M>,
+ <&topckgen CLK_TOP_AUD_ENGEN1_SEL>,
+ <&topckgen CLK_TOP_AUD_ENGEN2_SEL>,
+ <&topckgen CLK_TOP_AUD_1_SEL>,
+ <&topckgen CLK_TOP_AUD_2_SEL>,
+ <&topckgen CLK_TOP_APLL_I2S0_SEL>,
+ <&topckgen CLK_TOP_APLL_I2S1_SEL>,
+ <&topckgen CLK_TOP_APLL_I2S2_SEL>,
+ <&topckgen CLK_TOP_APLL_I2S3_SEL>;
+ clock-names = "top_clk26m_clk",
+ "top_audio_sel",
+ "audio_i2s0_m",
+ "audio_i2s1_m",
+ "audio_i2s2_m",
+ "audio_i2s3_m",
+ "engen1",
+ "engen2",
+ "aud1",
+ "aud2",
+ "i2s0_m_sel",
+ "i2s1_m_sel",
+ "i2s2_m_sel",
+ "i2s3_m_sel";
+ };
+ };
+
+...

--
2.25.1


2024-02-26 14:03:08

by Alexandre Mergnat

[permalink] [raw]
Subject: [PATCH 02/18] ASoC: dt-bindings: mediatek,mt8365-mt6357: Add audio sound card document

Add soundcard bindings for the MT8365 SoC with the MT6357 audio codec.

Signed-off-by: Alexandre Mergnat <[email protected]>
---
.../bindings/sound/mediatek,mt8365-mt6357.yaml | 127 +++++++++++++++++++++
1 file changed, 127 insertions(+)

diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8365-mt6357.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8365-mt6357.yaml
new file mode 100644
index 000000000000..f469611ec6b6
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mediatek,mt8365-mt6357.yaml
@@ -0,0 +1,127 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/mediatek,mt8365-mt6357.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Mediatek MT8365 sound card with MT6357 sound codec.
+
+maintainers:
+ - Alexandre Mergnat <[email protected]>
+
+description:
+ This binding describes the MT8365 sound card.
+
+properties:
+ compatible:
+ const: mediatek,mt8365-mt6357
+
+ mediatek,hp-pull-down:
+ description:
+ Earphone driver positive output stage short to the
+ audio reference ground.
+ Default value is false.
+ type: boolean
+
+ mediatek,micbias0-microvolt:
+ description: |
+ Selects MIC Bias 0 output voltage.
+ [1.7v, 1.8v, 1.9v, 2.0v, 2.1v, 2.5v, 2.6v, 2.7v]
+ enum: [0, 1, 2, 3, 4, 5, 6, 7]
+
+ mediatek,micbias1-microvolt:
+ description: |
+ Selects MIC Bias 1 output voltage.
+ [1.7v, 1.8v, 1.9v, 2.0v, 2.1v, 2.5v, 2.6v, 2.7v]
+ enum: [0, 1, 2, 3, 4, 5, 6, 7]
+
+ mediatek,platform:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: The phandle of MT8365 ASoC platform.
+
+ pinctrl-names:
+ minItems: 1
+ items:
+ - const: aud_default
+ - const: aud_dmic
+ - const: aud_miso_off
+ - const: aud_miso_on
+ - const: aud_mosi_off
+ - const: aud_mosi_on
+
+ vaud28-supply:
+ description:
+ 2.8 volt supply for the audio codec
+
+patternProperties:
+ "^dai-link-[0-9]+$":
+ type: object
+ description:
+ Container for dai-link level properties and CODEC sub-nodes.
+
+ properties:
+ codec:
+ type: object
+ description: Holds subnode which indicates codec dai.
+
+ properties:
+ sound-dai:
+ maxItems: 1
+ description: phandle of the codec DAI
+
+ additionalProperties: false
+
+ link-name:
+ description:
+ This property corresponds to the name of the BE dai-link to which
+ we are going to update parameters in this node.
+ items:
+ const: 2ND I2S BE
+
+ sound-dai:
+ maxItems: 1
+ description: phandle of the CPU DAI
+
+ additionalProperties: false
+
+ required:
+ - link-name
+ - sound-dai
+
+additionalProperties: false
+
+required:
+ - compatible
+ - mediatek,platform
+ - pinctrl-names
+ - vaud28-supply
+
+examples:
+ - |
+ sound {
+ compatible = "mediatek,mt8365-mt6357";
+ mediatek,platform = <&afe>;
+ pinctrl-names = "aud_default",
+ "aud_dmic",
+ "aud_miso_off",
+ "aud_miso_on",
+ "aud_mosi_off",
+ "aud_mosi_on";
+ pinctrl-0 = <&aud_default_pins>;
+ pinctrl-1 = <&aud_dmic_pins>;
+ pinctrl-2 = <&aud_miso_off_pins>;
+ pinctrl-3 = <&aud_miso_on_pins>;
+ pinctrl-4 = <&aud_mosi_off_pins>;
+ pinctrl-5 = <&aud_mosi_on_pins>;
+ vaud28-supply = <&mt6357_vaud28_reg>;
+
+ /* hdmi interface */
+ dai-link-0 {
+ sound-dai = <&afe>;
+ link-name = "2ND I2S BE";
+
+ codec {
+ sound-dai = <&it66121hdmitx>;
+ };
+ };
+ };

--
2.25.1


2024-02-26 14:04:32

by Alexandre Mergnat

[permalink] [raw]
Subject: [PATCH 04/18] ASoC: mediatek: mt8365: Add common header

Add header files for register definition and structure.

Signed-off-by: Alexandre Mergnat <[email protected]>
---
sound/soc/mediatek/mt8365/mt8365-afe-common.h | 495 +++++++++++++
sound/soc/mediatek/mt8365/mt8365-reg.h | 987 ++++++++++++++++++++++++++
2 files changed, 1482 insertions(+)

diff --git a/sound/soc/mediatek/mt8365/mt8365-afe-common.h b/sound/soc/mediatek/mt8365/mt8365-afe-common.h
new file mode 100644
index 000000000000..8c7a772e9011
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/mt8365-afe-common.h
@@ -0,0 +1,495 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Mediatek 8365 audio driver common definitions
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Authors: Jia Zeng <[email protected]>
+ * Alexandre Mergnat <[email protected]>
+ */
+
+#ifndef _MT8365_AFE_COMMON_H_
+#define _MT8365_AFE_COMMON_H_
+
+#define COMMON_CLOCK_FRAMEWORK_API
+#define IDLE_TASK_DRIVER_API
+#define ENABLE_AFE_APLL_TUNER
+
+#include <linux/clk.h>
+#include <linux/list.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/asound.h>
+#include "../common/mtk-base-afe.h"
+#include "mt8365-reg.h"
+
+#define ENUM_TO_STR(enum) #enum
+
+#define snd_soc_dai_stream_active_playback(dai) \
+ snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_PLAYBACK)
+#define snd_soc_dai_stream_active_capture(dai) \
+ snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_CAPTURE)
+
+enum {
+ MT8365_AFE_MEMIF_DL1,
+ MT8365_AFE_MEMIF_DL2,
+ MT8365_AFE_MEMIF_TDM_OUT,
+ /*
+ * MT8365_AFE_MEMIF_SPDIF_OUT,
+ */
+ MT8365_AFE_MEMIF_AWB,
+ MT8365_AFE_MEMIF_VUL,
+ MT8365_AFE_MEMIF_VUL2,
+ MT8365_AFE_MEMIF_VUL3,
+ MT8365_AFE_MEMIF_TDM_IN,
+ /*
+ * MT8365_AFE_MEMIF_SPDIF_IN,
+ */
+ MT8365_AFE_MEMIF_NUM,
+ MT8365_AFE_BACKEND_BASE = MT8365_AFE_MEMIF_NUM,
+ MT8365_AFE_IO_TDM_OUT = MT8365_AFE_BACKEND_BASE,
+ MT8365_AFE_IO_TDM_IN,
+ MT8365_AFE_IO_I2S,
+ MT8365_AFE_IO_2ND_I2S,
+ MT8365_AFE_IO_PCM1,
+ MT8365_AFE_IO_VIRTUAL_DL_SRC,
+ MT8365_AFE_IO_VIRTUAL_TDM_OUT_SRC,
+ MT8365_AFE_IO_VIRTUAL_FM,
+ MT8365_AFE_IO_DMIC,
+ MT8365_AFE_IO_INT_ADDA,
+ MT8365_AFE_IO_GASRC1,
+ MT8365_AFE_IO_GASRC2,
+ MT8365_AFE_IO_TDM_ASRC,
+ MT8365_AFE_IO_HW_GAIN1,
+ MT8365_AFE_IO_HW_GAIN2,
+ MT8365_AFE_BACKEND_END,
+ MT8365_AFE_BACKEND_NUM = (MT8365_AFE_BACKEND_END -
+ MT8365_AFE_BACKEND_BASE),
+};
+
+enum {
+ MT8365_AFE_IRQ1,
+ MT8365_AFE_IRQ2,
+ MT8365_AFE_IRQ3,
+ MT8365_AFE_IRQ4,
+ MT8365_AFE_IRQ5,
+ MT8365_AFE_IRQ6,
+ MT8365_AFE_IRQ7,
+ MT8365_AFE_IRQ8,
+ MT8365_AFE_IRQ9,
+ MT8365_AFE_IRQ10,
+ MT8365_AFE_IRQ_NUM,
+};
+
+enum {
+ MT8365_TOP_CG_AFE,
+ MT8365_TOP_CG_I2S_IN,
+ MT8365_TOP_CG_22M,
+ MT8365_TOP_CG_24M,
+ MT8365_TOP_CG_INTDIR_CK,
+ MT8365_TOP_CG_APLL2_TUNER,
+ MT8365_TOP_CG_APLL_TUNER,
+ MT8365_TOP_CG_SPDIF,
+ MT8365_TOP_CG_TDM_OUT,
+ MT8365_TOP_CG_TDM_IN,
+ MT8365_TOP_CG_ADC,
+ MT8365_TOP_CG_DAC,
+ MT8365_TOP_CG_DAC_PREDIS,
+ MT8365_TOP_CG_TML,
+ MT8365_TOP_CG_I2S1_BCLK,
+ MT8365_TOP_CG_I2S2_BCLK,
+ MT8365_TOP_CG_I2S3_BCLK,
+ MT8365_TOP_CG_I2S4_BCLK,
+ MT8365_TOP_CG_DMIC0_ADC,
+ MT8365_TOP_CG_DMIC1_ADC,
+ MT8365_TOP_CG_DMIC2_ADC,
+ MT8365_TOP_CG_DMIC3_ADC,
+ MT8365_TOP_CG_CONNSYS_I2S_ASRC,
+ MT8365_TOP_CG_GENERAL1_ASRC,
+ MT8365_TOP_CG_GENERAL2_ASRC,
+ MT8365_TOP_CG_TDM_ASRC,
+ MT8365_TOP_CG_NUM
+};
+
+enum {
+ MT8365_CLK_TOP_AUD_SEL,
+ MT8365_CLK_AUD_I2S0_M,
+ MT8365_CLK_AUD_I2S1_M,
+ MT8365_CLK_AUD_I2S2_M,
+ MT8365_CLK_AUD_I2S3_M,
+ MT8365_CLK_ENGEN1,
+ MT8365_CLK_ENGEN2,
+ MT8365_CLK_AUD1,
+ MT8365_CLK_AUD2,
+ MT8365_CLK_I2S0_M_SEL,
+ MT8365_CLK_I2S1_M_SEL,
+ MT8365_CLK_I2S2_M_SEL,
+ MT8365_CLK_I2S3_M_SEL,
+ MT8365_CLK_CLK26M,
+ MT8365_CLK_NUM
+};
+
+enum {
+ MT8365_AFE_APLL1 = 0,
+ MT8365_AFE_APLL2,
+ MT8365_AFE_APLL_NUM,
+};
+
+enum {
+ MT8365_AFE_1ST_I2S = 0,
+ MT8365_AFE_2ND_I2S,
+ MT8365_AFE_I2S_SETS,
+};
+
+enum {
+ MT8365_AFE_I2S_SEPARATE_CLOCK = 0,
+ MT8365_AFE_I2S_SHARED_CLOCK,
+};
+
+enum {
+ MT8365_AFE_TDM_OUT_I2S = 0,
+ MT8365_AFE_TDM_OUT_TDM,
+ MT8365_AFE_TDM_OUT_I2S_32BITS,
+};
+
+enum mt8365_afe_tdm_ch_start {
+ AFE_TDM_CH_START_O28_O29 = 0,
+ AFE_TDM_CH_START_O30_O31,
+ AFE_TDM_CH_START_O32_O33,
+ AFE_TDM_CH_START_O34_O35,
+ AFE_TDM_CH_ZERO,
+};
+
+enum {
+ MT8365_PCM_FORMAT_I2S = 0,
+ MT8365_PCM_FORMAT_EIAJ,
+ MT8365_PCM_FORMAT_PCMA,
+ MT8365_PCM_FORMAT_PCMB,
+};
+
+enum {
+ MT8365_FS_8K = 0,
+ MT8365_FS_11D025K,
+ MT8365_FS_12K,
+ MT8365_FS_384K,
+ MT8365_FS_16K,
+ MT8365_FS_22D05K,
+ MT8365_FS_24K,
+ MT8365_FS_130K,
+ MT8365_FS_32K,
+ MT8365_FS_44D1K,
+ MT8365_FS_48K,
+ MT8365_FS_88D2K,
+ MT8365_FS_96K,
+ MT8365_FS_176D4K,
+ MT8365_FS_192K,
+};
+
+enum {
+ FS_8000HZ = 0, /* 0000b */
+ FS_11025HZ = 1, /* 0001b */
+ FS_12000HZ = 2, /* 0010b */
+ FS_384000HZ = 3, /* 0011b */
+ FS_16000HZ = 4, /* 0100b */
+ FS_22050HZ = 5, /* 0101b */
+ FS_24000HZ = 6, /* 0110b */
+ FS_130000HZ = 7, /* 0111b */
+ FS_32000HZ = 8, /* 1000b */
+ FS_44100HZ = 9, /* 1001b */
+ FS_48000HZ = 10, /* 1010b */
+ FS_88200HZ = 11, /* 1011b */
+ FS_96000HZ = 12, /* 1100b */
+ FS_176400HZ = 13, /* 1101b */
+ FS_192000HZ = 14, /* 1110b */
+ FS_260000HZ = 15, /* 1111b */
+};
+
+enum {
+ MT8365_AFE_DEBUGFS_AFE,
+ MT8365_AFE_DEBUGFS_MEMIF,
+ MT8365_AFE_DEBUGFS_IRQ,
+ MT8365_AFE_DEBUGFS_CONN,
+ MT8365_AFE_DEBUGFS_DBG,
+ MT8365_AFE_DEBUGFS_NUM,
+};
+
+enum {
+ MT8365_AFE_IRQ_DIR_MCU = 0,
+ MT8365_AFE_IRQ_DIR_DSP,
+ MT8365_AFE_IRQ_DIR_BOTH,
+};
+
+/* MCLK */
+enum {
+ MT8365_I2S0_MCK = 0,
+ MT8365_I2S3_MCK,
+ MT8365_MCK_NUM,
+};
+
+struct mt8365_fe_dai_data {
+ bool use_sram;
+ unsigned int sram_phy_addr;
+ void __iomem *sram_vir_addr;
+ unsigned int sram_size;
+};
+
+struct mt8365_be_dai_data {
+ bool prepared[SNDRV_PCM_STREAM_LAST + 1];
+ unsigned int fmt_mode;
+};
+
+#define MT8365_CLK_26M 26000000
+#define MT8365_CLK_24M 24000000
+#define MT8365_CLK_22M 22000000
+#define MT8365_CM_UPDATA_CNT_SET 8
+
+enum mt8365_cm_num {
+ MT8365_CM1 = 0,
+ MT8365_CM2,
+ MT8365_CM_NUM,
+};
+
+enum mt8365_cm2_mux_in {
+ MT8365_FROM_GASRC1 = 1,
+ MT8365_FROM_GASRC2,
+ MT8365_FROM_TDM_ASRC,
+ MT8365_CM_MUX_NUM,
+};
+
+enum cm2_mux_conn_in {
+ GENERAL2_ASRC_OUT_LCH = 0,
+ GENERAL2_ASRC_OUT_RCH = 1,
+ TDM_IN_CH0 = 2,
+ TDM_IN_CH1 = 3,
+ TDM_IN_CH2 = 4,
+ TDM_IN_CH3 = 5,
+ TDM_IN_CH4 = 6,
+ TDM_IN_CH5 = 7,
+ TDM_IN_CH6 = 8,
+ TDM_IN_CH7 = 9,
+ GENERAL1_ASRC_OUT_LCH = 10,
+ GENERAL1_ASRC_OUT_RCH = 11,
+ TDM_OUT_ASRC_CH0 = 12,
+ TDM_OUT_ASRC_CH1 = 13,
+ TDM_OUT_ASRC_CH2 = 14,
+ TDM_OUT_ASRC_CH3 = 15,
+ TDM_OUT_ASRC_CH4 = 16,
+ TDM_OUT_ASRC_CH5 = 17,
+ TDM_OUT_ASRC_CH6 = 18,
+ TDM_OUT_ASRC_CH7 = 19
+};
+
+struct mt8365_cm_ctrl_reg {
+ unsigned int con0;
+ unsigned int con1;
+ unsigned int con2;
+ unsigned int con3;
+ unsigned int con4;
+};
+
+struct mt8365_control_data {
+ bool bypass_cm1;
+ bool bypass_cm2;
+ unsigned int loopback_type;
+};
+
+enum dmic_input_mode {
+ DMIC_MODE_3P25M = 0,
+ DMIC_MODE_1P625M,
+ DMIC_MODE_812P5K,
+ DMIC_MODE_406P25K,
+};
+
+enum iir_mode {
+ IIR_MODE0 = 0,
+ IIR_MODE1,
+ IIR_MODE2,
+ IIR_MODE3,
+ IIR_MODE4,
+ IIR_MODE5,
+};
+
+enum {
+ MT8365_GASRC1 = 0,
+ MT8365_GASRC2,
+ MT8365_GASRC_NUM,
+ MT8365_TDM_ASRC1 = MT8365_GASRC_NUM,
+ MT8365_TDM_ASRC2,
+ MT8365_TDM_ASRC3,
+ MT8365_TDM_ASRC4,
+ MT8365_TDM_ASRC_NUM,
+};
+
+struct mt8365_gasrc_ctrl_reg {
+ unsigned int con0;
+ unsigned int con2;
+ unsigned int con3;
+ unsigned int con4;
+ unsigned int con5;
+ unsigned int con6;
+ unsigned int con9;
+ unsigned int con10;
+ unsigned int con12;
+ unsigned int con13;
+};
+
+struct mt8365_gasrc_data {
+ bool duplex;
+ bool tx_mode;
+ bool cali_on;
+ bool tdm_asrc_out_cm2;
+ bool iir_on;
+};
+
+#ifdef CONFIG_MTK_HIFIXDSP_SUPPORT
+struct mt8365_adsp_data {
+ /* information adsp supply */
+ bool adsp_on;
+ int (*hostless_active)(void);
+ /* information afe supply */
+ int (*set_afe_memif)(struct mtk_base_afe *afe,
+ int memif_id,
+ unsigned int rate,
+ unsigned int channels,
+ snd_pcm_format_t format);
+ int (*set_afe_memif_enable)(struct mtk_base_afe *afe,
+ int memif_id,
+ unsigned int rate,
+ unsigned int period_size,
+ int enable);
+ void (*get_afe_memif_sram)(struct mtk_base_afe *afe,
+ int memif_id,
+ unsigned int *paddr,
+ unsigned int *size);
+ void (*set_afe_init)(struct mtk_base_afe *afe);
+ void (*set_afe_uninit)(struct mtk_base_afe *afe);
+};
+#endif
+
+struct mt8365_afe_private {
+ struct clk *clocks[MT8365_CLK_NUM];
+ struct regmap *topckgen;
+ struct mt8365_fe_dai_data fe_data[MT8365_AFE_MEMIF_NUM];
+ struct mt8365_be_dai_data be_data[MT8365_AFE_BACKEND_NUM];
+ struct mt8365_control_data ctrl_data;
+ struct mt8365_gasrc_data gasrc_data[MT8365_TDM_ASRC_NUM];
+#ifdef CONFIG_MTK_HIFIXDSP_SUPPORT
+ struct mt8365_adsp_data adsp_data;
+#endif
+ int afe_on_ref_cnt;
+ int top_cg_ref_cnt[MT8365_TOP_CG_NUM];
+ void __iomem *afe_sram_vir_addr;
+ unsigned int afe_sram_phy_addr;
+ unsigned int afe_sram_size;
+ /* locks */
+ spinlock_t afe_ctrl_lock;
+ struct mutex afe_clk_mutex;
+#ifdef IDLE_TASK_DRIVER_API
+ int emi_clk_ref_cnt;
+ struct mutex emi_clk_mutex;
+#endif
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs_dentry[MT8365_AFE_DEBUGFS_NUM];
+#endif
+ int apll_tuner_ref_cnt[MT8365_AFE_APLL_NUM];
+ unsigned int tdm_out_mode;
+ unsigned int cm2_mux_input;
+
+ /* dai */
+ bool dai_on[MT8365_AFE_BACKEND_END];
+ void *dai_priv[MT8365_AFE_BACKEND_END];
+};
+
+static inline u32 rx_frequency_palette(unsigned int fs)
+{
+ /* *
+ * A = (26M / fs) * 64
+ * B = 8125 / A
+ * return = DEC2HEX(B * 2^23)
+ */
+ switch (fs) {
+ case FS_8000HZ: return 0x050000;
+ case FS_11025HZ: return 0x06E400;
+ case FS_12000HZ: return 0x078000;
+ case FS_16000HZ: return 0x0A0000;
+ case FS_22050HZ: return 0x0DC800;
+ case FS_24000HZ: return 0x0F0000;
+ case FS_32000HZ: return 0x140000;
+ case FS_44100HZ: return 0x1B9000;
+ case FS_48000HZ: return 0x1E0000;
+ case FS_88200HZ: return 0x372000;
+ case FS_96000HZ: return 0x3C0000;
+ case FS_176400HZ: return 0x6E4000;
+ case FS_192000HZ: return 0x780000;
+ default: return 0x0;
+ }
+}
+
+static inline u32 AutoRstThHi(unsigned int fs)
+{
+ switch (fs) {
+ case FS_8000HZ: return 0x36000;
+ case FS_11025HZ: return 0x27000;
+ case FS_12000HZ: return 0x24000;
+ case FS_16000HZ: return 0x1B000;
+ case FS_22050HZ: return 0x14000;
+ case FS_24000HZ: return 0x12000;
+ case FS_32000HZ: return 0x0D800;
+ case FS_44100HZ: return 0x09D00;
+ case FS_48000HZ: return 0x08E00;
+ case FS_88200HZ: return 0x04E00;
+ case FS_96000HZ: return 0x04800;
+ case FS_176400HZ: return 0x02700;
+ case FS_192000HZ: return 0x02400;
+ default: return 0x0;
+ }
+}
+
+static inline u32 AutoRstThLo(unsigned int fs)
+{
+ switch (fs) {
+ case FS_8000HZ: return 0x30000;
+ case FS_11025HZ: return 0x23000;
+ case FS_12000HZ: return 0x20000;
+ case FS_16000HZ: return 0x18000;
+ case FS_22050HZ: return 0x11000;
+ case FS_24000HZ: return 0x0FE00;
+ case FS_32000HZ: return 0x0BE00;
+ case FS_44100HZ: return 0x08A00;
+ case FS_48000HZ: return 0x07F00;
+ case FS_88200HZ: return 0x04500;
+ case FS_96000HZ: return 0x04000;
+ case FS_176400HZ: return 0x02300;
+ case FS_192000HZ: return 0x02000;
+ default: return 0x0;
+ }
+}
+
+bool mt8365_afe_clk_group_48k(int sample_rate);
+bool mt8365_afe_rate_supported(unsigned int rate, unsigned int id);
+bool mt8365_afe_channel_supported(unsigned int channel, unsigned int id);
+#ifdef CONFIG_MTK_HIFIXDSP_SUPPORT
+struct mtk_base_afe *mt8365_afe_pcm_get_info(void);
+#endif
+
+int mt8365_dai_i2s_register(struct mtk_base_afe *afe);
+int mt8365_dai_set_priv(struct mtk_base_afe *afe,
+ int id,
+ int priv_size,
+ const void *priv_data);
+
+int mt8365_afe_fs_timing(unsigned int rate);
+
+void mt8365_afe_set_i2s_out_enable(struct mtk_base_afe *afe, bool enable);
+int mt8365_afe_set_i2s_out(struct mtk_base_afe *afe, unsigned int rate, int bit_width);
+
+int mt8365_dai_adda_register(struct mtk_base_afe *afe);
+int mt8365_dai_enable_adda_on(struct mtk_base_afe *afe);
+int mt8365_dai_disable_adda_on(struct mtk_base_afe *afe);
+
+int mt8365_dai_dmic_register(struct mtk_base_afe *afe);
+
+int mt8365_dai_pcm_register(struct mtk_base_afe *afe);
+
+int mt8365_dai_tdm_register(struct mtk_base_afe *afe);
+
+#endif
diff --git a/sound/soc/mediatek/mt8365/mt8365-reg.h b/sound/soc/mediatek/mt8365/mt8365-reg.h
new file mode 100644
index 000000000000..318be6d1f8b6
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/mt8365-reg.h
@@ -0,0 +1,987 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Mediatek 8365 audio driver reg definition
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Authors: Jia Zeng <[email protected]>
+ * Alexandre Mergnat <[email protected]>
+ */
+
+#ifndef _MT8365_REG_H_
+#define _MT8365_REG_H_
+
+#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_DAC_CON1 (0x0014)
+#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_MRGIF_CON (0x003c)
+#define AFE_DL1_BASE (0x0040)
+#define AFE_DL1_CUR (0x0044)
+#define AFE_DL1_END (0x0048)
+#define AFE_I2S_CON3 (0x004c)
+#define AFE_DL2_BASE (0x0050)
+#define AFE_DL2_CUR (0x0054)
+#define AFE_DL2_END (0x0058)
+#define AFE_CONN5 (0x005c)
+#define AFE_AWB_BASE (0x0070)
+#define AFE_AWB_END (0x0078)
+#define AFE_AWB_CUR (0x007c)
+#define AFE_VUL_BASE (0x0080)
+#define AFE_VUL_END (0x0088)
+#define AFE_VUL_CUR (0x008c)
+#define AFE_CONN6 (0x00bc)
+#define AFE_MEMIF_MSB (0x00cc)
+#define AFE_MEMIF_MON0 (0x00d0)
+#define AFE_MEMIF_MON1 (0x00d4)
+#define AFE_MEMIF_MON2 (0x00d8)
+#define AFE_MEMIF_MON3 (0x00dc)
+#define AFE_MEMIF_MON4 (0x00e0)
+#define AFE_MEMIF_MON5 (0x00e4)
+#define AFE_MEMIF_MON6 (0x00e8)
+#define AFE_MEMIF_MON7 (0x00ec)
+#define AFE_MEMIF_MON8 (0x00f0)
+#define AFE_MEMIF_MON9 (0x00f4)
+#define AFE_MEMIF_MON10 (0x00f8)
+#define AFE_MEMIF_MON11 (0x00fc)
+#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_SRAM_BOUND (0x0170)
+#define AFE_SECURE_CON (0x0174)
+#define AFE_SECURE_CONN0 (0x0178)
+#define AFE_SIDETONE_DEBUG (0x01d0)
+#define AFE_SIDETONE_MON (0x01d4)
+#define AFE_SIDETONE_CON0 (0x01e0)
+#define AFE_SIDETONE_COEFF (0x01e4)
+#define AFE_SIDETONE_CON1 (0x01e8)
+#define AFE_SIDETONE_GAIN (0x01ec)
+#define AFE_SGEN_CON0 (0x01f0)
+#define AFE_SINEGEN_CON_TDM (0x01f8)
+#define AFE_SINEGEN_CON_TDM_IN (0x01fc)
+#define AFE_TOP_CON0 (0x0200)
+#define AFE_BUS_CFG (0x0240)
+#define AFE_BUS_MON0 (0x0244)
+#define AFE_ADDA_PREDIS_CON0 (0x0260)
+#define AFE_ADDA_PREDIS_CON1 (0x0264)
+#define AFE_CONN_MON0 (0x0280)
+#define AFE_CONN_MON1 (0x0284)
+#define AFE_CONN_MON2 (0x0288)
+#define AFE_CONN_MON3 (0x028c)
+#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_VUL_D2_BASE (0x0350)
+#define AFE_VUL_D2_END (0x0358)
+#define AFE_VUL_D2_CUR (0x035c)
+#define AFE_HDMI_OUT_CON0 (0x0370)
+#define AFE_HDMI_OUT_BASE (0x0374)
+#define AFE_HDMI_OUT_CUR (0x0378)
+#define AFE_HDMI_OUT_END (0x037c)
+#define AFE_SPDIF_OUT_CON0 (0x0380)
+#define AFE_SPDIF_OUT_BASE (0x0384)
+#define AFE_SPDIF_OUT_CUR (0x0388)
+#define AFE_SPDIF_OUT_END (0x038c)
+#define AFE_HDMI_CONN0 (0x0390)
+#define AFE_HDMI_CONN1 (0x0398)
+#define AFE_CONN_TDMIN_CON (0x039c)
+#define AFE_IRQ_MCU_CON (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_IRQ1_MCU_EN_CNT_MON (0x03c8)
+#define AFE_IRQ5_MCU_CNT_MON (0x03cc)
+#define AFE_MEMIF_MINLEN (0x03d0)
+#define AFE_MEMIF_MAXLEN (0x03d4)
+#define AFE_MEMIF_PBUF_SIZE (0x03d8)
+#define AFE_IRQ_MCU_CNT7 (0x03dc)
+#define AFE_IRQ7_MCU_CNT_MON (0x03e0)
+#define AFE_MEMIF_PBUF2_SIZE (0x03ec)
+#define AFE_APLL_TUNER_CFG (0x03f0)
+#define AFE_APLL_TUNER_CFG1 (0x03f4)
+#define AFE_IRQ_MCU_CON2 (0x03f8)
+#define IRQ13_MCU_CNT (0x0408)
+#define IRQ13_MCU_CNT_MON (0x040c)
+#define AFE_GAIN1_CON0 (0x0410)
+#define AFE_GAIN1_CON1 (0x0414)
+#define AFE_GAIN1_CON2 (0x0418)
+#define AFE_GAIN1_CON3 (0x041c)
+#define AFE_GAIN2_CON0 (0x0428)
+#define AFE_GAIN2_CON1 (0x042c)
+#define AFE_GAIN2_CON2 (0x0430)
+#define AFE_GAIN2_CON3 (0x0434)
+#define AFE_GAIN2_CUR (0x043c)
+#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_CONN7 (0x0460)
+#define AFE_CONN8 (0x0464)
+#define AFE_CONN9 (0x0468)
+#define AFE_CONN10 (0x046c)
+#define AFE_CONN21 (0x0470)
+#define AFE_CONN22 (0x0474)
+#define AFE_CONN23 (0x0478)
+#define AFE_CONN24 (0x047c)
+#define AFE_IEC_CFG (0x0480)
+#define AFE_IEC_NSNUM (0x0484)
+#define AFE_IEC_BURST_INFO (0x0488)
+#define AFE_IEC_BURST_LEN (0x048c)
+#define AFE_IEC_NSADR (0x0490)
+#define AFE_CONN_RS (0x0494)
+#define AFE_CONN_DI (0x0498)
+#define AFE_IEC_CHL_STAT0 (0x04a0)
+#define AFE_IEC_CHL_STAT1 (0x04a4)
+#define AFE_IEC_CHR_STAT0 (0x04a8)
+#define AFE_IEC_CHR_STAT1 (0x04ac)
+#define AFE_CONN25 (0x04b0)
+#define AFE_CONN26 (0x04b4)
+#define FPGA_CFG2 (0x04b8)
+#define FPGA_CFG3 (0x04bc)
+#define FPGA_CFG0 (0x04c0)
+#define FPGA_CFG1 (0x04c4)
+#define AFE_SRAM_DELSEL_CON0 (0x04f0)
+#define AFE_SRAM_DELSEL_CON1 (0x04f4)
+#define AFE_SRAM_DELSEL_CON2 (0x04f8)
+#define FPGA_CFG4 (0x04fc)
+#define AFE_TDM_GASRC4_ASRC_2CH_CON0 (0x0500)
+#define AFE_TDM_GASRC4_ASRC_2CH_CON1 (0x0504)
+#define AFE_TDM_GASRC4_ASRC_2CH_CON2 (0x0508)
+#define AFE_TDM_GASRC4_ASRC_2CH_CON3 (0x050c)
+#define AFE_TDM_GASRC4_ASRC_2CH_CON4 (0x0510)
+#define AFE_TDM_GASRC4_ASRC_2CH_CON5 (0x0514)
+#define AFE_TDM_GASRC4_ASRC_2CH_CON6 (0x0518)
+#define AFE_TDM_GASRC4_ASRC_2CH_CON7 (0x051c)
+#define AFE_TDM_GASRC4_ASRC_2CH_CON8 (0x0520)
+#define AFE_TDM_GASRC4_ASRC_2CH_CON9 (0x0524)
+#define AFE_TDM_GASRC4_ASRC_2CH_CON10 (0x0528)
+#define AFE_TDM_GASRC4_ASRC_2CH_CON12 (0x0530)
+#define AFE_TDM_GASRC4_ASRC_2CH_CON13 (0x0534)
+#define PCM_INTF_CON2 (0x0538)
+#define PCM2_INTF_CON (0x053c)
+#define AFE_APB_MON (0x0540)
+#define AFE_CONN34 (0x0544)
+#define AFE_TDM_CON1 (0x0548)
+#define AFE_TDM_CON2 (0x054c)
+#define PCM_INTF_CON1 (0x0550)
+#define AFE_SECURE_MASK_CONN47_1 (0x0554)
+#define AFE_SECURE_MASK_CONN48_1 (0x0558)
+#define AFE_SECURE_MASK_CONN49_1 (0x055c)
+#define AFE_SECURE_MASK_CONN50_1 (0x0560)
+#define AFE_SECURE_MASK_CONN51_1 (0x0564)
+#define AFE_SECURE_MASK_CONN52_1 (0x0568)
+#define AFE_SECURE_MASK_CONN53_1 (0x056c)
+#define AFE_SE_SECURE_CON (0x0570)
+#define AFE_TDM_IN_CON1 (0x0588)
+#define AFE_TDM_IN_CON2 (0x058c)
+#define AFE_TDM_IN_MON1 (0x0590)
+#define AFE_TDM_IN_MON2 (0x0594)
+#define AFE_TDM_IN_MON3 (0x0598)
+#define AFE_DMIC0_UL_SRC_CON0 (0x05b4)
+#define AFE_DMIC0_UL_SRC_CON1 (0x05b8)
+#define AFE_DMIC0_SRC_DEBUG (0x05bc)
+#define AFE_DMIC0_SRC_DEBUG_MON0 (0x05c0)
+#define AFE_DMIC0_UL_SRC_MON0 (0x05c8)
+#define AFE_DMIC0_UL_SRC_MON1 (0x05cc)
+#define AFE_DMIC0_IIR_COEF_02_01 (0x05d0)
+#define AFE_DMIC0_IIR_COEF_04_03 (0x05d4)
+#define AFE_DMIC0_IIR_COEF_06_05 (0x05d8)
+#define AFE_DMIC0_IIR_COEF_08_07 (0x05dc)
+#define AFE_DMIC0_IIR_COEF_10_09 (0x05e0)
+#define AFE_DMIC1_UL_SRC_CON0 (0x0620)
+#define AFE_DMIC1_UL_SRC_CON1 (0x0624)
+#define AFE_DMIC1_SRC_DEBUG (0x0628)
+#define AFE_DMIC1_SRC_DEBUG_MON0 (0x062c)
+#define AFE_DMIC1_UL_SRC_MON0 (0x0634)
+#define AFE_DMIC1_UL_SRC_MON1 (0x0638)
+#define AFE_DMIC1_IIR_COEF_02_01 (0x063c)
+#define AFE_DMIC1_IIR_COEF_04_03 (0x0640)
+#define AFE_DMIC1_IIR_COEF_06_05 (0x0644)
+#define AFE_DMIC1_IIR_COEF_08_07 (0x0648)
+#define AFE_DMIC1_IIR_COEF_10_09 (0x064c)
+#define AFE_SECURE_MASK_CONN39_1 (0x068c)
+#define AFE_SECURE_MASK_CONN40_1 (0x0690)
+#define AFE_SECURE_MASK_CONN41_1 (0x0694)
+#define AFE_SECURE_MASK_CONN42_1 (0x0698)
+#define AFE_SECURE_MASK_CONN43_1 (0x069c)
+#define AFE_SECURE_MASK_CONN44_1 (0x06a0)
+#define AFE_SECURE_MASK_CONN45_1 (0x06a4)
+#define AFE_SECURE_MASK_CONN46_1 (0x06a8)
+#define AFE_TDM_GASRC1_ASRC_2CH_CON0 (0x06c0)
+#define AFE_TDM_GASRC1_ASRC_2CH_CON1 (0x06c4)
+#define AFE_TDM_GASRC1_ASRC_2CH_CON2 (0x06c8)
+#define AFE_TDM_GASRC1_ASRC_2CH_CON3 (0x06cc)
+#define AFE_TDM_GASRC1_ASRC_2CH_CON4 (0x06d0)
+#define AFE_TDM_GASRC1_ASRC_2CH_CON5 (0x06d4)
+#define AFE_TDM_GASRC1_ASRC_2CH_CON6 (0x06d8)
+#define AFE_TDM_GASRC1_ASRC_2CH_CON7 (0x06dc)
+#define AFE_TDM_GASRC1_ASRC_2CH_CON8 (0x06e0)
+#define AFE_TDM_GASRC1_ASRC_2CH_CON9 (0x06e4)
+#define AFE_TDM_GASRC1_ASRC_2CH_CON10 (0x06e8)
+#define AFE_TDM_GASRC1_ASRC_2CH_CON12 (0x06f0)
+#define AFE_TDM_GASRC1_ASRC_2CH_CON13 (0x06f4)
+#define AFE_TDM_ASRC_CON0 (0x06f8)
+#define AFE_TDM_GASRC2_ASRC_2CH_CON0 (0x0700)
+#define AFE_TDM_GASRC2_ASRC_2CH_CON1 (0x0704)
+#define AFE_TDM_GASRC2_ASRC_2CH_CON2 (0x0708)
+#define AFE_TDM_GASRC2_ASRC_2CH_CON3 (0x070c)
+#define AFE_TDM_GASRC2_ASRC_2CH_CON4 (0x0710)
+#define AFE_TDM_GASRC2_ASRC_2CH_CON5 (0x0714)
+#define AFE_TDM_GASRC2_ASRC_2CH_CON6 (0x0718)
+#define AFE_TDM_GASRC2_ASRC_2CH_CON7 (0x071c)
+#define AFE_TDM_GASRC2_ASRC_2CH_CON8 (0x0720)
+#define AFE_TDM_GASRC2_ASRC_2CH_CON9 (0x0724)
+#define AFE_TDM_GASRC2_ASRC_2CH_CON10 (0x0728)
+#define AFE_TDM_GASRC2_ASRC_2CH_CON12 (0x0730)
+#define AFE_TDM_GASRC2_ASRC_2CH_CON13 (0x0734)
+#define AFE_TDM_GASRC3_ASRC_2CH_CON0 (0x0740)
+#define AFE_TDM_GASRC3_ASRC_2CH_CON1 (0x0744)
+#define AFE_TDM_GASRC3_ASRC_2CH_CON2 (0x0748)
+#define AFE_TDM_GASRC3_ASRC_2CH_CON3 (0x074c)
+#define AFE_TDM_GASRC3_ASRC_2CH_CON4 (0x0750)
+#define AFE_TDM_GASRC3_ASRC_2CH_CON5 (0x0754)
+#define AFE_TDM_GASRC3_ASRC_2CH_CON6 (0x0758)
+#define AFE_TDM_GASRC3_ASRC_2CH_CON7 (0x075c)
+#define AFE_TDM_GASRC3_ASRC_2CH_CON8 (0x0760)
+#define AFE_TDM_GASRC3_ASRC_2CH_CON9 (0x0764)
+#define AFE_TDM_GASRC3_ASRC_2CH_CON10 (0x0768)
+#define AFE_TDM_GASRC3_ASRC_2CH_CON12 (0x0770)
+#define AFE_TDM_GASRC3_ASRC_2CH_CON13 (0x0774)
+#define AFE_DMIC2_UL_SRC_CON0 (0x0780)
+#define AFE_DMIC2_UL_SRC_CON1 (0x0784)
+#define AFE_DMIC2_SRC_DEBUG (0x0788)
+#define AFE_DMIC2_SRC_DEBUG_MON0 (0x078c)
+#define AFE_DMIC2_UL_SRC_MON0 (0x0794)
+#define AFE_DMIC2_UL_SRC_MON1 (0x0798)
+#define AFE_DMIC2_IIR_COEF_02_01 (0x079c)
+#define AFE_DMIC2_IIR_COEF_04_03 (0x07a0)
+#define AFE_DMIC2_IIR_COEF_06_05 (0x07a4)
+#define AFE_DMIC2_IIR_COEF_08_07 (0x07a8)
+#define AFE_DMIC2_IIR_COEF_10_09 (0x07ac)
+#define AFE_DMIC3_UL_SRC_CON0 (0x07ec)
+#define AFE_DMIC3_UL_SRC_CON1 (0x07f0)
+#define AFE_DMIC3_SRC_DEBUG (0x07f4)
+#define AFE_DMIC3_SRC_DEBUG_MON0 (0x07f8)
+#define AFE_DMIC3_UL_SRC_MON0 (0x0800)
+#define AFE_DMIC3_UL_SRC_MON1 (0x0804)
+#define AFE_DMIC3_IIR_COEF_02_01 (0x0808)
+#define AFE_DMIC3_IIR_COEF_04_03 (0x080c)
+#define AFE_DMIC3_IIR_COEF_06_05 (0x0810)
+#define AFE_DMIC3_IIR_COEF_08_07 (0x0814)
+#define AFE_DMIC3_IIR_COEF_10_09 (0x0818)
+#define AFE_SECURE_MASK_CONN25_1 (0x0858)
+#define AFE_SECURE_MASK_CONN26_1 (0x085c)
+#define AFE_SECURE_MASK_CONN27_1 (0x0860)
+#define AFE_SECURE_MASK_CONN28_1 (0x0864)
+#define AFE_SECURE_MASK_CONN29_1 (0x0868)
+#define AFE_SECURE_MASK_CONN30_1 (0x086c)
+#define AFE_SECURE_MASK_CONN31_1 (0x0870)
+#define AFE_SECURE_MASK_CONN32_1 (0x0874)
+#define AFE_SECURE_MASK_CONN33_1 (0x0878)
+#define AFE_SECURE_MASK_CONN34_1 (0x087c)
+#define AFE_SECURE_MASK_CONN35_1 (0x0880)
+#define AFE_SECURE_MASK_CONN36_1 (0x0884)
+#define AFE_SECURE_MASK_CONN37_1 (0x0888)
+#define AFE_SECURE_MASK_CONN38_1 (0x088c)
+#define AFE_IRQ_MCU_SCP_EN (0x0890)
+#define AFE_IRQ_MCU_DSP_EN (0x0894)
+#define AFE_IRQ3_MCU_CNT_MON (0x0898)
+#define AFE_IRQ4_MCU_CNT_MON (0x089c)
+#define AFE_IRQ8_MCU_CNT_MON (0x08a0)
+#define AFE_IRQ_MCU_CNT3 (0x08a4)
+#define AFE_IRQ_MCU_CNT4 (0x08a8)
+#define AFE_IRQ_MCU_CNT8 (0x08ac)
+#define AFE_IRQ_MCU_CNT11 (0x08b0)
+#define AFE_IRQ_MCU_CNT12 (0x08b4)
+#define AFE_IRQ11_MCU_CNT_MON (0x08b8)
+#define AFE_IRQ12_MCU_CNT_MON (0x08bc)
+#define AFE_VUL3_BASE (0x08c0)
+#define AFE_VUL3_CUR (0x08c4)
+#define AFE_VUL3_END (0x08c8)
+#define AFE_VUL3_BASE_MSB (0x08d0)
+#define AFE_VUL3_END_MSB (0x08d4)
+#define AFE_IRQ10_MCU_CNT_MON (0x08d8)
+#define AFE_IRQ_MCU_CNT10 (0x08dc)
+#define AFE_IRQ_ACC1_CNT (0x08e0)
+#define AFE_IRQ_ACC2_CNT (0x08e4)
+#define AFE_IRQ_ACC1_CNT_MON1 (0x08e8)
+#define AFE_IRQ_ACC2_CNT_MON (0x08ec)
+#define AFE_TSF_CON (0x08f0)
+#define AFE_TSF_MON (0x08f4)
+#define AFE_IRQ_ACC1_CNT_MON2 (0x08f8)
+#define AFE_SPDIFIN_CFG0 (0x0900)
+#define AFE_SPDIFIN_CFG1 (0x0904)
+#define AFE_SPDIFIN_CHSTS1 (0x0908)
+#define AFE_SPDIFIN_CHSTS2 (0x090c)
+#define AFE_SPDIFIN_CHSTS3 (0x0910)
+#define AFE_SPDIFIN_CHSTS4 (0x0914)
+#define AFE_SPDIFIN_CHSTS5 (0x0918)
+#define AFE_SPDIFIN_CHSTS6 (0x091c)
+#define AFE_SPDIFIN_DEBUG1 (0x0920)
+#define AFE_SPDIFIN_DEBUG2 (0x0924)
+#define AFE_SPDIFIN_DEBUG3 (0x0928)
+#define AFE_SPDIFIN_DEBUG4 (0x092c)
+#define AFE_SPDIFIN_EC (0x0930)
+#define AFE_SPDIFIN_CKLOCK_CFG (0x0934)
+#define AFE_SPDIFIN_BR (0x093c)
+#define AFE_SPDIFIN_BR_DBG1 (0x0940)
+#define AFE_SPDIFIN_INT_EXT (0x0948)
+#define AFE_SPDIFIN_INT_EXT2 (0x094c)
+#define SPDIFIN_FREQ_INFO (0x0950)
+#define SPDIFIN_FREQ_INFO_2 (0x0954)
+#define SPDIFIN_FREQ_INFO_3 (0x0958)
+#define SPDIFIN_FREQ_STATUS (0x095c)
+#define SPDIFIN_USERCODE1 (0x0960)
+#define SPDIFIN_USERCODE2 (0x0964)
+#define SPDIFIN_USERCODE3 (0x0968)
+#define SPDIFIN_USERCODE4 (0x096c)
+#define SPDIFIN_USERCODE5 (0x0970)
+#define SPDIFIN_USERCODE6 (0x0974)
+#define SPDIFIN_USERCODE7 (0x0978)
+#define SPDIFIN_USERCODE8 (0x097c)
+#define SPDIFIN_USERCODE9 (0x0980)
+#define SPDIFIN_USERCODE10 (0x0984)
+#define SPDIFIN_USERCODE11 (0x0988)
+#define SPDIFIN_USERCODE12 (0x098c)
+#define SPDIFIN_MEMIF_CON0 (0x0990)
+#define SPDIFIN_BASE_ADR (0x0994)
+#define SPDIFIN_END_ADR (0x0998)
+#define SPDIFIN_APLL_TUNER_CFG (0x09a0)
+#define SPDIFIN_APLL_TUNER_CFG1 (0x09a4)
+#define SPDIFIN_APLL2_TUNER_CFG (0x09a8)
+#define SPDIFIN_APLL2_TUNER_CFG1 (0x09ac)
+#define SPDIFIN_TYPE_DET (0x09b0)
+#define MPHONE_MULTI_CON0 (0x09b4)
+#define SPDIFIN_CUR_ADR (0x09b8)
+#define AFE_SINEGEN_CON_SPDIFIN (0x09bc)
+#define AFE_HDMI_IN_2CH_CON0 (0x09c0)
+#define AFE_HDMI_IN_2CH_BASE (0x09c4)
+#define AFE_HDMI_IN_2CH_END (0x09c8)
+#define AFE_HDMI_IN_2CH_CUR (0x09cc)
+#define AFE_MEMIF_BUF_MON0 (0x09d0)
+#define AFE_MEMIF_BUF_MON1 (0x09d4)
+#define AFE_MEMIF_BUF_MON2 (0x09d8)
+#define AFE_MEMIF_BUF_MON3 (0x09dc)
+#define AFE_MEMIF_BUF_MON6 (0x09e8)
+#define AFE_MEMIF_BUF_MON7 (0x09ec)
+#define AFE_MEMIF_BUF_MON8 (0x09f0)
+#define AFE_MEMIF_BUF_MON10 (0x09f8)
+#define AFE_MEMIF_BUF_MON11 (0x09fc)
+#define SYSTOP_STC_CONFIG (0x0a00)
+#define AUDIO_STC_STATUS (0x0a04)
+#define SYSTOP_W_STC_H (0x0a08)
+#define SYSTOP_W_STC_L (0x0a0c)
+#define SYSTOP_R_STC_H (0x0a10)
+#define SYSTOP_R_STC_L (0x0a14)
+#define AUDIO_W_STC_H (0x0a18)
+#define AUDIO_W_STC_L (0x0a1c)
+#define AUDIO_R_STC_H (0x0a20)
+#define AUDIO_R_STC_L (0x0a24)
+#define SYSTOP_W_STC2_H (0x0a28)
+#define SYSTOP_W_STC2_L (0x0a2c)
+#define SYSTOP_R_STC2_H (0x0a30)
+#define SYSTOP_R_STC2_L (0x0a34)
+#define AUDIO_W_STC2_H (0x0a38)
+#define AUDIO_W_STC2_L (0x0a3c)
+#define AUDIO_R_STC2_H (0x0a40)
+#define AUDIO_R_STC2_L (0x0a44)
+
+#define AFE_CONN17 (0x0a48)
+#define AFE_CONN18 (0x0a4c)
+#define AFE_CONN19 (0x0a50)
+#define AFE_CONN20 (0x0a54)
+#define AFE_CONN27 (0x0a58)
+#define AFE_CONN28 (0x0a5c)
+#define AFE_CONN29 (0x0a60)
+#define AFE_CONN30 (0x0a64)
+#define AFE_CONN31 (0x0a68)
+#define AFE_CONN32 (0x0a6c)
+#define AFE_CONN33 (0x0a70)
+#define AFE_CONN35 (0x0a74)
+#define AFE_CONN36 (0x0a78)
+#define AFE_CONN37 (0x0a7c)
+#define AFE_CONN38 (0x0a80)
+#define AFE_CONN39 (0x0a84)
+#define AFE_CONN40 (0x0a88)
+#define AFE_CONN41 (0x0a8c)
+#define AFE_CONN42 (0x0a90)
+#define AFE_CONN44 (0x0a94)
+#define AFE_CONN45 (0x0a98)
+#define AFE_CONN46 (0x0a9c)
+#define AFE_CONN47 (0x0aa0)
+#define AFE_CONN_24BIT (0x0aa4)
+#define AFE_CONN0_1 (0x0aa8)
+#define AFE_CONN1_1 (0x0aac)
+#define AFE_CONN2_1 (0x0ab0)
+#define AFE_CONN3_1 (0x0ab4)
+#define AFE_CONN4_1 (0x0ab8)
+#define AFE_CONN5_1 (0x0abc)
+#define AFE_CONN6_1 (0x0ac0)
+#define AFE_CONN7_1 (0x0ac4)
+#define AFE_CONN8_1 (0x0ac8)
+#define AFE_CONN9_1 (0x0acc)
+#define AFE_CONN10_1 (0x0ad0)
+#define AFE_CONN11_1 (0x0ad4)
+#define AFE_CONN12_1 (0x0ad8)
+#define AFE_CONN13_1 (0x0adc)
+#define AFE_CONN14_1 (0x0ae0)
+#define AFE_CONN15_1 (0x0ae4)
+#define AFE_CONN16_1 (0x0ae8)
+#define AFE_CONN17_1 (0x0aec)
+#define AFE_CONN18_1 (0x0af0)
+#define AFE_CONN19_1 (0x0af4)
+#define AFE_CONN43 (0x0af8)
+#define AFE_CONN43_1 (0x0afc)
+#define AFE_CONN21_1 (0x0b00)
+#define AFE_CONN22_1 (0x0b04)
+#define AFE_CONN23_1 (0x0b08)
+#define AFE_CONN24_1 (0x0b0c)
+#define AFE_CONN25_1 (0x0b10)
+#define AFE_CONN26_1 (0x0b14)
+#define AFE_CONN27_1 (0x0b18)
+#define AFE_CONN28_1 (0x0b1c)
+#define AFE_CONN29_1 (0x0b20)
+#define AFE_CONN30_1 (0x0b24)
+#define AFE_CONN31_1 (0x0b28)
+#define AFE_CONN32_1 (0x0b2c)
+#define AFE_CONN33_1 (0x0b30)
+#define AFE_CONN34_1 (0x0b34)
+#define AFE_CONN35_1 (0x0b38)
+#define AFE_CONN36_1 (0x0b3c)
+#define AFE_CONN37_1 (0x0b40)
+#define AFE_CONN38_1 (0x0b44)
+#define AFE_CONN39_1 (0x0b48)
+#define AFE_CONN40_1 (0x0b4c)
+#define AFE_CONN41_1 (0x0b50)
+#define AFE_CONN42_1 (0x0b54)
+#define AFE_CONN44_1 (0x0b58)
+#define AFE_CONN45_1 (0x0b5c)
+#define AFE_CONN46_1 (0x0b60)
+#define AFE_CONN47_1 (0x0b64)
+#define AFE_CONN_RS_1 (0x0b68)
+#define AFE_CONN_DI_1 (0x0b6c)
+#define AFE_CONN_24BIT_1 (0x0b70)
+#define AFE_GAIN1_CUR (0x0b78)
+#define AFE_CONN20_1 (0x0b7c)
+#define AFE_DL1_BASE_MSB (0x0b80)
+#define AFE_DL1_END_MSB (0x0b84)
+#define AFE_DL2_BASE_MSB (0x0b88)
+#define AFE_DL2_END_MSB (0x0b8c)
+#define AFE_AWB_BASE_MSB (0x0b90)
+#define AFE_AWB_END_MSB (0x0b94)
+#define AFE_VUL_BASE_MSB (0x0ba0)
+#define AFE_VUL_END_MSB (0x0ba4)
+#define AFE_VUL_D2_BASE_MSB (0x0ba8)
+#define AFE_VUL_D2_END_MSB (0x0bac)
+#define AFE_HDMI_OUT_BASE_MSB (0x0bb8)
+#define AFE_HDMI_OUT_END_MSB (0x0bbc)
+#define AFE_HDMI_IN_2CH_BASE_MSB (0x0bc0)
+#define AFE_HDMI_IN_2CH_END_MSB (0x0bc4)
+#define AFE_SPDIF_OUT_BASE_MSB (0x0bc8)
+#define AFE_SPDIF_OUT_END_MSB (0x0bcc)
+#define SPDIFIN_BASE_MSB (0x0bd0)
+#define SPDIFIN_END_MSB (0x0bd4)
+#define AFE_DL1_CUR_MSB (0x0bd8)
+#define AFE_DL2_CUR_MSB (0x0bdc)
+#define AFE_AWB_CUR_MSB (0x0be8)
+#define AFE_VUL_CUR_MSB (0x0bf8)
+#define AFE_VUL_D2_CUR_MSB (0x0c04)
+#define AFE_HDMI_OUT_CUR_MSB (0x0c0c)
+#define AFE_HDMI_IN_2CH_CUR_MSB (0x0c10)
+#define AFE_SPDIF_OUT_CUR_MSB (0x0c14)
+#define SPDIFIN_CUR_MSB (0x0c18)
+#define AFE_CONN_REG (0x0c20)
+#define AFE_SECURE_MASK_CONN14_1 (0x0c24)
+#define AFE_SECURE_MASK_CONN15_1 (0x0c28)
+#define AFE_SECURE_MASK_CONN16_1 (0x0c2c)
+#define AFE_SECURE_MASK_CONN17_1 (0x0c30)
+#define AFE_SECURE_MASK_CONN18_1 (0x0c34)
+#define AFE_SECURE_MASK_CONN19_1 (0x0c38)
+#define AFE_SECURE_MASK_CONN20_1 (0x0c3c)
+#define AFE_SECURE_MASK_CONN21_1 (0x0c40)
+#define AFE_SECURE_MASK_CONN22_1 (0x0c44)
+#define AFE_SECURE_MASK_CONN23_1 (0x0c48)
+#define AFE_SECURE_MASK_CONN24_1 (0x0c4c)
+#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_VUL3_CUR_MSB (0x0c78)
+#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_PCM_TX_ASRC_2CH_CON0 (0x0cc0)
+#define AFE_PCM_TX_ASRC_2CH_CON1 (0x0cc4)
+#define AFE_PCM_TX_ASRC_2CH_CON2 (0x0cc8)
+#define AFE_PCM_TX_ASRC_2CH_CON3 (0x0ccc)
+#define AFE_PCM_TX_ASRC_2CH_CON4 (0x0cd0)
+#define AFE_PCM_TX_ASRC_2CH_CON5 (0x0cd4)
+#define AFE_PCM_TX_ASRC_2CH_CON6 (0x0cd8)
+#define AFE_PCM_TX_ASRC_2CH_CON7 (0x0cdc)
+#define AFE_PCM_TX_ASRC_2CH_CON8 (0x0ce0)
+#define AFE_PCM_TX_ASRC_2CH_CON9 (0x0ce4)
+#define AFE_PCM_TX_ASRC_2CH_CON10 (0x0ce8)
+#define AFE_PCM_TX_ASRC_2CH_CON12 (0x0cf0)
+#define AFE_PCM_TX_ASRC_2CH_CON13 (0x0cf4)
+#define AFE_PCM_RX_ASRC_2CH_CON0 (0x0d00)
+#define AFE_PCM_RX_ASRC_2CH_CON1 (0x0d04)
+#define AFE_PCM_RX_ASRC_2CH_CON2 (0x0d08)
+#define AFE_PCM_RX_ASRC_2CH_CON3 (0x0d0c)
+#define AFE_PCM_RX_ASRC_2CH_CON4 (0x0d10)
+#define AFE_PCM_RX_ASRC_2CH_CON5 (0x0d14)
+#define AFE_PCM_RX_ASRC_2CH_CON6 (0x0d18)
+#define AFE_PCM_RX_ASRC_2CH_CON7 (0x0d1c)
+#define AFE_PCM_RX_ASRC_2CH_CON8 (0x0d20)
+#define AFE_PCM_RX_ASRC_2CH_CON9 (0x0d24)
+#define AFE_PCM_RX_ASRC_2CH_CON10 (0x0d28)
+#define AFE_PCM_RX_ASRC_2CH_CON12 (0x0d30)
+#define AFE_PCM_RX_ASRC_2CH_CON13 (0x0d34)
+
+#define AFE_ADDA_PREDIS_CON2 (0x0d40)
+#define AFE_ADDA_PREDIS_CON3 (0x0d44)
+#define AFE_SECURE_MASK_CONN4_1 (0x0d48)
+#define AFE_SECURE_MASK_CONN5_1 (0x0d4c)
+#define AFE_SECURE_MASK_CONN6_1 (0x0d50)
+#define AFE_SECURE_MASK_CONN7_1 (0x0d54)
+#define AFE_SECURE_MASK_CONN8_1 (0x0d58)
+#define AFE_SECURE_MASK_CONN9_1 (0x0d5c)
+#define AFE_SECURE_MASK_CONN10_1 (0x0d60)
+#define AFE_SECURE_MASK_CONN11_1 (0x0d64)
+#define AFE_SECURE_MASK_CONN12_1 (0x0d68)
+#define AFE_SECURE_MASK_CONN13_1 (0x0d6c)
+#define AFE_MEMIF_MON12 (0x0d70)
+#define AFE_MEMIF_MON13 (0x0d74)
+#define AFE_MEMIF_MON14 (0x0d78)
+#define AFE_MEMIF_MON15 (0x0d7c)
+#define AFE_SECURE_MASK_CONN42 (0x0dbc)
+#define AFE_SECURE_MASK_CONN43 (0x0dc0)
+#define AFE_SECURE_MASK_CONN44 (0x0dc4)
+#define AFE_SECURE_MASK_CONN45 (0x0dc8)
+#define AFE_SECURE_MASK_CONN46 (0x0dcc)
+#define AFE_HD_ENGEN_ENABLE (0x0dd0)
+#define AFE_SECURE_MASK_CONN47 (0x0dd4)
+#define AFE_SECURE_MASK_CONN48 (0x0dd8)
+#define AFE_SECURE_MASK_CONN49 (0x0ddc)
+#define AFE_SECURE_MASK_CONN50 (0x0de0)
+#define AFE_SECURE_MASK_CONN51 (0x0de4)
+#define AFE_SECURE_MASK_CONN52 (0x0de8)
+#define AFE_SECURE_MASK_CONN53 (0x0dec)
+#define AFE_SECURE_MASK_CONN0_1 (0x0df0)
+#define AFE_SECURE_MASK_CONN1_1 (0x0df4)
+#define AFE_SECURE_MASK_CONN2_1 (0x0df8)
+#define AFE_SECURE_MASK_CONN3_1 (0x0dfc)
+
+#define AFE_ADDA_MTKAIF_CFG0 (0x0e00)
+#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_CM1_CON4 (0x0e48)
+#define AFE_CM2_CON4 (0x0e4c)
+#define AFE_CM1_CON0 (0x0e50)
+#define AFE_CM1_CON1 (0x0e54)
+#define AFE_CM1_CON2 (0x0e58)
+#define AFE_CM1_CON3 (0x0e5c)
+#define AFE_CM2_CON0 (0x0e60)
+#define AFE_CM2_CON1 (0x0e64)
+#define AFE_CM2_CON2 (0x0e68)
+#define AFE_CM2_CON3 (0x0e6c)
+#define AFE_CM2_CONN0 (0x0e70)
+#define AFE_CM2_CONN1 (0x0e74)
+#define AFE_CM2_CONN2 (0x0e78)
+
+#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_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_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_SECURE_MASK_CONN28 (0x0f48)
+#define AFE_SECURE_MASK_CONN29 (0x0f4c)
+#define AFE_SECURE_MASK_CONN30 (0x0f50)
+#define AFE_SECURE_MASK_CONN31 (0x0f54)
+#define AFE_SECURE_MASK_CONN32 (0x0f58)
+#define AFE_SECURE_MASK_CONN33 (0x0f5c)
+#define AFE_SECURE_MASK_CONN34 (0x0f60)
+#define AFE_SECURE_MASK_CONN35 (0x0f64)
+#define AFE_SECURE_MASK_CONN36 (0x0f68)
+#define AFE_SECURE_MASK_CONN37 (0x0f6c)
+#define AFE_SECURE_MASK_CONN38 (0x0f70)
+#define AFE_SECURE_MASK_CONN39 (0x0f74)
+#define AFE_SECURE_MASK_CONN40 (0x0f78)
+#define AFE_SECURE_MASK_CONN41 (0x0f7c)
+#define AFE_SIDEBAND0 (0x0f80)
+#define AFE_SIDEBAND1 (0x0f84)
+#define AFE_SECURE_SIDEBAND0 (0x0f88)
+#define AFE_SECURE_SIDEBAND1 (0x0f8c)
+#define AFE_SECURE_MASK_CONN0 (0x0f90)
+#define AFE_SECURE_MASK_CONN1 (0x0f94)
+#define AFE_SECURE_MASK_CONN2 (0x0f98)
+#define AFE_SECURE_MASK_CONN3 (0x0f9c)
+#define AFE_SECURE_MASK_CONN4 (0x0fa0)
+#define AFE_SECURE_MASK_CONN5 (0x0fa4)
+#define AFE_SECURE_MASK_CONN6 (0x0fa8)
+#define AFE_SECURE_MASK_CONN7 (0x0fac)
+#define AFE_SECURE_MASK_CONN8 (0x0fb0)
+#define AFE_SECURE_MASK_CONN9 (0x0fb4)
+#define AFE_SECURE_MASK_CONN10 (0x0fb8)
+#define AFE_SECURE_MASK_CONN11 (0x0fbc)
+#define AFE_SECURE_MASK_CONN12 (0x0fc0)
+#define AFE_SECURE_MASK_CONN13 (0x0fc4)
+#define AFE_SECURE_MASK_CONN14 (0x0fc8)
+#define AFE_SECURE_MASK_CONN15 (0x0fcc)
+#define AFE_SECURE_MASK_CONN16 (0x0fd0)
+#define AFE_SECURE_MASK_CONN17 (0x0fd4)
+#define AFE_SECURE_MASK_CONN18 (0x0fd8)
+#define AFE_SECURE_MASK_CONN19 (0x0fdc)
+#define AFE_SECURE_MASK_CONN20 (0x0fe0)
+#define AFE_SECURE_MASK_CONN21 (0x0fe4)
+#define AFE_SECURE_MASK_CONN22 (0x0fe8)
+#define AFE_SECURE_MASK_CONN23 (0x0fec)
+#define AFE_SECURE_MASK_CONN24 (0x0ff0)
+#define AFE_SECURE_MASK_CONN25 (0x0ff4)
+#define AFE_SECURE_MASK_CONN26 (0x0ff8)
+#define AFE_SECURE_MASK_CONN27 (0x0ffc)
+
+#define MAX_REGISTER AFE_SECURE_MASK_CONN27
+
+#define AFE_IRQ_STATUS_BITS 0x3ff
+
+/* AUDIO_TOP_CON0 (0x0000) */
+#define AUD_TCON0_PDN_TML BIT(27)
+#define AUD_TCON0_PDN_DAC_PREDIS BIT(26)
+#define AUD_TCON0_PDN_DAC BIT(25)
+#define AUD_TCON0_PDN_ADC BIT(24)
+#define AUD_TCON0_PDN_TDM_IN BIT(23)
+#define AUD_TCON0_PDN_TDM_OUT BIT(22)
+#define AUD_TCON0_PDN_SPDIF BIT(21)
+#define AUD_TCON0_PDN_APLL_TUNER BIT(19)
+#define AUD_TCON0_PDN_APLL2_TUNER BIT(18)
+#define AUD_TCON0_PDN_INTDIR BIT(15)
+#define AUD_TCON0_PDN_24M BIT(9)
+#define AUD_TCON0_PDN_22M BIT(8)
+#define AUD_TCON0_PDN_I2S_IN BIT(6)
+#define AUD_TCON0_PDN_AFE BIT(2)
+
+/* AUDIO_TOP_CON1 (0x0004) */
+#define AUD_TCON1_PDN_TDM_ASRC BIT(15)
+#define AUD_TCON1_PDN_GENERAL2_ASRC BIT(14)
+#define AUD_TCON1_PDN_GENERAL1_ASRC BIT(13)
+#define AUD_TCON1_PDN_CONNSYS_I2S_ASRC BIT(12)
+#define AUD_TCON1_PDN_DMIC3_ADC BIT(11)
+#define AUD_TCON1_PDN_DMIC2_ADC BIT(10)
+#define AUD_TCON1_PDN_DMIC1_ADC BIT(9)
+#define AUD_TCON1_PDN_DMIC0_ADC BIT(8)
+#define AUD_TCON1_PDN_I2S4_BCLK BIT(7)
+#define AUD_TCON1_PDN_I2S3_BCLK BIT(6)
+#define AUD_TCON1_PDN_I2S2_BCLK BIT(5)
+#define AUD_TCON1_PDN_I2S1_BCLK BIT(4)
+
+/* AUDIO_TOP_CON3 (0x000C) */
+#define AUD_TCON3_HDMI_BCK_INV BIT(3)
+
+/* AFE_I2S_CON (0x0018) */
+#define AFE_I2S_CON_PHASE_SHIFT_FIX BIT(31)
+#define AFE_I2S_CON_FROM_IO_MUX BIT(28)
+#define AFE_I2S_CON_LOW_JITTER_CLK BIT(12)
+#define AFE_I2S_CON_RATE_MASK GENMASK(11, 8)
+#define AFE_I2S_CON_FORMAT_I2S BIT(3)
+#define AFE_I2S_CON_SRC_SLAVE BIT(2)
+
+/* AFE_ASRC_2CH_CON0 */
+#define ONE_HEART BIT(31)
+#define CHSET_STR_CLR BIT(4)
+#define COEFF_SRAM_CTRL BIT(1)
+#define ASM_ON BIT(0)
+
+/* CON2 */
+#define O16BIT BIT(19)
+#define CLR_IIR_HISTORY BIT(17)
+#define IS_MONO BIT(16)
+#define IIR_EN BIT(11)
+#define IIR_STAGE_MASK GENMASK(10, 8)
+
+/* CON5 */
+#define CALI_CYCLE_MASK GENMASK(31, 16)
+#define CALI_64_CYCLE FIELD_PREP(CALI_CYCLE_MASK, 0x3F)
+#define CALI_96_CYCLE FIELD_PREP(CALI_CYCLE_MASK, 0x5F)
+#define CALI_441_CYCLE FIELD_PREP(CALI_CYCLE_MASK, 0x1B8)
+
+#define CALI_AUTORST BIT(15)
+#define AUTO_TUNE_FREQ5 BIT(12)
+#define COMP_FREQ_RES BIT(11)
+
+#define CALI_SEL_MASK GENMASK(9, 8)
+#define CALI_SEL_00 FIELD_PREP(CALI_SEL_MASK, 0)
+#define CALI_SEL_01 FIELD_PREP(CALI_SEL_MASK, 1)
+
+#define CALI_BP_DGL BIT(7) /* Bypass the deglitch circuit */
+#define AUTO_TUNE_FREQ4 BIT(3)
+#define CALI_AUTO_RESTART BIT(2)
+#define CALI_USE_FREQ_OUT BIT(1)
+#define CALI_ON BIT(0)
+
+#define AFE_I2S_CON_WLEN_32BIT BIT(1)
+#define AFE_I2S_CON_EN BIT(0)
+
+#define AFE_CONN3_I03_O03_S BIT(3)
+#define AFE_CONN4_I04_O04_S BIT(4)
+#define AFE_CONN4_I03_O04_S BIT(3)
+
+/* AFE_I2S_CON1 (0x0034) */
+#define AFE_I2S_CON1_I2S2_TO_PAD BIT(18)
+#define AFE_I2S_CON1_TDMOUT_TO_PAD (0 << 18)
+#define AFE_I2S_CON1_RATE GENMASK(11, 8)
+#define AFE_I2S_CON1_FORMAT_I2S BIT(3)
+#define AFE_I2S_CON1_WLEN_32BIT BIT(1)
+#define AFE_I2S_CON1_EN BIT(0)
+
+/* AFE_I2S_CON2 (0x0038) */
+#define AFE_I2S_CON2_LOW_JITTER_CLK BIT(12)
+#define AFE_I2S_CON2_RATE GENMASK(11, 8)
+#define AFE_I2S_CON2_FORMAT_I2S BIT(3)
+#define AFE_I2S_CON2_WLEN_32BIT BIT(1)
+#define AFE_I2S_CON2_EN BIT(0)
+
+/* AFE_I2S_CON3 (0x004C) */
+#define AFE_I2S_CON3_LOW_JITTER_CLK BIT(12)
+#define AFE_I2S_CON3_RATE GENMASK(11, 8)
+#define AFE_I2S_CON3_FORMAT_I2S BIT(3)
+#define AFE_I2S_CON3_WLEN_32BIT BIT(1)
+#define AFE_I2S_CON3_EN BIT(0)
+
+/* AFE_ADDA_DL_SRC2_CON0 (0x0108) */
+#define AFE_ADDA_DL_8X_UPSAMPLE GENMASK(25, 24)
+#define AFE_ADDA_DL_MUTE_OFF_CH1 BIT(12)
+#define AFE_ADDA_DL_MUTE_OFF_CH2 BIT(11)
+#define AFE_ADDA_DL_VOICE_DATA BIT(5)
+#define AFE_ADDA_DL_DEGRADE_GAIN BIT(1)
+
+/* AFE_ADDA_UL_DL_CON0 */
+#define AFE_ADDA_UL_DL_ADDA_AFE_ON BIT(0)
+#define AFE_ADDA_UL_DL_DMIC_CLKDIV_ON BIT(1)
+
+/* AFE_APLL_TUNER_CFG (0x03f0) */
+#define AFE_APLL_TUNER_CFG_MASK GENMASK(15, 1)
+#define AFE_APLL_TUNER_CFG_EN_MASK BIT(0)
+
+/* AFE_APLL_TUNER_CFG1 (0x03f4) */
+#define AFE_APLL_TUNER_CFG1_MASK GENMASK(15, 1)
+#define AFE_APLL_TUNER_CFG1_EN_MASK BIT(0)
+
+/* PCM_INTF_CON1 (0x0550) */
+#define PCM_INTF_CON1_EXT_MODEM BIT(17)
+#define PCM_INTF_CON1_16BIT (0 << 16)
+#define PCM_INTF_CON1_24BIT BIT(16)
+#define PCM_INTF_CON1_32BCK (0 << 14)
+#define PCM_INTF_CON1_64BCK BIT(14)
+#define PCM_INTF_CON1_MASTER_MODE (0 << 5)
+#define PCM_INTF_CON1_SLAVE_MODE BIT(5)
+#define PCM_INTF_CON1_FS_MASK GENMASK(4, 3)
+#define PCM_INTF_CON1_FS_8K FIELD_PREP(PCM_INTF_CON1_FS_MASK, 0)
+#define PCM_INTF_CON1_FS_16K FIELD_PREP(PCM_INTF_CON1_FS_MASK, 1)
+#define PCM_INTF_CON1_FS_32K FIELD_PREP(PCM_INTF_CON1_FS_MASK, 2)
+#define PCM_INTF_CON1_FS_48K FIELD_PREP(PCM_INTF_CON1_FS_MASK, 3)
+#define PCM_INTF_CON1_SYNC_LEN_MASK GENMASK(13, 9)
+#define PCM_INTF_CON1_SYNC_LEN(x) FIELD_PREP(PCM_INTF_CON1_SYNC_LEN_MASK, ((x) - 1))
+#define PCM_INTF_CON1_FORMAT_MASK GENMASK(2, 1)
+#define PCM_INTF_CON1_SYNC_OUT_INV BIT(23)
+#define PCM_INTF_CON1_BCLK_OUT_INV BIT(22)
+#define PCM_INTF_CON1_SYNC_IN_INV BIT(21)
+#define PCM_INTF_CON1_BCLK_IN_INV BIT(20)
+#define PCM_INTF_CON1_BYPASS_ASRC BIT(6)
+#define PCM_INTF_CON1_EN BIT(0)
+#define PCM_INTF_CON1_CONFIG_MASK (0xf3fffe)
+
+/* AFE_DMIC0_UL_SRC_CON0 (0x05b4)
+ * AFE_DMIC1_UL_SRC_CON0 (0x0620)
+ * AFE_DMIC2_UL_SRC_CON0 (0x0780)
+ * AFE_DMIC3_UL_SRC_CON0 (0x07ec)
+ */
+#define DMIC_TOP_CON_CK_PHASE_SEL_CH1 GENMASK(29, 27)
+#define DMIC_TOP_CON_CK_PHASE_SEL_CH2 GENMASK(26, 24)
+#define DMIC_TOP_CON_TWO_WIRE_MODE BIT(23)
+#define DMIC_TOP_CON_CH2_ON BIT(22)
+#define DMIC_TOP_CON_CH1_ON BIT(21)
+#define DMIC_TOP_CON_VOICE_MODE_MASK GENMASK(19, 17)
+#define DMIC_TOP_CON_VOICE_MODE_8K FIELD_PREP(DMIC_TOP_CON_VOICE_MODE_MASK, 0)
+#define DMIC_TOP_CON_VOICE_MODE_16K FIELD_PREP(DMIC_TOP_CON_VOICE_MODE_MASK, 1)
+#define DMIC_TOP_CON_VOICE_MODE_32K FIELD_PREP(DMIC_TOP_CON_VOICE_MODE_MASK, 2)
+#define DMIC_TOP_CON_VOICE_MODE_48K FIELD_PREP(DMIC_TOP_CON_VOICE_MODE_MASK, 3)
+#define DMIC_TOP_CON_LOW_POWER_MODE_MASK GENMASK(19, 17)
+#define DMIC_TOP_CON_LOW_POWER_MODE(x) FIELD_PREP(DMIC_TOP_CON_LOW_POWER_MODE_MASK, (x))
+#define DMIC_TOP_CON_IIR_ON BIT(10)
+#define DMIC_TOP_CON_INPUT_MODE BIT(5)
+#define DMIC_TOP_CON_IIR_MODE GENMASK(9, 7)
+#define DMIC_TOP_CON_SDM3_LEVEL_MODE BIT(1)
+#define DMIC_TOP_CON_SRC_ON BIT(0)
+#define DMIC_TOP_CON_SDM3_DE_SELECT (0 << 1)
+#define DMIC_TOP_CON_CONFIG_MASK (0x3f8ed7a6)
+
+/* AFE_CONN_24BIT (0x0AA4) */
+#define AFE_CONN_24BIT_O10 BIT(10)
+#define AFE_CONN_24BIT_O09 BIT(9)
+#define AFE_CONN_24BIT_O06 BIT(6)
+#define AFE_CONN_24BIT_O05 BIT(5)
+#define AFE_CONN_24BIT_O04 BIT(4)
+#define AFE_CONN_24BIT_O03 BIT(3)
+#define AFE_CONN_24BIT_O02 BIT(2)
+#define AFE_CONN_24BIT_O01 BIT(1)
+#define AFE_CONN_24BIT_O00 BIT(0)
+
+/* AFE_HD_ENGEN_ENABLE */
+#define AFE_22M_PLL_EN BIT(0)
+#define AFE_24M_PLL_EN BIT(1)
+
+/* AFE_GAIN1_CON0 (0x0410) */
+#define AFE_GAIN1_CON0_EN_MASK GENMASK(0, 0)
+#define AFE_GAIN1_CON0_MODE_MASK GENMASK(7, 4)
+#define AFE_GAIN1_CON0_SAMPLE_PER_STEP_MASK GENMASK(15, 8)
+
+/* AFE_GAIN1_CON1 (0x0414) */
+#define AFE_GAIN1_CON1_MASK GENMASK(19, 0)
+
+/* AFE_GAIN1_CUR (0x0B78) */
+#define AFE_GAIN1_CUR_MASK GENMASK(19, 0)
+
+/* AFE_CM1_CON0 (0x0e50) */
+/* AFE_CM2_CON0 (0x0e60) */
+#define CM_AFE_CM_CH_NUM_MASK GENMASK(3, 0)
+#define CM_AFE_CM_CH_NUM(x) FIELD_PREP(CM_AFE_CM_CH_NUM_MASK, ((x) - 1))
+#define CM_AFE_CM_ON BIT(4)
+#define CM_AFE_CM_START_DATA_MASK GENMASK(11, 8)
+
+#define CM_AFE_CM1_VUL_SEL BIT(12)
+#define CM_AFE_CM1_IN_MODE_MASK GENMASK(19, 16)
+#define CM_AFE_CM2_TDM_SEL BIT(12)
+#define CM_AFE_CM2_CLK_SEL BIT(13)
+#define CM_AFE_CM2_GASRC1_OUT_SEL BIT(17)
+#define CM_AFE_CM2_GASRC2_OUT_SEL BIT(16)
+
+/* AFE_CM2_CONN* */
+#define CM2_AFE_CM2_CONN_CFG1(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG1_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG1_MASK GENMASK(4, 0)
+#define CM2_AFE_CM2_CONN_CFG2(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG2_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG2_MASK GENMASK(9, 5)
+#define CM2_AFE_CM2_CONN_CFG3(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG3_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG3_MASK GENMASK(14, 10)
+#define CM2_AFE_CM2_CONN_CFG4(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG4_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG4_MASK GENMASK(19, 15)
+#define CM2_AFE_CM2_CONN_CFG5(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG5_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG5_MASK GENMASK(24, 20)
+#define CM2_AFE_CM2_CONN_CFG6(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG6_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG6_MASK GENMASK(29, 25)
+#define CM2_AFE_CM2_CONN_CFG7(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG7_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG7_MASK GENMASK(4, 0)
+#define CM2_AFE_CM2_CONN_CFG8(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG8_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG8_MASK GENMASK(9, 5)
+#define CM2_AFE_CM2_CONN_CFG9(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG9_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG9_MASK GENMASK(14, 10)
+#define CM2_AFE_CM2_CONN_CFG10(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG10_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG10_MASK GENMASK(19, 15)
+#define CM2_AFE_CM2_CONN_CFG11(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG11_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG11_MASK GENMASK(24, 20)
+#define CM2_AFE_CM2_CONN_CFG12(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG12_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG12_MASK GENMASK(29, 25)
+#define CM2_AFE_CM2_CONN_CFG13(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG13_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG13_MASK GENMASK(4, 0)
+#define CM2_AFE_CM2_CONN_CFG14(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG14_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG14_MASK GENMASK(9, 5)
+#define CM2_AFE_CM2_CONN_CFG15(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG15_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG15_MASK GENMASK(14, 10)
+#define CM2_AFE_CM2_CONN_CFG16(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG16_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG16_MASK GENMASK(19, 15)
+
+/* AFE_CM1_CON* */
+#define CM_AFE_CM_UPDATE_CNT1_MASK GENMASK(15, 0)
+#define CM_AFE_CM_UPDATE_CNT1(x) FIELD_PREP(CM_AFE_CM_UPDATE_CNT1_MASK, (x))
+#define CM_AFE_CM_UPDATE_CNT2_MASK GENMASK(31, 16)
+#define CM_AFE_CM_UPDATE_CNT2(x) FIELD_PREP(CM_AFE_CM_UPDATE_CNT2_MASK, (x))
+
+#endif

--
2.25.1


2024-02-26 14:04:36

by Alexandre Mergnat

[permalink] [raw]
Subject: [PATCH 06/18] ASoC: mediatek: mt8365: Add I2S DAI support

Add I2S Device Audio Interface support for MT8365 SoC.

Signed-off-by: Alexandre Mergnat <[email protected]>
---
sound/soc/mediatek/mt8365/mt8365-dai-i2s.c | 901 +++++++++++++++++++++++++++++
1 file changed, 901 insertions(+)

diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c b/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c
new file mode 100644
index 000000000000..ba704d92094b
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c
@@ -0,0 +1,901 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Mediatek 8365 ALSA SoC Audio DAI I2S Control
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Authors: Jia Zeng <[email protected]>
+ * Alexandre Mergnat <[email protected]>
+ */
+
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8365-afe-clk.h"
+#include "mt8365-afe-common.h"
+
+struct mtk_afe_i2s_priv {
+ bool adda_link;
+ bool shared_clk;
+ int i2s_out_on_ref_cnt;
+ int id;
+ int low_jitter_en;
+ int mclk_id;
+ int share_i2s_id;
+ unsigned int clk_id_in;
+ unsigned int clk_id_in_m_sel;
+ unsigned int clk_id_out;
+ unsigned int clk_id_out_m_sel;
+ unsigned int clk_in_mult;
+ unsigned int clk_out_mult;
+ unsigned int config_val_in;
+ unsigned int config_val_out;
+ unsigned int dynamic_bck;
+ unsigned int reg_off_in;
+ unsigned int reg_off_out;
+};
+
+/* This enum is merely for mtk_afe_i2s_priv declare */
+enum {
+ DAI_I2S0 = 0,
+ DAI_I2S3,
+ DAI_I2S_NUM,
+};
+
+static const struct mtk_afe_i2s_priv mt8365_i2s_priv[DAI_I2S_NUM] = {
+ [DAI_I2S0] = {
+ .id = MT8365_AFE_IO_I2S,
+ .mclk_id = MT8365_I2S0_MCK,
+ .share_i2s_id = -1,
+ .clk_id_in = MT8365_CLK_AUD_I2S2_M,
+ .clk_id_out = MT8365_CLK_AUD_I2S1_M,
+ .clk_id_in_m_sel = MT8365_CLK_I2S2_M_SEL,
+ .clk_id_out_m_sel = MT8365_CLK_I2S1_M_SEL,
+ .clk_in_mult = 256,
+ .clk_out_mult = 256,
+ .adda_link = true,
+ .config_val_out = AFE_I2S_CON1_I2S2_TO_PAD,
+ .reg_off_in = AFE_I2S_CON2,
+ .reg_off_out = AFE_I2S_CON1,
+ },
+ [DAI_I2S3] = {
+ .id = MT8365_AFE_IO_2ND_I2S,
+ .mclk_id = MT8365_I2S3_MCK,
+ .share_i2s_id = -1,
+ .clk_id_in = MT8365_CLK_AUD_I2S0_M,
+ .clk_id_out = MT8365_CLK_AUD_I2S3_M,
+ .clk_id_in_m_sel = MT8365_CLK_I2S0_M_SEL,
+ .clk_id_out_m_sel = MT8365_CLK_I2S3_M_SEL,
+ .clk_in_mult = 256,
+ .clk_out_mult = 256,
+ .adda_link = false,
+ .config_val_in = AFE_I2S_CON_FROM_IO_MUX,
+ .reg_off_in = AFE_I2S_CON,
+ .reg_off_out = AFE_I2S_CON3,
+ },
+};
+
+static const u32 *get_iir_coef(unsigned int input_fs,
+ unsigned int output_fs, unsigned int *count)
+{
+#define RATIOVER 9
+#define INV_COEF 10
+#define NO_NEED 11
+
+ static const u32 IIR_COEF_48_TO_44p1[30] = {
+ 0x061fb0, 0x0bd256, 0x061fb0, 0xe3a3e6, 0xf0a300, 0x000003,
+ 0x0e416d, 0x1bb577, 0x0e416d, 0xe59178, 0xf23637, 0x000003,
+ 0x0c7d72, 0x189060, 0x0c7d72, 0xe96f09, 0xf505b2, 0x000003,
+ 0x126054, 0x249143, 0x126054, 0xe1fc0c, 0xf4b20a, 0x000002,
+ 0x000000, 0x323c85, 0x323c85, 0xf76d4e, 0x000000, 0x000002,
+ };
+
+ static const u32 IIR_COEF_44p1_TO_32[42] = {
+ 0x0a6074, 0x0d237a, 0x0a6074, 0xdd8d6c, 0xe0b3f6, 0x000002,
+ 0x0e41f8, 0x128d48, 0x0e41f8, 0xefc14e, 0xf12d7a, 0x000003,
+ 0x0cfa60, 0x11e89c, 0x0cfa60, 0xf1b09e, 0xf27205, 0x000003,
+ 0x15b69c, 0x20e7e4, 0x15b69c, 0xea799a, 0xe9314a, 0x000002,
+ 0x0f79e2, 0x1a7064, 0x0f79e2, 0xf65e4a, 0xf03d8e, 0x000002,
+ 0x10c34f, 0x1ffe4b, 0x10c34f, 0x0bbecb, 0xf2bc4b, 0x000001,
+ 0x000000, 0x23b063, 0x23b063, 0x07335f, 0x000000, 0x000002,
+ };
+
+ static const u32 IIR_COEF_48_TO_32[42] = {
+ 0x0a2a9b, 0x0a2f05, 0x0a2a9b, 0xe73873, 0xe0c525, 0x000002,
+ 0x0dd4ad, 0x0e765a, 0x0dd4ad, 0xf49808, 0xf14844, 0x000003,
+ 0x18a8cd, 0x1c40d0, 0x18a8cd, 0xed2aab, 0xe542ec, 0x000002,
+ 0x13e044, 0x1a47c4, 0x13e044, 0xf44aed, 0xe9acc7, 0x000002,
+ 0x1abd9c, 0x2a5429, 0x1abd9c, 0xff3441, 0xe0fc5f, 0x000001,
+ 0x0d86db, 0x193e2e, 0x0d86db, 0x1a6f15, 0xf14507, 0x000001,
+ 0x000000, 0x1f820c, 0x1f820c, 0x0a1b1f, 0x000000, 0x000002,
+ };
+
+ static const u32 IIR_COEF_32_TO_16[48] = {
+ 0x122893, 0xffadd4, 0x122893, 0x0bc205, 0xc0ee1c, 0x000001,
+ 0x1bab8a, 0x00750d, 0x1bab8a, 0x06a983, 0xe18a5c, 0x000002,
+ 0x18f68e, 0x02706f, 0x18f68e, 0x0886a9, 0xe31bcb, 0x000002,
+ 0x149c05, 0x054487, 0x149c05, 0x0bec31, 0xe5973e, 0x000002,
+ 0x0ea303, 0x07f24a, 0x0ea303, 0x115ff9, 0xe967b6, 0x000002,
+ 0x0823fd, 0x085531, 0x0823fd, 0x18d5b4, 0xee8d21, 0x000002,
+ 0x06888e, 0x0acbbb, 0x06888e, 0x40b55c, 0xe76dce, 0x000001,
+ 0x000000, 0x2d31a9, 0x2d31a9, 0x23ba4f, 0x000000, 0x000001,
+ };
+
+ static const u32 IIR_COEF_96_TO_44p1[48] = {
+ 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 const u32 IIR_COEF_44p1_TO_16[48] = {
+ 0x0998fb, 0xf7f925, 0x0998fb, 0x1e54a0, 0xe06605, 0x000002,
+ 0x0d828e, 0xf50f97, 0x0d828e, 0x0f41b5, 0xf0a999, 0x000003,
+ 0x17ebeb, 0xee30d8, 0x17ebeb, 0x1f48ca, 0xe2ae88, 0x000002,
+ 0x12fab5, 0xf46ddc, 0x12fab5, 0x20cc51, 0xe4d068, 0x000002,
+ 0x0c7ac6, 0xfbd00e, 0x0c7ac6, 0x2337da, 0xe8028c, 0x000002,
+ 0x060ddc, 0x015b3e, 0x060ddc, 0x266754, 0xec21b6, 0x000002,
+ 0x0407b5, 0x04f827, 0x0407b5, 0x52e3d0, 0xe0149f, 0x000001,
+ 0x000000, 0x1f9521, 0x1f9521, 0x2ac116, 0x000000, 0x000001,
+ };
+
+ static const u32 IIR_COEF_48_TO_16[48] = {
+ 0x0955ff, 0xf6544a, 0x0955ff, 0x2474e5, 0xe062e6, 0x000002,
+ 0x0d4180, 0xf297f4, 0x0d4180, 0x12415b, 0xf0a3b0, 0x000003,
+ 0x0ba079, 0xf4f0b0, 0x0ba079, 0x1285d3, 0xf1488b, 0x000003,
+ 0x12247c, 0xf1033c, 0x12247c, 0x2625be, 0xe48e0d, 0x000002,
+ 0x0b98e0, 0xf96d1a, 0x0b98e0, 0x27e79c, 0xe7798a, 0x000002,
+ 0x055e3b, 0xffed09, 0x055e3b, 0x2a2e2d, 0xeb2854, 0x000002,
+ 0x01a934, 0x01ca03, 0x01a934, 0x2c4fea, 0xee93ab, 0x000002,
+ 0x000000, 0x1c46c5, 0x1c46c5, 0x2d37dc, 0x000000, 0x000001,
+ };
+
+ static const u32 IIR_COEF_96_TO_16[48] = {
+ 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 struct {
+ const u32 *coef;
+ unsigned int cnt;
+ } iir_coef_tbl_list[8] = {
+ /* 0: 0.9188 */
+ { IIR_COEF_48_TO_44p1, ARRAY_SIZE(IIR_COEF_48_TO_44p1) },
+ /* 1: 0.7256 */
+ { IIR_COEF_44p1_TO_32, ARRAY_SIZE(IIR_COEF_44p1_TO_32) },
+ /* 2: 0.6667 */
+ { IIR_COEF_48_TO_32, ARRAY_SIZE(IIR_COEF_48_TO_32) },
+ /* 3: 0.5 */
+ { IIR_COEF_32_TO_16, ARRAY_SIZE(IIR_COEF_32_TO_16) },
+ /* 4: 0.4594 */
+ { IIR_COEF_96_TO_44p1, ARRAY_SIZE(IIR_COEF_96_TO_44p1) },
+ /* 5: 0.3628 */
+ { IIR_COEF_44p1_TO_16, ARRAY_SIZE(IIR_COEF_44p1_TO_16) },
+ /* 6: 0.3333 */
+ { IIR_COEF_48_TO_16, ARRAY_SIZE(IIR_COEF_48_TO_16) },
+ /* 7: 0.1667 */
+ { IIR_COEF_96_TO_16, ARRAY_SIZE(IIR_COEF_96_TO_16) },
+ };
+
+ static const u32 freq_new_index[16] = {
+ 0, 1, 2, 99, 3, 4, 5, 99, 6, 7, 8, 9, 10, 11, 12, 99
+ };
+
+ static const u32 iir_coef_tbl_matrix[13][13] = {
+ {/*0*/
+ NO_NEED, NO_NEED, NO_NEED, NO_NEED, NO_NEED,
+ NO_NEED, NO_NEED, NO_NEED, NO_NEED, NO_NEED,
+ NO_NEED, NO_NEED, NO_NEED
+ },
+ {/*1*/
+ 1, NO_NEED, NO_NEED, NO_NEED, NO_NEED,
+ NO_NEED, NO_NEED, NO_NEED, NO_NEED,
+ NO_NEED, NO_NEED, NO_NEED, NO_NEED
+ },
+ {/*2*/
+ 2, 0, NO_NEED, NO_NEED, NO_NEED, NO_NEED,
+ NO_NEED, NO_NEED, NO_NEED, NO_NEED,
+ NO_NEED, NO_NEED, NO_NEED
+ },
+ {/*3*/
+ 3, INV_COEF, INV_COEF, NO_NEED, NO_NEED,
+ NO_NEED, NO_NEED, NO_NEED, NO_NEED,
+ NO_NEED, NO_NEED, NO_NEED, NO_NEED
+ },
+ {/*4*/
+ 5, 3, INV_COEF, 2, NO_NEED, NO_NEED,
+ NO_NEED, NO_NEED, NO_NEED,
+ NO_NEED, NO_NEED, NO_NEED, NO_NEED
+ },
+ {/*5*/
+ 6, 4, 3, 2, 0, NO_NEED, NO_NEED, NO_NEED,
+ NO_NEED, NO_NEED, NO_NEED,
+ NO_NEED, NO_NEED
+ },
+ {/*6*/
+ INV_COEF, INV_COEF, INV_COEF, 3, INV_COEF,
+ INV_COEF, NO_NEED, NO_NEED, NO_NEED,
+ NO_NEED, NO_NEED, NO_NEED
+ },
+ {/*7*/
+ INV_COEF, INV_COEF, INV_COEF, 5, 3,
+ INV_COEF, 1, NO_NEED, NO_NEED,
+ NO_NEED, NO_NEED, NO_NEED, NO_NEED
+ },
+ {/*8*/
+ 7, INV_COEF, INV_COEF, 6, 4, 3, 2, 0, NO_NEED,
+ NO_NEED, NO_NEED, NO_NEED, NO_NEED
+ },
+ {/*9*/
+ INV_COEF, INV_COEF, INV_COEF, INV_COEF,
+ INV_COEF, INV_COEF, 5, 3, INV_COEF,
+ NO_NEED, NO_NEED, NO_NEED, NO_NEED
+ },
+ {/*10*/
+ INV_COEF, INV_COEF, INV_COEF, 7, INV_COEF,
+ INV_COEF, 6, 4, 3, 0,
+ NO_NEED, NO_NEED, NO_NEED
+ },
+ { /*11*/
+ RATIOVER, INV_COEF, INV_COEF, INV_COEF,
+ INV_COEF, INV_COEF, INV_COEF, INV_COEF,
+ INV_COEF, 3, INV_COEF, NO_NEED, NO_NEED
+ },
+ {/*12*/
+ RATIOVER, RATIOVER, INV_COEF, INV_COEF,
+ INV_COEF, INV_COEF, 7, INV_COEF,
+ INV_COEF, 4, 3, 0, NO_NEED
+ },
+ };
+
+ const u32 *coef = NULL;
+ unsigned int cnt = 0;
+ u32 i = freq_new_index[input_fs];
+ u32 j = freq_new_index[output_fs];
+
+ if (i >= 13 || j >= 13) {
+ } else {
+ u32 k = iir_coef_tbl_matrix[i][j];
+
+ if (k >= NO_NEED) {
+ } else if (k == RATIOVER) {
+ } else if (k == INV_COEF) {
+ } else {
+ coef = iir_coef_tbl_list[k].coef;
+ cnt = iir_coef_tbl_list[k].cnt;
+ }
+ }
+ *count = cnt;
+ return coef;
+}
+
+int mt8365_dai_set_config(struct mtk_base_afe *afe,
+ struct mtk_afe_i2s_priv *i2s_data, bool is_input,
+ unsigned int rate, int bit_width)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_be_dai_data *be =
+ &afe_priv->be_data[i2s_data->id - MT8365_AFE_BACKEND_BASE];
+ unsigned int val, reg_off;
+ int fs = mt8365_afe_fs_timing(rate);
+
+ if (fs < 0)
+ return -EINVAL;
+
+ val = AFE_I2S_CON_LOW_JITTER_CLK |
+ FIELD_PREP(AFE_I2S_CON_RATE_MASK, fs) |
+ AFE_I2S_CON_FORMAT_I2S;
+
+ if (is_input) {
+ reg_off = i2s_data->reg_off_in;
+ if (i2s_data->adda_link)
+ val |= i2s_data->config_val_in;
+ } else {
+ reg_off = i2s_data->reg_off_out;
+ val |= i2s_data->config_val_in;
+ }
+
+ /* 1:bck=32lrck(16bit) or bck=64lrck(32bit) 0:fix bck=64lrck */
+ if (i2s_data->dynamic_bck) {
+ if (bit_width > 16)
+ val |= AFE_I2S_CON_WLEN_32BIT;
+ else
+ val &= ~(u32)AFE_I2S_CON_WLEN_32BIT;
+ } else
+ val |= AFE_I2S_CON_WLEN_32BIT;
+
+ if ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK)
+ == SND_SOC_DAIFMT_CBM_CFM) {
+ val |= AFE_I2S_CON_SRC_SLAVE;
+ val &= ~(u32)AFE_I2S_CON_FROM_IO_MUX;//from consys
+ }
+
+ regmap_update_bits(afe->regmap, reg_off,
+ ~(u32)AFE_I2S_CON_EN, val);
+
+ if (i2s_data->adda_link && is_input)
+ regmap_update_bits(afe->regmap, AFE_ADDA_TOP_CON0, 0x1, 0x1);
+
+ return 0;
+}
+
+int mt8365_afe_set_i2s_out(struct mtk_base_afe *afe, unsigned int rate,
+ int bit_width)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_i2s_priv *i2s_data =
+ afe_priv->dai_priv[MT8365_AFE_IO_I2S];
+
+ return mt8365_dai_set_config(afe, i2s_data, false, rate, bit_width);
+}
+
+static int mt8365_afe_set_2nd_i2s_asrc(struct mtk_base_afe *afe,
+ unsigned int rate_in,
+ unsigned int rate_out, unsigned int width,
+ unsigned int mono, int o16bit, int tracking)
+{
+ int ifs, ofs = 0;
+ unsigned int val = 0;
+ unsigned int mask = 0;
+ const u32 *coef;
+ u32 iir_stage;
+ unsigned int coef_count = 0;
+
+ ifs = mt8365_afe_fs_timing(rate_in);
+
+ if (ifs < 0)
+ return -EINVAL;
+
+ ofs = mt8365_afe_fs_timing(rate_out);
+
+ if (ofs < 0)
+ return -EINVAL;
+
+ val = FIELD_PREP(O16BIT, o16bit) | FIELD_PREP(IS_MONO, mono);
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON2,
+ O16BIT | IS_MONO, val);
+
+ coef = get_iir_coef(ifs, ofs, &coef_count);
+ iir_stage = ((u32)coef_count / 6) - 1;
+
+ if (coef) {
+ unsigned int i;
+
+ /* CPU control IIR coeff SRAM */
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON0,
+ COEFF_SRAM_CTRL, COEFF_SRAM_CTRL);
+
+ /* set to 0, IIR coeff SRAM addr */
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON13,
+ 0xffffffff, 0x0);
+
+ for (i = 0; i < coef_count; ++i)
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON12,
+ 0xffffffff, coef[i]);
+
+ /* disable IIR coeff SRAM access */
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON0,
+ COEFF_SRAM_CTRL, ~COEFF_SRAM_CTRL);
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON2,
+ CLR_IIR_HISTORY | IIR_EN | IIR_STAGE_MASK,
+ CLR_IIR_HISTORY | IIR_EN | FIELD_PREP(IIR_STAGE_MASK, iir_stage));
+ } else {
+ /* disable IIR */
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON2, IIR_EN, ~IIR_EN);
+ }
+
+ /* CON3 setting (RX OFS) */
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON3,
+ 0x00FFFFFF, rx_frequency_palette(ofs));
+ /* CON4 setting (RX IFS) */
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON4,
+ 0x00FFFFFF, rx_frequency_palette(ifs));
+
+ /* CON5 setting */
+ if (tracking) {
+ val = CALI_64_CYCLE |
+ CALI_AUTORST |
+ AUTO_TUNE_FREQ5 |
+ COMP_FREQ_RES |
+ CALI_BP_DGL |
+ CALI_AUTO_RESTART |
+ CALI_USE_FREQ_OUT |
+ CALI_SEL_01;
+
+ mask = CALI_CYCLE_MASK |
+ CALI_AUTORST |
+ AUTO_TUNE_FREQ5 |
+ COMP_FREQ_RES |
+ CALI_SEL_MASK |
+ CALI_BP_DGL |
+ AUTO_TUNE_FREQ4 |
+ CALI_AUTO_RESTART |
+ CALI_USE_FREQ_OUT|
+ CALI_ON;
+
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON5,
+ mask, val);
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON5,
+ CALI_ON, CALI_ON);
+ } else {
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON5,
+ 0xffffffff, 0x0);
+ }
+ /* CON6 setting fix 8125 */
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON6,
+ 0x0000ffff, 0x1FBD);
+ /* CON9 setting (RX IFS) */
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON9,
+ 0x000fffff, AutoRstThHi(ifs));
+ /* CON10 setting (RX IFS) */
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON10,
+ 0x000fffff, AutoRstThLo(ifs));
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON0,
+ CHSET_STR_CLR, CHSET_STR_CLR);
+
+ return 0;
+}
+
+static int mt8365_afe_set_2nd_i2s_asrc_enable(
+ struct mtk_base_afe *afe, bool enable)
+{
+ if (enable)
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON0,
+ ASM_ON, ASM_ON);
+ else
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON0,
+ ASM_ON, ~ASM_ON);
+
+ return 0;
+}
+
+void mt8365_afe_set_i2s_out_enable(struct mtk_base_afe *afe, bool enable)
+{
+ int i;
+ unsigned long flags;
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_i2s_priv *i2s_data;
+
+ for (i = 0; i < DAI_I2S_NUM; i++) {
+ if (mt8365_i2s_priv[i].adda_link)
+ i2s_data = afe_priv->dai_priv[mt8365_i2s_priv[i].id];
+ }
+
+ spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags);
+
+ if (enable) {
+ i2s_data->i2s_out_on_ref_cnt++;
+ if (i2s_data->i2s_out_on_ref_cnt == 1)
+ regmap_update_bits(afe->regmap,
+ AFE_I2S_CON1, 0x1, enable);
+ } else {
+ i2s_data->i2s_out_on_ref_cnt--;
+ if (i2s_data->i2s_out_on_ref_cnt == 0)
+ regmap_update_bits(afe->regmap,
+ AFE_I2S_CON1, 0x1, enable);
+ else if (i2s_data->i2s_out_on_ref_cnt < 0)
+ i2s_data->i2s_out_on_ref_cnt = 0;
+ }
+
+ spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags);
+}
+
+static void mt8365_dai_set_enable(struct mtk_base_afe *afe,
+ struct mtk_afe_i2s_priv *i2s_data, bool is_input, bool enable)
+{
+ unsigned int reg_off;
+
+ if (is_input) {
+ reg_off = i2s_data->reg_off_in;
+ } else {
+ if (i2s_data->adda_link) {
+ mt8365_afe_set_i2s_out_enable(afe, enable);
+ return;
+ } else {
+ reg_off = i2s_data->reg_off_out;
+ }
+ }
+ regmap_update_bits(afe->regmap, reg_off, 0x1, enable);
+}
+
+static int mt8365_dai_i2s_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_i2s_priv *i2s_data = afe_priv->dai_priv[dai->id];
+ const bool shared_clk = i2s_data->shared_clk;
+ struct mt8365_be_dai_data *be =
+ &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
+ const bool i2s_in_slave = (substream->stream
+ == SNDRV_PCM_STREAM_CAPTURE)
+ && ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK)
+ == SND_SOC_DAIFMT_CBM_CFM);
+
+ dev_dbg(afe->dev, "%s '%s'\n",
+ __func__, snd_pcm_stream_str(substream));
+
+ if (shared_clk && snd_soc_dai_active(dai))
+ return 0;
+
+ mt8365_afe_enable_main_clk(afe);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK || shared_clk)
+ mt8365_afe_enable_clk(afe,
+ afe_priv->clocks[i2s_data->clk_id_out]);
+
+ if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE || shared_clk)
+ && !i2s_in_slave)
+ mt8365_afe_enable_clk(afe,
+ afe_priv->clocks[i2s_data->clk_id_in]);
+
+ if (i2s_in_slave)
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_I2S_IN);
+
+ return 0;
+}
+
+static void mt8365_dai_i2s_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_i2s_priv *i2s_data = afe_priv->dai_priv[dai->id];
+ struct mt8365_be_dai_data *be =
+ &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
+ const unsigned int rate = substream->runtime->rate;
+ const unsigned int stream = substream->stream;
+ const bool shared_clk =
+ i2s_data->shared_clk;
+ const bool reset_i2s_out_change =
+ (stream == SNDRV_PCM_STREAM_PLAYBACK) || shared_clk;
+ const bool reset_i2s_in_change =
+ (stream == SNDRV_PCM_STREAM_CAPTURE) || shared_clk;
+ const bool i2s_in_slave = (substream->stream
+ == SNDRV_PCM_STREAM_CAPTURE)
+ && ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK)
+ == SND_SOC_DAIFMT_CBM_CFM);
+
+ dev_dbg(afe->dev, "%s '%s'\n",
+ __func__, snd_pcm_stream_str(substream));
+
+ if (shared_clk && snd_soc_dai_active(dai))
+ return;
+
+ if (be->prepared[stream]) {
+ if (reset_i2s_out_change)
+ mt8365_dai_set_enable(afe, i2s_data, false, false);
+
+ if (reset_i2s_in_change)
+ mt8365_dai_set_enable(afe, i2s_data, true, false);
+
+ if (rate % 8000)
+ mt8365_afe_disable_apll_associated_cfg(afe,
+ MT8365_AFE_APLL1);
+ else
+ mt8365_afe_disable_apll_associated_cfg(afe,
+ MT8365_AFE_APLL2);
+
+ if (reset_i2s_out_change)
+ be->prepared[SNDRV_PCM_STREAM_PLAYBACK] = false;
+
+ if (reset_i2s_in_change)
+ be->prepared[SNDRV_PCM_STREAM_CAPTURE] = false;
+ }
+
+ if (reset_i2s_out_change)
+ mt8365_afe_disable_clk(afe,
+ afe_priv->clocks[i2s_data->clk_id_out]);
+
+ if (reset_i2s_in_change && !i2s_in_slave)
+ mt8365_afe_disable_clk(afe,
+ afe_priv->clocks[i2s_data->clk_id_in]);
+
+ if (i2s_in_slave)
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_I2S_IN);
+
+ mt8365_afe_disable_main_clk(afe);
+}
+
+static int mt8365_dai_i2s_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_i2s_priv *i2s_data = afe_priv->dai_priv[dai->id];
+ struct mt8365_be_dai_data *be =
+ &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
+ struct snd_soc_dapm_widget *p = snd_soc_dai_get_widget_playback(dai);
+ struct snd_soc_dapm_widget *c = snd_soc_dai_get_widget_capture(dai);
+ const unsigned int rate = substream->runtime->rate;
+ const int bit_width = snd_pcm_format_width(substream->runtime->format);
+ const unsigned int stream = substream->stream;
+ const bool shared_clk = i2s_data->shared_clk;
+ const bool apply_i2s_out_change =
+ (stream == SNDRV_PCM_STREAM_PLAYBACK) || shared_clk;
+ const bool apply_i2s_in_change =
+ (stream == SNDRV_PCM_STREAM_CAPTURE) || shared_clk;
+ int ret;
+
+ if (shared_clk && (p->power || c->power)) {
+ dev_dbg(afe->dev, "%s '%s' widget powered(%u-%u) already\n",
+ __func__, snd_pcm_stream_str(substream),
+ p->power,
+ c->power);
+ return 0;
+ }
+
+ if (be->prepared[stream]) {
+ dev_info(afe->dev, "%s '%s' prepared already\n",
+ __func__, snd_pcm_stream_str(substream));
+ return 0;
+ }
+
+ if (apply_i2s_out_change) {
+ ret = mt8365_dai_set_config(afe, i2s_data,
+ false, rate, bit_width);
+ if (ret)
+ return ret;
+ }
+
+ if (apply_i2s_in_change) {
+ if ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK)
+ == SND_SOC_DAIFMT_CBM_CFM) {
+ ret = mt8365_afe_set_2nd_i2s_asrc(afe, 32000, rate,
+ (unsigned int)bit_width, 0, 0, 1);
+ if (ret < 0)
+ return ret;
+ }
+ ret = mt8365_dai_set_config(afe, i2s_data,
+ true, rate, bit_width);
+ if (ret)
+ return ret;
+ }
+
+ if (rate % 8000)
+ mt8365_afe_enable_apll_associated_cfg(afe, MT8365_AFE_APLL1);
+ else
+ mt8365_afe_enable_apll_associated_cfg(afe, MT8365_AFE_APLL2);
+
+ if (apply_i2s_out_change) {
+ mt8365_afe_set_clk_parent(afe,
+ afe_priv->clocks[i2s_data->clk_id_out_m_sel],
+ ((rate % 8000) ?
+ afe_priv->clocks[MT8365_CLK_AUD1] :
+ afe_priv->clocks[MT8365_CLK_AUD2]));
+
+ mt8365_afe_set_clk_rate(afe,
+ afe_priv->clocks[i2s_data->clk_id_out],
+ rate * i2s_data->clk_out_mult);
+
+ mt8365_dai_set_enable(afe, i2s_data, false, true);
+ be->prepared[SNDRV_PCM_STREAM_PLAYBACK] = true;
+ }
+
+ if (apply_i2s_in_change) {
+ mt8365_afe_set_clk_parent(afe,
+ afe_priv->clocks[i2s_data->clk_id_in_m_sel],
+ ((rate % 8000) ?
+ afe_priv->clocks[MT8365_CLK_AUD1] :
+ afe_priv->clocks[MT8365_CLK_AUD2]));
+
+ mt8365_afe_set_clk_rate(afe,
+ afe_priv->clocks[i2s_data->clk_id_in],
+ rate * i2s_data->clk_in_mult);
+
+ mt8365_dai_set_enable(afe, i2s_data, true, true);
+
+ if ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK)
+ == SND_SOC_DAIFMT_CBM_CFM)
+ mt8365_afe_set_2nd_i2s_asrc_enable(afe, true);
+
+ be->prepared[SNDRV_PCM_STREAM_CAPTURE] = true;
+ }
+ return 0;
+}
+
+static int mt8365_afe_2nd_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 width_val = params_width(params) > 16 ?
+ (AFE_CONN_24BIT_O00 | AFE_CONN_24BIT_O01) : 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ regmap_update_bits(afe->regmap, AFE_CONN_24BIT,
+ AFE_CONN_24BIT_O00 | AFE_CONN_24BIT_O01, width_val);
+
+ return 0;
+}
+
+static int mt8365_afe_2nd_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_i2s_priv *i2s_data = afe_priv->dai_priv[dai->id];
+ struct mt8365_be_dai_data *be =
+ &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
+ const bool shared_clk = i2s_data->shared_clk;
+
+ be->fmt_mode = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ be->fmt_mode |= SND_SOC_DAIFMT_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ be->fmt_mode |= SND_SOC_DAIFMT_LEFT_J;
+ break;
+ default:
+ dev_info(afe->dev, "invalid audio format for 2nd i2s!\n");
+ return -EINVAL;
+ }
+
+ if (((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) &&
+ ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_IF) &&
+ ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_IB_NF) &&
+ ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_IB_IF)) {
+ dev_info(afe->dev, "invalid audio format for 2nd i2s!\n");
+ return -EINVAL;
+ }
+
+ be->fmt_mode |= (fmt & SND_SOC_DAIFMT_INV_MASK);
+
+ if (((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM) &&
+ !shared_clk)
+ be->fmt_mode |= (fmt & SND_SOC_DAIFMT_MASTER_MASK);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mt8365_afe_i2s_ops = {
+ .startup = mt8365_dai_i2s_startup,
+ .shutdown = mt8365_dai_i2s_shutdown,
+ .prepare = mt8365_dai_i2s_prepare,
+};
+
+static const struct snd_soc_dai_ops mt8365_afe_2nd_i2s_ops = {
+ .startup = mt8365_dai_i2s_startup,
+ .shutdown = mt8365_dai_i2s_shutdown,
+ .hw_params = mt8365_afe_2nd_i2s_hw_params,
+ .prepare = mt8365_dai_i2s_prepare,
+ .set_fmt = mt8365_afe_2nd_i2s_set_fmt,
+};
+
+static struct snd_soc_dai_driver mtk_dai_i2s_driver[] = {
+ {
+ .name = "I2S",
+ .id = MT8365_AFE_IO_I2S,
+ .playback = {
+ .stream_name = "I2S Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .capture = {
+ .stream_name = "I2S Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_afe_i2s_ops,
+ }, {
+ .name = "2ND I2S",
+ .id = MT8365_AFE_IO_2ND_I2S,
+ .playback = {
+ .stream_name = "2ND I2S Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .capture = {
+ .stream_name = "2ND I2S Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_afe_2nd_i2s_ops,
+ }
+};
+
+/* low jitter control */
+static const char * const mt8365_i2s_hd_str[] = {
+ "Normal", "Low_Jitter"
+};
+
+static SOC_ENUM_SINGLE_EXT_DECL(mt8365_i2s_enum, mt8365_i2s_hd_str);
+
+static const char * const fmi2sin_text[] = {
+ "OPEN", "FM_2ND_I2S_IN"
+};
+
+static SOC_ENUM_SINGLE_VIRT_DECL(fmi2sin_enum, fmi2sin_text);
+
+static const struct snd_kcontrol_new fmi2sin_mux =
+ SOC_DAPM_ENUM("FM 2ND I2S Source", fmi2sin_enum);
+
+static const struct snd_kcontrol_new i2s_o03_o04_enable_ctl =
+ SOC_DAPM_SINGLE_VIRT("Switch", 1);
+
+static const struct snd_soc_dapm_widget mtk_dai_i2s_widgets[] = {
+ SND_SOC_DAPM_SWITCH("I2S O03_O04", SND_SOC_NOPM, 0, 0,
+ &i2s_o03_o04_enable_ctl),
+ SND_SOC_DAPM_MUX("FM 2ND I2S Mux", SND_SOC_NOPM, 0, 0, &fmi2sin_mux),
+ SND_SOC_DAPM_INPUT("2ND I2S In"),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_i2s_routes[] = {
+ {"I2S O03_O04", "Switch", "O03"},
+ {"I2S O03_O04", "Switch", "O04"},
+ {"I2S Playback", NULL, "I2S O03_O04"},
+ {"2ND I2S Playback", NULL, "O00"},
+ {"2ND I2S Playback", NULL, "O01"},
+ {"2ND I2S Capture", NULL, "2ND I2S In"},
+ {"FM 2ND I2S Mux", "FM_2ND_I2S_IN", "2ND I2S Capture"},
+};
+
+static int mt8365_dai_i2s_set_priv(struct mtk_base_afe *afe)
+{
+ int i, ret;
+ bool tmp;
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+
+ tmp = of_property_read_bool(afe->dev->of_node,
+ "mediatek,i2s-shared-clock");
+
+ for (i = 0; i < DAI_I2S_NUM; i++) {
+ ret = mt8365_dai_set_priv(afe, mt8365_i2s_priv[i].id,
+ sizeof(struct mtk_afe_i2s_priv),
+ &mt8365_i2s_priv[i]);
+ if (ret)
+ return ret;
+ ((struct mtk_afe_i2s_priv *)afe_priv->dai_priv[mt8365_i2s_priv[i].id])->
+ shared_clk = tmp;
+ }
+ return 0;
+}
+
+int mt8365_dai_i2s_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+
+ dev_dbg(afe->dev, "%s()\n", __func__);
+
+ 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->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 */
+ return mt8365_dai_i2s_set_priv(afe);
+}

--
2.25.1


2024-02-26 14:04:55

by Alexandre Mergnat

[permalink] [raw]
Subject: [PATCH 08/18] ASoC: mediatek: mt8365: Add DMIC DAI support

Add Digital Micro Device Audio Interface support for MT8365 SoC.

Signed-off-by: Alexandre Mergnat <[email protected]>
---
sound/soc/mediatek/mt8365/mt8365-dai-dmic.c | 475 ++++++++++++++++++++++++++++
1 file changed, 475 insertions(+)

diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-dmic.c b/sound/soc/mediatek/mt8365/mt8365-dai-dmic.c
new file mode 100644
index 000000000000..1e59f456b7c9
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/mt8365-dai-dmic.c
@@ -0,0 +1,475 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Mediatek 8365 ALSA SoC Audio DAI DMIC Control
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Authors: Jia Zeng <[email protected]>
+ * Alexandre Mergnat <[email protected]>
+ */
+
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8365-afe-clk.h"
+#include "mt8365-afe-common.h"
+
+struct mt8365_dmic_data {
+ bool two_wire_mode;
+ unsigned int clk_phase_sel_ch1;
+ unsigned int clk_phase_sel_ch2;
+ bool iir_on;
+ unsigned int irr_mode;
+ unsigned int dmic_mode;
+ unsigned int dmic_channel;
+};
+
+/* DAI Drivers */
+
+static void audio_dmic_adda_enable(struct mtk_base_afe *afe)
+{
+ mt8365_dai_enable_adda_on(afe);
+ regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0,
+ AFE_ADDA_UL_DL_DMIC_CLKDIV_ON, AFE_ADDA_UL_DL_DMIC_CLKDIV_ON);
+}
+
+static void audio_dmic_adda_disable(struct mtk_base_afe *afe)
+{
+ regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0,
+ AFE_ADDA_UL_DL_DMIC_CLKDIV_ON, ~AFE_ADDA_UL_DL_DMIC_CLKDIV_ON);
+ mt8365_dai_disable_adda_on(afe);
+}
+
+static void mt8365_dai_enable_dmic(struct mtk_base_afe *afe,
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_dmic_data *dmic_data = afe_priv->dai_priv[MT8365_AFE_IO_DMIC];
+ unsigned int val_mask;
+
+ /* val and mask will be always same to enable */
+ val_mask = DMIC_TOP_CON_CH1_ON |
+ DMIC_TOP_CON_CH2_ON |
+ DMIC_TOP_CON_SRC_ON;
+
+ switch (dmic_data->dmic_channel) {
+ case 8:
+ fallthrough;
+ case 7:
+ regmap_update_bits(afe->regmap, AFE_DMIC3_UL_SRC_CON0,
+ val_mask, val_mask);
+ fallthrough;
+ case 6:
+ fallthrough;
+ case 5:
+ regmap_update_bits(afe->regmap, AFE_DMIC2_UL_SRC_CON0,
+ val_mask, val_mask);
+ fallthrough;
+ case 4:
+ fallthrough;
+ case 3:
+ regmap_update_bits(afe->regmap, AFE_DMIC1_UL_SRC_CON0,
+ val_mask, val_mask);
+ fallthrough;
+ case 2:
+ fallthrough;
+ case 1:
+ regmap_update_bits(afe->regmap, AFE_DMIC0_UL_SRC_CON0,
+ val_mask, val_mask);
+ break;
+ default:
+ break;
+ }
+}
+
+static void mt8365_dai_disable_dmic(struct mtk_base_afe *afe,
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_dmic_data *dmic_data = afe_priv->dai_priv[MT8365_AFE_IO_DMIC];
+ unsigned int val, mask;
+
+ dev_info(afe->dev, "%s dmic_channel %d\n",
+ __func__, dmic_data->dmic_channel);
+
+ mask = DMIC_TOP_CON_CH1_ON |
+ DMIC_TOP_CON_CH2_ON |
+ DMIC_TOP_CON_SRC_ON |
+ DMIC_TOP_CON_SDM3_LEVEL_MODE;
+
+ /* CH1, CH1 and ARC = 0 */
+ val = DMIC_TOP_CON_SDM3_DE_SELECT;
+
+ switch (dmic_data->dmic_channel) {
+ case 8:
+ fallthrough;
+ case 7:
+ regmap_update_bits(afe->regmap, AFE_DMIC3_UL_SRC_CON0,
+ mask, val);
+
+ fallthrough;
+ case 6:
+ fallthrough;
+ case 5:
+ regmap_update_bits(afe->regmap, AFE_DMIC2_UL_SRC_CON0,
+ mask, val);
+ fallthrough;
+ case 4:
+ case 3:
+ regmap_update_bits(afe->regmap, AFE_DMIC1_UL_SRC_CON0,
+ mask, val);
+ fallthrough;
+ case 2:
+ fallthrough;
+ case 1:
+ regmap_update_bits(afe->regmap, AFE_DMIC0_UL_SRC_CON0,
+ mask, val);
+ regmap_update_bits(afe->regmap, AFE_DMIC0_UL_SRC_CON0,
+ DMIC_TOP_CON_CH2_ON, 0);
+ regmap_update_bits(afe->regmap, AFE_DMIC0_UL_SRC_CON0,
+ DMIC_TOP_CON_SRC_ON, 0);
+ regmap_update_bits(afe->regmap, AFE_DMIC0_UL_SRC_CON0,
+ DMIC_TOP_CON_SDM3_LEVEL_MODE,
+ DMIC_TOP_CON_SDM3_DE_SELECT);
+ break;
+ default:
+ break;
+ }
+}
+
+static const struct reg_sequence mt8365_afe_dmic_iir_coeff_reg_defaults[] = {
+ { AFE_DMIC0_IIR_COEF_02_01, 0x00000000 },
+ { AFE_DMIC0_IIR_COEF_04_03, 0x00003FB8 },
+ { AFE_DMIC0_IIR_COEF_06_05, 0x3FB80000 },
+ { AFE_DMIC0_IIR_COEF_08_07, 0x3FB80000 },
+ { AFE_DMIC0_IIR_COEF_10_09, 0x0000C048 },
+ { AFE_DMIC1_IIR_COEF_02_01, 0x00000000 },
+ { AFE_DMIC1_IIR_COEF_04_03, 0x00003FB8 },
+ { AFE_DMIC1_IIR_COEF_06_05, 0x3FB80000 },
+ { AFE_DMIC1_IIR_COEF_08_07, 0x3FB80000 },
+ { AFE_DMIC1_IIR_COEF_10_09, 0x0000C048 },
+ { AFE_DMIC2_IIR_COEF_02_01, 0x00000000 },
+ { AFE_DMIC2_IIR_COEF_04_03, 0x00003FB8 },
+ { AFE_DMIC2_IIR_COEF_06_05, 0x3FB80000 },
+ { AFE_DMIC2_IIR_COEF_08_07, 0x3FB80000 },
+ { AFE_DMIC2_IIR_COEF_10_09, 0x0000C048 },
+ { AFE_DMIC3_IIR_COEF_02_01, 0x00000000 },
+ { AFE_DMIC3_IIR_COEF_04_03, 0x00003FB8 },
+ { AFE_DMIC3_IIR_COEF_06_05, 0x3FB80000 },
+ { AFE_DMIC3_IIR_COEF_08_07, 0x3FB80000 },
+ { AFE_DMIC3_IIR_COEF_10_09, 0x0000C048 },
+};
+
+static int mt8365_dai_load_dmic_iir_coeff_table(struct mtk_base_afe *afe)
+{
+ return regmap_multi_reg_write(afe->regmap,
+ mt8365_afe_dmic_iir_coeff_reg_defaults,
+ ARRAY_SIZE(mt8365_afe_dmic_iir_coeff_reg_defaults));
+}
+
+static int mt8365_dai_configure_dmic(struct mtk_base_afe *afe,
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_dmic_data *dmic_data = afe_priv->dai_priv[MT8365_AFE_IO_DMIC];
+ bool two_wire_mode = dmic_data->two_wire_mode;
+ unsigned int clk_phase_sel_ch1 = dmic_data->clk_phase_sel_ch1;
+ unsigned int clk_phase_sel_ch2 = dmic_data->clk_phase_sel_ch2;
+ bool iir_on = dmic_data->iir_on;
+ unsigned int irr_mode = dmic_data->irr_mode;
+ unsigned int dmic_mode = dmic_data->dmic_mode;
+ unsigned int val = 0;
+ unsigned int channels = dai->channels;
+ unsigned int rate = dai->rate;
+
+ dmic_data->dmic_channel = channels;
+
+ dev_info(afe->dev, "%s dmic_channel %d dmic_rate %d dmic_mode %d\n",
+ __func__, dmic_data->dmic_channel, rate, dmic_mode);
+
+ val |= DMIC_TOP_CON_SDM3_LEVEL_MODE;
+
+ if (dmic_mode > DMIC_MODE_1P625M)
+ val |= DMIC_TOP_CON_LOW_POWER_MODE(dmic_mode);
+ else {
+ val |= DMIC_TOP_CON_LOW_POWER_MODE(0) |
+ FIELD_PREP(DMIC_TOP_CON_INPUT_MODE, dmic_mode);
+ }
+
+ if (two_wire_mode) {
+ val |= DMIC_TOP_CON_TWO_WIRE_MODE;
+ } else {
+ val |= FIELD_PREP(DMIC_TOP_CON_CK_PHASE_SEL_CH1, clk_phase_sel_ch1);
+ val |= FIELD_PREP(DMIC_TOP_CON_CK_PHASE_SEL_CH2, clk_phase_sel_ch2);
+ }
+
+ switch (rate) {
+ case 48000:
+ val |= DMIC_TOP_CON_VOICE_MODE_48K;
+ break;
+ case 32000:
+ val |= DMIC_TOP_CON_VOICE_MODE_32K;
+ break;
+ case 16000:
+ val |= DMIC_TOP_CON_VOICE_MODE_16K;
+ break;
+ case 8000:
+ val |= DMIC_TOP_CON_VOICE_MODE_8K;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (iir_on) {
+ if (irr_mode == IIR_MODE0)
+ mt8365_dai_load_dmic_iir_coeff_table(afe); /* SW mode */
+ val |= FIELD_PREP(DMIC_TOP_CON_IIR_MODE, irr_mode);
+ val |= DMIC_TOP_CON_IIR_ON;
+ }
+
+ switch (dmic_data->dmic_channel) {
+ case 8:
+ fallthrough;
+ case 7:
+ regmap_update_bits(afe->regmap, AFE_DMIC3_UL_SRC_CON0,
+ DMIC_TOP_CON_CONFIG_MASK, val);
+ fallthrough;
+ case 6:
+ fallthrough;
+ case 5:
+ regmap_update_bits(afe->regmap, AFE_DMIC2_UL_SRC_CON0,
+ DMIC_TOP_CON_CONFIG_MASK, val);
+ fallthrough;
+ case 4:
+ fallthrough;
+ case 3:
+ regmap_update_bits(afe->regmap, AFE_DMIC1_UL_SRC_CON0,
+ DMIC_TOP_CON_CONFIG_MASK, val);
+ fallthrough;
+ case 2:
+ fallthrough;
+ case 1:
+ regmap_update_bits(afe->regmap, AFE_DMIC0_UL_SRC_CON0,
+ DMIC_TOP_CON_CONFIG_MASK, val);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mt8365_dai_dmic_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+ mt8365_afe_enable_main_clk(afe);
+
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DMIC0_ADC);
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DMIC1_ADC);
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DMIC2_ADC);
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DMIC3_ADC);
+
+ audio_dmic_adda_enable(afe);
+
+ return 0;
+}
+
+static void mt8365_dai_dmic_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+ mt8365_dai_disable_dmic(afe, substream, dai);
+ audio_dmic_adda_disable(afe);
+ /* HW Request delay 125ms before CG off */
+ udelay(125);
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DMIC3_ADC);
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DMIC2_ADC);
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DMIC1_ADC);
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DMIC0_ADC);
+
+ mt8365_afe_disable_main_clk(afe);
+}
+
+static int mt8365_dai_dmic_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+ mt8365_dai_configure_dmic(afe, substream, dai);
+ mt8365_dai_enable_dmic(afe, substream, dai);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mt8365_afe_dmic_ops = {
+ .startup = mt8365_dai_dmic_startup,
+ .shutdown = mt8365_dai_dmic_shutdown,
+ .prepare = mt8365_dai_dmic_prepare,
+};
+
+static struct snd_soc_dai_driver mtk_dai_dmic_driver[] = {
+ {
+ .name = "DMIC",
+ .id = MT8365_AFE_IO_DMIC,
+ .capture = {
+ .stream_name = "DMIC Capture",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_afe_dmic_ops,
+ }
+};
+
+/* DAI Controls */
+
+static int mt8365_afe_dmic_mode_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 mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_dmic_data *dmic_data = afe_priv->dai_priv[MT8365_AFE_IO_DMIC];
+
+ ucontrol->value.integer.value[0] = dmic_data->dmic_mode;
+
+ return 0;
+}
+
+static int mt8365_afe_dmic_mode_put(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 mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_dmic_data *dmic_data = afe_priv->dai_priv[MT8365_AFE_IO_DMIC];
+
+ unsigned int val = ucontrol->value.integer.value[0];
+
+ if (dmic_data->dmic_mode == val)
+ return 0;
+
+ dmic_data->dmic_mode = ucontrol->value.integer.value[0];
+
+ return 0;
+}
+
+static const char *const dmic_mode_func[] = {
+ ENUM_TO_STR(DMIC_MODE_3P25M),
+ ENUM_TO_STR(DMIC_MODE_1P625M),
+ ENUM_TO_STR(DMIC_MODE_812P5K),
+ ENUM_TO_STR(DMIC_MODE_406P25K),
+};
+
+static const struct soc_enum mt8365_afe_soc_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dmic_mode_func), dmic_mode_func);
+
+static const struct snd_kcontrol_new mtk_dai_dmic_controls[] = {
+ SOC_ENUM_EXT("DMIC_Mode_Select",
+ mt8365_afe_soc_enum,
+ mt8365_afe_dmic_mode_get,
+ mt8365_afe_dmic_mode_put),
+};
+
+/* DAI widget */
+
+static const struct snd_soc_dapm_widget mtk_dai_dmic_widgets[] = {
+ SND_SOC_DAPM_INPUT("DMIC In"),
+};
+
+/* DAI route */
+
+static const struct snd_soc_dapm_route mtk_dai_dmic_routes[] = {
+ {"I14", NULL, "DMIC Capture"},
+ {"I15", NULL, "DMIC Capture"},
+ {"I16", NULL, "DMIC Capture"},
+ {"I17", NULL, "DMIC Capture"},
+ {"I18", NULL, "DMIC Capture"},
+ {"I19", NULL, "DMIC Capture"},
+ {"I20", NULL, "DMIC Capture"},
+ {"I21", NULL, "DMIC Capture"},
+ {"DMIC Capture", NULL, "DMIC In"},
+};
+
+
+static int init_dmic_priv_data(struct mtk_base_afe *afe)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_dmic_data *dmic_priv;
+ struct device_node *np = afe->dev->of_node;
+ unsigned int temps[4];
+ int ret;
+
+ dmic_priv = devm_kzalloc(afe->dev, sizeof(struct mt8365_dmic_data),
+ GFP_KERNEL);
+ if (!dmic_priv)
+ return -ENOMEM;
+
+ ret = of_property_read_u32_array(np, "mediatek,dmic-mode",
+ &temps[0],
+ 1);
+ if (ret == 0)
+ dmic_priv->dmic_mode = temps[0];
+
+ dmic_priv->two_wire_mode = of_property_read_bool(np,
+ "mediatek,dmic-two-wire-mode");
+
+ ret = of_property_read_u32_array(np, "mediatek,dmic-clk-phases",
+ &temps[0],
+ 2);
+ if (ret == 0) {
+ dmic_priv->clk_phase_sel_ch1 = temps[0];
+ dmic_priv->clk_phase_sel_ch2 = temps[1];
+ } else if (!dmic_priv->two_wire_mode) {
+ dmic_priv->clk_phase_sel_ch1 = 0;
+ dmic_priv->clk_phase_sel_ch2 = 4;
+ }
+
+ dmic_priv->iir_on = of_property_read_bool(np,
+ "mediatek,dmic-iir-on");
+
+ if (dmic_priv->iir_on) {
+ ret = of_property_read_u32_array(np, "mediatek,dmic-irr-mode",
+ &temps[0],
+ 1);
+ if (ret == 0)
+ dmic_priv->irr_mode = temps[0];
+ }
+
+ afe_priv->dai_priv[MT8365_AFE_IO_DMIC] = dmic_priv;
+ return 0;
+}
+
+int mt8365_dai_dmic_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+
+ dev_dbg(afe->dev, "%s()\n", __func__);
+
+ 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_dmic_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_dmic_driver);
+ dai->controls = mtk_dai_dmic_controls;
+ dai->num_controls = ARRAY_SIZE(mtk_dai_dmic_controls);
+ dai->dapm_widgets = mtk_dai_dmic_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_dmic_widgets);
+ dai->dapm_routes = mtk_dai_dmic_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_dmic_routes);
+
+ return init_dmic_priv_data(afe);
+}

--
2.25.1


2024-02-26 14:04:57

by Alexandre Mergnat

[permalink] [raw]
Subject: [PATCH 09/18] ASoC: mediatek: mt8365: Add PCM DAI support

Add Pulse Code Modulation Device Audio Interface support for MT8365 SoC.

Signed-off-by: Alexandre Mergnat <[email protected]>
---
sound/soc/mediatek/mt8365/mt8365-dai-pcm.c | 298 +++++++++++++++++++++++++++++
1 file changed, 298 insertions(+)

diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c b/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c
new file mode 100644
index 000000000000..02ee81663e50
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c
@@ -0,0 +1,298 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Mediatek 8365 ALSA SoC Audio DAI PCM Control
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Authors: Jia Zeng <[email protected]>
+ * Alexandre Mergnat <[email protected]>
+ */
+
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8365-afe-clk.h"
+#include "mt8365-afe-common.h"
+
+struct mt8365_pcm_intf_data {
+ bool slave_mode;
+ bool lrck_inv;
+ bool bck_inv;
+ unsigned int format;
+};
+
+/* DAI Drivers */
+
+static void mt8365_dai_enable_pcm1(struct mtk_base_afe *afe)
+{
+ regmap_update_bits(afe->regmap, PCM_INTF_CON1,
+ PCM_INTF_CON1_EN, PCM_INTF_CON1_EN);
+}
+
+static void mt8365_dai_disable_pcm1(struct mtk_base_afe *afe)
+{
+ regmap_update_bits(afe->regmap, PCM_INTF_CON1,
+ PCM_INTF_CON1_EN, 0x0);
+}
+
+static int mt8365_dai_configure_pcm1(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_pcm_runtime * const runtime = substream->runtime;
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_pcm_intf_data *pcm_priv = afe_priv->dai_priv[MT8365_AFE_IO_PCM1];
+ bool slave_mode = pcm_priv->slave_mode;
+ bool lrck_inv = pcm_priv->lrck_inv;
+ bool bck_inv = pcm_priv->bck_inv;
+ unsigned int fmt = pcm_priv->format;
+ unsigned int bit_width = dai->sample_bits;
+ unsigned int val = 0;
+
+ if (!slave_mode) {
+ val |= PCM_INTF_CON1_MASTER_MODE |
+ PCM_INTF_CON1_BYPASS_ASRC;
+
+ if (lrck_inv)
+ val |= PCM_INTF_CON1_SYNC_OUT_INV;
+ if (bck_inv)
+ val |= PCM_INTF_CON1_BCLK_OUT_INV;
+ } else {
+ val |= PCM_INTF_CON1_SLAVE_MODE;
+
+ if (lrck_inv)
+ val |= PCM_INTF_CON1_SYNC_IN_INV;
+ if (bck_inv)
+ val |= PCM_INTF_CON1_BCLK_IN_INV;
+
+ // TODO: add asrc setting
+ }
+
+ val |= FIELD_PREP(PCM_INTF_CON1_FORMAT_MASK, fmt);
+
+ if (fmt == MT8365_PCM_FORMAT_PCMA ||
+ fmt == MT8365_PCM_FORMAT_PCMB)
+ val |= PCM_INTF_CON1_SYNC_LEN(1);
+ else
+ val |= PCM_INTF_CON1_SYNC_LEN(bit_width);
+
+ switch (runtime->rate) {
+ case 48000:
+ val |= PCM_INTF_CON1_FS_48K;
+ break;
+ case 32000:
+ val |= PCM_INTF_CON1_FS_32K;
+ break;
+ case 16000:
+ val |= PCM_INTF_CON1_FS_16K;
+ break;
+ case 8000:
+ val |= PCM_INTF_CON1_FS_8K;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (bit_width > 16)
+ val |= PCM_INTF_CON1_24BIT | PCM_INTF_CON1_64BCK;
+ else
+ val |= PCM_INTF_CON1_16BIT | PCM_INTF_CON1_32BCK;
+
+ val |= PCM_INTF_CON1_EXT_MODEM;
+
+ regmap_update_bits(afe->regmap, PCM_INTF_CON1,
+ PCM_INTF_CON1_CONFIG_MASK, val);
+
+ return 0;
+}
+
+static int mt8365_dai_pcm1_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+ if (snd_soc_dai_active(dai))
+ return 0;
+
+ mt8365_afe_enable_main_clk(afe);
+
+ return 0;
+}
+
+static void mt8365_dai_pcm1_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+ if (snd_soc_dai_active(dai))
+ return;
+
+ mt8365_dai_disable_pcm1(afe);
+ mt8365_afe_disable_main_clk(afe);
+}
+
+static int mt8365_dai_pcm1_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ int ret;
+
+ if ((snd_soc_dai_stream_active_playback(dai) + snd_soc_dai_stream_active_capture(dai))
+ > 1) {
+ dev_info(afe->dev, "%s '%s' active(%u-%u) already\n",
+ __func__, snd_pcm_stream_str(substream),
+ snd_soc_dai_stream_active_playback(dai),
+ snd_soc_dai_stream_active_capture(dai));
+ return 0;
+ }
+
+ ret = mt8365_dai_configure_pcm1(substream, dai);
+ if (ret)
+ return ret;
+
+ mt8365_dai_enable_pcm1(afe);
+
+ return 0;
+}
+
+static int mt8365_dai_pcm1_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_pcm_intf_data *pcm_priv = afe_priv->dai_priv[MT8365_AFE_IO_PCM1];
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ pcm_priv->format = MT8365_PCM_FORMAT_I2S;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ pcm_priv->bck_inv = false;
+ pcm_priv->lrck_inv = false;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ pcm_priv->bck_inv = false;
+ pcm_priv->lrck_inv = true;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ pcm_priv->bck_inv = true;
+ pcm_priv->lrck_inv = false;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ pcm_priv->bck_inv = true;
+ pcm_priv->lrck_inv = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ pcm_priv->slave_mode = true;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ pcm_priv->slave_mode = false;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mt8365_dai_pcm1_ops = {
+ .startup = mt8365_dai_pcm1_startup,
+ .shutdown = mt8365_dai_pcm1_shutdown,
+ .prepare = mt8365_dai_pcm1_prepare,
+ .set_fmt = mt8365_dai_pcm1_set_fmt,
+};
+
+static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
+ {
+ .name = "PCM1",
+ .id = MT8365_AFE_IO_PCM1,
+ .playback = {
+ .stream_name = "PCM1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .capture = {
+ .stream_name = "PCM1 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_dai_pcm1_ops,
+ .symmetric_rate = 1,
+ .symmetric_sample_bits = 1,
+ }
+};
+
+/* DAI widget */
+
+static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = {
+ SND_SOC_DAPM_OUTPUT("PCM1 Out"),
+ SND_SOC_DAPM_INPUT("PCM1 In"),
+};
+
+/* DAI route */
+
+static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = {
+ {"PCM1 Playback", NULL, "O07"},
+ {"PCM1 Playback", NULL, "O08"},
+ {"PCM1 Out", NULL, "PCM1 Playback"},
+
+ {"I09", NULL, "PCM1 Capture"},
+ {"I22", NULL, "PCM1 Capture"},
+ {"PCM1 Capture", NULL, "PCM1 In"},
+};
+
+static int init_pcmif_priv_data(struct mtk_base_afe *afe)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_pcm_intf_data *pcmif_priv;
+
+ pcmif_priv = devm_kzalloc(afe->dev, sizeof(struct mt8365_pcm_intf_data),
+ GFP_KERNEL);
+ if (!pcmif_priv)
+ return -ENOMEM;
+
+ afe_priv->dai_priv[MT8365_AFE_IO_PCM1] = pcmif_priv;
+ return 0;
+}
+
+int mt8365_dai_pcm_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+
+ dev_dbg(afe->dev, "%s()\n", __func__);
+
+ 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);
+
+ return init_pcmif_priv_data(afe);
+}

--
2.25.1


2024-02-26 14:07:26

by Alexandre Mergnat

[permalink] [raw]
Subject: [PATCH 17/18] arm64: dts: mediatek: add afe support for mt8365 SoC

Add audio front end support of MT8365 SoC.
Update the file header.

Signed-off-by: Alexandre Mergnat <[email protected]>
---
arch/arm64/boot/dts/mediatek/mt8365.dtsi | 47 ++++++++++++++++++++++++++++++--
1 file changed, 44 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/boot/dts/mediatek/mt8365.dtsi b/arch/arm64/boot/dts/mediatek/mt8365.dtsi
index 24581f7410aa..13cd1298832b 100644
--- a/arch/arm64/boot/dts/mediatek/mt8365.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8365.dtsi
@@ -1,10 +1,12 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/*
* (C) 2018 MediaTek Inc.
- * Copyright (C) 2022 BayLibre SAS
- * Fabien Parent <[email protected]>
- * Bernhard Rosenkränzer <[email protected]>
+ * Copyright (C) 2024 BayLibre SAS
+ * Authors: Fabien Parent <[email protected]>
+ * Bernhard Rosenkränzer <[email protected]>
+ * Alexandre Mergnat <[email protected]>
*/
+
#include <dt-bindings/clock/mediatek,mt8365-clk.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
@@ -813,6 +815,45 @@ apu: syscon@19020000 {
reg = <0 0x19020000 0 0x1000>;
#clock-cells = <1>;
};
+
+ afe: audio-controller@11220000 {
+ compatible = "mediatek,mt8365-afe-pcm";
+ reg = <0 0x11220000 0 0x1000>,
+ <0 0x11221000 0 0xA000>;
+ interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_LOW>;
+ power-domains = <&spm MT8365_POWER_DOMAIN_AUDIO>;
+ mediatek,topckgen = <&topckgen>;
+ #sound-dai-cells = <0>;
+ clocks = <&clk26m>,
+ <&topckgen CLK_TOP_AUDIO_SEL>,
+ <&topckgen CLK_TOP_AUD_I2S0_M>,
+ <&topckgen CLK_TOP_AUD_I2S1_M>,
+ <&topckgen CLK_TOP_AUD_I2S2_M>,
+ <&topckgen CLK_TOP_AUD_I2S3_M>,
+ <&topckgen CLK_TOP_AUD_ENGEN1_SEL>,
+ <&topckgen CLK_TOP_AUD_ENGEN2_SEL>,
+ <&topckgen CLK_TOP_AUD_1_SEL>,
+ <&topckgen CLK_TOP_AUD_2_SEL>,
+ <&topckgen CLK_TOP_APLL_I2S0_SEL>,
+ <&topckgen CLK_TOP_APLL_I2S1_SEL>,
+ <&topckgen CLK_TOP_APLL_I2S2_SEL>,
+ <&topckgen CLK_TOP_APLL_I2S3_SEL>;
+ clock-names = "top_clk26m_clk",
+ "top_audio_sel",
+ "audio_i2s0_m",
+ "audio_i2s1_m",
+ "audio_i2s2_m",
+ "audio_i2s3_m",
+ "engen1",
+ "engen2",
+ "aud1",
+ "aud2",
+ "i2s0_m_sel",
+ "i2s1_m_sel",
+ "i2s2_m_sel",
+ "i2s3_m_sel";
+ status = "disabled";
+ };
};

timer {

--
2.25.1


2024-02-26 14:07:30

by Alexandre Mergnat

[permalink] [raw]
Subject: [PATCH 14/18] ASoC: mediatek: Add MT8365 support

- Add specific config to enable:
- MT8365 sound support
- MT6357 audio codec support
- Add the mt8365 directory and all drivers under it.

Signed-off-by: Alexandre Mergnat <[email protected]>
---
sound/soc/mediatek/Kconfig | 20 ++++++++++++++++++++
sound/soc/mediatek/Makefile | 1 +
sound/soc/mediatek/mt8365/Makefile | 15 +++++++++++++++
3 files changed, 36 insertions(+)

diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index 296b434caf81..671020037a99 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -314,3 +314,23 @@ config SND_SOC_MT8195_MT6359
boards with the MT6359 and other I2S audio codecs.
Select Y if you have such device.
If unsure select "N".
+
+config SND_SOC_MT8365
+ tristate "ASoC support for Mediatek MT8365 chip"
+ depends on ARCH_MEDIATEK
+ select SND_SOC_MEDIATEK
+ help
+ This adds ASoC platform driver support for Mediatek MT8365 chip
+ that can be used with other codecs.
+ Select Y if you have such device.
+ If unsure select "N".
+
+config SND_SOC_MT8365_MT6357
+ tristate "ASoC Audio driver for MT8365 with MT6357 codec"
+ depends on SND_SOC_MT8365 && MTK_PMIC_WRAP
+ select SND_SOC_MT6357
+ help
+ This adds support for ASoC machine driver for Mediatek MT8365
+ boards with the MT6357 codec.
+ Select Y if you have such device.
+ If unsure select "N".
diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile
index 3938e7f75c2e..4b55434f2168 100644
--- a/sound/soc/mediatek/Makefile
+++ b/sound/soc/mediatek/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_SND_SOC_MT8186) += mt8186/
obj-$(CONFIG_SND_SOC_MT8188) += mt8188/
obj-$(CONFIG_SND_SOC_MT8192) += mt8192/
obj-$(CONFIG_SND_SOC_MT8195) += mt8195/
+obj-$(CONFIG_SND_SOC_MT8365) += mt8365/
diff --git a/sound/soc/mediatek/mt8365/Makefile b/sound/soc/mediatek/mt8365/Makefile
new file mode 100644
index 000000000000..52ba45a8498a
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/Makefile
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# MTK Platform driver
+snd-soc-mt8365-pcm-objs := \
+ mt8365-afe-clk.o \
+ mt8365-afe-pcm.o \
+ mt8365-dai-adda.o \
+ mt8365-dai-dmic.o \
+ mt8365-dai-i2s.o \
+ mt8365-dai-pcm.o
+
+obj-$(CONFIG_SND_SOC_MT8365) += snd-soc-mt8365-pcm.o
+
+# Machine driver
+obj-$(CONFIG_SND_SOC_MT8365_MT6357) += mt8365-mt6357.o

--
2.25.1


2024-02-26 14:07:39

by Alexandre Mergnat

[permalink] [raw]
Subject: [PATCH 16/18] arm64: dts: mediatek: add mt6357 audio codec support

Add audio codec support of MT6357 PMIC.
Update the file header.

Signed-off-by: Alexandre Mergnat <[email protected]>
---
arch/arm64/boot/dts/mediatek/mt6357.dtsi | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/mediatek/mt6357.dtsi b/arch/arm64/boot/dts/mediatek/mt6357.dtsi
index 3330a03c2f74..64b693049930 100644
--- a/arch/arm64/boot/dts/mediatek/mt6357.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt6357.dtsi
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/*
* Copyright (c) 2020 MediaTek Inc.
- * Copyright (c) 2023 BayLibre Inc.
+ * Copyright (c) 2024 BayLibre Inc.
*/

#include <dt-bindings/input/input.h>
@@ -10,6 +10,10 @@ &pwrap {
mt6357_pmic: pmic {
compatible = "mediatek,mt6357";

+ codec {
+ compatible = "mediatek,mt6357-sound";
+ };
+
regulators {
mt6357_vproc_reg: buck-vproc {
regulator-name = "vproc";

--
2.25.1


2024-02-26 14:07:47

by Alexandre Mergnat

[permalink] [raw]
Subject: [PATCH 18/18] arm64: dts: mediatek: add audio support for mt8365-evk

Add the sound node which is linked to the MT8365 SoC AFE and
the MT6357 audio codec.

Update the file header.

Signed-off-by: Alexandre Mergnat <[email protected]>
---
arch/arm64/boot/dts/mediatek/mt8365-evk.dts | 95 +++++++++++++++++++++++++++--
1 file changed, 91 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/boot/dts/mediatek/mt8365-evk.dts b/arch/arm64/boot/dts/mediatek/mt8365-evk.dts
index 50cbaefa1a99..818a8d263949 100644
--- a/arch/arm64/boot/dts/mediatek/mt8365-evk.dts
+++ b/arch/arm64/boot/dts/mediatek/mt8365-evk.dts
@@ -1,9 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright (c) 2021-2022 BayLibre, SAS.
- * Authors:
- * Fabien Parent <[email protected]>
- * Bernhard Rosenkränzer <[email protected]>
+ * Copyright (c) 2024 BayLibre, SAS.
+ * Authors: Fabien Parent <[email protected]>
+ * Bernhard Rosenkränzer <[email protected]>
+ * Alexandre Mergnat <[email protected]>
*/

/dts-v1/;
@@ -86,6 +86,25 @@ optee_reserved: optee@43200000 {
reg = <0 0x43200000 0 0x00c00000>;
};
};
+
+ sound: sound {
+ compatible = "mediatek,mt8365-mt6357";
+ mediatek,platform = <&afe>;
+ pinctrl-names = "aud_default",
+ "aud_dmic",
+ "aud_miso_off",
+ "aud_miso_on",
+ "aud_mosi_off",
+ "aud_mosi_on";
+ pinctrl-0 = <&aud_default_pins>;
+ pinctrl-1 = <&aud_dmic_pins>;
+ pinctrl-2 = <&aud_miso_off_pins>;
+ pinctrl-3 = <&aud_miso_on_pins>;
+ pinctrl-4 = <&aud_mosi_off_pins>;
+ pinctrl-5 = <&aud_mosi_on_pins>;
+ vaud28-supply = <&mt6357_vaud28_reg>;
+ status = "okay";
+ };
};

&cpu0 {
@@ -181,6 +200,67 @@ &mt6357_pmic {
};

&pio {
+ aud_default_pins: audiodefault-pins {
+ pins {
+ pinmux = <MT8365_PIN_72_CMDAT4__FUNC_I2S3_BCK>,
+ <MT8365_PIN_73_CMDAT5__FUNC_I2S3_LRCK>,
+ <MT8365_PIN_74_CMDAT6__FUNC_I2S3_MCK>,
+ <MT8365_PIN_75_CMDAT7__FUNC_I2S3_DO>;
+ };
+ };
+
+ aud_dmic_pins: audiodmic-pins {
+ pins {
+ pinmux = <MT8365_PIN_117_DMIC0_CLK__FUNC_DMIC0_CLK>,
+ <MT8365_PIN_118_DMIC0_DAT0__FUNC_DMIC0_DAT0>,
+ <MT8365_PIN_119_DMIC0_DAT1__FUNC_DMIC0_DAT1>;
+ };
+ };
+
+ aud_miso_off_pins: misooff-pins {
+ pins {
+ pinmux = <MT8365_PIN_53_AUD_CLK_MISO__FUNC_GPIO53>,
+ <MT8365_PIN_54_AUD_SYNC_MISO__FUNC_GPIO54>,
+ <MT8365_PIN_55_AUD_DAT_MISO0__FUNC_GPIO55>,
+ <MT8365_PIN_56_AUD_DAT_MISO1__FUNC_GPIO56>;
+ input-enable;
+ bias-pull-down;
+ drive-strength = <MTK_DRIVE_2mA>;
+ };
+ };
+
+ aud_miso_on_pins: misoon-pins {
+ pins {
+ pinmux = <MT8365_PIN_53_AUD_CLK_MISO__FUNC_AUD_CLK_MISO>,
+ <MT8365_PIN_54_AUD_SYNC_MISO__FUNC_AUD_SYNC_MISO>,
+ <MT8365_PIN_55_AUD_DAT_MISO0__FUNC_AUD_DAT_MISO0>,
+ <MT8365_PIN_56_AUD_DAT_MISO1__FUNC_AUD_DAT_MISO1>;
+ drive-strength = <MTK_DRIVE_6mA>;
+ };
+ };
+
+ aud_mosi_off_pins: mosioff-pins {
+ pins {
+ pinmux = <MT8365_PIN_49_AUD_CLK_MOSI__FUNC_GPIO49>,
+ <MT8365_PIN_50_AUD_SYNC_MOSI__FUNC_GPIO50>,
+ <MT8365_PIN_51_AUD_DAT_MOSI0__FUNC_GPIO51>,
+ <MT8365_PIN_52_AUD_DAT_MOSI1__FUNC_GPIO52>;
+ input-enable;
+ bias-pull-down;
+ drive-strength = <MTK_DRIVE_2mA>;
+ };
+ };
+
+ aud_mosi_on_pins: mosion-pins {
+ pins {
+ pinmux = <MT8365_PIN_49_AUD_CLK_MOSI__FUNC_AUD_CLK_MOSI>,
+ <MT8365_PIN_50_AUD_SYNC_MOSI__FUNC_AUD_SYNC_MOSI>,
+ <MT8365_PIN_51_AUD_DAT_MOSI0__FUNC_AUD_DAT_MOSI0>,
+ <MT8365_PIN_52_AUD_DAT_MOSI1__FUNC_AUD_DAT_MOSI1>;
+ drive-strength = <MTK_DRIVE_6mA>;
+ };
+ };
+
ethernet_pins: ethernet-pins {
phy_reset_pins {
pinmux = <MT8365_PIN_133_TDM_TX_DATA1__FUNC_GPIO133>;
@@ -416,3 +496,10 @@ &uart2 {
pinctrl-names = "default";
status = "okay";
};
+
+&afe {
+ mediatek,dmic-iir-on;
+ mediatek,dmic-irr-mode = <5>;
+ mediatek,dmic-two-wire-mode;
+ status = "okay";
+};

--
2.25.1


2024-02-26 14:07:57

by Alexandre Mergnat

[permalink] [raw]
Subject: [PATCH 11/18] ASoC: mediatek: mt8365: Add platform driver

Add mt8365 platform driver.

Signed-off-by: Alexandre Mergnat <[email protected]>
---
sound/soc/mediatek/mt8365/mt8365-afe-pcm.c | 2347 ++++++++++++++++++++++++++++
1 file changed, 2347 insertions(+)

diff --git a/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c b/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c
new file mode 100644
index 000000000000..16592f9ec3ec
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c
@@ -0,0 +1,2347 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Mediatek 8365 ALSA SoC AFE platform driver
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Authors: Jia Zeng <[email protected]>
+ * Alexandre Mergnat <[email protected]>
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#include "mt8365-afe-common.h"
+#include "mt8365-afe-clk.h"
+#include "mt8365-reg.h"
+#include "../common/mtk-base-afe.h"
+#include "../common/mtk-afe-platform-driver.h"
+#include "../common/mtk-afe-fe-dai.h"
+
+#define AFE_BASE_END_OFFSET 8
+
+static unsigned int mCM2Input;
+
+static const unsigned int mt8365_afe_backup_list[] = {
+ AUDIO_TOP_CON0,
+ AFE_CONN0,
+ AFE_CONN1,
+ AFE_CONN3,
+ AFE_CONN4,
+ AFE_CONN5,
+ AFE_CONN6,
+ AFE_CONN7,
+ AFE_CONN8,
+ AFE_CONN9,
+ AFE_CONN10,
+ AFE_CONN11,
+ AFE_CONN12,
+ AFE_CONN13,
+ AFE_CONN14,
+ AFE_CONN15,
+ AFE_CONN16,
+ AFE_CONN17,
+ AFE_CONN18,
+ AFE_CONN19,
+ AFE_CONN20,
+ AFE_CONN21,
+ AFE_CONN26,
+ AFE_CONN27,
+ AFE_CONN28,
+ AFE_CONN29,
+ AFE_CONN30,
+ AFE_CONN31,
+ AFE_CONN32,
+ AFE_CONN33,
+ AFE_CONN34,
+ AFE_CONN35,
+ AFE_CONN36,
+ AFE_CONN_24BIT,
+ AFE_CONN_24BIT_1,
+ AFE_DAC_CON0,
+ AFE_DAC_CON1,
+ AFE_DL1_BASE,
+ AFE_DL1_END,
+ AFE_DL2_BASE,
+ AFE_DL2_END,
+ AFE_VUL_BASE,
+ AFE_VUL_END,
+ AFE_AWB_BASE,
+ AFE_AWB_END,
+ AFE_VUL3_BASE,
+ AFE_VUL3_END,
+ AFE_HDMI_OUT_BASE,
+ AFE_HDMI_OUT_END,
+ AFE_HDMI_IN_2CH_BASE,
+ AFE_HDMI_IN_2CH_END,
+ AFE_ADDA_UL_DL_CON0,
+ AFE_ADDA_DL_SRC2_CON0,
+ AFE_ADDA_DL_SRC2_CON1,
+ AFE_I2S_CON,
+ AFE_I2S_CON1,
+ AFE_I2S_CON2,
+ AFE_I2S_CON3,
+ AFE_ADDA_UL_SRC_CON0,
+ AFE_AUD_PAD_TOP,
+ AFE_HD_ENGEN_ENABLE,
+};
+
+static const struct snd_pcm_hardware mt8365_afe_hardware = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP_VALID),
+ .buffer_bytes_max = 256 * 1024,
+ .period_bytes_min = 512,
+ .period_bytes_max = 128 * 1024,
+ .periods_min = 2,
+ .periods_max = 256,
+ .fifo_size = 0,
+};
+
+struct mt8365_afe_rate {
+ unsigned int rate;
+ unsigned int reg_val;
+};
+
+static const struct mt8365_afe_rate mt8365_afe_fs_rates[] = {
+ { .rate = 8000, .reg_val = MT8365_FS_8K },
+ { .rate = 11025, .reg_val = MT8365_FS_11D025K },
+ { .rate = 12000, .reg_val = MT8365_FS_12K },
+ { .rate = 16000, .reg_val = MT8365_FS_16K },
+ { .rate = 22050, .reg_val = MT8365_FS_22D05K },
+ { .rate = 24000, .reg_val = MT8365_FS_24K },
+ { .rate = 32000, .reg_val = MT8365_FS_32K },
+ { .rate = 44100, .reg_val = MT8365_FS_44D1K },
+ { .rate = 48000, .reg_val = MT8365_FS_48K },
+ { .rate = 88200, .reg_val = MT8365_FS_88D2K },
+ { .rate = 96000, .reg_val = MT8365_FS_96K },
+ { .rate = 176400, .reg_val = MT8365_FS_176D4K },
+ { .rate = 192000, .reg_val = MT8365_FS_192K },
+};
+
+int mt8365_afe_fs_timing(unsigned int rate)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mt8365_afe_fs_rates); i++)
+ if (mt8365_afe_fs_rates[i].rate == rate)
+ return mt8365_afe_fs_rates[i].reg_val;
+
+ return -EINVAL;
+}
+
+bool mt8365_afe_rate_supported(unsigned int rate, unsigned int id)
+{
+ switch (id) {
+ case MT8365_AFE_IO_TDM_IN:
+ if (rate >= 8000 && rate <= 192000)
+ return true;
+ break;
+ case MT8365_AFE_IO_DMIC:
+ if (rate >= 8000 && rate <= 48000)
+ return true;
+ break;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+bool mt8365_afe_channel_supported(unsigned int channel, unsigned int id)
+{
+ switch (id) {
+ case MT8365_AFE_IO_TDM_IN:
+ if (channel >= 1 && channel <= 8)
+ return true;
+ break;
+ case MT8365_AFE_IO_DMIC:
+ if (channel >= 1 && channel <= 8)
+ return true;
+ break;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+bool mt8365_afe_clk_group_44k(int sample_rate)
+{
+ if ((sample_rate == 11025)
+ || (sample_rate == 22050)
+ || (sample_rate == 44100)
+ || (sample_rate == 88200)
+ || (sample_rate == 176400))
+ return true;
+ else
+ return false;
+}
+
+bool mt8365_afe_clk_group_48k(int sample_rate)
+{
+ return (!mt8365_afe_clk_group_44k(sample_rate));
+}
+
+int mt8365_dai_set_priv(struct mtk_base_afe *afe, int id,
+ int priv_size, const void *priv_data)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ void *temp_data;
+
+ temp_data = devm_kzalloc(afe->dev,
+ priv_size,
+ GFP_KERNEL);
+ if (!temp_data)
+ return -ENOMEM;
+
+ if (priv_data)
+ memcpy(temp_data, priv_data, priv_size);
+
+ afe_priv->dai_priv[id] = temp_data;
+
+ return 0;
+}
+
+static int mt8365_afe_irq_direction_enable(struct mtk_base_afe *afe,
+ int irq_id,
+ int direction)
+{
+ struct mtk_base_afe_irq *irq;
+
+ if (irq_id >= MT8365_AFE_IRQ_NUM)
+ return -1;
+
+ irq = &afe->irqs[irq_id];
+
+ if (direction == MT8365_AFE_IRQ_DIR_MCU) {
+ regmap_update_bits(afe->regmap, AFE_IRQ_MCU_DSP_EN,
+ (1 << irq->irq_data->irq_clr_shift),
+ 0);
+ regmap_update_bits(afe->regmap, AFE_IRQ_MCU_EN,
+ (1 << irq->irq_data->irq_clr_shift),
+ (1 << irq->irq_data->irq_clr_shift));
+ } else if (direction == MT8365_AFE_IRQ_DIR_DSP) {
+ regmap_update_bits(afe->regmap, AFE_IRQ_MCU_DSP_EN,
+ (1 << irq->irq_data->irq_clr_shift),
+ (1 << irq->irq_data->irq_clr_shift));
+ regmap_update_bits(afe->regmap, AFE_IRQ_MCU_EN,
+ (1 << irq->irq_data->irq_clr_shift),
+ 0);
+ } else {
+ regmap_update_bits(afe->regmap, AFE_IRQ_MCU_DSP_EN,
+ (1 << irq->irq_data->irq_clr_shift),
+ (1 << irq->irq_data->irq_clr_shift));
+ regmap_update_bits(afe->regmap, AFE_IRQ_MCU_EN,
+ (1 << irq->irq_data->irq_clr_shift),
+ (1 << irq->irq_data->irq_clr_shift));
+ }
+ return 0;
+}
+
+static int mt8365_memif_fs(struct snd_pcm_substream *substream,
+ unsigned int rate)
+{
+ return mt8365_afe_fs_timing(rate);
+}
+
+static int mt8365_irq_fs(struct snd_pcm_substream *substream,
+ unsigned int rate)
+{
+ return mt8365_memif_fs(substream, rate);
+}
+
+static const struct mt8365_cm_ctrl_reg cm_ctrl_reg[MT8365_CM_NUM] = {
+ [MT8365_CM1] = {
+ .con0 = AFE_CM1_CON0,
+ .con1 = AFE_CM1_CON1,
+ .con2 = AFE_CM1_CON2,
+ .con3 = AFE_CM1_CON3,
+ .con4 = AFE_CM1_CON4,
+ },
+ [MT8365_CM2] = {
+ .con0 = AFE_CM2_CON0,
+ .con1 = AFE_CM2_CON1,
+ .con2 = AFE_CM2_CON2,
+ .con3 = AFE_CM2_CON3,
+ .con4 = AFE_CM2_CON4,
+ }
+};
+
+static int mt8365_afe_cm2_mux_conn(struct mtk_base_afe *afe)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ unsigned int input = afe_priv->cm2_mux_input;
+
+ dev_dbg(afe->dev, "%s input %d\n", __func__, input);
+
+ /* TDM_IN interconnect to CM2 */
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN0,
+ CM2_AFE_CM2_CONN_CFG1_MASK,
+ CM2_AFE_CM2_CONN_CFG1(TDM_IN_CH0));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN0,
+ CM2_AFE_CM2_CONN_CFG2_MASK,
+ CM2_AFE_CM2_CONN_CFG2(TDM_IN_CH1));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN0,
+ CM2_AFE_CM2_CONN_CFG3_MASK,
+ CM2_AFE_CM2_CONN_CFG3(TDM_IN_CH2));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN0,
+ CM2_AFE_CM2_CONN_CFG4_MASK,
+ CM2_AFE_CM2_CONN_CFG4(TDM_IN_CH3));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN0,
+ CM2_AFE_CM2_CONN_CFG5_MASK,
+ CM2_AFE_CM2_CONN_CFG5(TDM_IN_CH4));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN0,
+ CM2_AFE_CM2_CONN_CFG6_MASK,
+ CM2_AFE_CM2_CONN_CFG6(TDM_IN_CH5));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+ CM2_AFE_CM2_CONN_CFG7_MASK,
+ CM2_AFE_CM2_CONN_CFG7(TDM_IN_CH6));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+ CM2_AFE_CM2_CONN_CFG8_MASK,
+ CM2_AFE_CM2_CONN_CFG8(TDM_IN_CH7));
+
+ /* ref data interconnect to CM2 */
+ if (input == MT8365_FROM_GASRC1) {
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+ CM2_AFE_CM2_CONN_CFG9_MASK,
+ CM2_AFE_CM2_CONN_CFG9(GENERAL1_ASRC_OUT_LCH));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+ CM2_AFE_CM2_CONN_CFG10_MASK,
+ CM2_AFE_CM2_CONN_CFG10(GENERAL1_ASRC_OUT_RCH));
+ } else if (input == MT8365_FROM_GASRC2) {
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+ CM2_AFE_CM2_CONN_CFG9_MASK,
+ CM2_AFE_CM2_CONN_CFG9(GENERAL2_ASRC_OUT_LCH));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+ CM2_AFE_CM2_CONN_CFG10_MASK,
+ CM2_AFE_CM2_CONN_CFG10(GENERAL2_ASRC_OUT_RCH));
+ } else if (input == MT8365_FROM_TDM_ASRC) {
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+ CM2_AFE_CM2_CONN_CFG9_MASK,
+ CM2_AFE_CM2_CONN_CFG9(TDM_OUT_ASRC_CH0));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+ CM2_AFE_CM2_CONN_CFG10_MASK,
+ CM2_AFE_CM2_CONN_CFG10(TDM_OUT_ASRC_CH1));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+ CM2_AFE_CM2_CONN_CFG11_MASK,
+ CM2_AFE_CM2_CONN_CFG11(TDM_OUT_ASRC_CH2));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+ CM2_AFE_CM2_CONN_CFG12_MASK,
+ CM2_AFE_CM2_CONN_CFG12(TDM_OUT_ASRC_CH3));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN2,
+ CM2_AFE_CM2_CONN_CFG13_MASK,
+ CM2_AFE_CM2_CONN_CFG13(TDM_OUT_ASRC_CH4));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN2,
+ CM2_AFE_CM2_CONN_CFG14_MASK,
+ CM2_AFE_CM2_CONN_CFG14(TDM_OUT_ASRC_CH5));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN2,
+ CM2_AFE_CM2_CONN_CFG15_MASK,
+ CM2_AFE_CM2_CONN_CFG15(TDM_OUT_ASRC_CH6));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN2,
+ CM2_AFE_CM2_CONN_CFG16_MASK,
+ CM2_AFE_CM2_CONN_CFG16(TDM_OUT_ASRC_CH7));
+ } else {
+ dev_dbg(afe->dev, "%s wrong CM2 input %d\n",
+ __func__, input);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int mt8365_afe_get_cm_update_cnt(struct mtk_base_afe *afe,
+ enum mt8365_cm_num cmNum, unsigned int rate, unsigned int channel)
+{
+
+ /* calculate cm update cnt */
+ /* total_cnt = clk / fs, clk is 26m or 24m or 22m*/
+ /* div_cnt = total_cnt / ch_pair, max ch 16ch ,2ch is a set */
+ /* best_cnt < div_cnt ,we set best_cnt = div_cnt -10 */
+ /* ch01 = best_cnt, ch23 = 2* ch01_up_cnt */
+ /* ch45 = 3* ch01_up_cnt ...ch1415 = 8* ch01_up_cnt */
+
+ unsigned int total_cnt, div_cnt, ch_pair, best_cnt;
+ unsigned int ch_update_cnt[MT8365_CM_UPDATA_CNT_SET];
+ int i;
+
+ if (cmNum == MT8365_CM1) {
+ total_cnt = MT8365_CLK_26M / rate;
+ } else if (cmNum == MT8365_CM2) {
+ if (mt8365_afe_clk_group_48k(rate))
+ total_cnt = MT8365_CLK_24M / rate;
+ else
+ total_cnt = MT8365_CLK_22M / rate;
+ } else {
+ dev_dbg(afe->dev, "%s wrong cmNum %d\n",
+ __func__, cmNum);
+ return -1;
+ }
+
+ if (channel % 2)
+ ch_pair = (channel / 2) + 1;
+ else
+ ch_pair = channel / 2;
+
+ div_cnt = total_cnt / ch_pair;
+ best_cnt = div_cnt - 10;
+
+ if (best_cnt <= 0) {
+ dev_dbg(afe->dev, "%s wrong best_cnt %d\n",
+ __func__, best_cnt);
+ return -1;
+ }
+
+ for (i = 0; i < ch_pair; i++)
+ ch_update_cnt[i] = (i + 1) * best_cnt;
+
+ dev_dbg(afe->dev, "%s channel %d ch_pair %d\n",
+ __func__, channel, ch_pair);
+
+ switch (channel) {
+ case 16:
+ fallthrough;
+ case 15:
+ regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con4,
+ CM_AFE_CM_UPDATE_CNT2_MASK,
+ CM_AFE_CM_UPDATE_CNT2(ch_update_cnt[7]));
+ fallthrough;
+ case 14:
+ fallthrough;
+ case 13:
+ regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con4,
+ CM_AFE_CM_UPDATE_CNT1_MASK,
+ CM_AFE_CM_UPDATE_CNT1(ch_update_cnt[6]));
+ fallthrough;
+ case 12:
+ fallthrough;
+ case 11:
+ regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con3,
+ CM_AFE_CM_UPDATE_CNT2_MASK,
+ CM_AFE_CM_UPDATE_CNT2(ch_update_cnt[5]));
+ fallthrough;
+ case 10:
+ fallthrough;
+ case 9:
+ regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con3,
+ CM_AFE_CM_UPDATE_CNT1_MASK,
+ CM_AFE_CM_UPDATE_CNT1(ch_update_cnt[4]));
+ fallthrough;
+ case 8:
+ fallthrough;
+ case 7:
+ regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con2,
+ CM_AFE_CM_UPDATE_CNT2_MASK,
+ CM_AFE_CM_UPDATE_CNT2(ch_update_cnt[3]));
+ fallthrough;
+ case 6:
+ fallthrough;
+ case 5:
+ regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con2,
+ CM_AFE_CM_UPDATE_CNT1_MASK,
+ CM_AFE_CM_UPDATE_CNT1(ch_update_cnt[2]));
+ fallthrough;
+ case 4:
+ fallthrough;
+ case 3:
+ regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con1,
+ CM_AFE_CM_UPDATE_CNT2_MASK,
+ CM_AFE_CM_UPDATE_CNT2(ch_update_cnt[1]));
+ fallthrough;
+ case 2:
+ fallthrough;
+ case 1:
+ regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con1,
+ CM_AFE_CM_UPDATE_CNT1_MASK,
+ CM_AFE_CM_UPDATE_CNT1(ch_update_cnt[0]));
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static int mt8365_afe_configure_cm(struct mtk_base_afe *afe,
+ enum mt8365_cm_num cmNum,
+ unsigned int channels,
+ unsigned int rate)
+{
+ unsigned int val, mask;
+ unsigned int fs = mt8365_afe_fs_timing(rate);
+
+ val = FIELD_PREP(CM_AFE_CM_CH_NUM_MASK, (channels - 1)) |
+ FIELD_PREP(CM_AFE_CM_START_DATA_MASK, 0);
+
+ mask = CM_AFE_CM_CH_NUM_MASK |
+ CM_AFE_CM_START_DATA_MASK;
+
+ if (cmNum == MT8365_CM1) {
+ val |= FIELD_PREP(CM_AFE_CM1_IN_MODE_MASK, fs);
+
+ mask |= CM_AFE_CM1_VUL_SEL |
+ CM_AFE_CM1_IN_MODE_MASK;
+ } else if (cmNum == MT8365_CM2) {
+ if (mt8365_afe_clk_group_48k(rate))
+ val |= FIELD_PREP(CM_AFE_CM2_CLK_SEL, 0);
+ else
+ val |= FIELD_PREP(CM_AFE_CM2_CLK_SEL, 1);
+
+ val |= FIELD_PREP(CM_AFE_CM2_TDM_SEL, 1);
+
+ mask |= CM_AFE_CM2_TDM_SEL |
+ CM_AFE_CM1_IN_MODE_MASK |
+ CM_AFE_CM2_CLK_SEL;
+
+ mt8365_afe_cm2_mux_conn(afe);
+ } else {
+ dev_dbg(afe->dev, "%s wrong cmNum %d\n",
+ __func__, cmNum);
+ return -1;
+ }
+
+ regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con0, mask, val);
+
+ mt8365_afe_get_cm_update_cnt(afe, cmNum, rate, channels);
+
+ return 0;
+}
+
+int mt8365_afe_fe_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int memif_num = snd_soc_rtd_to_cpu(rtd, 0)->id;
+ struct mtk_base_afe_memif *memif = &afe->memif[memif_num];
+ const struct snd_pcm_hardware *mtk_afe_hardware = afe->mtk_afe_hardware;
+ int ret;
+
+ memif->substream = substream;
+
+ snd_pcm_hw_constraint_step(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16);
+
+ snd_soc_set_runtime_hwparams(substream, mtk_afe_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");
+
+ mt8365_afe_enable_main_clk(afe);
+ return ret;
+}
+
+static void mt8365_afe_fe_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ int memif_num = snd_soc_rtd_to_cpu(rtd, 0)->id;
+ struct mtk_base_afe_memif *memif = &afe->memif[memif_num];
+
+ dev_dbg(afe->dev, "%s %s\n", __func__, memif->data->name);
+
+ memif->substream = NULL;
+
+ mt8365_afe_disable_main_clk(afe);
+}
+
+static int mt8365_afe_fe_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ int dai_id = snd_soc_rtd_to_cpu(rtd, 0)->id;
+ struct mt8365_control_data *ctrl_data = &afe_priv->ctrl_data;
+ struct mtk_base_afe_memif *memif = &afe->memif[dai_id];
+ struct mt8365_fe_dai_data *fe_data = &afe_priv->fe_data[dai_id];
+ const size_t request_size = params_buffer_bytes(params);
+ unsigned int channels = params_channels(params);
+ unsigned int rate = params_rate(params);
+ int ret, fs = 0;
+ unsigned int base_end_offset = 8;
+
+ dev_info(afe->dev,
+ "%s %s period = %d rate = %d channels = %d\n",
+ __func__, memif->data->name, params_period_size(params),
+ rate, channels);
+
+ if (dai_id == MT8365_AFE_MEMIF_VUL2) {
+ if (!ctrl_data->bypass_cm1)
+ /* configure cm1 */
+ mt8365_afe_configure_cm(afe,
+ MT8365_CM1, channels, rate);
+ else
+ regmap_update_bits(afe->regmap, AFE_CM1_CON0,
+ CM_AFE_CM1_VUL_SEL, CM_AFE_CM1_VUL_SEL);
+ } else if (dai_id == MT8365_AFE_MEMIF_TDM_IN) {
+ if (!ctrl_data->bypass_cm2)
+ /* configure cm2 */
+ mt8365_afe_configure_cm(afe,
+ MT8365_CM2, channels, rate);
+ else
+ regmap_update_bits(afe->regmap, AFE_CM2_CON0,
+ CM_AFE_CM2_TDM_SEL, ~CM_AFE_CM2_TDM_SEL);
+
+ base_end_offset = 4;
+ }
+
+ if (request_size > fe_data->sram_size) {
+ ret = snd_pcm_lib_malloc_pages(substream, request_size);
+ if (ret < 0) {
+ dev_err(afe->dev,
+ "%s %s malloc pages %zu bytes failed %d\n",
+ __func__, memif->data->name, request_size, ret);
+ return ret;
+ }
+
+ fe_data->use_sram = false;
+
+ mt8365_afe_emi_clk_on(afe);
+ } else {
+ struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+
+ dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ dma_buf->dev.dev = substream->pcm->card->dev;
+ dma_buf->area = (unsigned char *)fe_data->sram_vir_addr;
+ dma_buf->addr = fe_data->sram_phy_addr;
+ dma_buf->bytes = request_size;
+ snd_pcm_set_runtime_buffer(substream, dma_buf);
+
+ fe_data->use_sram = true;
+ }
+
+ memif->phys_buf_addr = lower_32_bits(substream->runtime->dma_addr);
+ memif->buffer_size = substream->runtime->dma_bytes;
+
+ /* start */
+ regmap_write(afe->regmap, memif->data->reg_ofs_base,
+ memif->phys_buf_addr);
+ /* end */
+ regmap_write(afe->regmap,
+ memif->data->reg_ofs_base + base_end_offset,
+ memif->phys_buf_addr + memif->buffer_size - 1);
+
+ /* set channel */
+ if (memif->data->mono_shift >= 0) {
+ unsigned int mono = (params_channels(params) == 1) ? 1 : 0;
+
+ if (memif->data->mono_reg < 0)
+ dev_info(afe->dev, "%s mono_reg is NULL\n", __func__);
+ else
+ regmap_update_bits(afe->regmap, memif->data->mono_reg,
+ 1 << memif->data->mono_shift,
+ mono << memif->data->mono_shift);
+ }
+
+ /* set rate */
+ if (memif->data->fs_shift < 0)
+ return 0;
+
+ fs = afe->memif_fs(substream, params_rate(params));
+
+ if (fs < 0)
+ return -EINVAL;
+
+ if (memif->data->fs_reg < 0)
+ dev_info(afe->dev, "%s fs_reg is NULL\n", __func__);
+ else
+ regmap_update_bits(afe->regmap, memif->data->fs_reg,
+ memif->data->fs_maskbit << memif->data->fs_shift,
+ fs << memif->data->fs_shift);
+
+ return 0;
+}
+
+static int mt8365_afe_fe_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ int dai_id = snd_soc_rtd_to_cpu(rtd, 0)->id;
+ struct mtk_base_afe_memif *memif = &afe->memif[dai_id];
+ struct mt8365_fe_dai_data *fe_data = &afe_priv->fe_data[dai_id];
+ int ret = 0;
+
+ dev_dbg(afe->dev, "%s %s\n", __func__, memif->data->name);
+
+ if (fe_data->use_sram) {
+ snd_pcm_set_runtime_buffer(substream, NULL);
+ } else {
+ ret = snd_pcm_lib_free_pages(substream);
+
+ mt8365_afe_emi_clk_off(afe);
+ }
+
+ return ret;
+}
+
+static int mt8365_afe_fe_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ int dai_id = snd_soc_rtd_to_cpu(rtd, 0)->id;
+ struct mtk_base_afe_memif *memif = &afe->memif[dai_id];
+
+ /* set format */
+ if (memif->data->hd_reg >= 0) {
+ switch (substream->runtime->format) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ regmap_update_bits(afe->regmap, memif->data->hd_reg,
+ 3 << memif->data->hd_shift,
+ 0 << memif->data->hd_shift);
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ regmap_update_bits(afe->regmap, memif->data->hd_reg,
+ 3 << memif->data->hd_shift,
+ 3 << memif->data->hd_shift);
+
+ if (dai_id == MT8365_AFE_MEMIF_TDM_IN) {
+ regmap_update_bits(afe->regmap,
+ memif->data->hd_reg,
+ 3 << memif->data->hd_shift,
+ 1 << memif->data->hd_shift);
+ regmap_update_bits(afe->regmap,
+ memif->data->hd_reg,
+ 1 << memif->data->hd_align_mshift,
+ 1 << memif->data->hd_align_mshift);
+ }
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ regmap_update_bits(afe->regmap, memif->data->hd_reg,
+ 3 << memif->data->hd_shift,
+ 1 << memif->data->hd_shift);
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ mt8365_afe_irq_direction_enable(afe,
+ memif->irq_usage,
+ MT8365_AFE_IRQ_DIR_MCU);
+
+ return 0;
+}
+
+int mt8365_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ int dai_id = snd_soc_rtd_to_cpu(rtd, 0)->id;
+ struct mt8365_control_data *ctrl_data = &afe_priv->ctrl_data;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ /* enable channel merge */
+ if (dai_id == MT8365_AFE_MEMIF_VUL2 &&
+ !ctrl_data->bypass_cm1) {
+ regmap_update_bits(afe->regmap,
+ AFE_CM1_CON0,
+ CM_AFE_CM_ON, CM_AFE_CM_ON);
+ } else if (dai_id == MT8365_AFE_MEMIF_TDM_IN &&
+ !ctrl_data->bypass_cm2) {
+ regmap_update_bits(afe->regmap,
+ AFE_CM2_CON0,
+ CM_AFE_CM_ON, CM_AFE_CM_ON);
+ }
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ /* disable channel merge */
+ if (dai_id == MT8365_AFE_MEMIF_VUL2 &&
+ !ctrl_data->bypass_cm1) {
+ regmap_update_bits(afe->regmap,
+ AFE_CM1_CON0,
+ CM_AFE_CM_ON, ~CM_AFE_CM_ON);
+ } else if (dai_id == MT8365_AFE_MEMIF_TDM_IN &&
+ !ctrl_data->bypass_cm2) {
+ regmap_update_bits(afe->regmap,
+ AFE_CM2_CON0,
+ CM_AFE_CM_ON, ~CM_AFE_CM_ON);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return mtk_afe_fe_trigger(substream, cmd, dai);
+}
+
+static int mt8365_afe_hw_gain1_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+ mt8365_afe_enable_main_clk(afe);
+ return 0;
+}
+
+static void mt8365_afe_hw_gain1_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_be_dai_data *be =
+ &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
+
+ const unsigned int stream = substream->stream;
+
+ if (be->prepared[stream]) {
+ regmap_update_bits(afe->regmap, AFE_GAIN1_CON0,
+ AFE_GAIN1_CON0_EN_MASK, 0);
+ be->prepared[stream] = false;
+ }
+ mt8365_afe_disable_main_clk(afe);
+}
+
+static int mt8365_afe_hw_gain1_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_pcm_runtime * const runtime = substream->runtime;
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_be_dai_data *be =
+ &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
+
+ const unsigned int rate = runtime->rate;
+ const unsigned int stream = substream->stream;
+ int fs;
+ unsigned int val1 = 0, val2 = 0;
+
+ if (be->prepared[stream]) {
+ dev_info(afe->dev, "%s prepared already\n", __func__);
+ return 0;
+ }
+
+ fs = mt8365_afe_fs_timing(rate);
+ regmap_update_bits(afe->regmap, AFE_GAIN1_CON0,
+ AFE_GAIN1_CON0_MODE_MASK, (unsigned int)fs<<4);
+
+ regmap_read(afe->regmap, AFE_GAIN1_CON1, &val1);
+ regmap_read(afe->regmap, AFE_GAIN1_CUR, &val2);
+ if ((val1 & AFE_GAIN1_CON1_MASK) != (val2 & AFE_GAIN1_CUR_MASK))
+ regmap_update_bits(afe->regmap, AFE_GAIN1_CUR,
+ AFE_GAIN1_CUR_MASK, val1);
+
+ regmap_update_bits(afe->regmap, AFE_GAIN1_CON0,
+ AFE_GAIN1_CON0_EN_MASK, 1);
+ be->prepared[stream] = true;
+
+ return 0;
+}
+
+static const struct snd_pcm_hardware mt8365_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 = 8 * 48 * 1024,
+ .fifo_size = 0,
+};
+
+/* 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, &mt8365_hostless_hardware);
+
+ ret = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0)
+ dev_info(afe->dev, "snd_pcm_hw_constraint_integer failed\n");
+ return ret;
+}
+
+/* FE DAIs */
+static const struct snd_soc_dai_ops mt8365_afe_fe_dai_ops = {
+ .startup = mt8365_afe_fe_startup,
+ .shutdown = mt8365_afe_fe_shutdown,
+ .hw_params = mt8365_afe_fe_hw_params,
+ .hw_free = mt8365_afe_fe_hw_free,
+ .prepare = mt8365_afe_fe_prepare,
+ .trigger = mt8365_afe_fe_trigger,
+};
+
+static const struct snd_soc_dai_ops mt8365_dai_hostless_ops = {
+ .startup = mtk_dai_hostless_startup,
+};
+
+static const struct snd_soc_dai_ops mt8365_afe_hw_gain1_ops = {
+ .startup = mt8365_afe_hw_gain1_startup,
+ .shutdown = mt8365_afe_hw_gain1_shutdown,
+ .prepare = mt8365_afe_hw_gain1_prepare,
+};
+
+static struct snd_soc_dai_driver mt8365_memif_dai_driver[] = {
+ /* FE DAIs: memory intefaces to CPU */
+ {
+ .name = "DL1",
+ .id = MT8365_AFE_MEMIF_DL1,
+ .playback = {
+ .stream_name = "DL1",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_afe_fe_dai_ops,
+ }, {
+ .name = "DL2",
+ .id = MT8365_AFE_MEMIF_DL2,
+ .playback = {
+ .stream_name = "DL2",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_afe_fe_dai_ops,
+ }, {
+ .name = "TDM_OUT",
+ .id = MT8365_AFE_MEMIF_TDM_OUT,
+ .playback = {
+ .stream_name = "TDM_OUT",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_afe_fe_dai_ops,
+ }, {
+ .name = "AWB",
+ .id = MT8365_AFE_MEMIF_AWB,
+ .capture = {
+ .stream_name = "AWB",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_afe_fe_dai_ops,
+ }, {
+ .name = "VUL",
+ .id = MT8365_AFE_MEMIF_VUL,
+ .capture = {
+ .stream_name = "VUL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_afe_fe_dai_ops,
+ }, {
+ .name = "VUL2",
+ .id = MT8365_AFE_MEMIF_VUL2,
+ .capture = {
+ .stream_name = "VUL2",
+ .channels_min = 1,
+ .channels_max = 16,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_afe_fe_dai_ops,
+ }, {
+ .name = "VUL3",
+ .id = MT8365_AFE_MEMIF_VUL3,
+ .capture = {
+ .stream_name = "VUL3",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_afe_fe_dai_ops,
+ }, {
+ .name = "TDM_IN",
+ .id = MT8365_AFE_MEMIF_TDM_IN,
+ .capture = {
+ .stream_name = "TDM_IN",
+ .channels_min = 1,
+ .channels_max = 16,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_afe_fe_dai_ops,
+ }, {
+ .name = "Hostless FM DAI",
+ .id = MT8365_AFE_IO_VIRTUAL_FM,
+ .playback = {
+ .stream_name = "Hostless FM DL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .capture = {
+ .stream_name = "Hostless FM UL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_dai_hostless_ops,
+ }, {
+ .name = "HW_GAIN1",
+ .id = MT8365_AFE_IO_HW_GAIN1,
+ .playback = {
+ .stream_name = "HW Gain 1 In",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .capture = {
+ .stream_name = "HW Gain 1 Out",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_afe_hw_gain1_ops,
+ .symmetric_rate = 1,
+ .symmetric_channels = 1,
+ .symmetric_sample_bits = 1,
+ },
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o00_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN0, 5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN0, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o01_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN1, 6, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN1, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o03_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN3, 5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN3, 7, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN3, 0, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I10 Switch", AFE_CONN3, 10, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o04_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN4, 6, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN4, 8, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN4, 1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I11 Switch", AFE_CONN4, 11, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o05_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN5, 0, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN5, 3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN5, 5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN5, 7, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I09 Switch", AFE_CONN5, 9, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I14 Switch", AFE_CONN5, 14, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I16 Switch", AFE_CONN5, 16, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN5, 18, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I20 Switch", AFE_CONN5, 20, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN5, 23, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I10L Switch", AFE_CONN5, 10, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o06_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN6, 1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN6, 4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN6, 6, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN6, 8, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I22 Switch", AFE_CONN6, 22, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I15 Switch", AFE_CONN6, 15, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN6, 17, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I19 Switch", AFE_CONN6, 19, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I21 Switch", AFE_CONN6, 21, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN6, 24, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I11L Switch", AFE_CONN6, 11, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o07_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN7, 5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN7, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o08_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN8, 6, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN8, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o09_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN9, 0, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN9, 3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I09 Switch", AFE_CONN9, 9, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I14 Switch", AFE_CONN9, 14, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I16 Switch", AFE_CONN9, 16, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN9, 18, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I20 Switch", AFE_CONN9, 20, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o10_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN10, 1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN10, 4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I22 Switch", AFE_CONN10, 22, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I15 Switch", AFE_CONN10, 15, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN10, 17, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I19 Switch", AFE_CONN10, 19, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I21 Switch", AFE_CONN10, 21, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o11_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN11, 0, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN11, 3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I09 Switch", AFE_CONN11, 9, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I14 Switch", AFE_CONN11, 14, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I16 Switch", AFE_CONN11, 16, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN11, 18, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I20 Switch", AFE_CONN11, 20, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o12_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN12, 1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN12, 4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I22 Switch", AFE_CONN12, 22, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I15 Switch", AFE_CONN12, 15, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN12, 17, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I19 Switch", AFE_CONN12, 19, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I21 Switch", AFE_CONN12, 21, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o13_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN13, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o14_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN14, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o15_mix[] = {
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o16_mix[] = {
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o17_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN17, 3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I14 Switch", AFE_CONN17, 14, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o18_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN18, 4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I15 Switch", AFE_CONN18, 15, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN18, 23, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN18, 25, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o19_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN19, 4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I16 Switch", AFE_CONN19, 16, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN19, 23, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN19, 24, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN19, 25, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN19, 26, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o20_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN20, 17, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN20, 24, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN20, 26, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o21_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN21, 18, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN21, 23, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN21, 25, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o22_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I19 Switch", AFE_CONN22, 19, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN22, 24, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN22, 26, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o23_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I20 Switch", AFE_CONN23, 20, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN23, 23, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN23, 25, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o24_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I21 Switch", AFE_CONN24, 21, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN24, 24, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN24, 26, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN24, 23, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN24, 25, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o25_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I27 Switch", AFE_CONN25, 27, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN25, 23, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN25, 25, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o26_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I28 Switch", AFE_CONN26, 28, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN26, 24, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN26, 26, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o27_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN27, 5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN27, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o28_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN28, 6, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN28, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o29_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN29, 5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN29, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o30_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN30, 6, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN30, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o31_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I29 Switch", AFE_CONN31, 29, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o32_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I30 Switch", AFE_CONN32, 30, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o33_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I31 Switch", AFE_CONN33, 31, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o34_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I32 Switch", AFE_CONN34_1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o35_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I33 Switch", AFE_CONN35_1, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o36_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I34 Switch", AFE_CONN36_1, 2, 1, 0),
+};
+
+
+static const struct snd_kcontrol_new mtk_hw_gain1_in_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH1", AFE_CONN13,
+ 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_hw_gain1_in_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH2", AFE_CONN14,
+ 1, 1, 0),
+};
+
+static int mt8365_afe_cm2_io_input_mux_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = mCM2Input;
+
+ return 0;
+}
+
+static int mt8365_afe_cm2_io_input_mux_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct snd_soc_component *comp = snd_soc_dapm_to_component(dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(comp);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ mCM2Input = ucontrol->value.enumerated.item[0];
+
+ afe_priv->cm2_mux_input = mCM2Input;
+ ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+
+ return ret;
+}
+
+static const char * const fmhwgain_text[] = {
+ "OPEN", "FM_HW_GAIN_IO"
+};
+
+static const char * const ain_text[] = {
+ "INT ADC", "EXT ADC",
+};
+
+static const char * const vul2_in_input_text[] = {
+ "VUL2_IN_FROM_O17O18", "VUL2_IN_FROM_CM1",
+};
+
+static const char * const mt8365_afe_cm2_mux_text[] = {
+ "OPEN", "FROM_GASRC1_OUT", "FROM_GASRC2_OUT", "FROM_TDM_ASRC_OUT",
+};
+
+static SOC_ENUM_SINGLE_VIRT_DECL(fmhwgain_enum, fmhwgain_text);
+static SOC_ENUM_SINGLE_DECL(ain_enum, AFE_ADDA_TOP_CON0, 0, ain_text);
+static SOC_ENUM_SINGLE_VIRT_DECL(vul2_in_input_enum, vul2_in_input_text);
+static SOC_ENUM_SINGLE_VIRT_DECL(mt8365_afe_cm2_mux_input_enum,
+ mt8365_afe_cm2_mux_text);
+
+static const struct snd_kcontrol_new fmhwgain_mux =
+ SOC_DAPM_ENUM("FM HW Gain Source", fmhwgain_enum);
+
+static const struct snd_kcontrol_new ain_mux =
+ SOC_DAPM_ENUM("AIN Source", ain_enum);
+
+static const struct snd_kcontrol_new vul2_in_input_mux =
+ SOC_DAPM_ENUM("VUL2 Input", vul2_in_input_enum);
+
+static const struct snd_kcontrol_new mt8365_afe_cm2_mux_input_mux =
+ SOC_DAPM_ENUM_EXT("CM2_MUX Source", mt8365_afe_cm2_mux_input_enum,
+ mt8365_afe_cm2_io_input_mux_get,
+ mt8365_afe_cm2_io_input_mux_put);
+
+static const struct snd_soc_dapm_widget mt8365_memif_widgets[] = {
+ /* inter-connections */
+ SND_SOC_DAPM_MIXER("I00", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I01", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I03", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I04", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I05", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I06", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I07", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I08", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I05L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I06L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I07L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I08L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I09", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I10", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I11", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I10L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I11L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I12", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I13", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I14", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I15", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I16", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I17", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I18", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I19", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I20", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I21", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I22", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I23", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I24", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I25", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I26", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I27", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I28", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I29", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I30", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I31", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I32", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I33", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I34", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("O00", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o00_mix, ARRAY_SIZE(mt8365_afe_o00_mix)),
+ SND_SOC_DAPM_MIXER("O01", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o01_mix, ARRAY_SIZE(mt8365_afe_o01_mix)),
+ SND_SOC_DAPM_MIXER("O03", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o03_mix, ARRAY_SIZE(mt8365_afe_o03_mix)),
+ SND_SOC_DAPM_MIXER("O04", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o04_mix, ARRAY_SIZE(mt8365_afe_o04_mix)),
+ SND_SOC_DAPM_MIXER("O05", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o05_mix, ARRAY_SIZE(mt8365_afe_o05_mix)),
+ SND_SOC_DAPM_MIXER("O06", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o06_mix, ARRAY_SIZE(mt8365_afe_o06_mix)),
+ SND_SOC_DAPM_MIXER("O07", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o07_mix, ARRAY_SIZE(mt8365_afe_o07_mix)),
+ SND_SOC_DAPM_MIXER("O08", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o08_mix, ARRAY_SIZE(mt8365_afe_o08_mix)),
+ SND_SOC_DAPM_MIXER("O09", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o09_mix, ARRAY_SIZE(mt8365_afe_o09_mix)),
+ SND_SOC_DAPM_MIXER("O10", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o10_mix, ARRAY_SIZE(mt8365_afe_o10_mix)),
+ SND_SOC_DAPM_MIXER("O11", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o11_mix, ARRAY_SIZE(mt8365_afe_o11_mix)),
+ SND_SOC_DAPM_MIXER("O12", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o12_mix, ARRAY_SIZE(mt8365_afe_o12_mix)),
+ SND_SOC_DAPM_MIXER("O13", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o13_mix, ARRAY_SIZE(mt8365_afe_o13_mix)),
+ SND_SOC_DAPM_MIXER("O14", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o14_mix, ARRAY_SIZE(mt8365_afe_o14_mix)),
+ SND_SOC_DAPM_MIXER("O15", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o15_mix, ARRAY_SIZE(mt8365_afe_o15_mix)),
+ SND_SOC_DAPM_MIXER("O16", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o16_mix, ARRAY_SIZE(mt8365_afe_o16_mix)),
+ SND_SOC_DAPM_MIXER("O17", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o17_mix, ARRAY_SIZE(mt8365_afe_o17_mix)),
+ SND_SOC_DAPM_MIXER("O18", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o18_mix, ARRAY_SIZE(mt8365_afe_o18_mix)),
+ SND_SOC_DAPM_MIXER("O19", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o19_mix, ARRAY_SIZE(mt8365_afe_o19_mix)),
+ SND_SOC_DAPM_MIXER("O20", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o20_mix, ARRAY_SIZE(mt8365_afe_o20_mix)),
+ SND_SOC_DAPM_MIXER("O21", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o21_mix, ARRAY_SIZE(mt8365_afe_o21_mix)),
+ SND_SOC_DAPM_MIXER("O22", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o22_mix, ARRAY_SIZE(mt8365_afe_o22_mix)),
+ SND_SOC_DAPM_MIXER("O23", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o23_mix, ARRAY_SIZE(mt8365_afe_o23_mix)),
+ SND_SOC_DAPM_MIXER("O24", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o24_mix, ARRAY_SIZE(mt8365_afe_o24_mix)),
+ SND_SOC_DAPM_MIXER("O25", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o25_mix, ARRAY_SIZE(mt8365_afe_o25_mix)),
+ SND_SOC_DAPM_MIXER("O26", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o26_mix, ARRAY_SIZE(mt8365_afe_o26_mix)),
+ SND_SOC_DAPM_MIXER("O27", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o27_mix, ARRAY_SIZE(mt8365_afe_o27_mix)),
+ SND_SOC_DAPM_MIXER("O28", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o28_mix, ARRAY_SIZE(mt8365_afe_o28_mix)),
+ SND_SOC_DAPM_MIXER("O29", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o29_mix, ARRAY_SIZE(mt8365_afe_o29_mix)),
+ SND_SOC_DAPM_MIXER("O30", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o30_mix, ARRAY_SIZE(mt8365_afe_o30_mix)),
+ SND_SOC_DAPM_MIXER("O31", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o31_mix, ARRAY_SIZE(mt8365_afe_o31_mix)),
+ SND_SOC_DAPM_MIXER("O32", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o32_mix, ARRAY_SIZE(mt8365_afe_o32_mix)),
+ SND_SOC_DAPM_MIXER("O33", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o33_mix, ARRAY_SIZE(mt8365_afe_o33_mix)),
+ SND_SOC_DAPM_MIXER("O34", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o34_mix, ARRAY_SIZE(mt8365_afe_o34_mix)),
+ SND_SOC_DAPM_MIXER("O35", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o35_mix, ARRAY_SIZE(mt8365_afe_o35_mix)),
+ SND_SOC_DAPM_MIXER("O36", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o36_mix, ARRAY_SIZE(mt8365_afe_o36_mix)),
+ SND_SOC_DAPM_MIXER("CM2_Mux IO", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("CM1_IO", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("O17O18", SND_SOC_NOPM, 0, 0, NULL, 0),
+ /* 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_INPUT("DL Source"),
+
+ SND_SOC_DAPM_MUX("CM2_Mux_IO Input Mux",
+ SND_SOC_NOPM, 0, 0, &mt8365_afe_cm2_mux_input_mux),
+ SND_SOC_DAPM_MUX("AIN Mux", SND_SOC_NOPM, 0, 0, &ain_mux),
+ SND_SOC_DAPM_MUX("VUL2 Input Mux",
+ SND_SOC_NOPM, 0, 0, &vul2_in_input_mux),
+ SND_SOC_DAPM_MUX("FM HW Gain Mux", SND_SOC_NOPM, 0, 0, &fmhwgain_mux),
+
+ SND_SOC_DAPM_INPUT("HW Gain 1 Out Endpoint"),
+ SND_SOC_DAPM_OUTPUT("HW Gain 1 In Endpoint"),
+};
+
+static const struct snd_soc_dapm_route mt8365_memif_routes[] = {
+ /* downlink */
+ {"I00", NULL, "2ND I2S Capture"},
+ {"I01", NULL, "2ND I2S Capture"},
+ {"I05", NULL, "DL1"},
+ {"I06", NULL, "DL1"},
+ {"I07", NULL, "DL2"},
+ {"I08", NULL, "DL2"},
+
+ {"O03", "I05 Switch", "I05"},
+ {"O04", "I06 Switch", "I06"},
+ {"O00", "I05 Switch", "I05"},
+ {"O01", "I06 Switch", "I06"},
+ {"O07", "I05 Switch", "I05"},
+ {"O08", "I06 Switch", "I06"},
+ {"O27", "I05 Switch", "I05"},
+ {"O28", "I06 Switch", "I06"},
+ {"O29", "I05 Switch", "I05"},
+ {"O30", "I06 Switch", "I06"},
+
+ {"O03", "I07 Switch", "I07"},
+ {"O04", "I08 Switch", "I08"},
+ {"O00", "I07 Switch", "I07"},
+ {"O01", "I08 Switch", "I08"},
+ {"O07", "I07 Switch", "I07"},
+ {"O08", "I08 Switch", "I08"},
+
+ /* uplink */
+ {"AWB", NULL, "O05"},
+ {"AWB", NULL, "O06"},
+ {"VUL", NULL, "O09"},
+ {"VUL", NULL, "O10"},
+ {"VUL3", NULL, "O11"},
+ {"VUL3", NULL, "O12"},
+
+ {"AIN Mux", "EXT ADC", "I2S Capture"},
+ {"I03", NULL, "AIN Mux"},
+ {"I04", NULL, "AIN Mux"},
+
+ {"HW_GAIN1_IN_CH1", "CONNSYS_I2S_CH1", "Hostless FM DL"},
+ {"HW_GAIN1_IN_CH2", "CONNSYS_I2S_CH2", "Hostless FM DL"},
+
+ {"HW Gain 1 In Endpoint", NULL, "HW Gain 1 In"},
+ {"HW Gain 1 Out", NULL, "HW Gain 1 Out Endpoint"},
+ {"HW Gain 1 In", NULL, "HW_GAIN1_IN_CH1"},
+ {"HW Gain 1 In", NULL, "HW_GAIN1_IN_CH2"},
+
+ {"FM HW Gain Mux", "FM_HW_GAIN_IO", "HW Gain 1 Out"},
+ {"Hostless FM UL", NULL, "FM HW Gain Mux"},
+ {"Hostless FM UL", NULL, "FM 2ND I2S Mux"},
+
+ {"O05", "I05 Switch", "I05L"},
+ {"O06", "I06 Switch", "I06L"},
+ {"O05", "I07 Switch", "I07L"},
+ {"O06", "I08 Switch", "I08L"},
+
+ {"O05", "I03 Switch", "I03"},
+ {"O06", "I04 Switch", "I04"},
+ {"O05", "I00 Switch", "I00"},
+ {"O06", "I01 Switch", "I01"},
+ {"O05", "I09 Switch", "I09"},
+ {"O06", "I22 Switch", "I22"},
+ {"O05", "I14 Switch", "I14"},
+ {"O06", "I15 Switch", "I15"},
+ {"O05", "I16 Switch", "I16"},
+ {"O06", "I17 Switch", "I17"},
+ {"O05", "I18 Switch", "I18"},
+ {"O06", "I19 Switch", "I19"},
+ {"O05", "I20 Switch", "I20"},
+ {"O06", "I21 Switch", "I21"},
+ {"O05", "I23 Switch", "I23"},
+ {"O06", "I24 Switch", "I24"},
+
+ {"O09", "I03 Switch", "I03"},
+ {"O10", "I04 Switch", "I04"},
+ {"O09", "I00 Switch", "I00"},
+ {"O10", "I01 Switch", "I01"},
+ {"O09", "I09 Switch", "I09"},
+ {"O10", "I22 Switch", "I22"},
+ {"O09", "I14 Switch", "I14"},
+ {"O10", "I15 Switch", "I15"},
+ {"O09", "I16 Switch", "I16"},
+ {"O10", "I17 Switch", "I17"},
+ {"O09", "I18 Switch", "I18"},
+ {"O10", "I19 Switch", "I19"},
+ {"O09", "I20 Switch", "I20"},
+ {"O10", "I21 Switch", "I21"},
+
+ {"O11", "I03 Switch", "I03"},
+ {"O12", "I04 Switch", "I04"},
+ {"O11", "I00 Switch", "I00"},
+ {"O12", "I01 Switch", "I01"},
+ {"O11", "I09 Switch", "I09"},
+ {"O12", "I22 Switch", "I22"},
+ {"O11", "I14 Switch", "I14"},
+ {"O12", "I15 Switch", "I15"},
+ {"O11", "I16 Switch", "I16"},
+ {"O12", "I17 Switch", "I17"},
+ {"O11", "I18 Switch", "I18"},
+ {"O12", "I19 Switch", "I19"},
+ {"O11", "I20 Switch", "I20"},
+ {"O12", "I21 Switch", "I21"},
+
+ /* CM2_Mux*/
+ {"CM2_Mux IO", NULL, "CM2_Mux_IO Input Mux"},
+
+ /* VUL2 */
+ {"VUL2", NULL, "VUL2 Input Mux"},
+ {"VUL2 Input Mux", "VUL2_IN_FROM_O17O18", "O17O18"},
+ {"VUL2 Input Mux", "VUL2_IN_FROM_CM1", "CM1_IO"},
+
+ {"O17O18", NULL, "O17"},
+ {"O17O18", NULL, "O18"},
+ {"CM1_IO", NULL, "O17"},
+ {"CM1_IO", NULL, "O18"},
+ {"CM1_IO", NULL, "O19"},
+ {"CM1_IO", NULL, "O20"},
+ {"CM1_IO", NULL, "O21"},
+ {"CM1_IO", NULL, "O22"},
+ {"CM1_IO", NULL, "O23"},
+ {"CM1_IO", NULL, "O24"},
+ {"CM1_IO", NULL, "O25"},
+ {"CM1_IO", NULL, "O26"},
+ {"CM1_IO", NULL, "O31"},
+ {"CM1_IO", NULL, "O32"},
+ {"CM1_IO", NULL, "O33"},
+ {"CM1_IO", NULL, "O34"},
+ {"CM1_IO", NULL, "O35"},
+ {"CM1_IO", NULL, "O36"},
+
+ {"O17", "I14 Switch", "I14"},
+ {"O18", "I15 Switch", "I15"},
+ {"O19", "I16 Switch", "I16"},
+ {"O20", "I17 Switch", "I17"},
+ {"O21", "I18 Switch", "I18"},
+ {"O22", "I19 Switch", "I19"},
+ {"O23", "I20 Switch", "I20"},
+ {"O24", "I21 Switch", "I21"},
+ {"O25", "I23 Switch", "I23"},
+ {"O26", "I24 Switch", "I24"},
+ {"O25", "I25 Switch", "I25"},
+ {"O26", "I26 Switch", "I26"},
+
+ {"O17", "I03 Switch", "I03"},
+ {"O18", "I04 Switch", "I04"},
+ {"O18", "I23 Switch", "I23"},
+ {"O18", "I25 Switch", "I25"},
+ {"O19", "I04 Switch", "I04"},
+ {"O19", "I23 Switch", "I23"},
+ {"O19", "I24 Switch", "I24"},
+ {"O19", "I25 Switch", "I25"},
+ {"O19", "I26 Switch", "I26"},
+ {"O20", "I24 Switch", "I24"},
+ {"O20", "I26 Switch", "I26"},
+ {"O21", "I23 Switch", "I23"},
+ {"O21", "I25 Switch", "I25"},
+ {"O22", "I24 Switch", "I24"},
+ {"O22", "I26 Switch", "I26"},
+
+ {"O23", "I23 Switch", "I23"},
+ {"O23", "I25 Switch", "I25"},
+ {"O24", "I24 Switch", "I24"},
+ {"O24", "I26 Switch", "I26"},
+ {"O24", "I23 Switch", "I23"},
+ {"O24", "I25 Switch", "I25"},
+ {"O13", "I00 Switch", "I00"},
+ {"O14", "I01 Switch", "I01"},
+ {"O03", "I10 Switch", "I10"},
+ {"O04", "I11 Switch", "I11"},
+};
+
+static const struct mtk_base_memif_data memif_data[MT8365_AFE_MEMIF_NUM] = {
+ {
+ .name = "DL1",
+ .id = MT8365_AFE_MEMIF_DL1,
+ .reg_ofs_base = AFE_DL1_BASE,
+ .reg_ofs_cur = AFE_DL1_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = 0,
+ .fs_maskbit = 0xf,
+ .mono_reg = AFE_DAC_CON1,
+ .mono_shift = 21,
+ .hd_reg = AFE_MEMIF_PBUF_SIZE,
+ .hd_shift = 16,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 1,
+ .msb_reg = -1,
+ .msb_shift = -1,
+ .agent_disable_reg = -1,
+ .agent_disable_shift = -1,
+ }, {
+ .name = "DL2",
+ .id = MT8365_AFE_MEMIF_DL2,
+ .reg_ofs_base = AFE_DL2_BASE,
+ .reg_ofs_cur = AFE_DL2_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = 4,
+ .fs_maskbit = 0xf,
+ .mono_reg = AFE_DAC_CON1,
+ .mono_shift = 22,
+ .hd_reg = AFE_MEMIF_PBUF_SIZE,
+ .hd_shift = 18,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 2,
+ .msb_reg = -1,
+ .msb_shift = -1,
+ .agent_disable_reg = -1,
+ .agent_disable_shift = -1,
+ }, {
+ .name = "TDM OUT",
+ .id = MT8365_AFE_MEMIF_TDM_OUT,
+ .reg_ofs_base = AFE_HDMI_OUT_BASE,
+ .reg_ofs_cur = AFE_HDMI_OUT_CUR,
+ .fs_reg = -1,
+ .fs_shift = -1,
+ .fs_maskbit = -1,
+ .mono_reg = -1,
+ .mono_shift = -1,
+ .hd_reg = AFE_MEMIF_PBUF_SIZE,
+ .hd_shift = 28,
+ .enable_reg = AFE_HDMI_OUT_CON0,
+ .enable_shift = 0,
+ .msb_reg = -1,
+ .msb_shift = -1,
+ .agent_disable_reg = -1,
+ .agent_disable_shift = -1,
+ }, {
+ .name = "AWB",
+ .id = MT8365_AFE_MEMIF_AWB,
+ .reg_ofs_base = AFE_AWB_BASE,
+ .reg_ofs_cur = AFE_AWB_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = 12,
+ .fs_maskbit = 0xf,
+ .mono_reg = AFE_DAC_CON1,
+ .mono_shift = 24,
+ .hd_reg = AFE_MEMIF_PBUF_SIZE,
+ .hd_shift = 20,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 6,
+ .msb_reg = AFE_MEMIF_MSB,
+ .msb_shift = 17,
+ .agent_disable_reg = -1,
+ .agent_disable_shift = -1,
+ }, {
+ .name = "VUL",
+ .id = MT8365_AFE_MEMIF_VUL,
+ .reg_ofs_base = AFE_VUL_BASE,
+ .reg_ofs_cur = AFE_VUL_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = 16,
+ .fs_maskbit = 0xf,
+ .mono_reg = AFE_DAC_CON1,
+ .mono_shift = 27,
+ .hd_reg = AFE_MEMIF_PBUF_SIZE,
+ .hd_shift = 22,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 3,
+ .msb_reg = AFE_MEMIF_MSB,
+ .msb_shift = 20,
+ .agent_disable_reg = -1,
+ .agent_disable_shift = -1,
+ }, {
+ .name = "VUL2",
+ .id = MT8365_AFE_MEMIF_VUL2,
+ .reg_ofs_base = AFE_VUL_D2_BASE,
+ .reg_ofs_cur = AFE_VUL_D2_CUR,
+ .fs_reg = AFE_DAC_CON0,
+ .fs_shift = 20,
+ .fs_maskbit = 0xf,
+ .mono_reg = -1,
+ .mono_shift = -1,
+ .hd_reg = AFE_MEMIF_PBUF_SIZE,
+ .hd_shift = 14,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 9,
+ .msb_reg = AFE_MEMIF_MSB,
+ .msb_shift = 21,
+ .agent_disable_reg = -1,
+ .agent_disable_shift = -1,
+ }, {
+ .name = "VUL3",
+ .id = MT8365_AFE_MEMIF_VUL3,
+ .reg_ofs_base = AFE_VUL3_BASE,
+ .reg_ofs_cur = AFE_VUL3_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = 8,
+ .fs_maskbit = 0xf,
+ .mono_reg = AFE_DAC_CON0,
+ .mono_shift = 13,
+ .hd_reg = AFE_MEMIF_PBUF2_SIZE,
+ .hd_shift = 10,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 12,
+ .msb_reg = AFE_MEMIF_MSB,
+ .msb_shift = 27,
+ .agent_disable_reg = -1,
+ .agent_disable_shift = -1,
+ }, {
+ .name = "TDM IN",
+ .id = MT8365_AFE_MEMIF_TDM_IN,
+ .reg_ofs_base = AFE_HDMI_IN_2CH_BASE,
+ .reg_ofs_cur = AFE_HDMI_IN_2CH_CUR,
+ .fs_reg = -1,
+ .fs_shift = -1,
+ .fs_maskbit = -1,
+ .mono_reg = AFE_HDMI_IN_2CH_CON0,
+ .mono_shift = 1,
+ .hd_reg = AFE_MEMIF_PBUF2_SIZE,
+ .hd_shift = 8,
+ .hd_align_mshift = 5,
+ .enable_reg = AFE_HDMI_IN_2CH_CON0,
+ .enable_shift = 0,
+ .msb_reg = AFE_MEMIF_MSB,
+ .msb_shift = 28,
+ .agent_disable_reg = -1,
+ .agent_disable_shift = -1,
+ },
+};
+
+static const struct mtk_base_irq_data irq_data[MT8365_AFE_IRQ_NUM] = {
+ {
+ .id = MT8365_AFE_IRQ1,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT1,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_en_reg = AFE_IRQ_MCU_CON,
+ .irq_en_shift = 0,
+ .irq_fs_reg = AFE_IRQ_MCU_CON,
+ .irq_fs_shift = 4,
+ .irq_fs_maskbit = 0xf,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = 0,
+ }, {
+ .id = MT8365_AFE_IRQ2,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT2,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_en_reg = AFE_IRQ_MCU_CON,
+ .irq_en_shift = 1,
+ .irq_fs_reg = AFE_IRQ_MCU_CON,
+ .irq_fs_shift = 8,
+ .irq_fs_maskbit = 0xf,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = 1,
+ }, {
+ .id = MT8365_AFE_IRQ3,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT3,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_en_reg = AFE_IRQ_MCU_CON,
+ .irq_en_shift = 2,
+ .irq_fs_reg = AFE_IRQ_MCU_CON,
+ .irq_fs_shift = 16,
+ .irq_fs_maskbit = 0xf,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = 2,
+ }, {
+ .id = MT8365_AFE_IRQ4,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT4,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_en_reg = AFE_IRQ_MCU_CON,
+ .irq_en_shift = 3,
+ .irq_fs_reg = AFE_IRQ_MCU_CON,
+ .irq_fs_shift = 20,
+ .irq_fs_maskbit = 0xf,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = 3,
+ }, {
+ .id = MT8365_AFE_IRQ5,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT5,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_en_reg = AFE_IRQ_MCU_CON2,
+ .irq_en_shift = 3,
+ .irq_fs_reg = -1,
+ .irq_fs_shift = 0,
+ .irq_fs_maskbit = 0x0,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = 4,
+ }, {
+ .id = MT8365_AFE_IRQ6,
+ .irq_cnt_reg = -1,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x0,
+ .irq_en_reg = AFE_IRQ_MCU_CON,
+ .irq_en_shift = 13,
+ .irq_fs_reg = -1,
+ .irq_fs_shift = 0,
+ .irq_fs_maskbit = 0x0,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = 5,
+ }, {
+ .id = MT8365_AFE_IRQ7,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT7,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_en_reg = AFE_IRQ_MCU_CON,
+ .irq_en_shift = 14,
+ .irq_fs_reg = AFE_IRQ_MCU_CON,
+ .irq_fs_shift = 24,
+ .irq_fs_maskbit = 0xf,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = 6,
+ }, {
+ .id = MT8365_AFE_IRQ8,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT8,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_en_reg = AFE_IRQ_MCU_CON,
+ .irq_en_shift = 15,
+ .irq_fs_reg = AFE_IRQ_MCU_CON,
+ .irq_fs_shift = 28,
+ .irq_fs_maskbit = 0xf,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = 7,
+ }, {
+ .id = MT8365_AFE_IRQ9,
+ .irq_cnt_reg = -1,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x0,
+ .irq_en_reg = AFE_IRQ_MCU_CON2,
+ .irq_en_shift = 2,
+ .irq_fs_reg = -1,
+ .irq_fs_shift = 0,
+ .irq_fs_maskbit = 0x0,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = 8,
+ }, {
+ .id = MT8365_AFE_IRQ10,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT10,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_en_reg = AFE_IRQ_MCU_CON2,
+ .irq_en_shift = 4,
+ .irq_fs_reg = -1,
+ .irq_fs_shift = 0,
+ .irq_fs_maskbit = 0x0,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = 9,
+ },
+};
+
+static int memif_specified_irqs[MT8365_AFE_MEMIF_NUM] = {
+ [MT8365_AFE_MEMIF_DL1] = MT8365_AFE_IRQ1,
+ [MT8365_AFE_MEMIF_DL2] = MT8365_AFE_IRQ2,
+ [MT8365_AFE_MEMIF_TDM_OUT] = MT8365_AFE_IRQ5,
+ [MT8365_AFE_MEMIF_AWB] = MT8365_AFE_IRQ3,
+ [MT8365_AFE_MEMIF_VUL] = MT8365_AFE_IRQ4,
+ [MT8365_AFE_MEMIF_VUL2] = MT8365_AFE_IRQ7,
+ [MT8365_AFE_MEMIF_VUL3] = MT8365_AFE_IRQ8,
+ [MT8365_AFE_MEMIF_TDM_IN] = MT8365_AFE_IRQ10,
+};
+
+static const struct regmap_config mt8365_afe_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = MAX_REGISTER,
+ .cache_type = REGCACHE_NONE,
+};
+
+static irqreturn_t mt8365_afe_irq_handler(int irq, void *dev_id)
+{
+ struct mtk_base_afe *afe = dev_id;
+ unsigned int reg_value;
+ unsigned int mcu_irq_mask;
+ int i, ret;
+
+ ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, &reg_value);
+ if (ret) {
+ dev_err(afe->dev, "%s irq status err\n", __func__);
+ reg_value = AFE_IRQ_STATUS_BITS;
+ goto err_irq;
+ }
+
+ ret = regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_irq_mask);
+ if (ret) {
+ dev_err(afe->dev, "%s irq mcu_en err\n", __func__);
+ reg_value = AFE_IRQ_STATUS_BITS;
+ goto err_irq;
+ }
+
+ /* only clr cpu irq */
+ reg_value &= mcu_irq_mask;
+
+ for (i = 0; i < MT8365_AFE_MEMIF_NUM; i++) {
+ struct mtk_base_afe_memif *memif = &afe->memif[i];
+ struct mtk_base_afe_irq *mcu_irq;
+
+ if (memif->irq_usage < 0)
+ continue;
+
+ mcu_irq = &afe->irqs[memif->irq_usage];
+
+ if (!(reg_value & (1 << mcu_irq->irq_data->irq_clr_shift)))
+ continue;
+
+ snd_pcm_period_elapsed(memif->substream);
+ }
+
+err_irq:
+ /* clear irq */
+ regmap_write(afe->regmap, AFE_IRQ_MCU_CLR,
+ reg_value & AFE_IRQ_STATUS_BITS);
+
+ return IRQ_HANDLED;
+}
+
+static int __maybe_unused mt8365_afe_runtime_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int mt8365_afe_runtime_resume(struct device *dev)
+{
+ return 0;
+}
+
+static int __maybe_unused mt8365_afe_suspend(struct device *dev)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dev);
+ struct regmap *regmap = afe->regmap;
+ int i;
+
+ mt8365_afe_enable_main_clk(afe);
+
+ if (!afe->reg_back_up)
+ afe->reg_back_up =
+ devm_kcalloc(dev, afe->reg_back_up_list_num,
+ sizeof(unsigned int), GFP_KERNEL);
+
+ for (i = 0; i < afe->reg_back_up_list_num; i++)
+ regmap_read(regmap, afe->reg_back_up_list[i],
+ &afe->reg_back_up[i]);
+
+ mt8365_afe_disable_main_clk(afe);
+
+ return 0;
+}
+
+static int __maybe_unused mt8365_afe_resume(struct device *dev)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dev);
+ struct regmap *regmap = afe->regmap;
+ int i = 0;
+
+ if (!afe->reg_back_up) {
+ dev_dbg(dev, "%s no reg_backup\n", __func__);
+ return 0;
+ }
+
+ mt8365_afe_enable_main_clk(afe);
+
+ for (i = 0; i < afe->reg_back_up_list_num; i++)
+ regmap_write(regmap, afe->reg_back_up_list[i],
+ afe->reg_back_up[i]);
+
+ mt8365_afe_disable_main_clk(afe);
+
+ return 0;
+}
+
+static int __maybe_unused mt8365_afe_dev_runtime_suspend(struct device *dev)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dev);
+
+ dev_dbg(afe->dev, "%s suspend %d %d >>\n", __func__,
+ pm_runtime_status_suspended(dev), afe->suspended);
+
+ if (pm_runtime_status_suspended(dev) || afe->suspended)
+ return 0;
+
+ mt8365_afe_suspend(dev);
+
+ afe->suspended = true;
+
+ dev_dbg(afe->dev, "%s <<\n", __func__);
+
+ return 0;
+}
+
+static int __maybe_unused mt8365_afe_dev_runtime_resume(struct device *dev)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dev);
+
+ dev_dbg(afe->dev, "%s suspend %d %d >>\n", __func__,
+ pm_runtime_status_suspended(dev), afe->suspended);
+
+ if (pm_runtime_status_suspended(dev) || !afe->suspended)
+ return 0;
+
+ mt8365_afe_resume(dev);
+
+ afe->suspended = false;
+
+ dev_dbg(afe->dev, "%s <<\n", __func__);
+
+ return 0;
+}
+
+static int mt8365_afe_init_registers(struct mtk_base_afe *afe)
+{
+ size_t i;
+
+ static struct {
+ unsigned int reg;
+ unsigned int mask;
+ unsigned int val;
+ } init_regs[] = {
+ { AFE_CONN_24BIT, GENMASK(31, 0), GENMASK(31, 0) },
+ { AFE_CONN_24BIT_1, GENMASK(21, 0), GENMASK(21, 0) },
+ };
+
+ mt8365_afe_enable_main_clk(afe);
+
+ for (i = 0; i < ARRAY_SIZE(init_regs); i++)
+ regmap_update_bits(afe->regmap, init_regs[i].reg,
+ init_regs[i].mask, init_regs[i].val);
+
+ mt8365_afe_disable_main_clk(afe);
+
+ return 0;
+}
+
+static int mt8365_afe_component_probe(struct snd_soc_component *component)
+{
+ return mtk_afe_add_sub_dai_control(component);
+}
+
+static const struct snd_soc_component_driver mt8365_afe_component = {
+ .name = AFE_PCM_NAME,
+ .probe = mt8365_afe_component_probe,
+ .pointer = mtk_afe_pcm_pointer,
+ .pcm_construct = mtk_afe_pcm_new,
+};
+
+static const struct snd_soc_component_driver mt8365_afe_pcm_component = {
+ .name = "mt8365-afe-pcm-dai",
+};
+
+static int mt8365_dai_memif_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 = mt8365_memif_dai_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mt8365_memif_dai_driver);
+
+ dai->dapm_widgets = mt8365_memif_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mt8365_memif_widgets);
+ dai->dapm_routes = mt8365_memif_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mt8365_memif_routes);
+ return 0;
+}
+
+typedef int (*dai_register_cb)(struct mtk_base_afe *);
+static const dai_register_cb dai_register_cbs[] = {
+ mt8365_dai_pcm_register,
+ mt8365_dai_i2s_register,
+ mt8365_dai_adda_register,
+ mt8365_dai_dmic_register,
+ mt8365_dai_memif_register,
+};
+
+static int mt8365_afe_pcm_dev_probe(struct platform_device *pdev)
+{
+ struct mtk_base_afe *afe;
+ struct mt8365_afe_private *afe_priv;
+ struct device *dev;
+ int ret, i, sel_irq;
+ unsigned int irq_id;
+ struct resource *res;
+
+ afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
+ if (!afe)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, afe);
+
+ afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
+ GFP_KERNEL);
+ if (!afe->platform_priv)
+ return -ENOMEM;
+
+ afe_priv = afe->platform_priv;
+ afe->dev = &pdev->dev;
+ dev = afe->dev;
+
+ spin_lock_init(&afe_priv->afe_ctrl_lock);
+ mutex_init(&afe_priv->afe_clk_mutex);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ afe->base_addr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(afe->base_addr))
+ return PTR_ERR(afe->base_addr);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (res) {
+ afe_priv->afe_sram_vir_addr =
+ devm_ioremap_resource(&pdev->dev, res);
+ if (!IS_ERR(afe_priv->afe_sram_vir_addr)) {
+ afe_priv->afe_sram_phy_addr = res->start;
+ afe_priv->afe_sram_size = resource_size(res);
+ }
+ }
+
+ /* initial audio related clock */
+ ret = mt8365_afe_init_audio_clk(afe);
+ if (ret) {
+ dev_err(afe->dev, "mt8365_afe_init_audio_clk fail\n");
+ return ret;
+ }
+
+ afe->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "top_audio_sel",
+ afe->base_addr, &mt8365_afe_regmap_config);
+ if (IS_ERR(afe->regmap))
+ return PTR_ERR(afe->regmap);
+
+ /* memif % irq initialize*/
+ afe->memif_size = MT8365_AFE_MEMIF_NUM;
+ afe->memif = devm_kcalloc(afe->dev, afe->memif_size,
+ sizeof(*afe->memif), GFP_KERNEL);
+ if (!afe->memif)
+ return -ENOMEM;
+
+ afe->irqs_size = MT8365_AFE_IRQ_NUM;
+ afe->irqs = devm_kcalloc(afe->dev, afe->irqs_size,
+ sizeof(*afe->irqs), GFP_KERNEL);
+ if (!afe->irqs)
+ return -ENOMEM;
+
+ for (i = 0; i < afe->irqs_size; i++)
+ afe->irqs[i].irq_data = &irq_data[i];
+
+ irq_id = platform_get_irq(pdev, 0);
+ if (!irq_id) {
+ dev_err(afe->dev, "np %s no irq\n", afe->dev->of_node->name);
+ return -ENXIO;
+ }
+ ret = devm_request_irq(afe->dev, irq_id, mt8365_afe_irq_handler,
+ 0, "Afe_ISR_Handle", (void *)afe);
+ if (ret) {
+ dev_err(afe->dev, "could not request_irq\n");
+ return ret;
+ }
+
+ /* init sub_dais */
+ INIT_LIST_HEAD(&afe->sub_dais);
+
+ for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) {
+ ret = dai_register_cbs[i](afe);
+ if (ret) {
+ dev_warn(afe->dev, "dai register i %d fail, ret %d\n",
+ i, ret);
+ return ret;
+ }
+ }
+
+ /* init dai_driver and component_driver */
+ ret = mtk_afe_combine_sub_dai(afe);
+ if (ret) {
+ dev_warn(afe->dev, "mtk_afe_combine_sub_dai fail, ret %d\n",
+ ret);
+ return ret;
+ }
+
+ for (i = 0; i < afe->memif_size; i++) {
+ afe->memif[i].data = &memif_data[i];
+ sel_irq = memif_specified_irqs[i];
+ if (sel_irq >= 0) {
+ afe->memif[i].irq_usage = sel_irq;
+ afe->memif[i].const_irq = 1;
+ afe->irqs[sel_irq].irq_occupyed = true;
+ } else {
+ afe->memif[i].irq_usage = -1;
+ }
+ }
+
+ afe->mtk_afe_hardware = &mt8365_afe_hardware;
+ afe->memif_fs = mt8365_memif_fs;
+ afe->irq_fs = mt8365_irq_fs;
+
+ pm_runtime_enable(&pdev->dev);
+
+ pm_runtime_get_sync(&pdev->dev);
+ afe->reg_back_up_list = mt8365_afe_backup_list;
+ afe->reg_back_up_list_num = ARRAY_SIZE(mt8365_afe_backup_list);
+ afe->runtime_resume = mt8365_afe_runtime_resume;
+ afe->runtime_suspend = mt8365_afe_runtime_suspend;
+
+ /* open afe pdn for dapm read/write audio register */
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_AFE);
+
+ /* Set 26m parent clk */
+ mt8365_afe_set_clk_parent(afe,
+ afe_priv->clocks[MT8365_CLK_TOP_AUD_SEL],
+ afe_priv->clocks[MT8365_CLK_CLK26M]);
+
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &mt8365_afe_component, NULL, 0);
+ if (ret) {
+ dev_warn(dev, "err_platform\n");
+ return ret;
+ }
+
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &mt8365_afe_pcm_component,
+ afe->dai_drivers,
+ afe->num_dai_drivers);
+ if (ret) {
+ dev_warn(dev, "err_dai_component\n");
+ return ret;
+ }
+
+ mt8365_afe_init_registers(afe);
+
+ dev_info(&pdev->dev, "MT8365 AFE driver initialized.\n");
+
+ return 0;
+}
+
+static int mt8365_afe_pcm_dev_remove(struct platform_device *pdev)
+{
+ struct mtk_base_afe *afe = platform_get_drvdata(pdev);
+
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_AFE);
+
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ mt8365_afe_runtime_suspend(&pdev->dev);
+
+ return 0;
+}
+
+static const struct of_device_id mt8365_afe_pcm_dt_match[] = {
+ { .compatible = "mediatek,mt8365-afe-pcm", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mt8365_afe_pcm_dt_match);
+
+static const struct dev_pm_ops mt8365_afe_pm_ops = {
+ SET_RUNTIME_PM_OPS(mt8365_afe_dev_runtime_suspend,
+ mt8365_afe_dev_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(mt8365_afe_suspend,
+ mt8365_afe_resume)
+};
+
+static struct platform_driver mt8365_afe_pcm_driver = {
+ .driver = {
+ .name = "mt8365-afe-pcm",
+ .of_match_table = mt8365_afe_pcm_dt_match,
+ .pm = &mt8365_afe_pm_ops,
+ },
+ .probe = mt8365_afe_pcm_dev_probe,
+ .remove = mt8365_afe_pcm_dev_remove,
+};
+
+module_platform_driver(mt8365_afe_pcm_driver);
+
+MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver");
+MODULE_AUTHOR("Jia Zeng <[email protected]>");
+MODULE_AUTHOR("Alexandre Mergnat <[email protected]>");
+MODULE_LICENSE("GPL");

--
2.25.1


2024-02-26 14:08:17

by Alexandre Mergnat

[permalink] [raw]
Subject: [PATCH 12/18] ASoC: codecs: mt6357: add MT6357 codec

From: Nicolas Belin <[email protected]>

Add the support of MT6357 PMIC audio codec.

Signed-off-by: Nicolas Belin <[email protected]>
Signed-off-by: Alexandre Mergnat <[email protected]>
---
sound/soc/codecs/Kconfig | 7 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/mt6357.c | 1805 +++++++++++++++++++++++++++++++++++++++++++++
sound/soc/codecs/mt6357.h | 674 +++++++++++++++++
4 files changed, 2488 insertions(+)

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 59f9742e9ff4..9cf2b9b70472 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -153,6 +153,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_MC13783
imply SND_SOC_ML26124
imply SND_SOC_MT6351
+ imply SND_SOC_MT6357
imply SND_SOC_MT6358
imply SND_SOC_MT6359
imply SND_SOC_MT6660
@@ -2361,6 +2362,12 @@ config SND_SOC_ML26124
config SND_SOC_MT6351
tristate "MediaTek MT6351 Codec"

+config SND_SOC_MT6357
+ tristate "MediaTek MT6357 Codec"
+ help
+ Enable support for the platform which uses MT6357 as
+ external codec device.
+
config SND_SOC_MT6358
tristate "MediaTek MT6358 Codec"
help
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index f53baa2b9565..33e27612867e 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -169,6 +169,7 @@ snd-soc-ml26124-objs := ml26124.o
snd-soc-msm8916-analog-objs := msm8916-wcd-analog.o
snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o
snd-soc-mt6351-objs := mt6351.o
+snd-soc-mt6357-objs := mt6357.o
snd-soc-mt6358-objs := mt6358.o
snd-soc-mt6359-objs := mt6359.o
snd-soc-mt6359-accdet-objs := mt6359-accdet.o
@@ -554,6 +555,7 @@ obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o
obj-$(CONFIG_SND_SOC_MSM8916_WCD_ANALOG) +=snd-soc-msm8916-analog.o
obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o
obj-$(CONFIG_SND_SOC_MT6351) += snd-soc-mt6351.o
+obj-$(CONFIG_SND_SOC_MT6357) += snd-soc-mt6357.o
obj-$(CONFIG_SND_SOC_MT6358) += snd-soc-mt6358.o
obj-$(CONFIG_SND_SOC_MT6359) += snd-soc-mt6359.o
obj-$(CONFIG_SND_SOC_MT6359_ACCDET) += mt6359-accdet.o
diff --git a/sound/soc/codecs/mt6357.c b/sound/soc/codecs/mt6357.c
new file mode 100644
index 000000000000..13e95c227114
--- /dev/null
+++ b/sound/soc/codecs/mt6357.c
@@ -0,0 +1,1805 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MT6357 ALSA SoC audio codec driver
+ *
+ * Copyright (c) 2024 Baylibre
+ * Author: Nicolas Belin <[email protected]>
+ */
+
+#include <linux/dma-mapping.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <linux/mfd/mt6397/core.h>
+#include <linux/regulator/consumer.h>
+
+#include "mt6357.h"
+
+static void set_playback_gpio(struct mt6357_priv *priv, bool enable)
+{
+ if (enable) {
+ /* set gpio mosi mode */
+ regmap_write(priv->regmap, MT6357_GPIO_MODE2_CLR, GPIO_MODE2_CLEAR_ALL);
+ regmap_write(priv->regmap, MT6357_GPIO_MODE2_SET, GPIO8_MODE_SET_AUD_CLK_MOSI |
+ GPIO9_MODE_SET_AUD_DAT_MOSI0 |
+ GPIO10_MODE_SET_AUD_DAT_MOSI1 |
+ GPIO11_MODE_SET_AUD_SYNC_MOSI);
+ regmap_write(priv->regmap, MT6357_GPIO_MODE2, GPIO8_MODE_AUD_CLK_MOSI |
+ GPIO9_MODE_AUD_DAT_MOSI0 |
+ GPIO10_MODE_AUD_DAT_MOSI1 |
+ GPIO11_MODE_AUD_SYNC_MOSI);
+ } else {
+ /* set pad_aud_*_mosi to GPIO mode and dir input
+ * reason:
+ * pad_aud_dat_mosi*, because the pin is used as boot strap
+ */
+ regmap_write(priv->regmap, MT6357_GPIO_MODE2_CLR, GPIO_MODE2_CLEAR_ALL);
+ regmap_write(priv->regmap, MT6357_GPIO_MODE2, GPIO8_MODE_GPIO |
+ GPIO9_MODE_GPIO |
+ GPIO10_MODE_GPIO |
+ GPIO11_MODE_GPIO);
+ regmap_update_bits(priv->regmap, MT6357_GPIO_DIR0, GPIO8_DIR_MASK |
+ GPIO9_DIR_MASK |
+ GPIO10_DIR_MASK |
+ GPIO11_DIR_MASK,
+ GPIO8_DIR_INPUT |
+ GPIO9_DIR_INPUT |
+ GPIO10_DIR_INPUT |
+ GPIO11_DIR_INPUT);
+ }
+}
+
+static void set_capture_gpio(struct mt6357_priv *priv, bool enable)
+{
+ if (enable) {
+ /* set gpio miso mode */
+ regmap_write(priv->regmap, MT6357_GPIO_MODE3_CLR, GPIO_MODE3_CLEAR_ALL);
+ regmap_write(priv->regmap, MT6357_GPIO_MODE3_SET, GPIO12_MODE_SET_AUD_CLK_MISO |
+ GPIO13_MODE_SET_AUD_DAT_MISO0 |
+ GPIO14_MODE_SET_AUD_DAT_MISO1 |
+ GPIO15_MODE_SET_AUD_SYNC_MISO);
+ regmap_write(priv->regmap, MT6357_GPIO_MODE3, GPIO12_MODE_AUD_CLK_MISO |
+ GPIO13_MODE_AUD_DAT_MISO0 |
+ GPIO14_MODE_AUD_DAT_MISO1 |
+ GPIO15_MODE_AUD_SYNC_MISO);
+ } else {
+ /* set pad_aud_*_miso to GPIO mode and dir input
+ * reason:
+ * pad_aud_clk_miso, because when playback only the miso_clk
+ * will also have 26m, so will have power leak
+ * pad_aud_dat_miso*, because the pin is used as boot strap
+ */
+ regmap_write(priv->regmap, MT6357_GPIO_MODE3_CLR, GPIO_MODE3_CLEAR_ALL);
+ regmap_write(priv->regmap, MT6357_GPIO_MODE3, GPIO12_MODE_GPIO |
+ GPIO13_MODE_GPIO |
+ GPIO14_MODE_GPIO |
+ GPIO15_MODE_GPIO);
+ regmap_update_bits(priv->regmap, MT6357_GPIO_DIR0, GPIO12_DIR_MASK |
+ GPIO13_DIR_MASK |
+ GPIO14_DIR_MASK |
+ GPIO15_DIR_MASK,
+ GPIO12_DIR_INPUT |
+ GPIO13_DIR_INPUT |
+ GPIO14_DIR_INPUT |
+ GPIO15_DIR_INPUT);
+ }
+}
+
+static void hp_main_output_ramp(struct mt6357_priv *priv, bool up)
+{
+ int i = 0, stage = 0;
+ int target = 7;
+ /* Enable/Reduce HPL/R main output stage step by step */
+ for (i = 0; i <= target; i++) {
+ stage = up ? i : target - i;
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ HPLOUT_STG_CTRL_VAUDP15_MASK,
+ stage << HPLOUT_STG_CTRL_VAUDP15_SFT);
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ HPROUT_STG_CTRL_VAUDP15_MASK,
+ stage << HPROUT_STG_CTRL_VAUDP15_SFT);
+ usleep_range(600, 700);
+ }
+}
+
+static void hp_aux_feedback_loop_gain_ramp(struct mt6357_priv *priv, bool up)
+{
+ int i = 0, stage = 0;
+ /* Reduce HP aux feedback loop gain step by step */
+ for (i = 0; i <= 0xf; i++) {
+ stage = up ? i : 0xf - i;
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+ HP_AUX_LOOP_GAIN_MASK, stage << HP_AUX_LOOP_GAIN_SFT);
+ usleep_range(600, 700);
+ }
+}
+
+static void hp_pull_down(struct mt6357_priv *priv, bool enable)
+{
+ if (enable)
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON2,
+ HPP_SHORT_2VCM_VAUDP15_MASK, HPP_SHORT_2VCM_VAUDP15_ENABLE);
+ else
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON2,
+ HPP_SHORT_2VCM_VAUDP15_MASK, HPP_SHORT_2VCM_VAUDP15_DISABLE);
+}
+
+static bool is_valid_hp_pga_idx(int reg_idx)
+{
+ return (reg_idx >= DL_GAIN_8DB && reg_idx <= DL_GAIN_N_12DB) || reg_idx == DL_GAIN_N_40DB;
+}
+
+static void volume_ramp(struct mt6357_priv *priv, int lfrom, int lto,
+ int rfrom, int rto, unsigned int reg_addr)
+{
+ int lcount, rcount, sleep = 0;
+
+ if (!is_valid_hp_pga_idx(lfrom) || !is_valid_hp_pga_idx(lto))
+ pr_debug("%s(), invalid left volume index, from %d, to %d\n",
+ __func__, lfrom, lto);
+
+ if (!is_valid_hp_pga_idx(rfrom) || !is_valid_hp_pga_idx(rto))
+ pr_debug("%s(), invalid right volume index, from %d, to %d\n",
+ __func__, rfrom, rto);
+
+ if (lto > lfrom)
+ lcount = 1;
+ else
+ lcount = -1;
+
+ if (rto > rfrom)
+ rcount = 1;
+ else
+ rcount = -1;
+
+ while ((lto != lfrom) || (rto != rfrom)) {
+ if (lto != lfrom) {
+ lfrom += lcount;
+ if (is_valid_hp_pga_idx(lfrom)) {
+ regmap_update_bits(priv->regmap, reg_addr, DL_GAIN_REG_LEFT_MASK,
+ lfrom << DL_GAIN_REG_LEFT_SHIFT);
+ sleep = 1;
+ }
+ }
+ if (rto != rfrom) {
+ rfrom += rcount;
+ if (is_valid_hp_pga_idx(rfrom)) {
+ regmap_update_bits(priv->regmap, reg_addr, DL_GAIN_REG_RIGHT_MASK,
+ rfrom << DL_GAIN_REG_RIGHT_SHIFT);
+ sleep = 1;
+ }
+ }
+ if (sleep)
+ usleep_range(200, 300);
+ }
+}
+
+static void lo_volume_ramp(struct mt6357_priv *priv, int lfrom, int lto, int rfrom, int rto)
+{
+ volume_ramp(priv, lfrom, lto, rfrom, rto, MT6357_ZCD_CON1);
+}
+
+static void hp_volume_ramp(struct mt6357_priv *priv, int lfrom, int lto, int rfrom, int rto)
+{
+ volume_ramp(priv, lfrom, lto, rfrom, rto, MT6357_ZCD_CON2);
+}
+
+static void hs_volume_ramp(struct mt6357_priv *priv, int from, int to)
+{
+ volume_ramp(priv, from, to, 0, 0, MT6357_ZCD_CON3);
+}
+
+static int mt6357_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct mt6357_priv *priv = snd_soc_component_get_drvdata(component);
+ struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
+ unsigned int reg;
+ int ret;
+
+ ret = snd_soc_put_volsw(kcontrol, ucontrol);
+ if (ret < 0)
+ return ret;
+
+ switch (mc->reg) {
+ case MT6357_ZCD_CON2:
+ regmap_read(priv->regmap, MT6357_ZCD_CON2, &reg);
+ priv->ana_gain[ANALOG_VOLUME_HPOUTL] =
+ (reg & AUD_HPL_GAIN_MASK) >> AUD_HPL_GAIN_SFT;
+ priv->ana_gain[ANALOG_VOLUME_HPOUTR] =
+ (reg & AUD_HPR_GAIN_MASK) >> AUD_HPR_GAIN_SFT;
+ break;
+ case MT6357_ZCD_CON1:
+ regmap_read(priv->regmap, MT6357_ZCD_CON1, &reg);
+ priv->ana_gain[ANALOG_VOLUME_LINEOUTL] =
+ (reg & AUD_LOL_GAIN_MASK) >> AUD_LOL_GAIN_SFT;
+ priv->ana_gain[ANALOG_VOLUME_LINEOUTR] =
+ (reg & AUD_LOR_GAIN_MASK) >> AUD_LOR_GAIN_SFT;
+ break;
+ case MT6357_ZCD_CON3:
+ regmap_read(priv->regmap, MT6357_ZCD_CON3, &reg);
+ priv->ana_gain[ANALOG_VOLUME_HSOUT] =
+ (reg & AUD_HS_GAIN_MASK) >> AUD_HS_GAIN_SFT;
+ break;
+ case MT6357_AUDENC_ANA_CON0:
+ case MT6357_AUDENC_ANA_CON1:
+ regmap_read(priv->regmap, MT6357_AUDENC_ANA_CON0, &reg);
+ priv->ana_gain[ANALOG_VOLUME_MIC1] =
+ (reg & AUDPREAMPLGAIN_MASK) >> AUDPREAMPLGAIN_SFT;
+ regmap_read(priv->regmap, MT6357_AUDENC_ANA_CON1, &reg);
+ priv->ana_gain[ANALOG_VOLUME_MIC2] =
+ (reg & AUDPREAMPRGAIN_MASK) >> AUDPREAMPRGAIN_SFT;
+ break;
+ }
+
+ return ret;
+}
+
+/* Volume and channel swap controls */
+static const DECLARE_TLV_DB_SCALE(playback_tlv, -1000, 100, 0);
+static const DECLARE_TLV_DB_SCALE(capture_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(hp_degain_tlv, -1200, 1200, 0);
+
+static const struct snd_kcontrol_new mt6357_controls[] = {
+ /* dl pga gain */
+ SOC_DOUBLE_EXT_TLV("Headphone Volume",
+ MT6357_ZCD_CON2, AUD_HPL_GAIN_SFT, AUD_HPR_GAIN_SFT, AUD_HP_GAIN_MAX, 1,
+ snd_soc_get_volsw, mt6357_put_volsw, playback_tlv),
+ SOC_SINGLE_EXT_TLV("Headphone Vin Volume",
+ MT6357_AUDDEC_ANA_CON7, HP_IVBUF_DEGAIN_SFT, HP_IVBUF_DEGAIN_MAX, 1,
+ snd_soc_get_volsw, mt6357_put_volsw, hp_degain_tlv),
+ SOC_DOUBLE_EXT_TLV("Lineout Volume",
+ MT6357_ZCD_CON1, AUD_LOL_GAIN_SFT, AUD_LOR_GAIN_SFT, AUD_LO_GAIN_MAX, 1,
+ snd_soc_get_volsw, mt6357_put_volsw, playback_tlv),
+ SOC_SINGLE_EXT_TLV("Handset Volume",
+ MT6357_ZCD_CON3, AUD_HS_GAIN_SFT, AUD_HS_GAIN_MAX, 1,
+ snd_soc_get_volsw, mt6357_put_volsw, playback_tlv),
+ /* ul pga gain */
+ SOC_DOUBLE_R_EXT_TLV("Mic Volume",
+ MT6357_AUDENC_ANA_CON0, MT6357_AUDENC_ANA_CON1,
+ AUDPREAMPLGAIN_SFT, AUDPREAMPLGAIN_MAX, 0,
+ snd_soc_get_volsw, mt6357_put_volsw, capture_tlv),
+ /* ul channel swap */
+ SOC_SINGLE("UL LR Swap", MT6357_AFE_UL_DL_CON0, AFE_UL_LR_SWAP_SFT, 1, 0),
+};
+
+/* Uplink controls */
+#define IS_DCC_BASE(type) ((type) == MIC_TYPE_MUX_DCC || \
+ (type) == MIC_TYPE_MUX_DCC_ECM_DIFF || \
+ (type) == MIC_TYPE_MUX_DCC_ECM_SINGLE)
+
+static const char * const mic_type_mux_map[] = {
+ "Idle",
+ "ACC",
+ "DMIC",
+ "DCC",
+ "DCC_ECM_DIFF",
+ "DCC_ECM_SINGLE",
+ "Loopback",
+ "Sine Generator",
+};
+
+enum {
+ MIC_TYPE_MUX_IDLE = 0,
+ MIC_TYPE_MUX_ACC,
+ MIC_TYPE_MUX_DMIC,
+ MIC_TYPE_MUX_DCC,
+ MIC_TYPE_MUX_DCC_ECM_DIFF,
+ MIC_TYPE_MUX_DCC_ECM_SINGLE,
+ MIC_TYPE_MUX_LPBK,
+ MIC_TYPE_MUX_SGEN,
+ MIC_TYPE_MUX_MASK = 0x7,
+};
+
+static int mic_type_mux_map_value[] = {
+ MIC_TYPE_MUX_IDLE,
+ MIC_TYPE_MUX_ACC,
+ MIC_TYPE_MUX_DMIC,
+ MIC_TYPE_MUX_DCC,
+ MIC_TYPE_MUX_DCC_ECM_DIFF,
+ MIC_TYPE_MUX_DCC_ECM_SINGLE,
+ MIC_TYPE_MUX_LPBK,
+ MIC_TYPE_MUX_SGEN,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(mic_type_mux_map_enum, SND_SOC_NOPM, 0, MIC_TYPE_MUX_MASK,
+ mic_type_mux_map, mic_type_mux_map_value);
+
+static const struct snd_kcontrol_new mic_type_mux_control =
+ SOC_DAPM_ENUM("Mic Type Select", mic_type_mux_map_enum);
+
+enum {
+ PGA_MUX_NONE = 0,
+ PGA_MUX_AIN0,
+ PGA_MUX_AIN1,
+ PGA_MUX_AIN2,
+ PGA_MUX_MASK = 0x3,
+};
+
+static const char * const pga_mux_map[] = {
+ "None", "AIN0", "AIN1", "AIN2"
+};
+
+static int pga_mux_map_value[] = {
+ PGA_MUX_NONE,
+ PGA_MUX_AIN0,
+ PGA_MUX_AIN1,
+ PGA_MUX_AIN2,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(pga_left_mux_map_enum,
+ MT6357_AUDENC_ANA_CON0,
+ AUDPREAMPLINPUTSEL_SFT, AUDPREAMPLINPUTSEL_MASK_NOSFT,
+ pga_mux_map, pga_mux_map_value);
+
+static const struct snd_kcontrol_new pga_left_mux_control =
+ SOC_DAPM_ENUM("PGA L Select", pga_left_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(pga_right_mux_map_enum,
+ MT6357_AUDENC_ANA_CON1,
+ AUDPREAMPRINPUTSEL_SFT, AUDPREAMPRINPUTSEL_MASK_NOSFT,
+ pga_mux_map, pga_mux_map_value);
+
+static const struct snd_kcontrol_new pga_right_mux_control =
+ SOC_DAPM_ENUM("PGA R Select", pga_right_mux_map_enum);
+
+/* Downlink controls */
+static const char * const hslo_mux_map[] = {
+ "Open", "DACR", "Playback", "Test mode"
+};
+
+static int hslo_mux_map_value[] = {
+ 0x0, 0x1, 0x2, 0x3,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(lo_mux_map_enum,
+ MT6357_AUDDEC_ANA_CON4,
+ AUD_LOL_MUX_INPUT_VAUDP15_SFT,
+ AUD_LOL_MUX_INPUT_VAUDP15_MASK_NOSFT,
+ hslo_mux_map, hslo_mux_map_value);
+
+static const struct snd_kcontrol_new lo_mux_control =
+ SOC_DAPM_ENUM("Line out source", lo_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hs_mux_map_enum, MT6357_AUDDEC_ANA_CON3,
+ AUD_HS_MUX_INPUT_VAUDP15_SFT,
+ AUD_HS_MUX_INPUT_VAUDP15_MASK_NOSFT,
+ hslo_mux_map, hslo_mux_map_value);
+
+static const struct snd_kcontrol_new hs_mux_control =
+ SOC_DAPM_ENUM("Handset source", hs_mux_map_enum);
+
+static const char * const hplr_mux_map[] = {
+ "Open", "Line Out", "DAC", "Handset"
+};
+
+static int hplr_mux_map_value[] = {
+ 0x0, 0x1, 0x2, 0x3,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hpr_mux_map_enum, MT6357_AUDDEC_ANA_CON0,
+ AUD_HPR_MUX_INPUT_VAUDP15_SFT,
+ AUD_HPR_MUX_INPUT_VAUDP15_MASK_NOSFT,
+ hplr_mux_map, hplr_mux_map_value);
+
+static const struct snd_kcontrol_new hpr_mux_control =
+ SOC_DAPM_ENUM("Headphone Right source", hpr_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hpl_mux_map_enum, MT6357_AUDDEC_ANA_CON0,
+ AUD_HPL_MUX_INPUT_VAUDP15_SFT,
+ AUD_HPL_MUX_INPUT_VAUDP15_MASK_NOSFT,
+ hplr_mux_map, hplr_mux_map_value);
+
+static const struct snd_kcontrol_new hpl_mux_control =
+ SOC_DAPM_ENUM("Headphone Left source", hpl_mux_map_enum);
+
+static const char * const dac_mux_map[] = {
+ "Normal Path", "Sine Generator"
+};
+
+static int dac_mux_map_value[] = {
+ 0x0, 0x1,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(dac_mux_map_enum,
+ MT6357_AFE_TOP_CON0, DL_SINE_ON_SFT, DL_SINE_ON_MASK,
+ dac_mux_map, dac_mux_map_value);
+
+static const struct snd_kcontrol_new dac_mux_control =
+ SOC_DAPM_ENUM("DAC Select", dac_mux_map_enum);
+
+static int mt6357_set_dmic(struct mt6357_priv *priv, bool enable)
+{
+ if (enable) {
+ /* DMIC enable */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON7,
+ AUDDIGMICBIAS_MASK | AUDDIGMICEN_MASK,
+ AUDDIGMICBIAS_DEFAULT_VALUE | AUDDIGMICEN_ENABLE);
+ /* enable aud_pad TX fifos */
+ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+ AUD_PAD_TX_FIFO_NORMAL_PATH_MASK,
+ AUD_PAD_TX_FIFO_NORMAL_PATH_ENABLE);
+ /* UL dmic setting: dual mode */
+ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_H,
+ C_TWO_DIGITAL_MIC_CTL_MASK, C_TWO_DIGITAL_MIC_ENABLE);
+ /* UL turn on SDM 3 level mode */
+ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+ UL_SDM_3_LEVEL_CTL_MASK, UL_SDM_3_LEVEL_SELECT);
+ /* UL turn on */
+ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+ UL_SRC_ON_TMP_CTL_MASK, UL_SRC_ENABLE);
+ /* Wait to avoid any pop noises */
+ msleep(100);
+ } else {
+ /* UL turn off */
+ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+ UL_SRC_ON_TMP_CTL_MASK, UL_SRC_DISABLE);
+ /* UL turn on SDM 3 level mode */
+ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+ UL_SDM_3_LEVEL_CTL_MASK, UL_SDM_3_LEVEL_DESELECT);
+ /* disable aud_pad TX fifos */
+ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+ AUD_PAD_TX_FIFO_NORMAL_PATH_MASK,
+ AUD_PAD_TX_FIFO_NORMAL_PATH_DISABLE);
+ /* UL dmic setting: dual mode */
+ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_H,
+ C_TWO_DIGITAL_MIC_CTL_MASK, C_TWO_DIGITAL_MIC_DISABLE);
+ /* DMIC disable */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON7,
+ AUDDIGMICBIAS_MASK | AUDDIGMICEN_MASK,
+ AUDDIGMICBIAS_OFF | AUDDIGMICEN_DISABLE);
+ }
+ return 0;
+}
+
+static int mt6357_set_amic(struct mt6357_priv *priv, bool enable, unsigned int mic_type)
+{
+ dev_dbg(priv->dev, "%s(), mic %u\n", __func__, mic_type);
+ if (enable) {
+ if (IS_DCC_BASE(mic_type)) {
+ regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0,
+ DCCLK_DIV_MASK, DCCLK_DIV_RUN_VALUE);
+ regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0,
+ DCCLK_PDN_MASK, DCCLK_OUTPUT);
+ regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0,
+ DCCLK_GEN_ON_MASK, DCCLK_GEN_ON);
+ regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG1,
+ DCCLK_RESYNC_BYPASS_MASK, DCCLK_RESYNC_BYPASS);
+
+ /* mic bias 0: set the correct DC couple*/
+ switch (mic_type) {
+ case MIC_TYPE_MUX_DCC_ECM_DIFF:
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON8,
+ AUD_MICBIAS0_DC_MASK,
+ AUD_MICBIAS0_DC_ENABLE_ALL);
+ break;
+ case MIC_TYPE_MUX_DCC_ECM_SINGLE:
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON8,
+ AUD_MICBIAS0_DC_MASK,
+ AUD_MICBIAS0_DC_ENABLE_P1);
+ break;
+ default:
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON8,
+ AUD_MICBIAS0_DC_MASK,
+ AUD_MICBIAS0_DC_DISABLE_ALL);
+ break;
+ }
+
+ /* mic bias 1: set the correct DC couple */
+ if (mic_type == MIC_TYPE_MUX_DCC_ECM_SINGLE)
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON9,
+ AUD_MICBIAS1_DCSW1P_EN_MASK,
+ AUD_MICBIAS1_DCSW1P_ENABLE);
+
+ /* Audio L/R preamplifier DCC precharge */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+ AUDPREAMPLDCPRECHARGE_MASK,
+ AUDPREAMPLDCPRECHARGE_ENABLE);
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+ AUDPREAMPRDCPRECHARGE_MASK,
+ AUDPREAMPRDCPRECHARGE_ENABLE);
+ /* L preamplifier DCCEN */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+ AUDPREAMPLDCCEN_MASK,
+ AUDPREAMPLDCCEN_DC);
+ /* R preamplifier DCCEN */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+ AUDPREAMPRDCCEN_MASK,
+ AUDPREAMPRDCCEN_DC);
+ } else {
+ /* Audio L preamplifier DCC precharge disable */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+ AUDPREAMPLDCPRECHARGE_MASK,
+ AUDPREAMPLDCPRECHARGE_DISABLE);
+ /* L preamplifier ACC */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+ AUDPREAMPLDCCEN_MASK,
+ AUDPREAMPLDCCEN_AC);
+ /* Audio R preamplifier DCC precharge disable */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+ AUDPREAMPRDCPRECHARGE_MASK,
+ AUDPREAMPRDCPRECHARGE_DISABLE);
+ /* R preamplifier ACC */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+ AUDPREAMPRDCCEN_MASK,
+ AUDPREAMPRDCCEN_AC);
+ }
+ } else {
+ /* disable any Mic Bias 0 DC couple */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON8,
+ AUD_MICBIAS0_DC_MASK, AUD_MICBIAS0_DC_DISABLE_ALL);
+ /* disable any Mic Bias 1 DC couple */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON9,
+ AUD_MICBIAS1_DCSW1P_EN_MASK, AUD_MICBIAS1_DCSW1P_DISABLE);
+ if (IS_DCC_BASE(mic_type)) {
+ regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0,
+ DCCLK_GEN_ON_MASK, DCCLK_GEN_OFF);
+ regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0,
+ DCCLK_PDN_MASK, DCCLK_PDN);
+ regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0,
+ DCCLK_DIV_MASK, DCCLK_DIV_STOP_VALUE);
+ }
+ }
+
+ return 0;
+}
+
+static int mt6357_set_loopback(struct mt6357_priv *priv, bool enable)
+{
+ if (enable) {
+ /* enable aud_pad TX fifos */
+ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+ AUD_PAD_TX_FIFO_NORMAL_PATH_MASK,
+ AUD_PAD_TX_FIFO_NORMAL_PATH_ENABLE);
+ /* enable aud_pad lpk TX fifos */
+ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+ AUD_PAD_TX_FIFO_LPBK_MASK, AUD_PAD_TX_FIFO_LPBK_ENABLE);
+ /* Set UL Part: enable new lpbk 2 */
+ regmap_update_bits(priv->regmap, MT6357_AFE_ADDA_MTKAIF_CFG0,
+ ADDA_MTKAIF_LPBK_CTL_MASK, ADDA_MTKAIF_LPBK_ENABLE);
+ /* UL turn on */
+ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+ UL_SRC_ON_TMP_CTL_MASK, UL_SRC_ENABLE);
+ } else {
+ /* UL turn off */
+ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+ UL_SRC_ON_TMP_CTL_MASK, UL_SRC_DISABLE);
+ /* disable new lpbk 2 */
+ regmap_update_bits(priv->regmap, MT6357_AFE_ADDA_MTKAIF_CFG0,
+ ADDA_MTKAIF_LPBK_CTL_MASK, ADDA_MTKAIF_LPBK_DISABLE);
+ /* disable aud_pad lpbk TX fifos */
+ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+ AUD_PAD_TX_FIFO_LPBK_MASK, AUD_PAD_TX_FIFO_LPBK_DISABLE);
+ /* disable aud_pad TX fifos */
+ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+ AUD_PAD_TX_FIFO_NORMAL_PATH_MASK,
+ AUD_PAD_TX_FIFO_NORMAL_PATH_DISABLE);
+ }
+
+ return 0;
+}
+
+static int mt6357_set_ul_sine_gen(struct mt6357_priv *priv, bool enable)
+{
+ if (enable) {
+ /* enable aud_pad TX fifos */
+ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+ AUD_PAD_TX_FIFO_NORMAL_PATH_MASK,
+ AUD_PAD_TX_FIFO_NORMAL_PATH_ENABLE);
+ /* UL turn on */
+ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+ UL_SRC_ON_TMP_CTL_MASK, UL_SRC_ENABLE);
+ } else {
+ /* UL turn off */
+ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+ UL_SRC_ON_TMP_CTL_MASK, UL_SRC_DISABLE);
+ /* disable aud_pad TX fifos */
+ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+ AUD_PAD_TX_FIFO_NORMAL_PATH_MASK,
+ AUD_PAD_TX_FIFO_NORMAL_PATH_DISABLE);
+ }
+
+ return 0;
+}
+
+static int mt_aif_out_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+ dev_dbg(priv->dev, "%s(), event 0x%x\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ set_capture_gpio(priv, true);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ set_capture_gpio(priv, false);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mt_adc_supply_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+ dev_dbg(priv->dev, "%s(), event 0x%x\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Enable audio ADC CLKGEN */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON11,
+ RSTB_ENCODER_VA28_MASK, RSTB_ENCODER_VA28_ENABLE);
+ /* Enable LCLDO_ENC 2P8V */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12,
+ LCLDO_ENC_EN_VA28_MASK, LCLDO_ENC_EN_VA28_ENABLE);
+ /* LCLDO_ENC remote sense */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12,
+ VA28REFGEN_EN_VA28_MASK | LCLDO_ENC_REMOTE_SENSE_VA28_MASK,
+ VA28REFGEN_EN_VA28_ENABLE | LCLDO_ENC_REMOTE_SENSE_VA28_ENABLE);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* LCLDO_ENC remote sense off */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12,
+ VA28REFGEN_EN_VA28_MASK | LCLDO_ENC_REMOTE_SENSE_VA28_MASK,
+ VA28REFGEN_EN_VA28_DISABLE |
+ LCLDO_ENC_REMOTE_SENSE_VA28_DISABLE);
+ /* disable LCLDO_ENC 2P8V */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12,
+ LCLDO_ENC_EN_VA28_MASK, LCLDO_ENC_EN_VA28_DISABLE);
+ /* disable audio ADC CLKGEN */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON11,
+ RSTB_ENCODER_VA28_MASK, RSTB_ENCODER_VA28_DISABLE);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mt_mic_type_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+ unsigned int mic_type = dapm_kcontrol_get_value(w->kcontrols[0]);
+
+ dev_dbg(priv->dev, "%s(), event 0x%x, mic_type %u\n", __func__, event, mic_type);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ switch (mic_type) {
+ case MIC_TYPE_MUX_DMIC:
+ mt6357_set_dmic(priv, true);
+ break;
+ case MIC_TYPE_MUX_LPBK:
+ mt6357_set_loopback(priv, true);
+ break;
+ case MIC_TYPE_MUX_SGEN:
+ mt6357_set_ul_sine_gen(priv, true);
+ break;
+ default:
+ mt6357_set_amic(priv, true, mic_type);
+ break;
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ switch (mic_type) {
+ case MIC_TYPE_MUX_DMIC:
+ mt6357_set_dmic(priv, false);
+ break;
+ case MIC_TYPE_MUX_LPBK:
+ mt6357_set_loopback(priv, false);
+ break;
+ case MIC_TYPE_MUX_SGEN:
+ mt6357_set_ul_sine_gen(priv, false);
+ break;
+ default:
+ mt6357_set_amic(priv, false, mic_type);
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mt_pga_left_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+ dev_dbg(priv->dev, "%s(), event = 0x%x\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /* L preamplifier enable */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+ AUDPREAMPLON_MASK, AUDPREAMPLON_ENABLE);
+ /* L ADC input sel : L PGA. Enable audio L ADC */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, AUDADCLINPUTSEL_MASK,
+ AUDADCLINPUTSEL_PREAMPLIFIER);
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+ AUDADCLPWRUP_MASK, AUDADCLPWRUP);
+ /* Audio L preamplifier DCC precharge off */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+ AUDPREAMPLDCPRECHARGE_MASK, AUDPREAMPLDCPRECHARGE_DISABLE);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ /* Audio L ADC input sel : off, disable audio L ADC */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+ AUDADCLPWRUP_MASK, AUDADCLPWRDOWN);
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, AUDADCLINPUTSEL_MASK,
+ AUDADCLINPUTSEL_IDLE);
+ /* L PGA 0 dB gain */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, AUDPREAMPLGAIN_MASK,
+ UL_GAIN_0DB << AUDPREAMPLGAIN_SFT);
+ /* L preamplifier ACC */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+ AUDPREAMPLDCCEN_MASK, AUDPREAMPLDCCEN_AC);
+ /* L preamplifier disable */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+ AUDPREAMPLON_MASK, AUDPREAMPLON_DISABLE);
+ /* disable Audio L preamplifier DCC precharge */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+ AUDPREAMPLDCPRECHARGE_MASK, AUDPREAMPLDCPRECHARGE_DISABLE);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mt_pga_right_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+ dev_dbg(priv->dev, "%s(), event = 0x%x\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /* R preamplifier enable */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+ AUDPREAMPRON_MASK, AUDPREAMPRON_ENABLE);
+ /* R ADC input sel : R PGA. Enable audio R ADC */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, AUDADCRINPUTSEL_MASK,
+ AUDADCRINPUTSEL_PREAMPLIFIER);
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+ AUDADCRPWRUP_MASK, AUDADCRPWRUP);
+ /* Audio R preamplifier DCC precharge off */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+ AUDPREAMPRDCPRECHARGE_MASK, AUDPREAMPRDCPRECHARGE_DISABLE);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ /* Audio R ADC input sel : off, disable audio R ADC */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+ AUDADCRPWRUP_MASK, AUDADCRPWRDOWN);
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, AUDADCRINPUTSEL_MASK,
+ AUDADCRINPUTSEL_IDLE);
+ /* R PGA 0 dB gain */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, AUDPREAMPRGAIN_MASK,
+ UL_GAIN_0DB << AUDPREAMPRGAIN_SFT);
+ /* R preamplifier ACC */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+ AUDPREAMPRDCCEN_MASK, AUDPREAMPRDCCEN_AC);
+ /* R preamplifier disable */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+ AUDPREAMPRON_MASK, AUDPREAMPRON_DISABLE);
+ /* disable Audio R preamplifier DCC precharge */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+ AUDPREAMPRDCPRECHARGE_MASK, AUDPREAMPRDCPRECHARGE_DISABLE);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int adc_enable_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+ dev_dbg(priv->dev, "%s(), event = 0x%x\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* enable aud_pad TX fifos */
+ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+ AUD_PAD_TX_FIFO_NORMAL_PATH_MASK,
+ AUD_PAD_TX_FIFO_NORMAL_PATH_ENABLE);
+ /* UL turn on */
+ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+ UL_SRC_ON_TMP_CTL_MASK, UL_SRC_ENABLE);
+ /* Wait to avoid any pop noises */
+ msleep(100);
+ //set the mic gains to the stored values
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, AUDPREAMPLGAIN_MASK,
+ priv->ana_gain[ANALOG_VOLUME_MIC1] << AUDPREAMPLGAIN_SFT);
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, AUDPREAMPRGAIN_MASK,
+ priv->ana_gain[ANALOG_VOLUME_MIC2] << AUDPREAMPRGAIN_SFT);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* UL turn off */
+ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+ UL_SRC_ON_TMP_CTL_MASK, UL_SRC_DISABLE);
+ /* disable aud_pad TX fifos */
+ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+ AUD_PAD_TX_FIFO_NORMAL_PATH_MASK,
+ AUD_PAD_TX_FIFO_NORMAL_PATH_DISABLE);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static void configure_downlinks(struct mt6357_priv *priv, bool enable)
+{
+ if (enable) {
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ELR_0,
+ AUD_HP_TRIM_EN_VAUDP15_MASK, AUD_HP_TRIM_EN_VAUDP15_ENABLE);
+ /* Disable headphone short-circuit protection */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+ AUD_HPR_SC_VAUDP15_MASK | AUD_HPL_SC_VAUDP15_MASK,
+ AUD_HPR_SC_VAUDP15_DISABLE | AUD_HPL_SC_VAUDP15_DISABLE);
+ /* Disable handset short-circuit protection */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
+ AUD_HS_SC_VAUDP15_MASK, AUD_HS_SC_VAUDP15_DISABLE);
+ /* Disable lineout short-circuit protection */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
+ AUD_LOL_SC_VAUDP15_MASK, AUD_LOL_SC_VAUDP15_DISABLE);
+ /* Reduce ESD resistance of AU_REFN */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON2,
+ AUD_REFN_DERES_VAUDP15_MASK, AUD_REFN_DERES_VAUDP15_ENABLE);
+ /* Set HPR/HPL gain as minimum (~ -40dB) */
+ regmap_write(priv->regmap, MT6357_ZCD_CON2, DL_GAIN_N_40DB_REG);
+ /* Set LOL gain as minimum (~ -40dB) */
+ regmap_write(priv->regmap, MT6357_ZCD_CON1, DL_GAIN_N_40DB_REG);
+ /* Set HS gain as minimum (~ -40dB) */
+ regmap_write(priv->regmap, MT6357_ZCD_CON3, DL_GAIN_N_40DB);
+ /* Turn on DA_600K_NCP_VA18 */
+ regmap_write(priv->regmap, MT6357_AUDNCP_CLKDIV_CON1, DIVCKS_ON);
+ /* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */
+ regmap_write(priv->regmap, MT6357_AUDNCP_CLKDIV_CON2, 0x002c);
+ /* Toggle DIVCKS_CHG */
+ regmap_write(priv->regmap, MT6357_AUDNCP_CLKDIV_CON0, DIVCKS_CHG);
+ /* Set NCP soft start mode as default mode: 150us */
+ regmap_write(priv->regmap, MT6357_AUDNCP_CLKDIV_CON4, DIVCKS_PWD_NCP_ST_150US);
+ /* Enable NCP */
+ regmap_write(priv->regmap, MT6357_AUDNCP_CLKDIV_CON3, DIVCKS_PWD_NCP_ENABLE);
+ usleep_range(250, 270);
+ /* Enable cap-less LDOs (1.5V) */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12,
+ VA33REFGEN_EN_VA18_MASK |
+ LCLDO_REMOTE_SENSE_VA18_MASK | LCLDO_EN_VA18_MASK |
+ HCLDO_REMOTE_SENSE_VA18_MASK | HCLDO_EN_VA18_MASK,
+ VA33REFGEN_EN_VA18_ENABLE |
+ LCLDO_REMOTE_SENSE_VA18_ENABLE | LCLDO_EN_VA18_ENABLE |
+ HCLDO_REMOTE_SENSE_VA18_ENABLE | HCLDO_EN_VA18_ENABLE);
+ /* Enable NV regulator (-1.2V) */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON13,
+ NVREG_EN_VAUDP15_MASK, NVREG_EN_VAUDP15_ENABLE);
+ usleep_range(100, 120);
+ /* Enable IBIST */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON10,
+ AUD_IBIAS_PWRDN_VAUDP15_MASK, AUD_IBIAS_PWRDN_VAUDP15_ENABLE);
+ /* Enable AUD_CLK */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON11,
+ RSTB_DECODER_VA28_MASK, RSTB_DECODER_VA28_ENABLE);
+ /* Enable low-noise mode of DAC */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+ DAC_LOW_NOISE_MODE_MASK, DAC_LOW_NOISE_MODE_ENABLE);
+ usleep_range(100, 120);
+ } else {
+ /* Disable low-noise mode of DAC */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+ DAC_LOW_NOISE_MODE_MASK, DAC_LOW_NOISE_MODE_DISABLE);
+ /* Disable AUD_CLK */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON11,
+ RSTB_DECODER_VA28_MASK, RSTB_DECODER_VA28_DISABLE);
+ /* Enable linout short-circuit protection */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
+ AUD_LOL_SC_VAUDP15_MASK, AUD_LOL_SC_VAUDP15_ENABLE);
+ /* Enable handset short-circuit protection */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
+ AUD_HS_SC_VAUDP15_MASK, AUD_HS_SC_VAUDP15_ENABLE);
+ /* Enable headphone short-circuit protection */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+ AUD_HPR_SC_VAUDP15_MASK | AUD_HPL_SC_VAUDP15_MASK,
+ AUD_HPR_SC_VAUDP15_ENABLE | AUD_HPL_SC_VAUDP15_ENABLE);
+ /* Disable IBIST */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON10,
+ AUD_IBIAS_PWRDN_VAUDP15_MASK, AUD_IBIAS_PWRDN_VAUDP15_DISABLE);
+ /* Disable NV regulator (-1.2V) */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON13,
+ NVREG_EN_VAUDP15_MASK, NVREG_EN_VAUDP15_DISABLE);
+ /* Disable cap-less LDOs (1.5V) */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12,
+ VA33REFGEN_EN_VA18_MASK |
+ LCLDO_REMOTE_SENSE_VA18_MASK | LCLDO_EN_VA18_MASK |
+ HCLDO_REMOTE_SENSE_VA18_MASK | HCLDO_EN_VA18_MASK,
+ VA33REFGEN_EN_VA18_DISABLE |
+ LCLDO_REMOTE_SENSE_VA18_DISABLE | LCLDO_EN_VA18_DISABLE |
+ HCLDO_REMOTE_SENSE_VA18_DISABLE | HCLDO_EN_VA18_DISABLE);
+ /* Disable NCP */
+ regmap_update_bits(priv->regmap, MT6357_AUDNCP_CLKDIV_CON3, DIVCKS_PWD_NCP_MASK,
+ DIVCKS_PWD_NCP_DISABLE);
+ }
+}
+
+static int mt_audio_in_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+ dev_dbg(priv->dev, "%s(), event 0x%x\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ set_playback_gpio(priv, true);
+
+ /* Pull-down HPL/R to AVSS28_AUD */
+ if (priv->pull_down_needed)
+ hp_pull_down(priv, true);
+
+ /* Disable HP main CMFB Switch */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+ HPRL_MAIN_CMFB_LOOP_MASK, HPRL_MAIN_CMFB_LOOP_DISABLE);
+ /* Audio system digital clock power down release */
+ regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON2, CCI_AUDIO_FIFO_DISABLE |
+ CCI_ACD_MODE_NORMAL_PATH |
+ CCI_AFIFO_CLK_PWDB_ON |
+ CCI_ACD_FUNC_RSTB_RESET);
+ /* sdm audio fifo clock power on */
+ regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON0, CCI_AUD_ANACK_INVERT |
+ (4 << CCI_AUDIO_FIFO_WPTR_SFT) |
+ CCI_SCRAMBLER_CG_ENABLE |
+ CCI_RAND_ENABLE |
+ CCI_SPLT_SCRMB_CLK_ON |
+ CCI_SPLT_SCRMB_ON |
+ CCI_ZERO_PADDING_DISABLE |
+ CCI_SCRAMBLER_ENABLE);
+ /* scrambler clock on enable */
+ regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON2, CCI_AUDIO_FIFO_DISABLE |
+ CCI_ACD_MODE_TEST_PATH |
+ CCI_AFIFO_CLK_PWDB_ON |
+ CCI_ACD_FUNC_RSTB_RELEASE);
+ /* sdm power on */
+ regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON2, CCI_AUDIO_FIFO_ENABLE |
+ CCI_ACD_MODE_TEST_PATH |
+ CCI_AFIFO_CLK_PWDB_ON |
+ CCI_ACD_FUNC_RSTB_RELEASE);
+
+ configure_downlinks(priv, true);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ configure_downlinks(priv, false);
+ /* DL scrambler disabling sequence */
+ regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON2, CCI_AUDIO_FIFO_DISABLE |
+ CCI_ACD_MODE_TEST_PATH |
+ CCI_AFIFO_CLK_PWDB_DOWN |
+ CCI_ACD_FUNC_RSTB_RESET);
+ regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON0, CCI_AUD_ANACK_INVERT |
+ (4 << CCI_AUDIO_FIFO_WPTR_SFT) |
+ CCI_SCRAMBLER_CG_ENABLE |
+ CCI_RAND_ENABLE |
+ CCI_SPLT_SCRMB_CLK_ON |
+ CCI_SPLT_SCRMB_ON |
+ CCI_ZERO_PADDING_DISABLE |
+ CCI_SCRAMBLER_DISABLE);
+
+ set_playback_gpio(priv, false);
+
+ /* disable Pull-down HPL/R to AVSS28_AUD */
+ if (priv->pull_down_needed)
+ hp_pull_down(priv, false);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mt_delay_250_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+ dev_dbg(priv->dev, "%s(), event 0x%x\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(250, 270);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ usleep_range(250, 270);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int lol_mux_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+ dev_dbg(priv->dev, "%s(), event 0x%x\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /* Set LO STB enhance circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
+ AUD_LOLOUT_STB_ENH_VAUDP15_MASK,
+ AUD_LOLOUT_STB_ENH_VAUDP15_ENABLE);
+ /* Enable LO driver bias circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
+ AUD_LOL_PWRUP_BIAS_VAUDP15_MASK,
+ AUD_LOL_PWRUP_BIAS_VAUDP15_ENABLE);
+ /* Enable LO driver core circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
+ AUD_LOL_PWRUP_VAUDP15_MASK, AUD_LOL_PWRUP_VAUDP15_ENABLE);
+ /* Set LOL gain to normal gain step by step */
+ lo_volume_ramp(priv, DL_GAIN_N_40DB, priv->ana_gain[ANALOG_VOLUME_LINEOUTL],
+ DL_GAIN_N_40DB, priv->ana_gain[ANALOG_VOLUME_LINEOUTR]);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+
+ /* decrease LOL gain to minimum gain step by step */
+ lo_volume_ramp(priv, priv->ana_gain[ANALOG_VOLUME_LINEOUTL], DL_GAIN_N_40DB,
+ priv->ana_gain[ANALOG_VOLUME_LINEOUTR], DL_GAIN_N_40DB);
+ /* Disable LO driver core circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
+ AUD_LOL_PWRUP_VAUDP15_MASK, AUD_LOL_PWRUP_VAUDP15_DISABLE);
+ /* Disable LO driver bias circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
+ AUD_LOL_PWRUP_BIAS_VAUDP15_MASK,
+ AUD_LOL_PWRUP_BIAS_VAUDP15_DISABLE);
+ /* Clear LO STB enhance circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
+ AUD_LOLOUT_STB_ENH_VAUDP15_MASK,
+ AUD_LOLOUT_STB_ENH_VAUDP15_DISABLE);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int hs_mux_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+ dev_dbg(priv->dev, "%s(), event 0x%x\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+
+ /* Set HS STB enhance circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
+ AUD_HSOUT_STB_ENH_VAUDP15_MASK,
+ AUD_HSOUT_STB_ENH_VAUDP15_ENABLE);
+ /* Enable HS driver bias circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
+ AUD_HS_PWRUP_BIAS_VAUDP15_MASK,
+ AUD_HS_PWRUP_BIAS_VAUDP15_ENABLE);
+ /* Enable HS driver core circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
+ AUD_HS_PWRUP_VAUDP15_MASK, AUD_HS_PWRUP_VAUDP15_ENABLE);
+ /* Set HS gain to normal gain step by step */
+ hs_volume_ramp(priv, DL_GAIN_N_40DB, priv->ana_gain[ANALOG_VOLUME_HSOUT]);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+
+ /* decrease HS gain to minimum gain step by step */
+ hs_volume_ramp(priv, priv->ana_gain[ANALOG_VOLUME_HSOUT], DL_GAIN_N_40DB);
+ /* Disable HS driver core circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
+ AUD_HS_PWRUP_VAUDP15_MASK, AUD_HS_PWRUP_VAUDP15_DISABLE);
+ /* Disable HS driver bias circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
+ AUD_HS_PWRUP_BIAS_VAUDP15_MASK,
+ AUD_HS_PWRUP_BIAS_VAUDP15_ENABLE);
+ /* Clear HS STB enhance circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
+ AUD_HSOUT_STB_ENH_VAUDP15_MASK,
+ AUD_HSOUT_STB_ENH_VAUDP15_DISABLE);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int hp_main_mux_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+ dev_dbg(priv->dev, "%s(), event 0x%x\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ priv->hp_channel_number++;
+ if (priv->hp_channel_number > 1)
+ break;
+ /* Set HPP/N STB enhance circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON2,
+ HPROUT_STB_ENH_VAUDP15_MASK | HPLOUT_STB_ENH_VAUDP15_MASK,
+ HPROUT_STB_ENH_VAUDP15_N470_P250 |
+ HPLOUT_STB_ENH_VAUDP15_N470_P250);
+ /* Enable HP aux output stage */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ HPROUT_AUX_PWRUP_VAUDP15_MASK | HPLOUT_AUX_PWRUP_VAUDP15_MASK,
+ HPROUT_AUX_PWRUP_VAUDP15_ENABLE |
+ HPLOUT_AUX_PWRUP_VAUDP15_ENABLE);
+ /* Enable HP aux feedback loop */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ HPR_AUX_FBRSW_VAUDP15_MASK | HPL_AUX_FBRSW_VAUDP15_MASK,
+ HPR_AUX_FBRSW_VAUDP15_ENABLE | HPL_AUX_FBRSW_VAUDP15_ENABLE);
+ /* Enable HP aux CMFB loop */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+ HP_CMFB_RST_MASK |
+ HPL_AUX_CMFB_LOOP_MASK | HPR_AUX_CMFB_LOOP_MASK,
+ HP_CMFB_RST_NORMAL |
+ HPL_AUX_CMFB_LOOP_ENABLE | HPR_AUX_CMFB_LOOP_ENABLE);
+ /* Enable HP driver bias circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+ AUD_HPR_BIAS_VAUDP15_MASK | AUD_HPL_BIAS_VAUDP15_MASK,
+ AUD_HPR_BIAS_VAUDP15_ENABLE | AUD_HPL_BIAS_VAUDP15_ENABLE);
+ /* Enable HP driver core circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+ AUD_HPR_PWRUP_VAUDP15_MASK | AUD_HPL_PWRUP_VAUDP15_MASK,
+ AUD_HPR_PWRUP_VAUDP15_ENABLE | AUD_HPL_PWRUP_VAUDP15_ENABLE);
+ /* Short HP main output to HP aux output stage */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ HPR_SHORT2HPR_AUX_VAUDP15_MASK | HPL_SHORT2HPR_AUX_VAUDP15_MASK,
+ HPR_SHORT2HPR_AUX_VAUDP15_ENABLE |
+ HPL_SHORT2HPR_AUX_VAUDP15_ENABLE);
+ /* Enable HP main CMFB loop */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+ HPRL_MAIN_CMFB_LOOP_MASK, HPRL_MAIN_CMFB_LOOP_ENABLE);
+ /* Disable HP aux CMFB loop */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+ HPR_AUX_CMFB_LOOP_MASK | HPL_AUX_CMFB_LOOP_MASK,
+ HPR_AUX_CMFB_LOOP_DISABLE | HPL_AUX_CMFB_LOOP_DISABLE);
+ /* Enable HP main output stage */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ HPROUT_PWRUP_VAUDP15_MASK | HPLOUT_PWRUP_VAUDP15_MASK,
+ HPROUT_PWRUP_VAUDP15_ENABLE | HPLOUT_PWRUP_VAUDP15_ENABLE);
+ /* Enable HPR/L main output stage step by step */
+ hp_main_output_ramp(priv, true);
+ usleep_range(1000, 1200);
+ /* Reduce HP aux feedback loop gain */
+ hp_aux_feedback_loop_gain_ramp(priv, true);
+ /* Disable HP aux feedback loop */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ HPR_AUX_FBRSW_VAUDP15_MASK | HPL_AUX_FBRSW_VAUDP15_MASK,
+ HPR_AUX_FBRSW_VAUDP15_DISABLE | HPL_AUX_FBRSW_VAUDP15_DISABLE);
+ /* apply volume setting */
+ hp_volume_ramp(priv, DL_GAIN_N_40DB, priv->ana_gain[ANALOG_VOLUME_HPOUTL],
+ DL_GAIN_N_40DB, priv->ana_gain[ANALOG_VOLUME_HPOUTR]);
+ /* Disable HP aux output stage */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ HPROUT_AUX_PWRUP_VAUDP15_MASK | HPLOUT_AUX_PWRUP_VAUDP15_MASK,
+ HPROUT_AUX_PWRUP_VAUDP15_DISABLE |
+ HPLOUT_AUX_PWRUP_VAUDP15_DISABLE);
+ /* Unshort HP main output to HP aux output stage */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ HPR_SHORT2HPR_AUX_VAUDP15_MASK | HPL_SHORT2HPR_AUX_VAUDP15_MASK,
+ HPR_SHORT2HPR_AUX_VAUDP15_DISABLE |
+ HPL_SHORT2HPR_AUX_VAUDP15_DISABLE);
+ usleep_range(100, 120);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ priv->hp_channel_number--;
+ if (priv->hp_channel_number > 0)
+ break;
+ /* Short HP main output to HP aux output stage */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ HPR_SHORT2HPR_AUX_VAUDP15_MASK | HPL_SHORT2HPR_AUX_VAUDP15_MASK,
+ HPR_SHORT2HPR_AUX_VAUDP15_ENABLE |
+ HPL_SHORT2HPR_AUX_VAUDP15_ENABLE);
+ /* Enable HP aux output stage */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ HPROUT_AUX_PWRUP_VAUDP15_MASK | HPLOUT_AUX_PWRUP_VAUDP15_MASK,
+ HPROUT_AUX_PWRUP_VAUDP15_ENABLE |
+ HPLOUT_AUX_PWRUP_VAUDP15_ENABLE);
+ /* decrease HPL/R gain to normal gain step by step */
+ hp_volume_ramp(priv, priv->ana_gain[ANALOG_VOLUME_HPOUTL], DL_GAIN_N_40DB,
+ priv->ana_gain[ANALOG_VOLUME_HPOUTR], DL_GAIN_N_40DB);
+ /* Enable HP aux feedback loop */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ HPR_AUX_FBRSW_VAUDP15_MASK | HPL_AUX_FBRSW_VAUDP15_MASK,
+ HPR_AUX_FBRSW_VAUDP15_ENABLE | HPL_AUX_FBRSW_VAUDP15_ENABLE);
+ /* Reduce HP aux feedback loop gain */
+ hp_aux_feedback_loop_gain_ramp(priv, false);
+ /* decrease HPR/L main output stage step by step */
+ hp_main_output_ramp(priv, false);
+ /* Disable HP main output stage */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ HPROUT_PWRUP_VAUDP15_MASK | HPLOUT_PWRUP_VAUDP15_MASK,
+ HPROUT_PWRUP_VAUDP15_DISABLE | HPLOUT_PWRUP_VAUDP15_DISABLE);
+ /* Enable HP aux CMFB loop */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+ HP_CMFB_RST_MASK |
+ HPL_AUX_CMFB_LOOP_MASK | HPR_AUX_CMFB_LOOP_MASK,
+ HP_CMFB_RST_RESET |
+ HPL_AUX_CMFB_LOOP_ENABLE | HPR_AUX_CMFB_LOOP_ENABLE);
+ /* Disable HP main CMFB loop */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+ HPRL_MAIN_CMFB_LOOP_MASK, HPRL_MAIN_CMFB_LOOP_DISABLE);
+ /* Unshort HP main output to HP aux output stage */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ HPR_SHORT2HPR_AUX_VAUDP15_MASK | HPL_SHORT2HPR_AUX_VAUDP15_MASK,
+ HPR_SHORT2HPR_AUX_VAUDP15_DISABLE |
+ HPL_SHORT2HPR_AUX_VAUDP15_DISABLE);
+ /* Disable HP driver core circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+ AUD_HPR_PWRUP_VAUDP15_MASK | AUD_HPL_PWRUP_VAUDP15_MASK,
+ AUD_HPR_PWRUP_VAUDP15_DISABLE | AUD_HPL_PWRUP_VAUDP15_DISABLE);
+ /* Disable HP driver bias circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+ AUD_HPR_BIAS_VAUDP15_MASK | AUD_HPL_BIAS_VAUDP15_MASK,
+ AUD_HPR_BIAS_VAUDP15_DISABLE | AUD_HPL_BIAS_VAUDP15_DISABLE);
+ /* Disable HP aux CMFB loop,
+ * Enable HP main CMFB for HP off state
+ */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+ HPRL_MAIN_CMFB_LOOP_MASK |
+ HPR_AUX_CMFB_LOOP_MASK | HPL_AUX_CMFB_LOOP_MASK,
+ HPRL_MAIN_CMFB_LOOP_ENABLE |
+ HPR_AUX_CMFB_LOOP_DISABLE | HPL_AUX_CMFB_LOOP_DISABLE);
+ /* Disable HP aux feedback loop */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ HPR_AUX_FBRSW_VAUDP15_MASK | HPL_AUX_FBRSW_VAUDP15_MASK,
+ HPR_AUX_FBRSW_VAUDP15_DISABLE | HPL_AUX_FBRSW_VAUDP15_DISABLE);
+ /* Disable HP aux output stage */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ HPROUT_AUX_PWRUP_VAUDP15_MASK | HPLOUT_AUX_PWRUP_VAUDP15_MASK,
+ HPROUT_AUX_PWRUP_VAUDP15_DISABLE |
+ HPLOUT_AUX_PWRUP_VAUDP15_DISABLE);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int right_dac_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+ dev_dbg(priv->dev, "%s(), event 0x%x\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Enable Audio DAC and control audio bias gen */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+ AUD_DACR_PWRUP_VA28_MASK | AUD_DACR_PWRUP_VAUDP15_MASK,
+ AUD_DACR_PWRUP_VA28_ENABLE | AUD_DACR_PWRUP_VAUDP15_ENABLE);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /* disable Pull-down HPL/R to AVSS28_AUD */
+ if (priv->pull_down_needed)
+ hp_pull_down(priv, false);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ /* Pull-down HPL/R to AVSS28_AUD */
+ if (priv->pull_down_needed)
+ hp_pull_down(priv, true);
+ /* Disable Audio DAC and control audio bias gen */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+ AUD_DACR_PWRUP_VA28_MASK | AUD_DACR_PWRUP_VAUDP15_MASK,
+ AUD_DACR_PWRUP_VA28_DISABLE | AUD_DACR_PWRUP_VAUDP15_DISABLE);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int left_dac_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+ dev_dbg(priv->dev, "%s(), event 0x%x\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Enable Audio DAC and control audio bias gen */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+ AUD_DACL_PWRUP_VA28_MASK | AUD_DACL_PWRUP_VAUDP15_MASK,
+ AUD_DACL_PWRUP_VA28_ENABLE | AUD_DACL_PWRUP_VAUDP15_ENABLE);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /* disable Pull-down HPL/R to AVSS28_AUD */
+ if (priv->pull_down_needed)
+ hp_pull_down(priv, false);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ /* Pull-down HPL/R to AVSS28_AUD */
+ if (priv->pull_down_needed)
+ hp_pull_down(priv, true);
+ /* Disable Audio DAC and control audio bias gen */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+ AUD_DACL_PWRUP_VA28_MASK | AUD_DACL_PWRUP_VAUDP15_MASK,
+ AUD_DACL_PWRUP_VA28_DISABLE | AUD_DACL_PWRUP_VAUDP15_DISABLE);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* Supply widgets subsequence */
+enum {
+ /* common */
+ SUPPLY_SEQ_CLK_BUF,
+ SUPPLY_SEQ_AUD_GLB,
+ SUPPLY_SEQ_CLKSQ,
+ SUPPLY_SEQ_VOW_AUD_LPW,
+ SUPPLY_SEQ_AUD_VOW,
+ SUPPLY_SEQ_VOW_CLK,
+ SUPPLY_SEQ_VOW_LDO,
+ SUPPLY_SEQ_TOP_CK,
+ SUPPLY_SEQ_TOP_CK_LAST,
+ SUPPLY_SEQ_AUD_TOP,
+ SUPPLY_SEQ_AUD_TOP_LAST,
+ SUPPLY_SEQ_AFE,
+ /* capture */
+ SUPPLY_SEQ_ADC_SUPPLY,
+};
+
+/* DAPM Widgets */
+static const struct snd_soc_dapm_widget mt6357_dapm_widgets[] = {
+ /* Analog Clocks */
+ SND_SOC_DAPM_SUPPLY_S("CLK_BUF", SUPPLY_SEQ_CLK_BUF,
+ MT6357_DCXO_CW14,
+ XO_AUDIO_EN_M_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("AUDGLB", SUPPLY_SEQ_AUD_GLB,
+ MT6357_AUDDEC_ANA_CON11,
+ AUDGLB_PWRDN_VA28_SFT, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("CLKSQ Audio", SUPPLY_SEQ_CLKSQ,
+ MT6357_AUDENC_ANA_CON6,
+ CLKSQ_EN_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("AUDNCP_CK", SUPPLY_SEQ_TOP_CK,
+ MT6357_AUD_TOP_CKPDN_CON0,
+ AUDNCP_CK_PDN_SFT, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("ZCD13M_CK", SUPPLY_SEQ_TOP_CK,
+ MT6357_AUD_TOP_CKPDN_CON0,
+ ZCD13M_CK_PDN_SFT, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("AUD_CK", SUPPLY_SEQ_TOP_CK_LAST,
+ MT6357_AUD_TOP_CKPDN_CON0,
+ AUD_CK_PDN_SFT, 1,
+ mt_delay_250_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY_S("AUDIF_CK", SUPPLY_SEQ_TOP_CK,
+ MT6357_AUD_TOP_CKPDN_CON0,
+ AUDIF_CK_PDN_SFT, 1, NULL, 0),
+
+ /* Digital Clocks */
+ SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_AFE_CTL", SUPPLY_SEQ_AUD_TOP_LAST,
+ MT6357_AUDIO_TOP_CON0,
+ PDN_AFE_CTL_SFT, 1,
+ mt_delay_250_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_DAC_CTL", SUPPLY_SEQ_AUD_TOP,
+ MT6357_AUDIO_TOP_CON0,
+ PDN_DAC_CTL_SFT, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_ADC_CTL", SUPPLY_SEQ_AUD_TOP,
+ MT6357_AUDIO_TOP_CON0,
+ PDN_ADC_CTL_SFT, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_I2S_DL", SUPPLY_SEQ_AUD_TOP,
+ MT6357_AUDIO_TOP_CON0,
+ PDN_I2S_DL_CTL_SFT, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_PWR_CLK", SUPPLY_SEQ_AUD_TOP,
+ MT6357_AUDIO_TOP_CON0,
+ PWR_CLK_DIS_CTL_SFT, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_PDN_AFE_TESTMODEL", SUPPLY_SEQ_AUD_TOP,
+ MT6357_AUDIO_TOP_CON0,
+ PDN_AFE_TESTMODEL_CTL_SFT, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_PDN_RESERVED", SUPPLY_SEQ_AUD_TOP,
+ MT6357_AUDIO_TOP_CON0,
+ PDN_RESERVED_SFT, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_LPBK", SUPPLY_SEQ_AUD_TOP,
+ MT6357_AUDIO_TOP_CON0,
+ PDN_LPBK_CTL_SFT, 1, NULL, 0),
+
+ /* General */
+ SND_SOC_DAPM_SUPPLY_S("AFE_ON", SUPPLY_SEQ_AFE,
+ MT6357_AFE_UL_DL_CON0, AFE_ON_SFT, 0,
+ NULL, 0),
+
+ /* Uplinks */
+ SND_SOC_DAPM_AIF_OUT_E("AIF1TX", "MT6357 Capture", 0,
+ SND_SOC_NOPM, 0, 0,
+ mt_aif_out_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S("ADC Supply", SUPPLY_SEQ_ADC_SUPPLY,
+ SND_SOC_NOPM, 0, 0,
+ mt_adc_supply_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC", NULL, SND_SOC_NOPM, 0, 0, adc_enable_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("PGA L Mux", SND_SOC_NOPM, 0, 0,
+ &pga_left_mux_control,
+ mt_pga_left_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_MUX_E("PGA R Mux", SND_SOC_NOPM, 0, 0,
+ &pga_right_mux_control,
+ mt_pga_right_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_PGA("PGA L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("PGA R", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MUX_E("Mic Type Mux", SND_SOC_NOPM, 0, 0,
+ &mic_type_mux_control,
+ mt_mic_type_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("MICBIAS0", MT6357_AUDENC_ANA_CON8, AUD_MICBIAS0_PWD_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MICBIAS1", MT6357_AUDENC_ANA_CON9, AUD_MICBIAS1_PWD_SFT, 0, NULL, 0),
+
+ /* UL inputs */
+ SND_SOC_DAPM_INPUT("AIN0"),
+ SND_SOC_DAPM_INPUT("AIN1"),
+ SND_SOC_DAPM_INPUT("AIN2"),
+ SND_SOC_DAPM_INPUT("LPBK"),
+ SND_SOC_DAPM_INPUT("SGEN UL"),
+
+ /* Downlinks */
+ SND_SOC_DAPM_AIF_IN_E("AIF_RX", "MT6357 Playback", 0,
+ SND_SOC_NOPM, 0, 0,
+ mt_audio_in_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_INPUT("SGEN DL"),
+ SND_SOC_DAPM_MUX("DAC Mux", SND_SOC_NOPM, 0, 0, &dac_mux_control),
+
+ SND_SOC_DAPM_DAC_E("DACR", NULL, SND_SOC_NOPM, 0, 0, right_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_DAC_E("DACL", NULL, SND_SOC_NOPM, 0, 0, left_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_SUPPLY("DL Digital Supply", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DL Analog Supply", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DL SRC", MT6357_AFE_DL_SRC2_CON0_L,
+ DL_2_SRC_ON_TMP_CTL_PRE_SFT, 0, NULL, 0),
+
+ SND_SOC_DAPM_MUX_E("Line Out Source", SND_SOC_NOPM, 0, 0, &lo_mux_control,
+ lol_mux_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_MUX_E("Handset Source", SND_SOC_NOPM, 0, 0, &hs_mux_control,
+ hs_mux_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_MUX_E("Headphone Right Source", SND_SOC_NOPM, 0, 0, &hpr_mux_control,
+ hp_main_mux_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_MUX_E("Headphone Left Source", SND_SOC_NOPM, 0, 0, &hpl_mux_control,
+ hp_main_mux_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ /* DL outputs */
+ SND_SOC_DAPM_OUTPUT("Headphones"),
+ SND_SOC_DAPM_OUTPUT("Hansdet"),
+ SND_SOC_DAPM_OUTPUT("Line out"),
+
+ /* Sine generator */
+ SND_SOC_DAPM_SUPPLY("SGEN UL Enable",
+ MT6357_AFE_TOP_CON0, UL_SINE_ON_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("SGEN Enable",
+ MT6357_AFE_SGEN_CFG0,
+ SGEN_DAC_EN_CTL_SFT, 0, mt_audio_in_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("SGEN MUTE",
+ MT6357_AFE_SGEN_CFG0,
+ SGEN_MUTE_SW_CTL_SFT, 1, NULL, 0)
+};
+
+static const struct snd_soc_dapm_route mt6357_dapm_routes[] = {
+ /* Capture */
+ {"AIF1TX", NULL, "Mic Type Mux"},
+ {"AIF1TX", NULL, "CLK_BUF"},
+ {"AIF1TX", NULL, "AUDGLB"},
+ {"AIF1TX", NULL, "CLKSQ Audio"},
+ {"AIF1TX", NULL, "AUD_CK"},
+ {"AIF1TX", NULL, "AUDIF_CK"},
+
+ {"AIF1TX", NULL, "AUDIO_TOP_AFE_CTL"},
+ {"AIF1TX", NULL, "AUDIO_TOP_ADC_CTL"},
+ {"AIF1TX", NULL, "AUDIO_TOP_PWR_CLK"},
+ {"AIF1TX", NULL, "AUDIO_TOP_PDN_RESERVED"},
+ {"AIF1TX", NULL, "AUDIO_TOP_I2S_DL"},
+ {"AIF1TX", NULL, "AFE_ON"},
+
+ {"Mic Type Mux", "ACC", "ADC"},
+ {"Mic Type Mux", "DCC", "ADC"},
+ {"Mic Type Mux", "DCC_ECM_DIFF", "ADC"},
+ {"Mic Type Mux", "DCC_ECM_SINGLE", "ADC"},
+ {"Mic Type Mux", "DMIC", "AIN0"},
+ {"Mic Type Mux", "DMIC", "AIN2"},
+ {"Mic Type Mux", "Loopback", "LPBK"},
+ {"Mic Type Mux", "Sine Generator", "SGEN UL"},
+
+ {"SGEN UL", NULL, "AUDIO_TOP_PDN_AFE_TESTMODEL"},
+ {"SGEN UL", NULL, "SGEN UL Enable"},
+ {"SGEN UL", NULL, "SGEN MUTE"},
+ {"SGEN UL", NULL, "SGEN Enable"},
+
+ {"ADC", NULL, "PGA L Mux"},
+ {"ADC", NULL, "PGA R Mux"},
+ {"ADC", NULL, "ADC Supply"},
+
+ {"PGA L Mux", "AIN0", "AIN0"},
+ {"PGA L Mux", "AIN1", "AIN1"},
+ {"PGA L Mux", "AIN2", "AIN2"},
+
+ {"PGA R Mux", "AIN0", "AIN0"},
+ {"PGA R Mux", "AIN1", "AIN1"},
+ {"PGA R Mux", "AIN2", "AIN2"},
+
+ {"AIN0", NULL, "MICBIAS0"},
+ {"AIN1", NULL, "MICBIAS1"},
+ {"AIN2", NULL, "MICBIAS0"},
+ {"LPBK", NULL, "AUDIO_TOP_LPBK"},
+
+ /* Playback */
+ {"DAC Mux", "Normal Path", "AIF_RX"},
+ {"DAC Mux", "Sine Generator", "SGEN DL"},
+
+ {"AIF_RX", NULL, "DL SRC"},
+
+ {"SGEN DL", NULL, "DL SRC"},
+ {"SGEN DL", NULL, "SGEN MUTE"},
+ {"SGEN DL", NULL, "SGEN Enable"},
+ {"SGEN DL", NULL, "DL Digital Supply"},
+ {"SGEN DL", NULL, "AUDIO_TOP_PDN_AFE_TESTMODEL"},
+
+ {"DACL", NULL, "DAC Mux"},
+ {"DACR", NULL, "DAC Mux"},
+
+ {"DL Analog Supply", NULL, "CLK_BUF"},
+ {"DL Analog Supply", NULL, "AUDGLB"},
+ {"DL Analog Supply", NULL, "CLKSQ Audio"},
+ {"DL Analog Supply", NULL, "AUDNCP_CK"},
+ {"DL Analog Supply", NULL, "ZCD13M_CK"},
+ {"DL Analog Supply", NULL, "AUD_CK"},
+ {"DL Analog Supply", NULL, "AUDIF_CK"},
+
+ {"DL Digital Supply", NULL, "AUDIO_TOP_AFE_CTL"},
+ {"DL Digital Supply", NULL, "AUDIO_TOP_DAC_CTL"},
+ {"DL Digital Supply", NULL, "AUDIO_TOP_PWR_CLK"},
+ {"DL Digital Supply", NULL, "AFE_ON"},
+
+ {"DACR", NULL, "DL Digital Supply"},
+ {"DACR", NULL, "DL Analog Supply"},
+ {"DACL", NULL, "DL Digital Supply"},
+ {"DACL", NULL, "DL Analog Supply"},
+
+ {"Line Out Source", "DACR", "DACR"},
+ {"Line Out Source", "Playback", "DACL"},
+ {"Line Out Source", "Test mode", "DACL"},
+
+ {"Handset Source", "DACR", "DACR"},
+ {"Handset Source", "Playback", "DACL"},
+ {"Handset Source", "Test mode", "DACL"},
+
+ {"Headphone Right Source", "DAC", "DACR"},
+ {"Headphone Right Source", "Line Out", "Line Out Source"},
+ {"Headphone Right Source", "Handset", "Handset Source"},
+
+ {"Headphone Left Source", "DAC", "DACL"},
+ {"Headphone Left Source", "Line Out", "Line Out Source"},
+ {"Headphone Left Source", "Handset", "Handset Source"},
+
+ {"Line out", NULL, "Line Out Source"},
+ {"Hansdet", NULL, "Handset Source"},
+
+ {"Headphones", NULL, "Headphone Right Source"},
+ {"Headphones", NULL, "Headphone Left Source"},
+};
+
+static struct snd_soc_dai_driver mtk_6357_dai_codecs[] = {
+ {
+ .name = "mt6357-snd-codec-aif1",
+ .playback = {
+ .stream_name = "MT6357 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SND_SOC_ADV_MT_FMTS,
+ },
+ .capture = {
+ .stream_name = "MT6357 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SOC_HIGH_USE_RATE,
+ .formats = SND_SOC_ADV_MT_FMTS,
+ },
+ },
+};
+
+static void mt6357_codec_init(struct mt6357_priv *priv)
+{
+ /* Enable audio part */
+ regmap_update_bits(priv->regmap, MT6357_DCXO_CW14,
+ XO_AUDIO_EN_M_MASK, XO_AUDIO_EN_M_ENABLE);
+ /* Disable HeadphoneL/HeadphoneR short circuit protection */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+ AUD_HPR_SC_VAUDP15_MASK | AUD_HPL_SC_VAUDP15_MASK,
+ AUD_HPR_SC_VAUDP15_DISABLE | AUD_HPL_SC_VAUDP15_DISABLE);
+ /* Disable voice short circuit protection */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
+ AUD_HS_SC_VAUDP15_MASK, AUD_HS_SC_VAUDP15_DISABLE);
+ /* disable LO buffer left short circuit protection */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
+ AUD_LOL_SC_VAUDP15_MASK, AUD_LOL_SC_VAUDP15_DISABLE);
+ /* set gpio */
+ set_playback_gpio(priv, false);
+ set_capture_gpio(priv, false);
+ /* Disable audio part */
+ regmap_update_bits(priv->regmap, MT6357_DCXO_CW14,
+ XO_AUDIO_EN_M_MASK, XO_AUDIO_EN_M_DISABLE);
+
+ /* gain default values*/
+ priv->ana_gain[ANALOG_VOLUME_MIC1] = UL_GAIN_0DB;
+ priv->ana_gain[ANALOG_VOLUME_MIC2] = UL_GAIN_0DB;
+ priv->ana_gain[ANALOG_VOLUME_HPOUTR] = DL_GAIN_0DB;
+ priv->ana_gain[ANALOG_VOLUME_HSOUT] = DL_GAIN_0DB;
+}
+
+static int mt6357_codec_probe(struct snd_soc_component *codec)
+{
+ struct mt6357_priv *priv = snd_soc_component_get_drvdata(codec);
+
+ mt6357_codec_init(priv);
+ return 0;
+}
+
+static unsigned int mt6357_read(struct snd_soc_component *codec, unsigned int reg)
+{
+ struct mt6357_priv *priv = snd_soc_component_get_drvdata(codec);
+ unsigned int val;
+
+ pr_debug("%s() reg = 0x%x", __func__, reg);
+ regmap_read(priv->regmap, reg, &val);
+ return val;
+}
+
+static int mt6357_write(struct snd_soc_component *codec, unsigned int reg, unsigned int value)
+{
+ struct mt6357_priv *priv = snd_soc_component_get_drvdata(codec);
+
+ pr_debug("%s() reg = 0x%x value= 0x%x\n", __func__, reg, value);
+ regmap_update_bits(priv->regmap, reg, 0xffff, value);
+ return 0;
+}
+
+static const struct snd_soc_component_driver mt6357_soc_component_driver = {
+ .probe = mt6357_codec_probe,
+ .read = mt6357_read,
+ .write = mt6357_write,
+ .controls = mt6357_controls,
+ .num_controls = ARRAY_SIZE(mt6357_controls),
+ .dapm_widgets = mt6357_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt6357_dapm_widgets),
+ .dapm_routes = mt6357_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(mt6357_dapm_routes),
+};
+
+static void mt6357_parse_dt(struct mt6357_priv *priv)
+{
+ int ret, voltage_index;
+ u32 micbias_voltage_index = 0;
+ struct device *dev = priv->dev;
+
+ priv->pull_down_needed = false;
+ if (of_property_read_bool(dev->of_node, "mediatek,hp-pull-down"))
+ priv->pull_down_needed = true;
+
+ micbias_voltage_index = MT6357_MICBIAS0_DEFAULT_VOLTAGE_INDEX;
+ ret = of_property_read_u32(dev->of_node, "mediatek,micbias0-microvolt", &voltage_index);
+ if (!ret)
+ micbias_voltage_index = voltage_index;
+
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON8, AUD_MICBIAS0_VREF_MASK,
+ micbias_voltage_index << AUD_MICBIAS0_VREF_SFT);
+
+ micbias_voltage_index = MT6357_MICBIAS1_DEFAULT_VOLTAGE_INDEX;
+ ret = of_property_read_u32(dev->of_node, "mediatek,micbias1-microvolt", &voltage_index);
+ if (!ret)
+ micbias_voltage_index = voltage_index;
+
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON9, AUD_MICBIAS1_VREF_MASK,
+ micbias_voltage_index << AUD_MICBIAS1_VREF_SFT);
+}
+
+static int mt6357_platform_driver_probe(struct platform_device *pdev)
+{
+ struct mt6357_priv *priv;
+ struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent);
+ int ret;
+
+ ret = devm_regulator_get_enable(&pdev->dev, "vaud28");
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "failed to enable vaud28 regulator\n");
+
+ priv = devm_kzalloc(&pdev->dev,
+ sizeof(struct mt6357_priv),
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev_set_drvdata(&pdev->dev, priv);
+ priv->dev = &pdev->dev;
+
+ priv->regmap = mt6397->regmap;
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+ mt6357_parse_dt(priv);
+
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(64);
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+
+ return devm_snd_soc_register_component(&pdev->dev,
+ &mt6357_soc_component_driver,
+ mtk_6357_dai_codecs,
+ ARRAY_SIZE(mtk_6357_dai_codecs));
+}
+
+static const struct of_device_id mt6357_of_match[] = {
+ {.compatible = "mediatek,mt6357-sound",},
+ {}
+};
+MODULE_DEVICE_TABLE(of, mt6357_of_match);
+
+static struct platform_driver mt6357_platform_driver = {
+ .driver = {
+ .name = "mt6357-sound",
+ .of_match_table = mt6357_of_match,
+ },
+ .probe = mt6357_platform_driver_probe,
+};
+
+module_platform_driver(mt6357_platform_driver)
+
+MODULE_DESCRIPTION("MT6357 ALSA SoC codec driver");
+MODULE_AUTHOR("Nicolas Belin <[email protected]>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/mt6357.h b/sound/soc/codecs/mt6357.h
new file mode 100644
index 000000000000..9d55f2f97a1d
--- /dev/null
+++ b/sound/soc/codecs/mt6357.h
@@ -0,0 +1,674 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt6357.h -- mt6357 ALSA SoC audio codec driver
+ *
+ * Copyright (c) 2024 Baylibre
+ * Author: Nicolas Belin <[email protected]>
+ */
+
+#ifndef __MT6357_H__
+#define __MT6357_H__
+
+#include <linux/types.h>
+
+/* Reg bit defines */
+/* MT6357_GPIO_DIR0 */
+#define GPIO8_DIR_MASK BIT(8)
+#define GPIO8_DIR_INPUT 0
+#define GPIO8_DIR_OUTPUT BIT(8)
+#define GPIO9_DIR_MASK BIT(9)
+#define GPIO9_DIR_INPUT 0
+#define GPIO9_DIR_OUTPUT BIT(9)
+#define GPIO10_DIR_MASK BIT(10)
+#define GPIO10_DIR_INPUT 0
+#define GPIO10_DIR_OUTPUT BIT(10)
+#define GPIO11_DIR_MASK BIT(11)
+#define GPIO11_DIR_INPUT 0
+#define GPIO11_DIR_OUTPUT BIT(11)
+#define GPIO12_DIR_MASK BIT(12)
+#define GPIO12_DIR_INPUT 0
+#define GPIO12_DIR_OUTPUT BIT(12)
+#define GPIO13_DIR_MASK BIT(13)
+#define GPIO13_DIR_INPUT 0
+#define GPIO13_DIR_OUTPUT BIT(13)
+#define GPIO14_DIR_MASK BIT(14)
+#define GPIO14_DIR_INPUT 0
+#define GPIO14_DIR_OUTPUT BIT(14)
+#define GPIO15_DIR_MASK BIT(15)
+#define GPIO15_DIR_INPUT 0
+#define GPIO15_DIR_OUTPUT BIT(15)
+
+/* MT6357_GPIO_MODE2 */
+#define GPIO8_MODE_MASK GENMASK(2, 0)
+#define GPIO8_MODE_AUD_CLK_MOSI BIT(0)
+#define GPIO8_MODE_GPIO 0
+#define GPIO9_MODE_MASK GENMASK(5, 3)
+#define GPIO9_MODE_AUD_DAT_MOSI0 BIT(3)
+#define GPIO9_MODE_GPIO 0
+#define GPIO10_MODE_MASK GENMASK(8, 6)
+#define GPIO10_MODE_AUD_DAT_MOSI1 BIT(6)
+#define GPIO10_MODE_GPIO 0
+#define GPIO11_MODE_MASK GENMASK(11, 9)
+#define GPIO11_MODE_AUD_SYNC_MOSI BIT(9)
+#define GPIO11_MODE_GPIO 0
+
+/* MT6357_GPIO_MODE2_SET */
+#define GPIO8_MODE_SET_MASK GENMASK(2, 0)
+#define GPIO8_MODE_SET_AUD_CLK_MOSI BIT(0)
+#define GPIO9_MODE_SET_MASK GENMASK(5, 3)
+#define GPIO9_MODE_SET_AUD_DAT_MOSI0 BIT(3)
+#define GPIO10_MODE_SET_MASK GENMASK(8, 6)
+#define GPIO10_MODE_SET_AUD_DAT_MOSI1 BIT(6)
+#define GPIO11_MODE_SET_MASK GENMASK(11, 9)
+#define GPIO11_MODE_SET_AUD_SYNC_MOSI BIT(9)
+
+/* MT6357_GPIO_MODE2_CLR */
+#define GPIO_MODE2_CLEAR_ALL GENMASK(15, 0)
+
+/* MT6357_GPIO_MODE3 */
+#define GPIO12_MODE_MASK GENMASK(2, 0)
+#define GPIO12_MODE_AUD_CLK_MISO BIT(0)
+#define GPIO12_MODE_GPIO 0
+#define GPIO13_MODE_MASK GENMASK(5, 3)
+#define GPIO13_MODE_AUD_DAT_MISO0 BIT(3)
+#define GPIO13_MODE_GPIO 0
+#define GPIO14_MODE_MASK GENMASK(8, 6)
+#define GPIO14_MODE_AUD_DAT_MISO1 BIT(6)
+#define GPIO14_MODE_GPIO 0
+#define GPIO15_MODE_MASK GENMASK(11, 9)
+#define GPIO15_MODE_AUD_SYNC_MISO BIT(9)
+#define GPIO15_MODE_GPIO 0
+
+/* MT6357_GPIO_MODE3_SET */
+#define GPIO12_MODE_SET_MASK GENMASK(2, 0)
+#define GPIO12_MODE_SET_AUD_CLK_MISO BIT(0)
+#define GPIO13_MODE_SET_MASK GENMASK(5, 3)
+#define GPIO13_MODE_SET_AUD_DAT_MISO0 BIT(3)
+#define GPIO14_MODE_SET_MASK GENMASK(8, 6)
+#define GPIO14_MODE_SET_AUD_DAT_MISO1 BIT(6)
+#define GPIO15_MODE_SET_MASK GENMASK(11, 9)
+#define GPIO15_MODE_SET_AUD_SYNC_MISO BIT(9)
+
+/* MT6357_GPIO_MODE3_CLR */
+#define GPIO_MODE3_CLEAR_ALL GENMASK(15, 0)
+
+/* MT6357_DCXO_CW14 */
+#define XO_AUDIO_EN_M_SFT 13
+#define XO_AUDIO_EN_M_MASK BIT(13)
+#define XO_AUDIO_EN_M_ENABLE BIT(13)
+#define XO_AUDIO_EN_M_DISABLE 0
+
+/* MT6357_AUD_TOP_CKPDN_CON0 */
+#define AUDNCP_CK_PDN_SFT 6
+#define ZCD13M_CK_PDN_SFT 5
+#define AUDIF_CK_PDN_SFT 2
+#define AUD_CK_PDN_SFT 1
+
+/* MT6357_AUDNCP_CLKDIV_CON0 */
+#define DIVCKS_CHG BIT(0)
+
+/* MT6357_AUDNCP_CLKDIV_CON1 */
+#define DIVCKS_ON BIT(0)
+
+/* MT6357_AUDNCP_CLKDIV_CON3 */
+#define DIVCKS_PWD_NCP_MASK BIT(0)
+#define DIVCKS_PWD_NCP_DISABLE BIT(0)
+#define DIVCKS_PWD_NCP_ENABLE 0
+
+/* MT6357_AUDNCP_CLKDIV_CON4 */
+#define DIVCKS_PWD_NCP_ST_SEL_MASK GENMASK(1, 0)
+#define DIVCKS_PWD_NCP_ST_50US 0
+#define DIVCKS_PWD_NCP_ST_100US 1
+#define DIVCKS_PWD_NCP_ST_150US 2
+#define DIVCKS_PWD_NCP_ST_200US 3
+
+/* MT6357_AFE_UL_DL_CON0 */
+#define AFE_UL_LR_SWAP_SFT 15
+#define AFE_ON_SFT 0
+
+/* MT6357_AFE_DL_SRC2_CON0_L */
+#define DL_2_SRC_ON_TMP_CTL_PRE_SFT 0
+
+/* MT6357_AFE_UL_SRC_CON0_H */
+#define C_TWO_DIGITAL_MIC_CTL_MASK BIT(7)
+#define C_TWO_DIGITAL_MIC_ENABLE BIT(7)
+#define C_TWO_DIGITAL_MIC_DISABLE 0
+
+/* MT6357_AFE_UL_SRC_CON0_L */
+#define UL_SDM_3_LEVEL_CTL_MASK BIT(1)
+#define UL_SDM_3_LEVEL_SELECT BIT(1)
+#define UL_SDM_3_LEVEL_DESELECT 0
+#define UL_SRC_ON_TMP_CTL_MASK BIT(0)
+#define UL_SRC_ENABLE BIT(0)
+#define UL_SRC_DISABLE 0
+
+/* MT6357_AFE_TOP_CON0 */
+#define UL_SINE_ON_SFT 1
+#define UL_SINE_ON_MASK BIT(1)
+#define DL_SINE_ON_SFT 0
+#define DL_SINE_ON_MASK BIT(0)
+
+/* MT6357_AUDIO_TOP_CON0 */
+#define PDN_LPBK_CTL_SFT 15
+#define PDN_AFE_CTL_SFT 7
+#define PDN_DAC_CTL_SFT 6
+#define PDN_ADC_CTL_SFT 5
+#define PDN_I2S_DL_CTL_SFT 3
+#define PWR_CLK_DIS_CTL_SFT 2
+#define PDN_AFE_TESTMODEL_CTL_SFT 1
+#define PDN_RESERVED_SFT 0
+
+/* MT6357_AFUNC_AUD_CON0 */
+#define CCI_AUD_ANACK_INVERT BIT(15)
+#define CCI_AUD_ANACK_NORMAL 0
+#define CCI_AUDIO_FIFO_WPTR_SFT 12
+#define CCI_SCRAMBLER_CG_ENABLE BIT(11)
+#define CCI_SCRAMBLER_CG_DISABLE 0
+#define CCI_LCK_INV_OUT_OF_PHASE BIT(10)
+#define CCI_LCK_INV_IN_PHASE 0
+#define CCI_RAND_ENABLE BIT(9)
+#define CCI_RAND_DISABLE 0
+#define CCI_SPLT_SCRMB_CLK_ON BIT(8)
+#define CCI_SPLT_SCRMB_CLK_OFF 0
+#define CCI_SPLT_SCRMB_ON BIT(7)
+#define CCI_SPLT_SCRMB_OFF 0
+#define CCI_AUD_IDAC_TEST_EN_FROM_TEST_IN BIT(6)
+#define CCI_AUD_IDAC_TEST_EN_NORMAL_PATH 0
+#define CCI_ZERO_PADDING_DISABLE BIT(5)
+#define CCI_ZERO_PADDING_ENABLE 0
+#define CCI_AUD_SPLIT_TEST_EN_FROM_TEST_IN BIT(4)
+#define CCI_AUD_SPLIT_TEST_EN_NORMAL_PATH 0
+#define CCI_AUD_SDM_MUTE_L_REG_CTL BIT(3)
+#define CCI_AUD_SDM_MUTE_L_NO_CTL 0
+#define CCI_AUD_SDM_MUTE_R_REG_CTL BIT(2)
+#define CCI_AUD_SDM_MUTE_R_NO_CTL 0
+#define CCI_AUD_SDM_7BIT_FROM_SPLITTER3 BIT(1)
+#define CCI_AUD_SDM_7BIT_FROM_SPLITTER1 0
+#define CCI_SCRAMBLER_ENABLE BIT(0)
+#define CCI_SCRAMBLER_DISABLE 0
+
+/* MT6357_AFUNC_AUD_CON2 */
+#define CCI_AUDIO_FIFO_ENABLE BIT(3)
+#define CCI_AUDIO_FIFO_DISABLE 0
+#define CCI_ACD_MODE_NORMAL_PATH BIT(2)
+#define CCI_ACD_MODE_TEST_PATH 0
+#define CCI_AFIFO_CLK_PWDB_ON BIT(1)
+#define CCI_AFIFO_CLK_PWDB_DOWN 0
+#define CCI_ACD_FUNC_RSTB_RELEASE BIT(0)
+#define CCI_ACD_FUNC_RSTB_RESET 0
+
+/* MT6357_AFE_ADDA_MTKAIF_CFG0 */
+#define ADDA_MTKAIF_LPBK_CTL_MASK BIT(1)
+#define ADDA_MTKAIF_LPBK_ENABLE BIT(1)
+#define ADDA_MTKAIF_LPBK_DISABLE 0
+
+/* MT6357_AFE_SGEN_CFG0 */
+#define SGEN_DAC_EN_CTL_SFT 7
+#define SGEN_DAC_ENABLE BIT(7)
+#define SGEN_MUTE_SW_CTL_SFT 6
+#define SGEN_MUTE_SW_DISABLE 0
+
+/* MT6357_AFE_DCCLK_CFG0 */
+#define DCCLK_DIV_MASK GENMASK(15, 5)
+#define DCCLK_DIV_SFT 5
+#define DCCLK_DIV_RUN_VALUE (32 << DCCLK_DIV_SFT)
+#define DCCLK_DIV_STOP_VALUE (259 << DCCLK_DIV_SFT)
+#define DCCLK_PDN_MASK BIT(1)
+#define DCCLK_PDN BIT(1)
+#define DCCLK_OUTPUT 0
+#define DCCLK_GEN_ON_MASK BIT(0)
+#define DCCLK_GEN_ON BIT(0)
+#define DCCLK_GEN_OFF 0
+
+/* MT6357_AFE_DCCLK_CFG1 */
+#define DCCLK_RESYNC_BYPASS_MASK BIT(8)
+#define DCCLK_RESYNC_BYPASS BIT(8)
+
+/* MT6357_AFE_AUD_PAD_TOP */
+#define AUD_PAD_TX_FIFO_NORMAL_PATH_MASK GENMASK(15, 8)
+#define AUD_PAD_TX_FIFO_NORMAL_PATH_ENABLE (BIT(13) | BIT(12) | BIT(8))
+#define AUD_PAD_TX_FIFO_NORMAL_PATH_DISABLE (BIT(13) | BIT(12))
+#define AUD_PAD_TX_FIFO_LPBK_MASK GENMASK(7, 0)
+#define AUD_PAD_TX_FIFO_LPBK_ENABLE (BIT(5) | BIT(4) | BIT(0))
+#define AUD_PAD_TX_FIFO_LPBK_DISABLE 0
+
+/* MT6357_AUDENC_ANA_CON0 */
+#define AUDADCLINPUTSEL_MASK GENMASK(14, 13)
+#define AUDADCLINPUTSEL_PREAMPLIFIER BIT(14)
+#define AUDADCLINPUTSEL_IDLE 0
+#define AUDADCLPWRUP_SFT 12
+#define AUDADCLPWRUP_MASK BIT(12)
+#define AUDADCLPWRUP BIT(12)
+#define AUDADCLPWRDOWN 0
+#define AUDPREAMPLGAIN_SFT 8
+#define AUDPREAMPLGAIN_MASK GENMASK(10, 8)
+#define AUDPREAMPLGAIN_MAX 4
+#define AUDPREAMPLINPUTSEL_SFT 6
+#define AUDPREAMPLINPUTSEL_MASK_NOSFT GENMASK(1, 0)
+#define AUDPREAMPLDCPRECHARGE_MASK BIT(2)
+#define AUDPREAMPLDCPRECHARGE_ENABLE BIT(2)
+#define AUDPREAMPLDCPRECHARGE_DISABLE 0
+#define AUDPREAMPLDCCEN_MASK BIT(1)
+#define AUDPREAMPLDCCEN_DC BIT(1)
+#define AUDPREAMPLDCCEN_AC 0
+#define AUDPREAMPLON_MASK BIT(0)
+#define AUDPREAMPLON_ENABLE BIT(0)
+#define AUDPREAMPLON_DISABLE 0
+
+/* MT6357_AUDENC_ANA_CON1 */
+#define AUDADCRINPUTSEL_MASK GENMASK(14, 13)
+#define AUDADCRINPUTSEL_PREAMPLIFIER BIT(14)
+#define AUDADCRINPUTSEL_IDLE 0
+#define AUDADCRPWRUP_SFT 12
+#define AUDADCRPWRUP_MASK BIT(12)
+#define AUDADCRPWRUP BIT(12)
+#define AUDADCRPWRDOWN 0
+#define AUDPREAMPRGAIN_SFT 8
+#define AUDPREAMPRGAIN_MASK GENMASK(10, 8)
+#define AUDPREAMPRGAIN_MAX 4
+#define AUDPREAMPRINPUTSEL_SFT 6
+#define AUDPREAMPRINPUTSEL_MASK_NOSFT GENMASK(1, 0)
+#define AUDPREAMPRDCPRECHARGE_MASK BIT(2)
+#define AUDPREAMPRDCPRECHARGE_ENABLE BIT(2)
+#define AUDPREAMPRDCPRECHARGE_DISABLE 0
+#define AUDPREAMPRDCCEN_MASK BIT(1)
+#define AUDPREAMPRDCCEN_DC BIT(1)
+#define AUDPREAMPRDCCEN_AC 0
+#define AUDPREAMPRON_MASK BIT(0)
+#define AUDPREAMPRON_ENABLE BIT(0)
+#define AUDPREAMPRON_DISABLE 0
+
+/* MT6357_AUDENC_ANA_CON6 */
+#define CLKSQ_EN_SFT 0
+
+/* MT6357_AUDENC_ANA_CON7 */
+#define AUDDIGMICBIAS_MASK GENMASK(2, 1)
+#define AUDDIGMICBIAS_DEFAULT_VALUE BIT(2)
+#define AUDDIGMICBIAS_OFF 0
+#define AUDDIGMICEN_MASK BIT(0)
+#define AUDDIGMICEN_ENABLE BIT(0)
+#define AUDDIGMICEN_DISABLE 0
+
+/* MT6357_AUDENC_ANA_CON8 */
+#define AUD_MICBIAS0_DCSW2N_EN_MASK BIT(14)
+#define AUD_MICBIAS0_DCSW2N_ENABLE BIT(14)
+#define AUD_MICBIAS0_DCSW2N_DISABLE 0
+#define AUD_MICBIAS0_DCSW2P2_EN_MASK BIT(13)
+#define AUD_MICBIAS0_DCSW2P2_ENABLE BIT(13)
+#define AUD_MICBIAS0_DCSW2P2_DISABLE 0
+#define AUD_MICBIAS0_DCSW2P1_EN_MASK BIT(12)
+#define AUD_MICBIAS0_DCSW2P1_ENABLE BIT(12)
+#define AUD_MICBIAS0_DCSW2P1_DISABLE 0
+#define AUD_MICBIAS0_DCSW0N_EN_MASK BIT(10)
+#define AUD_MICBIAS0_DCSW0N_ENABLE BIT(10)
+#define AUD_MICBIAS0_DCSWN_DISABLE 0
+#define AUD_MICBIAS0_DCSW0P2_EN_MASK BIT(9)
+#define AUD_MICBIAS0_DCSW0P2_ENABLE BIT(9)
+#define AUD_MICBIAS0_DCSW0P2_DISABLE 0
+#define AUD_MICBIAS0_DCSW0P1_EN_MASK BIT(8)
+#define AUD_MICBIAS0_DCSW0P1_ENABLE BIT(8)
+#define AUD_MICBIAS0_DCSW0P1_DISABLE 0
+#define AUD_MICBIAS0_VREF_MASK GENMASK(6, 4)
+#define AUD_MICBIAS0_VREF_SFT 4
+#define AUD_MICBIAS0_PWD_SFT 0
+
+#define AUD_MICBIAS0_DC_MASK (AUD_MICBIAS0_DCSW2N_EN_MASK | \
+ AUD_MICBIAS0_DCSW2P2_EN_MASK | \
+ AUD_MICBIAS0_DCSW2P1_EN_MASK | \
+ AUD_MICBIAS0_DCSW0N_EN_MASK | \
+ AUD_MICBIAS0_DCSW0P2_EN_MASK | \
+ AUD_MICBIAS0_DCSW0P1_EN_MASK)
+
+#define AUD_MICBIAS0_DC_ENABLE_ALL (AUD_MICBIAS0_DCSW2N_ENABLE | \
+ AUD_MICBIAS0_DCSW2P2_ENABLE | \
+ AUD_MICBIAS0_DCSW2P1_ENABLE | \
+ AUD_MICBIAS0_DCSW0N_ENABLE | \
+ AUD_MICBIAS0_DCSW0P2_ENABLE | \
+ AUD_MICBIAS0_DCSW0P1_ENABLE)
+
+#define AUD_MICBIAS0_DC_ENABLE_P1 (AUD_MICBIAS0_DCSW2P1_ENABLE | \
+ AUD_MICBIAS0_DCSW0P1_ENABLE)
+
+#define AUD_MICBIAS0_DC_DISABLE_ALL 0
+
+/* MT6357_AUDENC_ANA_CON9 */
+#define AUD_MICBIAS1_DCSW1P_EN_MASK BIT(8)
+#define AUD_MICBIAS1_DCSW1P_ENABLE BIT(8)
+#define AUD_MICBIAS1_DCSW1P_DISABLE 0
+#define AUD_MICBIAS1_VREF_MASK GENMASK(6, 4)
+#define AUD_MICBIAS1_VREF_SFT 4
+#define AUD_MICBIAS1_PWD_SFT 0
+
+/* MT6357_AUDDEC_ANA_CON0 */
+#define AUD_HPR_SC_VAUDP15_MASK BIT(13)
+#define AUD_HPR_SC_VAUDP15_DISABLE BIT(13)
+#define AUD_HPR_SC_VAUDP15_ENABLE 0
+#define AUD_HPL_SC_VAUDP15_MASK BIT(12)
+#define AUD_HPL_SC_VAUDP15_DISABLE BIT(12)
+#define AUD_HPL_SC_VAUDP15_ENABLE 0
+#define AUD_HPR_MUX_INPUT_VAUDP15_MASK_NOSFT GENMASK(1, 0)
+#define AUD_HPR_MUX_INPUT_VAUDP15_SFT 10
+#define AUD_HPL_MUX_INPUT_VAUDP15_MASK_NOSFT GENMASK(1, 0)
+#define AUD_HPL_MUX_INPUT_VAUDP15_SFT 8
+#define AUD_HPR_BIAS_VAUDP15_MASK BIT(7)
+#define AUD_HPR_BIAS_VAUDP15_ENABLE BIT(7)
+#define AUD_HPR_BIAS_VAUDP15_DISABLE 0
+#define AUD_HPL_BIAS_VAUDP15_MASK BIT(6)
+#define AUD_HPL_BIAS_VAUDP15_ENABLE BIT(6)
+#define AUD_HPL_BIAS_VAUDP15_DISABLE 0
+#define AUD_HPR_PWRUP_VAUDP15_MASK BIT(5)
+#define AUD_HPR_PWRUP_VAUDP15_ENABLE BIT(5)
+#define AUD_HPR_PWRUP_VAUDP15_DISABLE 0
+#define AUD_HPL_PWRUP_VAUDP15_MASK BIT(4)
+#define AUD_HPL_PWRUP_VAUDP15_ENABLE BIT(4)
+#define AUD_HPL_PWRUP_VAUDP15_DISABLE 0
+#define AUD_DACL_PWRUP_VA28_MASK BIT(3)
+#define AUD_DACL_PWRUP_VA28_ENABLE BIT(3)
+#define AUD_DACL_PWRUP_VA28_DISABLE 0
+#define AUD_DACR_PWRUP_VA28_MASK BIT(2)
+#define AUD_DACR_PWRUP_VA28_ENABLE BIT(2)
+#define AUD_DACR_PWRUP_VA28_DISABLE 0
+#define AUD_DACR_PWRUP_VAUDP15_MASK BIT(1)
+#define AUD_DACR_PWRUP_VAUDP15_ENABLE BIT(1)
+#define AUD_DACR_PWRUP_VAUDP15_DISABLE 0
+#define AUD_DACL_PWRUP_VAUDP15_MASK BIT(0)
+#define AUD_DACL_PWRUP_VAUDP15_ENABLE BIT(0)
+#define AUD_DACL_PWRUP_VAUDP15_DISABLE 0
+
+/* MT6357_AUDDEC_ANA_CON1 */
+#define HPROUT_STG_CTRL_VAUDP15_MASK GENMASK(14, 12)
+#define HPROUT_STG_CTRL_VAUDP15_SFT 12
+#define HPLOUT_STG_CTRL_VAUDP15_MASK GENMASK(10, 8)
+#define HPLOUT_STG_CTRL_VAUDP15_SFT 8
+#define HPR_SHORT2HPR_AUX_VAUDP15_MASK BIT(7)
+#define HPR_SHORT2HPR_AUX_VAUDP15_ENABLE BIT(7)
+#define HPR_SHORT2HPR_AUX_VAUDP15_DISABLE 0
+#define HPL_SHORT2HPR_AUX_VAUDP15_MASK BIT(6)
+#define HPL_SHORT2HPR_AUX_VAUDP15_ENABLE BIT(6)
+#define HPL_SHORT2HPR_AUX_VAUDP15_DISABLE 0
+#define HPR_AUX_FBRSW_VAUDP15_MASK BIT(5)
+#define HPR_AUX_FBRSW_VAUDP15_ENABLE BIT(5)
+#define HPR_AUX_FBRSW_VAUDP15_DISABLE 0
+#define HPL_AUX_FBRSW_VAUDP15_MASK BIT(4)
+#define HPL_AUX_FBRSW_VAUDP15_ENABLE BIT(4)
+#define HPL_AUX_FBRSW_VAUDP15_DISABLE 0
+#define HPROUT_AUX_PWRUP_VAUDP15_MASK BIT(3)
+#define HPROUT_AUX_PWRUP_VAUDP15_ENABLE BIT(3)
+#define HPROUT_AUX_PWRUP_VAUDP15_DISABLE 0
+#define HPLOUT_AUX_PWRUP_VAUDP15_MASK BIT(2)
+#define HPLOUT_AUX_PWRUP_VAUDP15_ENABLE BIT(2)
+#define HPLOUT_AUX_PWRUP_VAUDP15_DISABLE 0
+#define HPROUT_PWRUP_VAUDP15_MASK BIT(1)
+#define HPROUT_PWRUP_VAUDP15_ENABLE BIT(1)
+#define HPROUT_PWRUP_VAUDP15_DISABLE 0
+#define HPLOUT_PWRUP_VAUDP15_MASK BIT(0)
+#define HPLOUT_PWRUP_VAUDP15_ENABLE BIT(0)
+#define HPLOUT_PWRUP_VAUDP15_DISABLE 0
+
+/* MT6357_AUDDEC_ANA_CON2 */
+#define HPP_SHORT_2VCM_VAUDP15_MASK BIT(10)
+#define HPP_SHORT_2VCM_VAUDP15_ENABLE BIT(10)
+#define HPP_SHORT_2VCM_VAUDP15_DISABLE 0
+#define AUD_REFN_DERES_VAUDP15_MASK BIT(9)
+#define AUD_REFN_DERES_VAUDP15_ENABLE BIT(9)
+#define AUD_REFN_DERES_VAUDP15_DISABLE 0
+#define HPROUT_STB_ENH_VAUDP15_MASK GENMASK(6, 4)
+#define HPROUT_STB_ENH_VAUDP15_OPEN 0
+#define HPROUT_STB_ENH_VAUDP15_NOPEN_P250 BIT(4)
+#define HPROUT_STB_ENH_VAUDP15_N470_POPEN BIT(5)
+#define HPROUT_STB_ENH_VAUDP15_N470_P250 (BIT(4) | BIT(5))
+#define HPROUT_STB_ENH_VAUDP15_NOPEN_P470 (BIT(4) | BIT(6))
+#define HPROUT_STB_ENH_VAUDP15_N470_P470 (BIT(4) | BIT(5) | BIT(6))
+#define HPLOUT_STB_ENH_VAUDP15_MASK GENMASK(2, 0)
+#define HPLOUT_STB_ENH_VAUDP15_OPEN 0
+#define HPLOUT_STB_ENH_VAUDP15_NOPEN_P250 BIT(0)
+#define HPLOUT_STB_ENH_VAUDP15_N470_POPEN BIT(1)
+#define HPLOUT_STB_ENH_VAUDP15_N470_P250 (BIT(0) | BIT(1))
+#define HPLOUT_STB_ENH_VAUDP15_NOPEN_P470 (BIT(0) | BIT(2))
+#define HPLOUT_STB_ENH_VAUDP15_N470_P470 (BIT(0) | BIT(1) | BIT(2))
+
+/* MT6357_AUDDEC_ANA_CON3 */
+#define AUD_HSOUT_STB_ENH_VAUDP15_MASK BIT(7)
+#define AUD_HSOUT_STB_ENH_VAUDP15_ENABLE BIT(7)
+#define AUD_HSOUT_STB_ENH_VAUDP15_DISABLE 0
+#define AUD_HS_SC_VAUDP15_MASK BIT(4)
+#define AUD_HS_SC_VAUDP15_DISABLE BIT(4)
+#define AUD_HS_SC_VAUDP15_ENABLE 0
+#define AUD_HS_MUX_INPUT_VAUDP15_MASK_NOSFT GENMASK(1, 0)
+#define AUD_HS_MUX_INPUT_VAUDP15_SFT 2
+#define AUD_HS_PWRUP_BIAS_VAUDP15_MASK BIT(1)
+#define AUD_HS_PWRUP_BIAS_VAUDP15_ENABLE BIT(1)
+#define AUD_HS_PWRUP_BIAS_VAUDP15_DISABLE 0
+#define AUD_HS_PWRUP_VAUDP15_MASK BIT(0)
+#define AUD_HS_PWRUP_VAUDP15_ENABLE BIT(0)
+#define AUD_HS_PWRUP_VAUDP15_DISABLE 0
+
+/* MT6357_AUDDEC_ANA_CON4 */
+#define AUD_LOLOUT_STB_ENH_VAUDP15_MASK BIT(8)
+#define AUD_LOLOUT_STB_ENH_VAUDP15_ENABLE BIT(8)
+#define AUD_LOLOUT_STB_ENH_VAUDP15_DISABLE 0
+#define AUD_LOL_SC_VAUDP15_MASK BIT(4)
+#define AUD_LOL_SC_VAUDP15_DISABLE BIT(4)
+#define AUD_LOL_SC_VAUDP15_ENABLE 0
+#define AUD_LOL_MUX_INPUT_VAUDP15_MASK_NOSFT GENMASK(1, 0)
+#define AUD_LOL_MUX_INPUT_VAUDP15_SFT 2
+#define AUD_LOL_PWRUP_BIAS_VAUDP15_MASK BIT(1)
+#define AUD_LOL_PWRUP_BIAS_VAUDP15_ENABLE BIT(1)
+#define AUD_LOL_PWRUP_BIAS_VAUDP15_DISABLE 0
+#define AUD_LOL_PWRUP_VAUDP15_MASK BIT(0)
+#define AUD_LOL_PWRUP_VAUDP15_ENABLE BIT(0)
+#define AUD_LOL_PWRUP_VAUDP15_DISABLE 0
+
+/* MT6357_AUDDEC_ANA_CON6 */
+#define HP_AUX_LOOP_GAIN_MASK GENMASK(15, 12)
+#define HP_AUX_LOOP_GAIN_SFT 12
+#define HPR_AUX_CMFB_LOOP_MASK BIT(11)
+#define HPR_AUX_CMFB_LOOP_ENABLE BIT(11)
+#define HPR_AUX_CMFB_LOOP_DISABLE 0
+#define HPL_AUX_CMFB_LOOP_MASK BIT(10)
+#define HPL_AUX_CMFB_LOOP_ENABLE BIT(10)
+#define HPL_AUX_CMFB_LOOP_DISABLE 0
+#define HPRL_MAIN_CMFB_LOOP_MASK BIT(9)
+#define HPRL_MAIN_CMFB_LOOP_ENABLE BIT(9)
+#define HPRL_MAIN_CMFB_LOOP_DISABLE 0
+#define HP_CMFB_RST_MASK BIT(7)
+#define HP_CMFB_RST_NORMAL BIT(7)
+#define HP_CMFB_RST_RESET 0
+#define DAC_LOW_NOISE_MODE_MASK BIT(0)
+#define DAC_LOW_NOISE_MODE_ENABLE BIT(0)
+#define DAC_LOW_NOISE_MODE_DISABLE 0
+
+/* MT6357_AUDDEC_ANA_CON7 */
+#define HP_IVBUF_DEGAIN_SFT 2
+#define HP_IVBUF_DEGAIN_MAX 1
+
+/* MT6357_AUDDEC_ANA_CON10 */
+#define AUD_IBIAS_PWRDN_VAUDP15_MASK BIT(8)
+#define AUD_IBIAS_PWRDN_VAUDP15_DISABLE BIT(8)
+#define AUD_IBIAS_PWRDN_VAUDP15_ENABLE 0
+
+/* MT6357_AUDDEC_ANA_CON11 */
+#define RSTB_ENCODER_VA28_MASK BIT(5)
+#define RSTB_ENCODER_VA28_ENABLE BIT(5)
+#define RSTB_ENCODER_VA28_DISABLE 0
+#define AUDGLB_PWRDN_VA28_SFT 4
+#define RSTB_DECODER_VA28_MASK BIT(0)
+#define RSTB_DECODER_VA28_ENABLE BIT(0)
+#define RSTB_DECODER_VA28_DISABLE 0
+
+/* MT6357_AUDDEC_ANA_CON12 */
+#define VA28REFGEN_EN_VA28_MASK BIT(13)
+#define VA28REFGEN_EN_VA28_ENABLE BIT(13)
+#define VA28REFGEN_EN_VA28_DISABLE 0
+#define VA33REFGEN_EN_VA18_MASK BIT(12)
+#define VA33REFGEN_EN_VA18_ENABLE BIT(12)
+#define VA33REFGEN_EN_VA18_DISABLE 0
+#define LCLDO_ENC_REMOTE_SENSE_VA28_MASK BIT(10)
+#define LCLDO_ENC_REMOTE_SENSE_VA28_ENABLE BIT(10)
+#define LCLDO_ENC_REMOTE_SENSE_VA28_DISABLE 0
+#define LCLDO_ENC_EN_VA28_MASK BIT(8)
+#define LCLDO_ENC_EN_VA28_ENABLE BIT(8)
+#define LCLDO_ENC_EN_VA28_DISABLE 0
+#define LCLDO_REMOTE_SENSE_VA18_MASK BIT(6)
+#define LCLDO_REMOTE_SENSE_VA18_ENABLE BIT(6)
+#define LCLDO_REMOTE_SENSE_VA18_DISABLE 0
+#define LCLDO_EN_VA18_MASK BIT(4)
+#define LCLDO_EN_VA18_ENABLE BIT(4)
+#define LCLDO_EN_VA18_DISABLE 0
+#define HCLDO_REMOTE_SENSE_VA18_MASK BIT(2)
+#define HCLDO_REMOTE_SENSE_VA18_ENABLE BIT(2)
+#define HCLDO_REMOTE_SENSE_VA18_DISABLE 0
+#define HCLDO_EN_VA18_MASK BIT(0)
+#define HCLDO_EN_VA18_ENABLE BIT(0)
+#define HCLDO_EN_VA18_DISABLE 0
+
+/* MT6357_AUDDEC_ANA_CON13 */
+#define NVREG_EN_VAUDP15_MASK BIT(0)
+#define NVREG_EN_VAUDP15_ENABLE BIT(0)
+#define NVREG_EN_VAUDP15_DISABLE 0
+
+/* MT6357_AUDDEC_ELR_0 */
+#define AUD_HP_TRIM_EN_VAUDP15_MASK BIT(12)
+#define AUD_HP_TRIM_EN_VAUDP15_ENABLE BIT(12)
+#define AUD_HP_TRIM_EN_VAUDP15_DISABLE 0
+
+/* MT6357_ZCD_CON1 */
+#define AUD_LOL_GAIN_MASK GENMASK(4, 0)
+#define AUD_LOL_GAIN_SFT 0
+#define AUD_LOR_GAIN_MASK GENMASK(11, 7)
+#define AUD_LOR_GAIN_SFT 7
+#define AUD_LO_GAIN_MAX 0x12
+
+/* MT6357_ZCD_CON2 */
+#define AUD_HPL_GAIN_MASK GENMASK(4, 0)
+#define AUD_HPL_GAIN_SFT 0
+#define AUD_HPR_GAIN_MASK GENMASK(11, 7)
+#define AUD_HPR_GAIN_SFT 7
+#define AUD_HP_GAIN_MAX 0x12
+
+/* MT6357_ZCD_CON3 */
+#define AUD_HS_GAIN_MASK GENMASK(4, 0)
+#define AUD_HS_GAIN_SFT 0
+#define AUD_HS_GAIN_MAX 0x12
+
+/* Registers list */
+/* gpio direction */
+#define MT6357_GPIO_DIR0 0x0088
+/* mosi */
+#define MT6357_GPIO_MODE2 0x00B6
+#define MT6357_GPIO_MODE2_SET 0x00B8
+#define MT6357_GPIO_MODE2_CLR 0x00BA
+/* miso */
+#define MT6357_GPIO_MODE3 0x00BC
+#define MT6357_GPIO_MODE3_SET 0x00BE
+#define MT6357_GPIO_MODE3_CLR 0x00C0
+
+#define MT6357_DCXO_CW14 0x07AC
+
+#define MT6357_AUD_TOP_CKPDN_CON0 0x208C
+#define MT6357_AUDNCP_CLKDIV_CON0 0x20B4
+#define MT6357_AUDNCP_CLKDIV_CON1 0x20B6
+#define MT6357_AUDNCP_CLKDIV_CON2 0x20B8
+#define MT6357_AUDNCP_CLKDIV_CON3 0x20BA
+#define MT6357_AUDNCP_CLKDIV_CON4 0x20BC
+#define MT6357_AFE_UL_DL_CON0 0x2108
+#define MT6357_AFE_DL_SRC2_CON0_L 0x210A
+#define MT6357_AFE_UL_SRC_CON0_H 0x210C
+#define MT6357_AFE_UL_SRC_CON0_L 0x210E
+#define MT6357_AFE_TOP_CON0 0x2110
+#define MT6357_AUDIO_TOP_CON0 0x2112
+#define MT6357_AFUNC_AUD_CON0 0x2116
+#define MT6357_AFUNC_AUD_CON2 0x211A
+#define MT6357_AFE_ADDA_MTKAIF_CFG0 0x2134
+#define MT6357_AFE_SGEN_CFG0 0x2140
+#define MT6357_AFE_DCCLK_CFG0 0x2146
+#define MT6357_AFE_DCCLK_CFG1 0x2148
+#define MT6357_AFE_AUD_PAD_TOP 0x214C
+#define MT6357_AUDENC_ANA_CON0 0x2188
+#define MT6357_AUDENC_ANA_CON1 0x218A
+#define MT6357_AUDENC_ANA_CON6 0x2194
+#define MT6357_AUDENC_ANA_CON7 0x2196
+#define MT6357_AUDENC_ANA_CON8 0x2198
+#define MT6357_AUDENC_ANA_CON9 0x219A
+#define MT6357_AUDDEC_ANA_CON0 0x2208
+#define MT6357_AUDDEC_ANA_CON1 0x220A
+#define MT6357_AUDDEC_ANA_CON2 0x220C
+#define MT6357_AUDDEC_ANA_CON3 0x220E
+#define MT6357_AUDDEC_ANA_CON4 0x2210
+#define MT6357_AUDDEC_ANA_CON6 0x2214
+#define MT6357_AUDDEC_ANA_CON7 0x2216
+#define MT6357_AUDDEC_ANA_CON10 0x221C
+#define MT6357_AUDDEC_ANA_CON11 0x221E
+#define MT6357_AUDDEC_ANA_CON12 0x2220
+#define MT6357_AUDDEC_ANA_CON13 0x2222
+#define MT6357_AUDDEC_ELR_0 0x2226
+#define MT6357_ZCD_CON1 0x228A
+#define MT6357_ZCD_CON2 0x228C
+#define MT6357_ZCD_CON3 0x228E
+
+/* enums and other defines */
+enum analog_volume_type {
+ ANALOG_VOLUME_HSOUT = 0,
+ ANALOG_VOLUME_HPOUTL,
+ ANALOG_VOLUME_HPOUTR,
+ ANALOG_VOLUME_LINEOUTL,
+ ANALOG_VOLUME_LINEOUTR,
+ ANALOG_VOLUME_MIC1,
+ ANALOG_VOLUME_MIC2,
+ ANALOG_VOLUME_TYPE_MAX
+};
+
+enum {
+ DL_GAIN_8DB = 0,
+ DL_GAIN_0DB = 8,
+ DL_GAIN_N_1DB = 9,
+ DL_GAIN_N_10DB = 18,
+ DL_GAIN_N_12DB = 20,
+ DL_GAIN_N_40DB = 0x1f,
+};
+
+enum {
+ UL_GAIN_0DB = 0,
+ UL_GAIN_6DB,
+ UL_GAIN_12DB,
+ UL_GAIN_18DB,
+ UL_GAIN_24DB,
+};
+
+#define DL_GAIN_N_40DB_REG (DL_GAIN_N_40DB << 7 | DL_GAIN_N_40DB)
+#define DL_GAIN_REG_LEFT_MASK 0x001f
+#define DL_GAIN_REG_LEFT_SHIFT 0
+#define DL_GAIN_REG_RIGHT_MASK 0x0f80
+#define DL_GAIN_REG_RIGHT_SHIFT 7
+#define DL_GAIN_REG_MASK 0x0f9f
+
+#define SND_SOC_ADV_MT_FMTS (\
+ SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S16_BE |\
+ SNDRV_PCM_FMTBIT_U16_LE |\
+ SNDRV_PCM_FMTBIT_U16_BE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S24_BE |\
+ SNDRV_PCM_FMTBIT_U24_LE |\
+ SNDRV_PCM_FMTBIT_U24_BE |\
+ SNDRV_PCM_FMTBIT_S32_LE |\
+ SNDRV_PCM_FMTBIT_S32_BE |\
+ SNDRV_PCM_FMTBIT_U32_LE |\
+ SNDRV_PCM_FMTBIT_U32_BE)
+
+#define SOC_HIGH_USE_RATE (\
+ SNDRV_PCM_RATE_CONTINUOUS |\
+ SNDRV_PCM_RATE_8000_192000)
+
+#define MT6357_MICBIAS0_DEFAULT_VOLTAGE_INDEX 2 /* 1.9 Volt */
+#define MT6357_MICBIAS1_DEFAULT_VOLTAGE_INDEX 0 /* 1.7 Volt */
+
+/* codec private structure */
+struct mt6357_priv {
+ struct device *dev;
+ struct regmap *regmap;
+ int ana_gain[ANALOG_VOLUME_TYPE_MAX];
+ bool pull_down_needed;
+ int hp_channel_number;
+};
+#endif

--
2.25.1


2024-02-26 14:08:33

by Alexandre Mergnat

[permalink] [raw]
Subject: [PATCH 10/18] ASoc: mediatek: mt8365: Add a specific soundcard for EVK

From: Nicolas Belin <[email protected]>

Add a specific soundcard for mt8365-evk. It supports audio jack
in/out, dmics, the amic and lineout.

Signed-off-by: Nicolas Belin <[email protected]>
Signed-off-by: Alexandre Mergnat <[email protected]>
---
sound/soc/mediatek/mt8365/mt8365-mt6357.c | 379 ++++++++++++++++++++++++++++++
1 file changed, 379 insertions(+)

diff --git a/sound/soc/mediatek/mt8365/mt8365-mt6357.c b/sound/soc/mediatek/mt8365/mt8365-mt6357.c
new file mode 100644
index 000000000000..5192b35458e6
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/mt8365-mt6357.c
@@ -0,0 +1,379 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Mediatek MT8365 Sound Card driver
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Authors: Nicolas Belin <[email protected]>
+ */
+
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#include "mt8365-afe-common.h"
+#include <linux/pinctrl/consumer.h>
+#include "../common/mtk-soundcard-driver.h"
+
+enum PINCTRL_PIN_STATE {
+ PIN_STATE_DEFAULT = 0,
+ PIN_STATE_DMIC,
+ PIN_STATE_MISO_OFF,
+ PIN_STATE_MISO_ON,
+ PIN_STATE_MOSI_OFF,
+ PIN_STATE_MOSI_ON,
+ PIN_STATE_MAX
+};
+
+static const char * const mt8365_mt6357_pin_str[PIN_STATE_MAX] = {
+ "aud_default",
+ "aud_dmic",
+ "aud_miso_off",
+ "aud_miso_on",
+ "aud_mosi_off",
+ "aud_mosi_on",
+};
+
+struct mt8365_mt6357_priv {
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pin_states[PIN_STATE_MAX];
+};
+
+struct mt8365_dai_link_prop {
+ char *name;
+ unsigned int link_id;
+};
+
+enum {
+ /* FE */
+ DAI_LINK_DL1_PLAYBACK = 0,
+ DAI_LINK_DL2_PLAYBACK,
+ DAI_LINK_AWB_CAPTURE,
+ DAI_LINK_VUL_CAPTURE,
+ /* BE */
+ DAI_LINK_2ND_I2S_INTF,
+ DAI_LINK_DMIC,
+ DAI_LINK_INT_ADDA,
+ DAI_LINK_NUM
+};
+
+static const struct snd_soc_dapm_widget mt8365_mt6357_widgets[] = {
+ SND_SOC_DAPM_OUTPUT("HDMI Out"),
+};
+
+static const struct snd_soc_dapm_route mt8365_mt6357_routes[] = {
+ {"HDMI Out", NULL, "2ND I2S Playback"},
+ {"DMIC In", NULL, "MICBIAS0"},
+};
+
+static int mt8365_mt6357_int_adda_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+ int ret = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (IS_ERR(priv->pin_states[PIN_STATE_MOSI_ON]))
+ return ret;
+
+ ret = pinctrl_select_state(priv->pinctrl,
+ priv->pin_states[PIN_STATE_MOSI_ON]);
+ if (ret)
+ dev_err(rtd->card->dev, "%s failed to select state %d\n",
+ __func__, ret);
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (IS_ERR(priv->pin_states[PIN_STATE_MISO_ON]))
+ return ret;
+
+ ret = pinctrl_select_state(priv->pinctrl,
+ priv->pin_states[PIN_STATE_MISO_ON]);
+ if (ret)
+ dev_err(rtd->card->dev, "%s failed to select state %d\n",
+ __func__, ret);
+ }
+
+ return 0;
+}
+
+static void mt8365_mt6357_int_adda_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+ int ret = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (IS_ERR(priv->pin_states[PIN_STATE_MOSI_OFF]))
+ return;
+
+ ret = pinctrl_select_state(priv->pinctrl,
+ priv->pin_states[PIN_STATE_MOSI_OFF]);
+ if (ret)
+ dev_err(rtd->card->dev, "%s failed to select state %d\n",
+ __func__, ret);
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (IS_ERR(priv->pin_states[PIN_STATE_MISO_OFF]))
+ return;
+
+ ret = pinctrl_select_state(priv->pinctrl,
+ priv->pin_states[PIN_STATE_MISO_OFF]);
+ if (ret)
+ dev_err(rtd->card->dev, "%s failed to select state %d\n",
+ __func__, ret);
+ }
+
+}
+
+static const struct snd_soc_ops mt8365_mt6357_int_adda_ops = {
+ .startup = mt8365_mt6357_int_adda_startup,
+ .shutdown = mt8365_mt6357_int_adda_shutdown,
+};
+
+SND_SOC_DAILINK_DEFS(playback1,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(playback2,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL2")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(awb_capture,
+ DAILINK_COMP_ARRAY(COMP_CPU("AWB")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(vul,
+ DAILINK_COMP_ARRAY(COMP_CPU("VUL")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s3,
+ DAILINK_COMP_ARRAY(COMP_CPU("2ND I2S")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(dmic,
+ DAILINK_COMP_ARRAY(COMP_CPU("DMIC")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(primary_codec,
+ DAILINK_COMP_ARRAY(COMP_CPU("INT ADDA")),
+ DAILINK_COMP_ARRAY(COMP_CODEC("mt6357-sound", "mt6357-snd-codec-aif1")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link mt8365_mt6357_dais[] = {
+ /* Front End DAI links */
+ [DAI_LINK_DL1_PLAYBACK] = {
+ .name = "DL1_FE",
+ .stream_name = "MultiMedia1_PLayback",
+ .id = DAI_LINK_DL1_PLAYBACK,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST
+ },
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_merged_rate = 1,
+ SND_SOC_DAILINK_REG(playback1),
+ },
+ [DAI_LINK_DL2_PLAYBACK] = {
+ .name = "DL2_FE",
+ .stream_name = "MultiMedia2_PLayback",
+ .id = DAI_LINK_DL2_PLAYBACK,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST
+ },
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_merged_rate = 1,
+ SND_SOC_DAILINK_REG(playback2),
+ },
+ [DAI_LINK_AWB_CAPTURE] = {
+ .name = "AWB_FE",
+ .stream_name = "DL1_AWB_Record",
+ .id = DAI_LINK_AWB_CAPTURE,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST
+ },
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_merged_rate = 1,
+ SND_SOC_DAILINK_REG(awb_capture),
+ },
+ [DAI_LINK_VUL_CAPTURE] = {
+ .name = "VUL_FE",
+ .stream_name = "MultiMedia1_Capture",
+ .id = DAI_LINK_VUL_CAPTURE,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST
+ },
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_merged_rate = 1,
+ SND_SOC_DAILINK_REG(vul),
+ },
+ /* Back End DAI links */
+ [DAI_LINK_2ND_I2S_INTF] = {
+ .name = "2ND I2S BE",
+ .no_pcm = 1,
+ .id = DAI_LINK_2ND_I2S_INTF,
+ .dai_fmt = SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(i2s3),
+ },
+ [DAI_LINK_DMIC] = {
+ .name = "DMIC BE",
+ .no_pcm = 1,
+ .id = DAI_LINK_DMIC,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(dmic),
+ },
+ [DAI_LINK_INT_ADDA] = {
+ .name = "MTK Codec",
+ .no_pcm = 1,
+ .id = DAI_LINK_INT_ADDA,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .ops = &mt8365_mt6357_int_adda_ops,
+ SND_SOC_DAILINK_REG(primary_codec),
+ },
+};
+
+static int pinctrl_setup(struct snd_soc_card *card,
+ struct mt8365_mt6357_priv *priv,
+ unsigned int pin_id)
+{
+ int ret = 0;
+ /* if pin exist */
+ if (!IS_ERR(priv->pin_states[pin_id])) {
+ ret = pinctrl_select_state(priv->pinctrl,
+ priv->pin_states[pin_id]);
+ if (ret)
+ dev_err(card->dev,
+ "%s failed to select state %d\n",
+ __func__, ret);
+ }
+ return ret;
+}
+
+static int mt8365_mt6357_gpio_probe(struct snd_soc_card *card)
+{
+ struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(card);
+ int ret = 0;
+ int i;
+
+ priv->pinctrl = devm_pinctrl_get(card->dev);
+ if (IS_ERR(priv->pinctrl)) {
+ ret = PTR_ERR(priv->pinctrl);
+ dev_err(card->dev, "%s devm_pinctrl_get failed %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ for (i = 0 ; i < PIN_STATE_MAX ; i++) {
+ priv->pin_states[i] = pinctrl_lookup_state(priv->pinctrl,
+ mt8365_mt6357_pin_str[i]);
+ if (IS_ERR(priv->pin_states[i])) {
+ ret = PTR_ERR(priv->pin_states[i]);
+ dev_err(card->dev, "%s Can't find pin state %s %d\n",
+ __func__, mt8365_mt6357_pin_str[i], ret);
+ }
+ }
+
+ /* Setup pins */
+ ret |= pinctrl_setup(card, priv, PIN_STATE_DEFAULT);
+ ret |= pinctrl_setup(card, priv, PIN_STATE_DMIC);
+ ret |= pinctrl_setup(card, priv, PIN_STATE_MISO_OFF);
+ ret |= pinctrl_setup(card, priv, PIN_STATE_MOSI_OFF);
+
+ return ret;
+}
+
+static struct snd_soc_card mt8365_mt6357_card = {
+ .name = "mt8365-evk",
+ .owner = THIS_MODULE,
+ .dai_link = mt8365_mt6357_dais,
+ .num_links = ARRAY_SIZE(mt8365_mt6357_dais),
+ .dapm_widgets = mt8365_mt6357_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt8365_mt6357_widgets),
+ .dapm_routes = mt8365_mt6357_routes,
+ .num_dapm_routes = ARRAY_SIZE(mt8365_mt6357_routes),
+};
+
+static int mt8365_mt6357_dev_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &mt8365_mt6357_card;
+ struct device *dev = &pdev->dev;
+ struct device_node *platform_node;
+ struct mt8365_mt6357_priv *priv;
+ int i, ret;
+
+ card->dev = dev;
+ ret = parse_dai_link_info(card);
+ if (ret)
+ goto err;
+
+ platform_node = of_parse_phandle(dev->of_node, "mediatek,platform", 0);
+ if (!platform_node) {
+ dev_err(dev, "Property 'platform' missing or invalid\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < card->num_links; i++) {
+ if (mt8365_mt6357_dais[i].platforms->name)
+ continue;
+ mt8365_mt6357_dais[i].platforms->of_node = platform_node;
+ }
+
+ priv = devm_kzalloc(dev, sizeof(struct mt8365_mt6357_priv),
+ GFP_KERNEL);
+ if (!priv) {
+ ret = -ENOMEM;
+ dev_err(dev, "%s allocate card private data fail %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ snd_soc_card_set_drvdata(card, priv);
+
+ mt8365_mt6357_gpio_probe(card);
+
+ ret = devm_snd_soc_register_card(dev, card);
+ if (ret)
+ dev_err(dev, "%s snd_soc_register_card fail %d\n",
+ __func__, ret);
+err:
+ of_node_put(platform_node);
+ clean_card_reference(card);
+ return ret;
+}
+
+static const struct of_device_id mt8365_mt6357_dt_match[] = {
+ { .compatible = "mediatek,mt8365-mt6357", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mt8365_mt6357_dt_match);
+
+static struct platform_driver mt8365_mt6357_driver = {
+ .driver = {
+ .name = "mt8365_mt6357",
+ .of_match_table = mt8365_mt6357_dt_match,
+ .pm = &snd_soc_pm_ops,
+ },
+ .probe = mt8365_mt6357_dev_probe,
+};
+
+module_platform_driver(mt8365_mt6357_driver);
+
+/* Module information */
+MODULE_DESCRIPTION("MT8365 EVK SoC machine driver");
+MODULE_AUTHOR("Nicolas Belin <[email protected]>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("mt8365 mt6357 soc card");

--
2.25.1


2024-02-26 14:08:52

by Alexandre Mergnat

[permalink] [raw]
Subject: [PATCH 13/18] mfd: mt6397-core: register mt6357 sound codec

From: Fabien Parent <[email protected]>

Add MT6357 codec entry in the MFD driver.

Signed-off-by: Fabien Parent <[email protected]>
Signed-off-by: Alexandre Mergnat <[email protected]>
---
drivers/mfd/mt6397-core.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c
index 4449dde05021..4fd4a2da5ad7 100644
--- a/drivers/mfd/mt6397-core.c
+++ b/drivers/mfd/mt6397-core.c
@@ -141,6 +141,9 @@ static const struct mfd_cell mt6357_devs[] = {
.num_resources = ARRAY_SIZE(mt6357_rtc_resources),
.resources = mt6357_rtc_resources,
.of_compatible = "mediatek,mt6357-rtc",
+ }, {
+ .name = "mt6357-sound",
+ .of_compatible = "mediatek,mt6357-sound"
}, {
.name = "mtk-pmic-keys",
.num_resources = ARRAY_SIZE(mt6357_keys_resources),

--
2.25.1


2024-02-26 14:09:24

by Alexandre Mergnat

[permalink] [raw]
Subject: [PATCH 15/18] arm64: defconfig: enable mt8365 sound

Enable the MediaTek MT8365-EVK sound support.

The audio feature is handled by the MT8365 SoC and
the MT6357 PMIC codec audio.

Signed-off-by: Alexandre Mergnat <[email protected]>
---
arch/arm64/configs/defconfig | 2 ++
1 file changed, 2 insertions(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index e6cf3e5d63c3..83aaefb1c866 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -929,6 +929,8 @@ CONFIG_SND_SOC_MT8192=m
CONFIG_SND_SOC_MT8192_MT6359_RT1015_RT5682=m
CONFIG_SND_SOC_MT8195=m
CONFIG_SND_SOC_MT8195_MT6359=m
+CONFIG_SND_SOC_MT8365=m
+CONFIG_SND_SOC_MT8365_MT6357=m
CONFIG_SND_MESON_AXG_SOUND_CARD=m
CONFIG_SND_MESON_GX_SOUND_CARD=m
CONFIG_SND_SOC_QCOM=m

--
2.25.1


2024-02-26 14:14:18

by Alexandre Mergnat

[permalink] [raw]
Subject: [PATCH 03/18] dt-bindings: mfd: mediatek: Add codec property for MT6357 PMIC

Add the codec property along with the mt6357.c codec driver support.

Signed-off-by: Alexandre Mergnat <[email protected]>
---
Documentation/devicetree/bindings/mfd/mediatek,mt6357.yaml | 11 +++++++++++
1 file changed, 11 insertions(+)

diff --git a/Documentation/devicetree/bindings/mfd/mediatek,mt6357.yaml b/Documentation/devicetree/bindings/mfd/mediatek,mt6357.yaml
index 37423c2e0fdf..d25a78070744 100644
--- a/Documentation/devicetree/bindings/mfd/mediatek,mt6357.yaml
+++ b/Documentation/devicetree/bindings/mfd/mediatek,mt6357.yaml
@@ -37,6 +37,17 @@ properties:
"#interrupt-cells":
const: 2

+ codec:
+ type: object
+ unevaluatedProperties: false
+ description:
+ MT6357 sound codec.
+ properties:
+ compatible:
+ const: mediatek,mt6357-sound
+ required:
+ - compatible
+
regulators:
type: object
$ref: /schemas/regulator/mediatek,mt6357-regulator.yaml

--
2.25.1


2024-02-26 14:23:26

by Alexandre Mergnat

[permalink] [raw]
Subject: [PATCH 05/18] SoC: mediatek: mt8365: support audio clock control

Add audio clock wrapper and audio tuner control.

Signed-off-by: Alexandre Mergnat <[email protected]>
---
sound/soc/mediatek/mt8365/mt8365-afe-clk.c | 455 +++++++++++++++++++++++++++++
sound/soc/mediatek/mt8365/mt8365-afe-clk.h | 55 ++++
2 files changed, 510 insertions(+)

diff --git a/sound/soc/mediatek/mt8365/mt8365-afe-clk.c b/sound/soc/mediatek/mt8365/mt8365-afe-clk.c
new file mode 100644
index 000000000000..2df781a22bf0
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/mt8365-afe-clk.c
@@ -0,0 +1,455 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Mediatek 8365 AFE clock control
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Authors: Jia Zeng <[email protected]>
+ * Alexandre Mergnat <[email protected]>
+ */
+
+#include "mt8365-afe-clk.h"
+#include "mt8365-afe-common.h"
+#include "mt8365-reg.h"
+#include "../common/mtk-base-afe.h"
+#include <linux/device.h>
+#include <linux/mfd/syscon.h>
+
+static const char *aud_clks[MT8365_CLK_NUM] = {
+ [MT8365_CLK_TOP_AUD_SEL] = "top_audio_sel",
+ [MT8365_CLK_AUD_I2S0_M] = "audio_i2s0_m",
+ [MT8365_CLK_AUD_I2S1_M] = "audio_i2s1_m",
+ [MT8365_CLK_AUD_I2S2_M] = "audio_i2s2_m",
+ [MT8365_CLK_AUD_I2S3_M] = "audio_i2s3_m",
+ [MT8365_CLK_ENGEN1] = "engen1",
+ [MT8365_CLK_ENGEN2] = "engen2",
+ [MT8365_CLK_AUD1] = "aud1",
+ [MT8365_CLK_AUD2] = "aud2",
+ [MT8365_CLK_I2S0_M_SEL] = "i2s0_m_sel",
+ [MT8365_CLK_I2S1_M_SEL] = "i2s1_m_sel",
+ [MT8365_CLK_I2S2_M_SEL] = "i2s2_m_sel",
+ [MT8365_CLK_I2S3_M_SEL] = "i2s3_m_sel",
+ [MT8365_CLK_CLK26M] = "top_clk26m_clk",
+};
+
+int mt8365_afe_init_audio_clk(struct mtk_base_afe *afe)
+{
+ size_t i;
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+
+ for (i = 0; i < ARRAY_SIZE(aud_clks); i++) {
+ afe_priv->clocks[i] = devm_clk_get(afe->dev, aud_clks[i]);
+ if (IS_ERR(afe_priv->clocks[i])) {
+ dev_err(afe->dev, "%s devm_clk_get %s fail\n",
+ __func__, aud_clks[i]);
+ return PTR_ERR(afe_priv->clocks[i]);
+ }
+ }
+ return 0;
+
+ afe_priv->topckgen = syscon_regmap_lookup_by_phandle(afe->dev->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);
+ }
+}
+
+int mt8365_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk)
+{
+ int ret;
+
+ if (clk) {
+ ret = clk_prepare_enable(clk);
+ if (ret) {
+ dev_err(afe->dev, "Failed to enable clk\n");
+ return ret;
+ }
+ }
+ return 0;
+}
+
+void mt8365_afe_disable_clk(struct mtk_base_afe *afe, struct clk *clk)
+{
+ if (clk)
+ clk_disable_unprepare(clk);
+}
+
+int mt8365_afe_set_clk_rate(struct mtk_base_afe *afe, struct clk *clk,
+ unsigned int rate)
+{
+ int ret;
+
+ if (clk) {
+ ret = clk_set_rate(clk, rate);
+ if (ret) {
+ dev_err(afe->dev, "Failed to set rate\n");
+ return ret;
+ }
+ }
+ return 0;
+}
+
+int mt8365_afe_set_clk_parent(struct mtk_base_afe *afe, struct clk *clk,
+ struct clk *parent)
+{
+ int ret;
+
+ if (clk && parent) {
+ ret = clk_set_parent(clk, parent);
+ if (ret) {
+ dev_err(afe->dev, "Failed to set parent\n");
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static unsigned int get_top_cg_reg(unsigned int cg_type)
+{
+ switch (cg_type) {
+ case MT8365_TOP_CG_AFE:
+ case MT8365_TOP_CG_I2S_IN:
+ case MT8365_TOP_CG_22M:
+ case MT8365_TOP_CG_24M:
+ case MT8365_TOP_CG_INTDIR_CK:
+ case MT8365_TOP_CG_APLL2_TUNER:
+ case MT8365_TOP_CG_APLL_TUNER:
+ case MT8365_TOP_CG_SPDIF:
+ case MT8365_TOP_CG_TDM_OUT:
+ case MT8365_TOP_CG_TDM_IN:
+ case MT8365_TOP_CG_ADC:
+ case MT8365_TOP_CG_DAC:
+ case MT8365_TOP_CG_DAC_PREDIS:
+ case MT8365_TOP_CG_TML:
+ return AUDIO_TOP_CON0;
+ case MT8365_TOP_CG_I2S1_BCLK:
+ case MT8365_TOP_CG_I2S2_BCLK:
+ case MT8365_TOP_CG_I2S3_BCLK:
+ case MT8365_TOP_CG_I2S4_BCLK:
+ case MT8365_TOP_CG_DMIC0_ADC:
+ case MT8365_TOP_CG_DMIC1_ADC:
+ case MT8365_TOP_CG_DMIC2_ADC:
+ case MT8365_TOP_CG_DMIC3_ADC:
+ case MT8365_TOP_CG_CONNSYS_I2S_ASRC:
+ case MT8365_TOP_CG_GENERAL1_ASRC:
+ case MT8365_TOP_CG_GENERAL2_ASRC:
+ case MT8365_TOP_CG_TDM_ASRC:
+ return AUDIO_TOP_CON1;
+ default:
+ return 0;
+ }
+}
+
+static unsigned int get_top_cg_mask(unsigned int cg_type)
+{
+ switch (cg_type) {
+ case MT8365_TOP_CG_AFE:
+ return AUD_TCON0_PDN_AFE;
+ case MT8365_TOP_CG_I2S_IN:
+ return AUD_TCON0_PDN_I2S_IN;
+ case MT8365_TOP_CG_22M:
+ return AUD_TCON0_PDN_22M;
+ case MT8365_TOP_CG_24M:
+ return AUD_TCON0_PDN_24M;
+ case MT8365_TOP_CG_INTDIR_CK:
+ return AUD_TCON0_PDN_INTDIR;
+ case MT8365_TOP_CG_APLL2_TUNER:
+ return AUD_TCON0_PDN_APLL2_TUNER;
+ case MT8365_TOP_CG_APLL_TUNER:
+ return AUD_TCON0_PDN_APLL_TUNER;
+ case MT8365_TOP_CG_SPDIF:
+ return AUD_TCON0_PDN_SPDIF;
+ case MT8365_TOP_CG_TDM_OUT:
+ return AUD_TCON0_PDN_TDM_OUT;
+ case MT8365_TOP_CG_TDM_IN:
+ return AUD_TCON0_PDN_TDM_IN;
+ case MT8365_TOP_CG_ADC:
+ return AUD_TCON0_PDN_ADC;
+ case MT8365_TOP_CG_DAC:
+ return AUD_TCON0_PDN_DAC;
+ case MT8365_TOP_CG_DAC_PREDIS:
+ return AUD_TCON0_PDN_DAC_PREDIS;
+ case MT8365_TOP_CG_TML:
+ return AUD_TCON0_PDN_TML;
+ case MT8365_TOP_CG_I2S1_BCLK:
+ return AUD_TCON1_PDN_I2S1_BCLK;
+ case MT8365_TOP_CG_I2S2_BCLK:
+ return AUD_TCON1_PDN_I2S2_BCLK;
+ case MT8365_TOP_CG_I2S3_BCLK:
+ return AUD_TCON1_PDN_I2S3_BCLK;
+ case MT8365_TOP_CG_I2S4_BCLK:
+ return AUD_TCON1_PDN_I2S4_BCLK;
+ case MT8365_TOP_CG_DMIC0_ADC:
+ return AUD_TCON1_PDN_DMIC0_ADC;
+ case MT8365_TOP_CG_DMIC1_ADC:
+ return AUD_TCON1_PDN_DMIC1_ADC;
+ case MT8365_TOP_CG_DMIC2_ADC:
+ return AUD_TCON1_PDN_DMIC2_ADC;
+ case MT8365_TOP_CG_DMIC3_ADC:
+ return AUD_TCON1_PDN_DMIC3_ADC;
+ case MT8365_TOP_CG_CONNSYS_I2S_ASRC:
+ return AUD_TCON1_PDN_CONNSYS_I2S_ASRC;
+ case MT8365_TOP_CG_GENERAL1_ASRC:
+ return AUD_TCON1_PDN_GENERAL1_ASRC;
+ case MT8365_TOP_CG_GENERAL2_ASRC:
+ return AUD_TCON1_PDN_GENERAL2_ASRC;
+ case MT8365_TOP_CG_TDM_ASRC:
+ return AUD_TCON1_PDN_TDM_ASRC;
+ default:
+ return 0;
+ }
+}
+
+static unsigned int get_top_cg_on_val(unsigned int cg_type)
+{
+ return 0;
+}
+
+static unsigned int get_top_cg_off_val(unsigned int cg_type)
+{
+ return get_top_cg_mask(cg_type);
+}
+
+int mt8365_afe_enable_top_cg(struct mtk_base_afe *afe, unsigned int cg_type)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ unsigned int reg = get_top_cg_reg(cg_type);
+ unsigned int mask = get_top_cg_mask(cg_type);
+ unsigned int val = get_top_cg_on_val(cg_type);
+ unsigned long flags;
+
+ spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags);
+
+ afe_priv->top_cg_ref_cnt[cg_type]++;
+ if (afe_priv->top_cg_ref_cnt[cg_type] == 1)
+ regmap_update_bits(afe->regmap, reg, mask, val);
+
+ spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags);
+
+ return 0;
+}
+
+int mt8365_afe_disable_top_cg(struct mtk_base_afe *afe, unsigned int cg_type)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ unsigned int reg = get_top_cg_reg(cg_type);
+ unsigned int mask = get_top_cg_mask(cg_type);
+ unsigned int val = get_top_cg_off_val(cg_type);
+ unsigned long flags;
+
+ spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags);
+
+ afe_priv->top_cg_ref_cnt[cg_type]--;
+ if (afe_priv->top_cg_ref_cnt[cg_type] == 0)
+ regmap_update_bits(afe->regmap, reg, mask, val);
+ else if (afe_priv->top_cg_ref_cnt[cg_type] < 0)
+ afe_priv->top_cg_ref_cnt[cg_type] = 0;
+
+ spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags);
+
+ return 0;
+}
+
+int mt8365_afe_enable_main_clk(struct mtk_base_afe *afe)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+
+ mt8365_afe_enable_clk(afe, afe_priv->clocks[MT8365_CLK_TOP_AUD_SEL]);
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_AFE);
+ mt8365_afe_enable_afe_on(afe);
+
+ return 0;
+}
+
+int mt8365_afe_disable_main_clk(struct mtk_base_afe *afe)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+
+ mt8365_afe_disable_afe_on(afe);
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_AFE);
+ mt8365_afe_disable_clk(afe, afe_priv->clocks[MT8365_CLK_TOP_AUD_SEL]);
+
+ return 0;
+}
+
+int mt8365_afe_emi_clk_on(struct mtk_base_afe *afe)
+{
+ return 0;
+}
+
+int mt8365_afe_emi_clk_off(struct mtk_base_afe *afe)
+{
+ return 0;
+}
+
+int mt8365_afe_enable_afe_on(struct mtk_base_afe *afe)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags);
+
+ afe_priv->afe_on_ref_cnt++;
+ if (afe_priv->afe_on_ref_cnt == 1)
+ regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x1);
+
+ spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags);
+
+ return 0;
+}
+
+int mt8365_afe_disable_afe_on(struct mtk_base_afe *afe)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags);
+
+ afe_priv->afe_on_ref_cnt--;
+ if (afe_priv->afe_on_ref_cnt == 0)
+ regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x0);
+ else if (afe_priv->afe_on_ref_cnt < 0)
+ afe_priv->afe_on_ref_cnt = 0;
+
+ spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags);
+
+ return 0;
+}
+
+int mt8365_afe_hd_engen_enable(struct mtk_base_afe *afe, bool apll1)
+{
+ if (apll1)
+ regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
+ AFE_22M_PLL_EN, AFE_22M_PLL_EN);
+ else
+ regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
+ AFE_24M_PLL_EN, AFE_24M_PLL_EN);
+
+ return 0;
+}
+
+int mt8365_afe_hd_engen_disable(struct mtk_base_afe *afe, bool apll1)
+{
+ if (apll1)
+ regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
+ AFE_22M_PLL_EN, ~AFE_22M_PLL_EN);
+ else
+ regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
+ AFE_24M_PLL_EN, ~AFE_24M_PLL_EN);
+
+ return 0;
+}
+
+int mt8365_afe_enable_apll_tuner_cfg(struct mtk_base_afe *afe,
+ unsigned int apll)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+
+ mutex_lock(&afe_priv->afe_clk_mutex);
+
+ afe_priv->apll_tuner_ref_cnt[apll]++;
+ if (afe_priv->apll_tuner_ref_cnt[apll] != 1) {
+ mutex_unlock(&afe_priv->afe_clk_mutex);
+ return 0;
+ }
+
+ if (apll == MT8365_AFE_APLL1) {
+ regmap_update_bits(afe->regmap, AFE_APLL_TUNER_CFG,
+ AFE_APLL_TUNER_CFG_MASK, 0x432);
+ regmap_update_bits(afe->regmap, AFE_APLL_TUNER_CFG,
+ AFE_APLL_TUNER_CFG_EN_MASK, 0x1);
+ } else {
+ regmap_update_bits(afe->regmap, AFE_APLL_TUNER_CFG1,
+ AFE_APLL_TUNER_CFG1_MASK, 0x434);
+ regmap_update_bits(afe->regmap, AFE_APLL_TUNER_CFG1,
+ AFE_APLL_TUNER_CFG1_EN_MASK, 0x1);
+ }
+
+ mutex_unlock(&afe_priv->afe_clk_mutex);
+ return 0;
+}
+
+int mt8365_afe_disable_apll_tuner_cfg(struct mtk_base_afe *afe,
+ unsigned int apll)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+
+ mutex_lock(&afe_priv->afe_clk_mutex);
+
+ afe_priv->apll_tuner_ref_cnt[apll]--;
+ if (afe_priv->apll_tuner_ref_cnt[apll] == 0) {
+ if (apll == MT8365_AFE_APLL1)
+ regmap_update_bits(afe->regmap, AFE_APLL_TUNER_CFG,
+ AFE_APLL_TUNER_CFG_EN_MASK, 0x0);
+ else
+ regmap_update_bits(afe->regmap, AFE_APLL_TUNER_CFG1,
+ AFE_APLL_TUNER_CFG1_EN_MASK, 0x0);
+
+ } else if (afe_priv->apll_tuner_ref_cnt[apll] < 0) {
+ afe_priv->apll_tuner_ref_cnt[apll] = 0;
+ }
+
+ mutex_unlock(&afe_priv->afe_clk_mutex);
+ return 0;
+}
+
+int mt8365_afe_enable_apll_associated_cfg(struct mtk_base_afe *afe,
+ unsigned int apll)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+
+ if (apll == MT8365_AFE_APLL1) {
+ if (clk_prepare_enable(afe_priv->clocks[MT8365_CLK_ENGEN1])) {
+ dev_info(afe->dev, "%s Failed to enable ENGEN1 clk\n",
+ __func__);
+ return 0;
+ }
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_22M);
+ mt8365_afe_hd_engen_enable(afe, true);
+#ifdef ENABLE_AFE_APLL_TUNER
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_APLL_TUNER);
+ mt8365_afe_enable_apll_tuner_cfg(afe, MT8365_AFE_APLL1);
+#endif
+ } else {
+ if (clk_prepare_enable(afe_priv->clocks[MT8365_CLK_ENGEN2])) {
+ dev_info(afe->dev, "%s Failed to enable ENGEN2 clk\n",
+ __func__);
+ return 0;
+ }
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_24M);
+ mt8365_afe_hd_engen_enable(afe, false);
+#ifdef ENABLE_AFE_APLL_TUNER
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_APLL2_TUNER);
+ mt8365_afe_enable_apll_tuner_cfg(afe, MT8365_AFE_APLL2);
+#endif
+ }
+
+ return 0;
+}
+
+int mt8365_afe_disable_apll_associated_cfg(struct mtk_base_afe *afe,
+ unsigned int apll)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+
+ if (apll == MT8365_AFE_APLL1) {
+#ifdef ENABLE_AFE_APLL_TUNER
+ mt8365_afe_disable_apll_tuner_cfg(afe, MT8365_AFE_APLL1);
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_APLL_TUNER);
+#endif
+ mt8365_afe_hd_engen_disable(afe, true);
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_22M);
+ clk_disable_unprepare(afe_priv->clocks[MT8365_CLK_ENGEN1]);
+ } else {
+#ifdef ENABLE_AFE_APLL_TUNER
+ mt8365_afe_disable_apll_tuner_cfg(afe, MT8365_AFE_APLL2);
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_APLL2_TUNER);
+#endif
+ mt8365_afe_hd_engen_disable(afe, false);
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_24M);
+ clk_disable_unprepare(afe_priv->clocks[MT8365_CLK_ENGEN2]);
+ }
+
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt8365/mt8365-afe-clk.h b/sound/soc/mediatek/mt8365/mt8365-afe-clk.h
new file mode 100644
index 000000000000..89377464c2b5
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/mt8365-afe-clk.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Mediatek 8365 AFE clock control definitions
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Authors: Jia Zeng <[email protected]>
+ * Alexandre Mergnat <[email protected]>
+ */
+
+#ifndef _MT8365_AFE_UTILS_H_
+#define _MT8365_AFE_UTILS_H_
+
+struct mtk_base_afe;
+struct clk;
+
+int mt8365_afe_init_audio_clk(struct mtk_base_afe *afe);
+
+int mt8365_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk);
+
+void mt8365_afe_disable_clk(struct mtk_base_afe *afe, struct clk *clk);
+
+int mt8365_afe_set_clk_rate(struct mtk_base_afe *afe, struct clk *clk,
+ unsigned int rate);
+
+int mt8365_afe_set_clk_parent(struct mtk_base_afe *afe, struct clk *clk,
+ struct clk *parent);
+
+int mt8365_afe_enable_top_cg(struct mtk_base_afe *afe, unsigned int cg_type);
+
+int mt8365_afe_disable_top_cg(struct mtk_base_afe *afe, unsigned int cg_type);
+
+int mt8365_afe_enable_main_clk(struct mtk_base_afe *afe);
+
+int mt8365_afe_disable_main_clk(struct mtk_base_afe *afe);
+
+int mt8365_afe_emi_clk_on(struct mtk_base_afe *afe);
+
+int mt8365_afe_emi_clk_off(struct mtk_base_afe *afe);
+
+int mt8365_afe_enable_afe_on(struct mtk_base_afe *afe);
+
+int mt8365_afe_disable_afe_on(struct mtk_base_afe *afe);
+
+int mt8365_afe_enable_apll_tuner_cfg(struct mtk_base_afe *afe,
+ unsigned int apll);
+
+int mt8365_afe_disable_apll_tuner_cfg(struct mtk_base_afe *afe,
+ unsigned int apll);
+
+int mt8365_afe_enable_apll_associated_cfg(struct mtk_base_afe *afe,
+ unsigned int apll);
+
+int mt8365_afe_disable_apll_associated_cfg(struct mtk_base_afe *afe,
+ unsigned int apll);
+#endif

--
2.25.1


2024-02-26 14:23:49

by Alexandre Mergnat

[permalink] [raw]
Subject: [PATCH 07/18] ASoC: mediatek: mt8365: Add ADDA DAI support

Add ADDA Device Audio Interface support for MT8365 SoC.

Signed-off-by: Alexandre Mergnat <[email protected]>
---
sound/soc/mediatek/mt8365/mt8365-dai-adda.c | 355 ++++++++++++++++++++++++++++
1 file changed, 355 insertions(+)

diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-adda.c b/sound/soc/mediatek/mt8365/mt8365-dai-adda.c
new file mode 100644
index 000000000000..798b749c0cc5
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/mt8365-dai-adda.c
@@ -0,0 +1,355 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Mediatek 8365 ALSA SoC Audio DAI ADDA Control
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Authors: Jia Zeng <[email protected]>
+ * Alexandre Mergnat <[email protected]>
+ */
+
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8365-afe-clk.h"
+#include "mt8365-afe-common.h"
+
+static int adda_afe_on_ref_cnt;
+
+/* DAI Drivers */
+
+static int mt8365_dai_set_adda_out(struct mtk_base_afe *afe, unsigned int rate)
+{
+ unsigned int val = 0;
+
+ switch (rate) {
+ case 8000:
+ val |= (0 << 28) | AFE_ADDA_DL_VOICE_DATA;
+ break;
+ case 11025:
+ val |= 1 << 28;
+ break;
+ case 12000:
+ val |= 2 << 28;
+ break;
+ case 16000:
+ val |= (3 << 28) | AFE_ADDA_DL_VOICE_DATA;
+ break;
+ case 22050:
+ val |= 4 << 28;
+ break;
+ case 24000:
+ val |= 5 << 28;
+ break;
+ case 32000:
+ val |= 6 << 28;
+ break;
+ case 44100:
+ val |= 7 << 28;
+ break;
+ case 48000:
+ val |= 8 << 28;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ val |= AFE_ADDA_DL_8X_UPSAMPLE |
+ AFE_ADDA_DL_MUTE_OFF_CH1 |
+ AFE_ADDA_DL_MUTE_OFF_CH2 |
+ AFE_ADDA_DL_DEGRADE_GAIN;
+
+ regmap_update_bits(afe->regmap, AFE_ADDA_PREDIS_CON0, 0xffffffff, 0);
+ regmap_update_bits(afe->regmap, AFE_ADDA_PREDIS_CON1, 0xffffffff, 0);
+ regmap_update_bits(afe->regmap, AFE_ADDA_DL_SRC2_CON0, 0xffffffff, val);
+ /* SA suggest apply -0.3db to audio/speech path */
+ regmap_update_bits(afe->regmap, AFE_ADDA_DL_SRC2_CON1,
+ 0xffffffff, 0xf74f0000);
+ /* SA suggest use default value for sdm */
+ regmap_update_bits(afe->regmap, AFE_ADDA_DL_SDM_DCCOMP_CON,
+ 0xffffffff, 0x0700701e);
+
+ return 0;
+}
+
+static int mt8365_dai_set_adda_in(struct mtk_base_afe *afe, unsigned int rate)
+{
+ unsigned int val = 0;
+
+ switch (rate) {
+ case 8000:
+ val |= (0 << 17);
+ break;
+ case 16000:
+ val |= (1 << 17);
+ break;
+ case 32000:
+ val |= (2 << 17);
+ break;
+ case 48000:
+ val |= (3 << 17);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0, 0x000e0000, val);
+ /* Using Internal ADC */
+ regmap_update_bits(afe->regmap, AFE_ADDA_TOP_CON0, 0x1, 0x0);
+
+ return 0;
+}
+
+int mt8365_dai_enable_adda_on(struct mtk_base_afe *afe)
+{
+ unsigned long flags;
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+
+ spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags);
+
+ adda_afe_on_ref_cnt++;
+ if (adda_afe_on_ref_cnt == 1)
+ regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0,
+ AFE_ADDA_UL_DL_ADDA_AFE_ON, AFE_ADDA_UL_DL_ADDA_AFE_ON);
+
+ spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags);
+
+ return 0;
+}
+
+int mt8365_dai_disable_adda_on(struct mtk_base_afe *afe)
+{
+ unsigned long flags;
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+
+ spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags);
+
+ adda_afe_on_ref_cnt--;
+ if (adda_afe_on_ref_cnt == 0)
+ regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0,
+ AFE_ADDA_UL_DL_ADDA_AFE_ON, ~AFE_ADDA_UL_DL_ADDA_AFE_ON);
+ else if (adda_afe_on_ref_cnt < 0)
+ adda_afe_on_ref_cnt = 0;
+
+ spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags);
+
+ return 0;
+}
+
+static void mt8365_dai_set_adda_out_enable(struct mtk_base_afe *afe,
+ bool enable)
+{
+ regmap_update_bits(afe->regmap, AFE_ADDA_DL_SRC2_CON0, 0x1, enable);
+
+ if (enable)
+ mt8365_dai_enable_adda_on(afe);
+ else
+ mt8365_dai_disable_adda_on(afe);
+}
+
+static void mt8365_dai_set_adda_in_enable(struct mtk_base_afe *afe,
+ bool enable)
+{
+ if (enable) {
+ regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0, 0x1, 0x1);
+ mt8365_dai_enable_adda_on(afe);
+ /* enable aud_pad_top fifo */
+ regmap_update_bits(afe->regmap, AFE_AUD_PAD_TOP,
+ 0xffffffff, 0x31);
+ } else {
+ /* disable aud_pad_top fifo */
+ regmap_update_bits(afe->regmap, AFE_AUD_PAD_TOP,
+ 0xffffffff, 0x30);
+ regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0, 0x1, 0x0);
+ /* de suggest disable ADDA_UL_SRC at least wait 125us */
+ udelay(150);
+ mt8365_dai_disable_adda_on(afe);
+ }
+}
+
+static int mt8365_dai_int_adda_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ unsigned int stream = substream->stream;
+
+ mt8365_afe_enable_main_clk(afe);
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DAC);
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DAC_PREDIS);
+ } else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_ADC);
+ }
+
+ return 0;
+}
+
+static void mt8365_dai_int_adda_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_be_dai_data *be =
+ &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
+ unsigned int stream = substream->stream;
+
+ if (be->prepared[stream]) {
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ mt8365_dai_set_adda_out_enable(afe, false);
+ mt8365_afe_set_i2s_out_enable(afe, false);
+ } else
+ mt8365_dai_set_adda_in_enable(afe, false);
+
+ be->prepared[stream] = false;
+ }
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DAC_PREDIS);
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DAC);
+ } else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_ADC);
+ }
+
+ mt8365_afe_disable_main_clk(afe);
+}
+
+static int mt8365_dai_int_adda_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_be_dai_data *be =
+ &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
+ const unsigned int rate = substream->runtime->rate;
+ const unsigned int stream = substream->stream;
+ const int bit_width = snd_pcm_format_width(substream->runtime->format);
+ int ret;
+
+ dev_info(afe->dev, "%s '%s' rate = %u\n", __func__,
+ snd_pcm_stream_str(substream), rate);
+
+ if (be->prepared[stream]) {
+ dev_info(afe->dev, "%s '%s' prepared already\n",
+ __func__, snd_pcm_stream_str(substream));
+ return 0;
+ }
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = mt8365_dai_set_adda_out(afe, rate);
+ if (ret)
+ return ret;
+
+ ret = mt8365_afe_set_i2s_out(afe, rate, bit_width);
+ if (ret)
+ return ret;
+
+ mt8365_dai_set_adda_out_enable(afe, true);
+ mt8365_afe_set_i2s_out_enable(afe, true);
+ } else {
+ ret = mt8365_dai_set_adda_in(afe, rate);
+ if (ret)
+ return ret;
+
+ mt8365_dai_set_adda_in_enable(afe, true);
+ }
+
+ be->prepared[stream] = true;
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mt8365_afe_int_adda_ops = {
+ .startup = mt8365_dai_int_adda_startup,
+ .shutdown = mt8365_dai_int_adda_shutdown,
+ .prepare = mt8365_dai_int_adda_prepare,
+};
+
+static struct snd_soc_dai_driver mtk_dai_adda_driver[] = {
+ {
+ .name = "INT ADDA",
+ .id = MT8365_AFE_IO_INT_ADDA,
+ .playback = {
+ .stream_name = "INT ADDA Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .stream_name = "INT ADDA Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_afe_int_adda_ops,
+ }
+};
+
+/* DAI Controls */
+
+static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1", AFE_CONN3,
+ 10, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_adda_dl_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2", AFE_CONN4,
+ 11, 1, 0),
+};
+
+static const struct snd_kcontrol_new int_adda_o03_o04_enable_ctl =
+ SOC_DAPM_SINGLE_VIRT("Switch", 1);
+
+/* DAI widget */
+
+static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = {
+ SND_SOC_DAPM_SWITCH("INT ADDA O03_O04", SND_SOC_NOPM, 0, 0,
+ &int_adda_o03_o04_enable_ctl),
+ /* 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)),
+};
+
+/* DAI route */
+
+static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = {
+ {"INT ADDA O03_O04", "Switch", "O03"},
+ {"INT ADDA O03_O04", "Switch", "O04"},
+ {"INT ADDA Playback", NULL, "INT ADDA O03_O04"},
+ {"INT ADDA Playback", NULL, "ADDA_DL_CH1"},
+ {"INT ADDA Playback", NULL, "ADDA_DL_CH2"},
+ {"AIN Mux", "INT ADC", "INT ADDA Capture"},
+ {"ADDA_DL_CH1", "GAIN1_OUT_CH1", "Hostless FM DL"},
+ {"ADDA_DL_CH2", "GAIN1_OUT_CH2", "Hostless FM DL"},
+};
+
+int mt8365_dai_adda_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+
+ dev_dbg(afe->dev, "%s()\n", __func__);
+
+ 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->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);
+
+ return 0;
+}

--
2.25.1


Subject: Re: [PATCH 00/18] Add audio support for the MediaTek Genio 350-evk board

Il 26/02/24 15:01, Alexandre Mergnat ha scritto:
> This serie aim to add the following audio support for the Genio 350-evk:
> - Playback
> - 2ch Headset Jack (Earphone)
> - 1ch Line-out Jack (Speaker)
> - 8ch HDMI Tx
> - Capture
> - 1ch DMIC (On-board Digital Microphone)
> - 1ch AMIC (On-board Analogic Microphone)
> - 1ch Headset Jack (External Analogic Microphone)
>
> Of course, HDMI playback need the MT8365 display patches [1] and a DTS
> change documented in "mediatek,mt8365-mt6357.yaml".
>
> [1]: https://lore.kernel.org/all/[email protected]/
>
> Signed-off-by: Alexandre Mergnat <[email protected]>

Actually, I am cooking a series (I'm finishing the testing....) that brings quite
a bit of cleanups in MTK ASoC, including the commonization of the machine driver
probe, with the dai-link DT nodes, and which also modernizes most of the existing
drivers to use that instead.

If you wait for a day or two, your mt8365-mt6357.c driver's probe function can be
shrunk to ~3 lines or something like that.. very easily :-)

Cheers,
Angelo

> ---
> Alexandre Mergnat (15):
> ASoC: dt-bindings: mediatek,mt8365-afe: Add audio afe document
> ASoC: dt-bindings: mediatek,mt8365-mt6357: Add audio sound card document
> dt-bindings: mfd: mediatek: Add codec property for MT6357 PMIC
> ASoC: mediatek: mt8365: Add common header
> SoC: mediatek: mt8365: support audio clock control
> ASoC: mediatek: mt8365: Add I2S DAI support
> ASoC: mediatek: mt8365: Add ADDA DAI support
> ASoC: mediatek: mt8365: Add DMIC DAI support
> ASoC: mediatek: mt8365: Add PCM DAI support
> ASoC: mediatek: mt8365: Add platform driver
> ASoC: mediatek: Add MT8365 support
> arm64: defconfig: enable mt8365 sound
> arm64: dts: mediatek: add mt6357 audio codec support
> arm64: dts: mediatek: add afe support for mt8365 SoC
> arm64: dts: mediatek: add audio support for mt8365-evk
>
> Fabien Parent (1):
> mfd: mt6397-core: register mt6357 sound codec
>
> Nicolas Belin (2):
> ASoc: mediatek: mt8365: Add a specific soundcard for EVK
> ASoC: codecs: mt6357: add MT6357 codec
>
> .../devicetree/bindings/mfd/mediatek,mt6357.yaml | 11 +
> .../bindings/sound/mediatek,mt8365-afe.yaml | 164 ++
> .../bindings/sound/mediatek,mt8365-mt6357.yaml | 127 ++
> arch/arm64/boot/dts/mediatek/mt6357.dtsi | 6 +-
> arch/arm64/boot/dts/mediatek/mt8365-evk.dts | 95 +-
> arch/arm64/boot/dts/mediatek/mt8365.dtsi | 47 +-
> arch/arm64/configs/defconfig | 2 +
> drivers/mfd/mt6397-core.c | 3 +
> sound/soc/codecs/Kconfig | 7 +
> sound/soc/codecs/Makefile | 2 +
> sound/soc/codecs/mt6357.c | 1805 +++++++++++++++
> sound/soc/codecs/mt6357.h | 674 ++++++
> sound/soc/mediatek/Kconfig | 20 +
> sound/soc/mediatek/Makefile | 1 +
> sound/soc/mediatek/mt8365/Makefile | 15 +
> sound/soc/mediatek/mt8365/mt8365-afe-clk.c | 455 ++++
> sound/soc/mediatek/mt8365/mt8365-afe-clk.h | 55 +
> sound/soc/mediatek/mt8365/mt8365-afe-common.h | 495 +++++
> sound/soc/mediatek/mt8365/mt8365-afe-pcm.c | 2347 ++++++++++++++++++++
> sound/soc/mediatek/mt8365/mt8365-dai-adda.c | 355 +++
> sound/soc/mediatek/mt8365/mt8365-dai-dmic.c | 475 ++++
> sound/soc/mediatek/mt8365/mt8365-dai-i2s.c | 901 ++++++++
> sound/soc/mediatek/mt8365/mt8365-dai-pcm.c | 298 +++
> sound/soc/mediatek/mt8365/mt8365-mt6357.c | 379 ++++
> sound/soc/mediatek/mt8365/mt8365-reg.h | 987 ++++++++
> 25 files changed, 9718 insertions(+), 8 deletions(-)
> ---
> base-commit: 6613476e225e090cc9aad49be7fa504e290dd33d
> change-id: 20240226-audio-i350-4e11da088e55
>
> Best regards,



Subject: Re: [PATCH 13/18] mfd: mt6397-core: register mt6357 sound codec

Il 26/02/24 15:01, [email protected] ha scritto:
> From: Fabien Parent <[email protected]>
>
> Add MT6357 codec entry in the MFD driver.
>
> Signed-off-by: Fabien Parent <[email protected]>
> Signed-off-by: Alexandre Mergnat <[email protected]>

Reviewed-by: AngeloGioacchino Del Regno <[email protected]>

> ---
> drivers/mfd/mt6397-core.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c
> index 4449dde05021..4fd4a2da5ad7 100644
> --- a/drivers/mfd/mt6397-core.c
> +++ b/drivers/mfd/mt6397-core.c
> @@ -141,6 +141,9 @@ static const struct mfd_cell mt6357_devs[] = {
> .num_resources = ARRAY_SIZE(mt6357_rtc_resources),
> .resources = mt6357_rtc_resources,
> .of_compatible = "mediatek,mt6357-rtc",
> + }, {
> + .name = "mt6357-sound",
> + .of_compatible = "mediatek,mt6357-sound"
> }, {
> .name = "mtk-pmic-keys",
> .num_resources = ARRAY_SIZE(mt6357_keys_resources),
>



2024-02-26 16:10:09

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH 12/18] ASoC: codecs: mt6357: add MT6357 codec

On Mon, Feb 26, 2024 at 03:01:50PM +0100, [email protected] wrote:

> index 000000000000..13e95c227114
> --- /dev/null
> +++ b/sound/soc/codecs/mt6357.c
> @@ -0,0 +1,1805 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * MT6357 ALSA SoC audio codec driver
> + *

Please use a C++ comment for the whole comment to make it clearer that
this is intentional.

> +static void set_playback_gpio(struct mt6357_priv *priv, bool enable)
> +{
> + if (enable) {
> + /* set gpio mosi mode */
> + regmap_write(priv->regmap, MT6357_GPIO_MODE2_CLR, GPIO_MODE2_CLEAR_ALL);
> + regmap_write(priv->regmap, MT6357_GPIO_MODE2_SET, GPIO8_MODE_SET_AUD_CLK_MOSI |
> + GPIO9_MODE_SET_AUD_DAT_MOSI0 |
> + GPIO10_MODE_SET_AUD_DAT_MOSI1 |
> + GPIO11_MODE_SET_AUD_SYNC_MOSI);

This would be a lot more legible if you worked out the values to set and
then had a single set of writes, currently the indentation makes it very
hard to read. Similarly for other similar functions.

> +static int mt6357_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
> +{
> + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
> + struct mt6357_priv *priv = snd_soc_component_get_drvdata(component);
> + struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
> + unsigned int reg;
> + int ret;
> +
> + ret = snd_soc_put_volsw(kcontrol, ucontrol);
> + if (ret < 0)
> + return ret;
> +
> + switch (mc->reg) {
> + case MT6357_ZCD_CON2:
> + regmap_read(priv->regmap, MT6357_ZCD_CON2, &reg);
> + priv->ana_gain[ANALOG_VOLUME_HPOUTL] =
> + (reg & AUD_HPL_GAIN_MASK) >> AUD_HPL_GAIN_SFT;
> + priv->ana_gain[ANALOG_VOLUME_HPOUTR] =
> + (reg & AUD_HPR_GAIN_MASK) >> AUD_HPR_GAIN_SFT;
> + break;

It would probably be less code and would definitely be clearer and
simpler to just read the values when we need them rather than constatly
keeping a cache separate to the register cache.

> + /* ul channel swap */
> + SOC_SINGLE("UL LR Swap", MT6357_AFE_UL_DL_CON0, AFE_UL_LR_SWAP_SFT, 1, 0),

On/off controls should end in Switch.

> +static const char * const hslo_mux_map[] = {
> + "Open", "DACR", "Playback", "Test mode"
> +};
> +
> +static int hslo_mux_map_value[] = {
> + 0x0, 0x1, 0x2, 0x3,
> +};

Why not just use a normal mux here, there's no missing values or
reordering? Similarly for other muxes.

> +static unsigned int mt6357_read(struct snd_soc_component *codec, unsigned int reg)
> +{
> + struct mt6357_priv *priv = snd_soc_component_get_drvdata(codec);
> + unsigned int val;
> +
> + pr_debug("%s() reg = 0x%x", __func__, reg);
> + regmap_read(priv->regmap, reg, &val);
> + return val;
> +}

Remove these, there are vastly more logging facilities as standard in
the regmap core.

> +/* Reg bit defines */
> +/* MT6357_GPIO_DIR0 */
> +#define GPIO8_DIR_MASK BIT(8)
> +#define GPIO8_DIR_INPUT 0

Please namespace your defines, these look very generic.


Attachments:
(No filename) (2.96 kB)
signature.asc (499.00 B)
Download all attachments

2024-02-27 08:43:43

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH 10/18] ASoc: mediatek: mt8365: Add a specific soundcard for EVK

On 26/02/2024 15:01, [email protected] wrote:
> From: Nicolas Belin <[email protected]>
>
> Add a specific soundcard for mt8365-evk. It supports audio jack
> in/out, dmics, the amic and lineout.
>
> Signed-off-by: Nicolas Belin <[email protected]>
> Signed-off-by: Alexandre Mergnat <[email protected]>


..

> +static int mt8365_mt6357_dev_probe(struct platform_device *pdev)
> +{
> + struct snd_soc_card *card = &mt8365_mt6357_card;
> + struct device *dev = &pdev->dev;
> + struct device_node *platform_node;
> + struct mt8365_mt6357_priv *priv;
> + int i, ret;
> +
> + card->dev = dev;
> + ret = parse_dai_link_info(card);
> + if (ret)
> + goto err;
> +
> + platform_node = of_parse_phandle(dev->of_node, "mediatek,platform", 0);
> + if (!platform_node) {
> + dev_err(dev, "Property 'platform' missing or invalid\n");
> + return -EINVAL;
> + }
> +
> + for (i = 0; i < card->num_links; i++) {
> + if (mt8365_mt6357_dais[i].platforms->name)
> + continue;
> + mt8365_mt6357_dais[i].platforms->of_node = platform_node;
> + }
> +
> + priv = devm_kzalloc(dev, sizeof(struct mt8365_mt6357_priv),
> + GFP_KERNEL);
> + if (!priv) {
> + ret = -ENOMEM;
> + dev_err(dev, "%s allocate card private data fail %d\n",
> + __func__, ret);

Don't print anything on memory allocations failures.

Run coccinelle/coccicheck to detect such trivial issues.

> + return ret;
> + }
> +
> + snd_soc_card_set_drvdata(card, priv);
> +
> + mt8365_mt6357_gpio_probe(card);
> +
> + ret = devm_snd_soc_register_card(dev, card);
> + if (ret)
> + dev_err(dev, "%s snd_soc_register_card fail %d\n",
> + __func__, ret);
> +err:
> + of_node_put(platform_node);
> + clean_card_reference(card);
> + return ret;
> +}
> +
> +static const struct of_device_id mt8365_mt6357_dt_match[] = {
> + { .compatible = "mediatek,mt8365-mt6357", },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, mt8365_mt6357_dt_match);
> +
> +static struct platform_driver mt8365_mt6357_driver = {
> + .driver = {
> + .name = "mt8365_mt6357",
> + .of_match_table = mt8365_mt6357_dt_match,
> + .pm = &snd_soc_pm_ops,
> + },
> + .probe = mt8365_mt6357_dev_probe,
> +};
> +
> +module_platform_driver(mt8365_mt6357_driver);
> +
> +/* Module information */
> +MODULE_DESCRIPTION("MT8365 EVK SoC machine driver");
> +MODULE_AUTHOR("Nicolas Belin <[email protected]>");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("mt8365 mt6357 soc card");

This does not look like correct alias. Drop.

>

Best regards,
Krzysztof


2024-02-27 08:51:26

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH 11/18] ASoC: mediatek: mt8365: Add platform driver

On 26/02/2024 15:01, Alexandre Mergnat wrote:
> Add mt8365 platform driver.
>
> Signed-off-by: Alexandre Mergnat <[email protected]>

..

> + memif->substream = substream;
> +
> + snd_pcm_hw_constraint_step(substream->runtime, 0,
> + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16);
> +
> + snd_soc_set_runtime_hwparams(substream, mtk_afe_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");
> +
> + mt8365_afe_enable_main_clk(afe);
> + return ret;
> +}
> +
> +static void mt8365_afe_fe_shutdown(struct snd_pcm_substream *substream,
> + struct snd_soc_dai *dai)
> +{
> + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
> + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
> + int memif_num = snd_soc_rtd_to_cpu(rtd, 0)->id;
> + struct mtk_base_afe_memif *memif = &afe->memif[memif_num];
> +
> + dev_dbg(afe->dev, "%s %s\n", __func__, memif->data->name);

Drop trace-like prints. Tracing is for this. Before upstreaming driver
from vendor repository, such stuff should be cleaned.


> +
> + memif->substream = NULL;
> +
> + mt8365_afe_disable_main_clk(afe);
> +}
> +
> +static int mt8365_afe_fe_hw_params(struct snd_pcm_substream *substream,
> + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
> +{
> + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
> + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
> + struct mt8365_afe_private *afe_priv = afe->platform_priv;
> + int dai_id = snd_soc_rtd_to_cpu(rtd, 0)->id;
> + struct mt8365_control_data *ctrl_data = &afe_priv->ctrl_data;
> + struct mtk_base_afe_memif *memif = &afe->memif[dai_id];
> + struct mt8365_fe_dai_data *fe_data = &afe_priv->fe_data[dai_id];
> + const size_t request_size = params_buffer_bytes(params);
> + unsigned int channels = params_channels(params);
> + unsigned int rate = params_rate(params);
> + int ret, fs = 0;
> + unsigned int base_end_offset = 8;
> +
> + dev_info(afe->dev,
> + "%s %s period = %d rate = %d channels = %d\n",
> + __func__, memif->data->name, params_period_size(params),
> + rate, channels);
> +
> + if (dai_id == MT8365_AFE_MEMIF_VUL2) {
> + if (!ctrl_data->bypass_cm1)
> + /* configure cm1 */
> + mt8365_afe_configure_cm(afe,
> + MT8365_CM1, channels, rate);
> + else
> + regmap_update_bits(afe->regmap, AFE_CM1_CON0,
> + CM_AFE_CM1_VUL_SEL, CM_AFE_CM1_VUL_SEL);
> + } else if (dai_id == MT8365_AFE_MEMIF_TDM_IN) {
> + if (!ctrl_data->bypass_cm2)
> + /* configure cm2 */
> + mt8365_afe_configure_cm(afe,
> + MT8365_CM2, channels, rate);
> + else
> + regmap_update_bits(afe->regmap, AFE_CM2_CON0,
> + CM_AFE_CM2_TDM_SEL, ~CM_AFE_CM2_TDM_SEL);
> +
> + base_end_offset = 4;
> + }
> +
> + if (request_size > fe_data->sram_size) {
> + ret = snd_pcm_lib_malloc_pages(substream, request_size);
> + if (ret < 0) {
> + dev_err(afe->dev,
> + "%s %s malloc pages %zu bytes failed %d\n",
> + __func__, memif->data->name, request_size, ret);
> + return ret;
> + }
> +
> + fe_data->use_sram = false;
> +
> + mt8365_afe_emi_clk_on(afe);
> + } else {
> + struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
> +
> + dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
> + dma_buf->dev.dev = substream->pcm->card->dev;
> + dma_buf->area = (unsigned char *)fe_data->sram_vir_addr;
> + dma_buf->addr = fe_data->sram_phy_addr;
> + dma_buf->bytes = request_size;
> + snd_pcm_set_runtime_buffer(substream, dma_buf);
> +
> + fe_data->use_sram = true;
> + }
> +
> + memif->phys_buf_addr = lower_32_bits(substream->runtime->dma_addr);
> + memif->buffer_size = substream->runtime->dma_bytes;
> +
> + /* start */
> + regmap_write(afe->regmap, memif->data->reg_ofs_base,
> + memif->phys_buf_addr);
> + /* end */
> + regmap_write(afe->regmap,
> + memif->data->reg_ofs_base + base_end_offset,
> + memif->phys_buf_addr + memif->buffer_size - 1);
> +
> + /* set channel */
> + if (memif->data->mono_shift >= 0) {
> + unsigned int mono = (params_channels(params) == 1) ? 1 : 0;
> +
> + if (memif->data->mono_reg < 0)
> + dev_info(afe->dev, "%s mono_reg is NULL\n", __func__);
> + else
> + regmap_update_bits(afe->regmap, memif->data->mono_reg,
> + 1 << memif->data->mono_shift,
> + mono << memif->data->mono_shift);
> + }
> +
> + /* set rate */
> + if (memif->data->fs_shift < 0)
> + return 0;
> +
> + fs = afe->memif_fs(substream, params_rate(params));
> +
> + if (fs < 0)
> + return -EINVAL;
> +
> + if (memif->data->fs_reg < 0)
> + dev_info(afe->dev, "%s fs_reg is NULL\n", __func__);
> + else
> + regmap_update_bits(afe->regmap, memif->data->fs_reg,
> + memif->data->fs_maskbit << memif->data->fs_shift,
> + fs << memif->data->fs_shift);
> +
> + return 0;
> +}
> +
> +static int mt8365_afe_fe_hw_free(struct snd_pcm_substream *substream,
> + struct snd_soc_dai *dai)
> +{
> + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
> + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
> + struct mt8365_afe_private *afe_priv = afe->platform_priv;
> + int dai_id = snd_soc_rtd_to_cpu(rtd, 0)->id;
> + struct mtk_base_afe_memif *memif = &afe->memif[dai_id];
> + struct mt8365_fe_dai_data *fe_data = &afe_priv->fe_data[dai_id];
> + int ret = 0;
> +
> + dev_dbg(afe->dev, "%s %s\n", __func__, memif->data->name);

Drop

> +
> + if (fe_data->use_sram) {
> + snd_pcm_set_runtime_buffer(substream, NULL);
> + } else {
> + ret = snd_pcm_lib_free_pages(substream);
> +
> + mt8365_afe_emi_clk_off(afe);
> + }
> +
> + return ret;
> +}
> +
> +static int mt8365_afe_fe_prepare(struct snd_pcm_substream *substream,
> + struct snd_soc_dai *dai)
> +{
> + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
> + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
> + int dai_id = snd_soc_rtd_to_cpu(rtd, 0)->id;
> + struct mtk_base_afe_memif *memif = &afe->memif[dai_id];
> +
> + /* set format */
> + if (memif->data->hd_reg >= 0) {
> + switch (substream->runtime->format) {
> + case SNDRV_PCM_FORMAT_S16_LE:
> + regmap_update_bits(afe->regmap, memif->data->hd_reg,
> + 3 << memif->data->hd_shift,
> + 0 << memif->data->hd_shift);
> + break;
> + case SNDRV_PCM_FORMAT_S32_LE:
> + regmap_update_bits(afe->regmap, memif->data->hd_reg,
> + 3 << memif->data->hd_shift,
> + 3 << memif->data->hd_shift);
> +
> + if (dai_id == MT8365_AFE_MEMIF_TDM_IN) {
> + regmap_update_bits(afe->regmap,
> + memif->data->hd_reg,
> + 3 << memif->data->hd_shift,
> + 1 << memif->data->hd_shift);
> + regmap_update_bits(afe->regmap,
> + memif->data->hd_reg,
> + 1 << memif->data->hd_align_mshift,
> + 1 << memif->data->hd_align_mshift);
> + }
> + break;
> + case SNDRV_PCM_FORMAT_S24_LE:
> + regmap_update_bits(afe->regmap, memif->data->hd_reg,
> + 3 << memif->data->hd_shift,
> + 1 << memif->data->hd_shift);
> + break;
> + default:
> + return -EINVAL;
> + }
> + }
> +
> + mt8365_afe_irq_direction_enable(afe,
> + memif->irq_usage,
> + MT8365_AFE_IRQ_DIR_MCU);
> +
> + return 0;
> +}
> +
> +int mt8365_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd,
> + struct snd_soc_dai *dai)
> +{
> + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
> + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
> + struct mt8365_afe_private *afe_priv = afe->platform_priv;
> + int dai_id = snd_soc_rtd_to_cpu(rtd, 0)->id;
> + struct mt8365_control_data *ctrl_data = &afe_priv->ctrl_data;
> +
> + switch (cmd) {
> + case SNDRV_PCM_TRIGGER_START:
> + case SNDRV_PCM_TRIGGER_RESUME:
> + /* enable channel merge */
> + if (dai_id == MT8365_AFE_MEMIF_VUL2 &&
> + !ctrl_data->bypass_cm1) {
> + regmap_update_bits(afe->regmap,
> + AFE_CM1_CON0,
> + CM_AFE_CM_ON, CM_AFE_CM_ON);
> + } else if (dai_id == MT8365_AFE_MEMIF_TDM_IN &&
> + !ctrl_data->bypass_cm2) {
> + regmap_update_bits(afe->regmap,
> + AFE_CM2_CON0,
> + CM_AFE_CM_ON, CM_AFE_CM_ON);
> + }
> + break;
> + case SNDRV_PCM_TRIGGER_STOP:
> + case SNDRV_PCM_TRIGGER_SUSPEND:
> + /* disable channel merge */
> + if (dai_id == MT8365_AFE_MEMIF_VUL2 &&
> + !ctrl_data->bypass_cm1) {
> + regmap_update_bits(afe->regmap,
> + AFE_CM1_CON0,
> + CM_AFE_CM_ON, ~CM_AFE_CM_ON);
> + } else if (dai_id == MT8365_AFE_MEMIF_TDM_IN &&
> + !ctrl_data->bypass_cm2) {
> + regmap_update_bits(afe->regmap,
> + AFE_CM2_CON0,
> + CM_AFE_CM_ON, ~CM_AFE_CM_ON);
> + }
> + break;
> + default:
> + break;
> + }
> +
> + return mtk_afe_fe_trigger(substream, cmd, dai);
> +}
> +
> +static int mt8365_afe_hw_gain1_startup(struct snd_pcm_substream *substream,
> + struct snd_soc_dai *dai)
> +{
> + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
> +
> + mt8365_afe_enable_main_clk(afe);
> + return 0;
> +}
> +
> +static void mt8365_afe_hw_gain1_shutdown(struct snd_pcm_substream *substream,
> + struct snd_soc_dai *dai)
> +{
> + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
> + struct mt8365_afe_private *afe_priv = afe->platform_priv;
> + struct mt8365_be_dai_data *be =
> + &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
> +
> + const unsigned int stream = substream->stream;

Why do you const local scalars? What is the point of this variable anyway?

> +
> + if (be->prepared[stream]) {
> + regmap_update_bits(afe->regmap, AFE_GAIN1_CON0,
> + AFE_GAIN1_CON0_EN_MASK, 0);
> + be->prepared[stream] = false;
> + }
> + mt8365_afe_disable_main_clk(afe);
> +}
> +
> +static int mt8365_afe_hw_gain1_prepare(struct snd_pcm_substream *substream,
> + struct snd_soc_dai *dai)
> +{
> + struct snd_pcm_runtime * const runtime = substream->runtime;
> + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
> + struct mt8365_afe_private *afe_priv = afe->platform_priv;
> + struct mt8365_be_dai_data *be =
> + &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
> +
> + const unsigned int rate = runtime->rate;
> + const unsigned int stream = substream->stream;

So this const is everywhere? How does it change it from code safety? No
one expects to overwrite such variables anyway, so there is no increase
in readability, either.

> + int fs;
> + unsigned int val1 = 0, val2 = 0;
> +
> + if (be->prepared[stream]) {
> + dev_info(afe->dev, "%s prepared already\n", __func__);
> + return 0;
> + }
> +
> + fs = mt8365_afe_fs_timing(rate);
> + regmap_update_bits(afe->regmap, AFE_GAIN1_CON0,
> + AFE_GAIN1_CON0_MODE_MASK, (unsigned int)fs<<4);
> +
> + regmap_read(afe->regmap, AFE_GAIN1_CON1, &val1);
> + regmap_read(afe->regmap, AFE_GAIN1_CUR, &val2);
> + if ((val1 & AFE_GAIN1_CON1_MASK) != (val2 & AFE_GAIN1_CUR_MASK))
> + regmap_update_bits(afe->regmap, AFE_GAIN1_CUR,
> + AFE_GAIN1_CUR_MASK, val1);
> +
> + regmap_update_bits(afe->regmap, AFE_GAIN1_CON0,
> + AFE_GAIN1_CON0_EN_MASK, 1);
> + be->prepared[stream] = true;
> +
> + return 0;
> +}
> +
> +static const struct snd_pcm_hardware mt8365_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 = 8 * 48 * 1024,
> + .fifo_size = 0,
> +};
> +
> +/* 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, &mt8365_hostless_hardware);
> +
> + ret = snd_pcm_hw_constraint_integer(runtime,
> + SNDRV_PCM_HW_PARAM_PERIODS);
> + if (ret < 0)
> + dev_info(afe->dev, "snd_pcm_hw_constraint_integer failed\n");
> + return ret;
> +}
> +
> +/* FE DAIs */
> +static const struct snd_soc_dai_ops mt8365_afe_fe_dai_ops = {
> + .startup = mt8365_afe_fe_startup,
> + .shutdown = mt8365_afe_fe_shutdown,
> + .hw_params = mt8365_afe_fe_hw_params,
> + .hw_free = mt8365_afe_fe_hw_free,
> + .prepare = mt8365_afe_fe_prepare,
> + .trigger = mt8365_afe_fe_trigger,
> +};
> +
> +static const struct snd_soc_dai_ops mt8365_dai_hostless_ops = {
> + .startup = mtk_dai_hostless_startup,
> +};
> +

..

> +static int mt8365_afe_cm2_io_input_mux_get(struct snd_kcontrol *kcontrol,
> + struct snd_ctl_elem_value *ucontrol)
> +{
> + ucontrol->value.integer.value[0] = mCM2Input;
> +
> + return 0;
> +}
> +
> +static int mt8365_afe_cm2_io_input_mux_put(struct snd_kcontrol *kcontrol,
> + struct snd_ctl_elem_value *ucontrol)

Run checkpatch --strict

> +{
> + struct snd_soc_dapm_context *dapm =
> + snd_soc_dapm_kcontrol_dapm(kcontrol);
> + struct snd_soc_component *comp = snd_soc_dapm_to_component(dapm);
> + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(comp);
> + struct mt8365_afe_private *afe_priv = afe->platform_priv;
> + int ret;
> +
> + mCM2Input = ucontrol->value.enumerated.item[0];
> +
> + afe_priv->cm2_mux_input = mCM2Input;
> + ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
> +
> + return ret;
> +}
> +

..

> +
> +static const struct regmap_config mt8365_afe_regmap_config = {
> + .reg_bits = 32,
> + .reg_stride = 4,
> + .val_bits = 32,
> + .max_register = MAX_REGISTER,
> + .cache_type = REGCACHE_NONE,
> +};
> +
> +static irqreturn_t mt8365_afe_irq_handler(int irq, void *dev_id)
> +{
> + struct mtk_base_afe *afe = dev_id;
> + unsigned int reg_value;
> + unsigned int mcu_irq_mask;
> + int i, ret;
> +
> + ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, &reg_value);
> + if (ret) {
> + dev_err(afe->dev, "%s irq status err\n", __func__);

I can imagine happy user seeing flooded dmesg on each IRQ with these
messages...

> + reg_value = AFE_IRQ_STATUS_BITS;
> + goto err_irq;
> + }
> +
> + ret = regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_irq_mask);
> + if (ret) {
> + dev_err(afe->dev, "%s irq mcu_en err\n", __func__);
> + reg_value = AFE_IRQ_STATUS_BITS;
> + goto err_irq;
> + }
> +
> + /* only clr cpu irq */
> + reg_value &= mcu_irq_mask;
> +
> + for (i = 0; i < MT8365_AFE_MEMIF_NUM; i++) {
> + struct mtk_base_afe_memif *memif = &afe->memif[i];
> + struct mtk_base_afe_irq *mcu_irq;
> +
> + if (memif->irq_usage < 0)
> + continue;
> +
> + mcu_irq = &afe->irqs[memif->irq_usage];
> +
> + if (!(reg_value & (1 << mcu_irq->irq_data->irq_clr_shift)))
> + continue;
> +
> + snd_pcm_period_elapsed(memif->substream);
> + }
> +
> +err_irq:
> + /* clear irq */
> + regmap_write(afe->regmap, AFE_IRQ_MCU_CLR,
> + reg_value & AFE_IRQ_STATUS_BITS);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int __maybe_unused mt8365_afe_runtime_suspend(struct device *dev)
> +{
> + return 0;
> +}
> +
> +static int mt8365_afe_runtime_resume(struct device *dev)
> +{
> + return 0;
> +}
> +
> +static int __maybe_unused mt8365_afe_suspend(struct device *dev)
> +{
> + struct mtk_base_afe *afe = dev_get_drvdata(dev);
> + struct regmap *regmap = afe->regmap;
> + int i;
> +
> + mt8365_afe_enable_main_clk(afe);
> +
> + if (!afe->reg_back_up)
> + afe->reg_back_up =
> + devm_kcalloc(dev, afe->reg_back_up_list_num,
> + sizeof(unsigned int), GFP_KERNEL);
> +
> + for (i = 0; i < afe->reg_back_up_list_num; i++)
> + regmap_read(regmap, afe->reg_back_up_list[i],
> + &afe->reg_back_up[i]);
> +
> + mt8365_afe_disable_main_clk(afe);
> +
> + return 0;
> +}
> +
> +static int __maybe_unused mt8365_afe_resume(struct device *dev)
> +{
> + struct mtk_base_afe *afe = dev_get_drvdata(dev);
> + struct regmap *regmap = afe->regmap;
> + int i = 0;
> +
> + if (!afe->reg_back_up) {
> + dev_dbg(dev, "%s no reg_backup\n", __func__);
> + return 0;
> + }
> +
> + mt8365_afe_enable_main_clk(afe);
> +
> + for (i = 0; i < afe->reg_back_up_list_num; i++)
> + regmap_write(regmap, afe->reg_back_up_list[i],
> + afe->reg_back_up[i]);
> +
> + mt8365_afe_disable_main_clk(afe);
> +
> + return 0;
> +}
> +
> +static int __maybe_unused mt8365_afe_dev_runtime_suspend(struct device *dev)
> +{
> + struct mtk_base_afe *afe = dev_get_drvdata(dev);
> +
> + dev_dbg(afe->dev, "%s suspend %d %d >>\n", __func__,
> + pm_runtime_status_suspended(dev), afe->suspended);

Drop silly trace-like prints. Tracing is for this.

> +
> + if (pm_runtime_status_suspended(dev) || afe->suspended)
> + return 0;
> +
> + mt8365_afe_suspend(dev);
> +
> + afe->suspended = true;
> +
> + dev_dbg(afe->dev, "%s <<\n", __func__);

Drop silly trace-like prints. Tracing is for this.

> +
> + return 0;
> +}
> +
> +static int __maybe_unused mt8365_afe_dev_runtime_resume(struct device *dev)
> +{
> + struct mtk_base_afe *afe = dev_get_drvdata(dev);
> +
> + dev_dbg(afe->dev, "%s suspend %d %d >>\n", __func__,
> + pm_runtime_status_suspended(dev), afe->suspended);

Drop silly trace-like prints. Tracing is for this.

> +
> + if (pm_runtime_status_suspended(dev) || !afe->suspended)
> + return 0;
> +
> + mt8365_afe_resume(dev);
> +
> + afe->suspended = false;
> +
> + dev_dbg(afe->dev, "%s <<\n", __func__);

Drop silly trace-like prints. Tracing is for this.

> +
> + return 0;
> +}
> +
> +static int mt8365_afe_init_registers(struct mtk_base_afe *afe)
> +{
> + size_t i;
> +
> + static struct {
> + unsigned int reg;
> + unsigned int mask;
> + unsigned int val;
> + } init_regs[] = {
> + { AFE_CONN_24BIT, GENMASK(31, 0), GENMASK(31, 0) },
> + { AFE_CONN_24BIT_1, GENMASK(21, 0), GENMASK(21, 0) },
> + };
> +
> + mt8365_afe_enable_main_clk(afe);
> +
> + for (i = 0; i < ARRAY_SIZE(init_regs); i++)
> + regmap_update_bits(afe->regmap, init_regs[i].reg,
> + init_regs[i].mask, init_regs[i].val);
> +
> + mt8365_afe_disable_main_clk(afe);
> +
> + return 0;
> +}
> +
> +static int mt8365_afe_component_probe(struct snd_soc_component *component)
> +{
> + return mtk_afe_add_sub_dai_control(component);
> +}
> +
> +static const struct snd_soc_component_driver mt8365_afe_component = {
> + .name = AFE_PCM_NAME,
> + .probe = mt8365_afe_component_probe,
> + .pointer = mtk_afe_pcm_pointer,
> + .pcm_construct = mtk_afe_pcm_new,
> +};
> +
> +static const struct snd_soc_component_driver mt8365_afe_pcm_component = {
> + .name = "mt8365-afe-pcm-dai",
> +};
> +
> +static int mt8365_dai_memif_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 = mt8365_memif_dai_driver;
> + dai->num_dai_drivers = ARRAY_SIZE(mt8365_memif_dai_driver);
> +
> + dai->dapm_widgets = mt8365_memif_widgets;
> + dai->num_dapm_widgets = ARRAY_SIZE(mt8365_memif_widgets);
> + dai->dapm_routes = mt8365_memif_routes;
> + dai->num_dapm_routes = ARRAY_SIZE(mt8365_memif_routes);
> + return 0;
> +}
> +
> +typedef int (*dai_register_cb)(struct mtk_base_afe *);
> +static const dai_register_cb dai_register_cbs[] = {
> + mt8365_dai_pcm_register,
> + mt8365_dai_i2s_register,
> + mt8365_dai_adda_register,
> + mt8365_dai_dmic_register,
> + mt8365_dai_memif_register,
> +};
> +
> +static int mt8365_afe_pcm_dev_probe(struct platform_device *pdev)
> +{
> + struct mtk_base_afe *afe;
> + struct mt8365_afe_private *afe_priv;
> + struct device *dev;
> + int ret, i, sel_irq;
> + unsigned int irq_id;
> + struct resource *res;
> +
> + afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
> + if (!afe)
> + return -ENOMEM;
> + platform_set_drvdata(pdev, afe);
> +
> + afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
> + GFP_KERNEL);
> + if (!afe->platform_priv)
> + return -ENOMEM;
> +
> + afe_priv = afe->platform_priv;
> + afe->dev = &pdev->dev;
> + dev = afe->dev;
> +
> + spin_lock_init(&afe_priv->afe_ctrl_lock);
> + mutex_init(&afe_priv->afe_clk_mutex);
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + afe->base_addr = devm_ioremap_resource(&pdev->dev, res);

Why not using helper combining these two?

> + if (IS_ERR(afe->base_addr))
> + return PTR_ERR(afe->base_addr);
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> + if (res) {
> + afe_priv->afe_sram_vir_addr =
> + devm_ioremap_resource(&pdev->dev, res);
> + if (!IS_ERR(afe_priv->afe_sram_vir_addr)) {
> + afe_priv->afe_sram_phy_addr = res->start;
> + afe_priv->afe_sram_size = resource_size(res);
> + }
> + }
> +
> + /* initial audio related clock */
> + ret = mt8365_afe_init_audio_clk(afe);
> + if (ret) {
> + dev_err(afe->dev, "mt8365_afe_init_audio_clk fail\n");

return dev_err_probe()

> + return ret;
> + }
> +
> + afe->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "top_audio_sel",
> + afe->base_addr, &mt8365_afe_regmap_config);
> + if (IS_ERR(afe->regmap))
> + return PTR_ERR(afe->regmap);
> +
> + /* memif % irq initialize*/
> + afe->memif_size = MT8365_AFE_MEMIF_NUM;
> + afe->memif = devm_kcalloc(afe->dev, afe->memif_size,
> + sizeof(*afe->memif), GFP_KERNEL);
> + if (!afe->memif)
> + return -ENOMEM;
> +
> + afe->irqs_size = MT8365_AFE_IRQ_NUM;
> + afe->irqs = devm_kcalloc(afe->dev, afe->irqs_size,
> + sizeof(*afe->irqs), GFP_KERNEL);
> + if (!afe->irqs)
> + return -ENOMEM;
> +
> + for (i = 0; i < afe->irqs_size; i++)
> + afe->irqs[i].irq_data = &irq_data[i];
> +
> + irq_id = platform_get_irq(pdev, 0);
> + if (!irq_id) {

That does not look correct. 0 is valid. Look at help of this function.

> + dev_err(afe->dev, "np %s no irq\n", afe->dev->of_node->name);

return dev_err_probe()

> + return -ENXIO;
> + }
> + ret = devm_request_irq(afe->dev, irq_id, mt8365_afe_irq_handler,
> + 0, "Afe_ISR_Handle", (void *)afe);
> + if (ret) {
> + dev_err(afe->dev, "could not request_irq\n");

return dev_err_probe()

> + return ret;
> + }
> +
> + /* init sub_dais */
> + INIT_LIST_HEAD(&afe->sub_dais);
> +
> + for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) {
> + ret = dai_register_cbs[i](afe);
> + if (ret) {
> + dev_warn(afe->dev, "dai register i %d fail, ret %d\n",
> + i, ret);
> + return ret;
> + }
> + }
> +
> + /* init dai_driver and component_driver */
> + ret = mtk_afe_combine_sub_dai(afe);
> + if (ret) {
> + dev_warn(afe->dev, "mtk_afe_combine_sub_dai fail, ret %d\n",
> + ret);
> + return ret;
> + }
> +
> + for (i = 0; i < afe->memif_size; i++) {
> + afe->memif[i].data = &memif_data[i];
> + sel_irq = memif_specified_irqs[i];
> + if (sel_irq >= 0) {
> + afe->memif[i].irq_usage = sel_irq;
> + afe->memif[i].const_irq = 1;
> + afe->irqs[sel_irq].irq_occupyed = true;
> + } else {
> + afe->memif[i].irq_usage = -1;
> + }
> + }
> +
> + afe->mtk_afe_hardware = &mt8365_afe_hardware;
> + afe->memif_fs = mt8365_memif_fs;
> + afe->irq_fs = mt8365_irq_fs;
> +
> + pm_runtime_enable(&pdev->dev);
> +
> + pm_runtime_get_sync(&pdev->dev);
> + afe->reg_back_up_list = mt8365_afe_backup_list;
> + afe->reg_back_up_list_num = ARRAY_SIZE(mt8365_afe_backup_list);
> + afe->runtime_resume = mt8365_afe_runtime_resume;
> + afe->runtime_suspend = mt8365_afe_runtime_suspend;
> +
> + /* open afe pdn for dapm read/write audio register */
> + mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_AFE);
> +
> + /* Set 26m parent clk */
> + mt8365_afe_set_clk_parent(afe,
> + afe_priv->clocks[MT8365_CLK_TOP_AUD_SEL],
> + afe_priv->clocks[MT8365_CLK_CLK26M]);
> +
> + ret = devm_snd_soc_register_component(&pdev->dev,
> + &mt8365_afe_component, NULL, 0);
> + if (ret) {
> + dev_warn(dev, "err_platform\n");
> + return ret;
> + }
> +
> + ret = devm_snd_soc_register_component(&pdev->dev,
> + &mt8365_afe_pcm_component,
> + afe->dai_drivers,
> + afe->num_dai_drivers);
> + if (ret) {
> + dev_warn(dev, "err_dai_component\n");
> + return ret;
> + }
> +
> + mt8365_afe_init_registers(afe);
> +
> + dev_info(&pdev->dev, "MT8365 AFE driver initialized.\n");

Drop simple probe success messages everywhere. They are not needed and
they don't bring useful information.

Best regards,
Krzysztof


2024-02-27 09:08:43

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH 02/18] ASoC: dt-bindings: mediatek,mt8365-mt6357: Add audio sound card document

On 26/02/2024 15:01, Alexandre Mergnat wrote:
> Add soundcard bindings for the MT8365 SoC with the MT6357 audio codec.
>
> Signed-off-by: Alexandre Mergnat <[email protected]>
> ---
> .../bindings/sound/mediatek,mt8365-mt6357.yaml | 127 +++++++++++++++++++++
> 1 file changed, 127 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8365-mt6357.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8365-mt6357.yaml
> new file mode 100644
> index 000000000000..f469611ec6b6
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/mediatek,mt8365-mt6357.yaml
> @@ -0,0 +1,127 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/sound/mediatek,mt8365-mt6357.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Mediatek MT8365 sound card with MT6357 sound codec.

Drop full stop. This is title.

> +
> +maintainers:
> + - Alexandre Mergnat <[email protected]>
> +
> +description:
> + This binding describes the MT8365 sound card.

Say something useful. There is no need to say that binding is a binding
describing something. Or just drop it if this is obvious.


> +
> +properties:
> + compatible:
> + const: mediatek,mt8365-mt6357
> +
> + mediatek,hp-pull-down:
> + description:
> + Earphone driver positive output stage short to the
> + audio reference ground.
> + Default value is false.

That's obvious, isn't it? Drop.

> + type: boolean
> +
> + mediatek,micbias0-microvolt:
> + description: |
> + Selects MIC Bias 0 output voltage.
> + [1.7v, 1.8v, 1.9v, 2.0v, 2.1v, 2.5v, 2.6v, 2.7v]
> + enum: [0, 1, 2, 3, 4, 5, 6, 7]

0 is 0V, not 1.7! That's total mess. You use here microvolts. Look at
property name.

> +
> + mediatek,micbias1-microvolt:
> + description: |
> + Selects MIC Bias 1 output voltage.
> + [1.7v, 1.8v, 1.9v, 2.0v, 2.1v, 2.5v, 2.6v, 2.7v]
> + enum: [0, 1, 2, 3, 4, 5, 6, 7]
> +
> + mediatek,platform:
> + $ref: /schemas/types.yaml#/definitions/phandle
> + description: The phandle of MT8365 ASoC platform.
> +
> + pinctrl-names:
> + minItems: 1
> + items:
> + - const: aud_default

Drop redundant parts. aud looks like block name.

> + - const: aud_dmic
> + - const: aud_miso_off
> + - const: aud_miso_on
> + - const: aud_mosi_off
> + - const: aud_mosi_on
> +
> + vaud28-supply:
> + description:
> + 2.8 volt supply for the audio codec
> +
> +patternProperties:
> + "^dai-link-[0-9]+$":
> + type: object
> + description:
> + Container for dai-link level properties and CODEC sub-nodes.
> +
> + properties:
> + codec:
> + type: object
> + description: Holds subnode which indicates codec dai.
> +
> + properties:
> + sound-dai:
> + maxItems: 1
> + description: phandle of the codec DAI
> +
> + additionalProperties: false
> +
> + link-name:
> + description:
> + This property corresponds to the name of the BE dai-link to which
> + we are going to update parameters in this node.
> + items:
> + const: 2ND I2S BE
> +
> + sound-dai:
> + maxItems: 1
> + description: phandle of the CPU DAI
> +
> + additionalProperties: false
> +
> + required:
> + - link-name
> + - sound-dai
> +
> +additionalProperties: false

This goes after required: block. See example schema.

> +
> +required:
> + - compatible
> + - mediatek,platform
> + - pinctrl-names
> + - vaud28-supply
> +


Best regards,
Krzysztof


2024-02-27 09:09:21

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH 03/18] dt-bindings: mfd: mediatek: Add codec property for MT6357 PMIC

On 26/02/2024 15:01, Alexandre Mergnat wrote:
> Add the codec property along with the mt6357.c codec driver support.

Describe the hardware, not the Linux drivers. There is no codec driver
support in the bindings.

https://elixir.bootlin.com/linux/v6.8-rc6/source/Documentation/devicetree/bindings/writing-bindings.rst#L21

>
> Signed-off-by: Alexandre Mergnat <[email protected]>
> ---
> Documentation/devicetree/bindings/mfd/mediatek,mt6357.yaml | 11 +++++++++++
> 1 file changed, 11 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/mfd/mediatek,mt6357.yaml b/Documentation/devicetree/bindings/mfd/mediatek,mt6357.yaml
> index 37423c2e0fdf..d25a78070744 100644
> --- a/Documentation/devicetree/bindings/mfd/mediatek,mt6357.yaml
> +++ b/Documentation/devicetree/bindings/mfd/mediatek,mt6357.yaml
> @@ -37,6 +37,17 @@ properties:
> "#interrupt-cells":
> const: 2
>
> + codec:
> + type: object
> + unevaluatedProperties: false
> + description:
> + MT6357 sound codec.
> + properties:
> + compatible:
> + const: mediatek,mt6357-sound
> + required:
> + - compatible

No resources? Then no need for this node.

We have it even documented (if my repeating every time is not enough)...
https://elixir.bootlin.com/linux/v6.8-rc6/source/Documentation/devicetree/bindings/writing-bindings.rst#L30



Best regards,
Krzysztof


2024-02-27 09:17:06

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH 01/18] ASoC: dt-bindings: mediatek,mt8365-afe: Add audio afe document

On 26/02/2024 15:01, Alexandre Mergnat wrote:
> Add MT8365 audio front-end bindings
>
> Signed-off-by: Alexandre Mergnat <[email protected]>
> ---
> .../bindings/sound/mediatek,mt8365-afe.yaml | 164 +++++++++++++++++++++
> 1 file changed, 164 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8365-afe.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8365-afe.yaml
> new file mode 100644
> index 000000000000..1d7eb2532ad2
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/mediatek,mt8365-afe.yaml
> @@ -0,0 +1,164 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/sound/mediatek,mt8365-afe.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MediaTek AFE PCM controller for MT8365
> +
> +maintainers:
> + - Alexandre Mergnat <[email protected]>
> +
> +properties:
> + compatible:
> + const: mediatek,mt8365-afe-pcm
> +
> + reg:
> + maxItems: 2

You must describe the items.

> +
> + interrupts:
> + maxItems: 1
> +
> + mediatek,topckgen:
> + $ref: /schemas/types.yaml#/definitions/phandle
> + description: The phandle of the mediatek topckgen controller

What for? Don't repeat the property name. Say something useful.

> +
> + power-domains:
> + maxItems: 1
> +
> + "#sound-dai-cells":
> + const: 0
> +
> + clocks:
> + items:
> + - description: 26M clock
> + - description: mux for audio clock
> + - description: audio i2s0 mck
> + - description: audio i2s1 mck
> + - description: audio i2s2 mck
> + - description: audio i2s3 mck
> + - description: engen 1 clock
> + - description: engen 2 clock
> + - description: audio 1 clock
> + - description: audio 2 clock
> + - description: mux for i2s0
> + - description: mux for i2s1
> + - description: mux for i2s2
> + - description: mux for i2s3
> +
> + clock-names:
> + items:
> + - const: top_clk26m_clk
> + - const: top_audio_sel
> + - const: audio_i2s0_m
> + - const: audio_i2s1_m
> + - const: audio_i2s2_m
> + - const: audio_i2s3_m
> + - const: engen1
> + - const: engen2
> + - const: aud1
> + - const: aud2
> + - const: i2s0_m_sel
> + - const: i2s1_m_sel
> + - const: i2s2_m_sel
> + - const: i2s3_m_sel
> +
> + mediatek,i2s-shared-clock:

Why do you need this property? Linux (and other systems) handle sharing
clocks properly.

> + description:
> + i2s modules can share the same external clock pin.
> + If this property is not present the clock mode is separrate.

Typo

> + type: boolean
> +
> + mediatek,dmic-iir-on:
> + description:
> + Boolean which specifies whether the DMIC IIR is enabled.
> + If this property is not present the IIR is disabled.

"is enabled" or "enable it"?

You described the desired Linux feature or behavior, not the actual
hardware. The bindings are about the latter, so instead you need to
rephrase the property and its description to match actual hardware
capabilities/features/configuration etc.

> + type: boolean
> +
> + mediatek,dmic-irr-mode:
> + $ref: /schemas/types.yaml#/definitions/uint32
> + description:
> + Selects stop band of IIR DC-removal filter.
> + 0 = Software programmable custom coeff loaded by the driver.

Bindings are for hardware, not drivers. Why is this a property of board DTS?

> + 1 = 5Hz if 48KHz mode.
> + 2 = 10Hz if 48KHz mode.
> + 3 = 25Hz if 48KHz mode.
> + 4 = 50Hz if 48KHz mode.
> + 5 = 65Hz if 48KHz mode.

Use proper unit suffixes - hz.


> + enum:
> + - 0
> + - 1
> + - 2
> + - 3
> + - 4
> + - 5
> +
> + mediatek,dmic-two-wire-mode:
> + description:
> + Boolean which turns on digital microphone for two wire mode.
> + If this property is not present the two wire mode is disabled.

This looks like hardware property, but the naming looks like SW. Again
you instruct what driver should do. Standard disclaimer:

You described the desired Linux feature or behavior, not the actual
hardware. The bindings are about the latter, so instead you need to
rephrase the property and its description to match actual hardware
capabilities/features/configuration etc.


> + type: boolean
> +
> +

Just one blank line.

> +required:
> + - compatible
> + - reg
> + - interrupts
> + - power-domains
> + - mediatek,topckgen
> + - clocks
> + - clock-names
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/clock/mediatek,mt8365-clk.h>
> + #include <dt-bindings/interrupt-controller/arm-gic.h>
> + #include <dt-bindings/interrupt-controller/irq.h>
> + #include <dt-bindings/power/mediatek,mt8365-power.h>
> +
> + soc {
> + #address-cells = <2>;
> + #size-cells = <2>;
> +
> + afe@11220000 {

What is AFE?

https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation


> + compatible = "mediatek,mt8365-afe-pcm";


Best regards,
Krzysztof


2024-02-27 09:35:27

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH 08/18] ASoC: mediatek: mt8365: Add DMIC DAI support

On 26/02/2024 15:01, Alexandre Mergnat wrote:
> Add Digital Micro Device Audio Interface support for MT8365 SoC.
>
> Signed-off-by: Alexandre Mergnat <[email protected]>


> +
> +static int init_dmic_priv_data(struct mtk_base_afe *afe)
> +{
> + struct mt8365_afe_private *afe_priv = afe->platform_priv;
> + struct mt8365_dmic_data *dmic_priv;
> + struct device_node *np = afe->dev->of_node;
> + unsigned int temps[4];
> + int ret;
> +
> + dmic_priv = devm_kzalloc(afe->dev, sizeof(struct mt8365_dmic_data),
> + GFP_KERNEL);

You have very inconsistent style of coding. Some patches are done
correctly, some repeast known issues. All over. This is sizeof(*). This
comment (and all others) apply everywhere, just in case.

Best regards,
Krzysztof


2024-02-27 10:23:57

by Alexandre Mergnat

[permalink] [raw]
Subject: Re: [PATCH 02/18] ASoC: dt-bindings: mediatek,mt8365-mt6357: Add audio sound card document



On 26/02/2024 16:30, AngeloGioacchino Del Regno wrote:
> Il 26/02/24 15:01, Alexandre Mergnat ha scritto:
>> Add soundcard bindings for the MT8365 SoC with the MT6357 audio codec.
>>
>> Signed-off-by: Alexandre Mergnat <[email protected]>
>> ---
>>   .../bindings/sound/mediatek,mt8365-mt6357.yaml     | 127
>> +++++++++++++++++++++
>>   1 file changed, 127 insertions(+)
>>
>> diff --git
>> a/Documentation/devicetree/bindings/sound/mediatek,mt8365-mt6357.yaml
>> b/Documentation/devicetree/bindings/sound/mediatek,mt8365-mt6357.yaml
>> new file mode 100644
>> index 000000000000..f469611ec6b6
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/sound/mediatek,mt8365-mt6357.yaml
>> @@ -0,0 +1,127 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/sound/mediatek,mt8365-mt6357.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Mediatek MT8365 sound card with MT6357 sound codec.
>> +
>> +maintainers:
>> +  - Alexandre Mergnat <[email protected]>
>> +
>> +description:
>> +  This binding describes the MT8365 sound card.
>> +
>> +properties:
>> +  compatible:
>> +    const: mediatek,mt8365-mt6357
>> +
>> +  mediatek,hp-pull-down:
>> +    description:
>> +      Earphone driver positive output stage short to the
>> +      audio reference ground.
>> +      Default value is false.
>> +    type: boolean
>> +
>> +  mediatek,micbias0-microvolt:
>> +    description: |
>
> description: Selects MIC Bias 0 output voltage
>
>> +      Selects MIC Bias 0 output voltage.
>> +      [1.7v, 1.8v, 1.9v, 2.0v, 2.1v, 2.5v, 2.6v, 2.7v]
>> +    enum: [0, 1, 2, 3, 4, 5, 6, 7]
>
> No, you don't say 0 1 2 3 4 to a property that says "microvolt", that's
> simply
> wrong.
>
> mediatek,micbias0-microvolt = <2100000>;
>
> ...so you want a binding that says
> enum: [ 1700000, 1800000, this, that, 2700000]
>

Is it correct if I put "description: Selects MIC Bias 0 output voltage
index" ?

>> +
>> +  mediatek,micbias1-microvolt:
>> +    description: |
>> +      Selects MIC Bias 1 output voltage.
>> +      [1.7v, 1.8v, 1.9v, 2.0v, 2.1v, 2.5v, 2.6v, 2.7v]
>> +    enum: [0, 1, 2, 3, 4, 5, 6, 7]
>
> same here.
>
>> +
>> +  mediatek,platform:
>> +    $ref: /schemas/types.yaml#/definitions/phandle
>> +    description: The phandle of MT8365 ASoC platform.
>> +
>> +  pinctrl-names:
>> +    minItems: 1
>> +    items:
>> +      - const: aud_default
>> +      - const: aud_dmic
>> +      - const: aud_miso_off
>> +      - const: aud_miso_on
>> +      - const: aud_mosi_off
>> +      - const: aud_mosi_on
>> +
>> +  vaud28-supply:
>> +    description:
>> +      2.8 volt supply for the audio codec
>> +
>> +patternProperties:
>> +  "^dai-link-[0-9]+$":
>> +    type: object
>> +    description:
>> +      Container for dai-link level properties and CODEC sub-nodes.
>> +
>> +    properties:
>> +      codec:
>> +        type: object
>> +        description: Holds subnode which indicates codec dai.
>> +
>> +        properties:
>> +          sound-dai:
>> +            maxItems: 1
>> +            description: phandle of the codec DAI
>> +
>> +        additionalProperties: false
>> +
>> +      link-name:
>> +        description:
>> +          This property corresponds to the name of the BE dai-link to
>> which
>> +          we are going to update parameters in this node.
>> +        items:
>> +          const: 2ND I2S BE
>> +
>> +      sound-dai:
>> +        maxItems: 1
>> +        description: phandle of the CPU DAI
>> +
>> +    additionalProperties: false
>> +
>> +    required:
>> +      - link-name
>> +      - sound-dai
>> +
>> +additionalProperties: false
>> +
>> +required:
>> +  - compatible
>> +  - mediatek,platform
>> +  - pinctrl-names
>> +  - vaud28-supply
>> +
>> +examples:
>> +  - |
>> +    sound {
>> +        compatible = "mediatek,mt8365-mt6357";
>> +        mediatek,platform = <&afe>;
>
> Please:
>
> https://docs.kernel.org/devicetree/bindings/dts-coding-style.html

Is it about the wrong pinctrl-names tab alignment ?
Also, 2ND I2S BE => 2ND_I2S_BE ?
Otherwise, I don't get it sorry.

>
> Regards,
> Angelo
>
>> +        pinctrl-names = "aud_default",
>> +            "aud_dmic",
>> +            "aud_miso_off",
>> +            "aud_miso_on",
>> +            "aud_mosi_off",
>> +            "aud_mosi_on";
>> +        pinctrl-0 = <&aud_default_pins>;
>> +        pinctrl-1 = <&aud_dmic_pins>;
>> +        pinctrl-2 = <&aud_miso_off_pins>;
>> +        pinctrl-3 = <&aud_miso_on_pins>;
>> +        pinctrl-4 = <&aud_mosi_off_pins>;
>> +        pinctrl-5 = <&aud_mosi_on_pins>;
>> +        vaud28-supply = <&mt6357_vaud28_reg>;
>> +
>> +        /* hdmi interface */
>> +        dai-link-0 {
>> +            sound-dai = <&afe>;
>> +            link-name = "2ND I2S BE";
>> +
>> +            codec {
>> +                sound-dai = <&it66121hdmitx>;
>> +            };
>> +        };
>> +    };
>>
>

--
Regards,
Alexandre

2024-02-27 10:31:49

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH 02/18] ASoC: dt-bindings: mediatek,mt8365-mt6357: Add audio sound card document

On 27/02/2024 11:23, Alexandre Mergnat wrote:
>>> +
>>> +examples:
>>> +  - |
>>> +    sound {
>>> +        compatible = "mediatek,mt8365-mt6357";
>>> +        mediatek,platform = <&afe>;
>>
>> Please:
>>
>> https://docs.kernel.org/devicetree/bindings/dts-coding-style.html
>
> Is it about the wrong pinctrl-names tab alignment ?
> Also, 2ND I2S BE => 2ND_I2S_BE ?
> Otherwise, I don't get it sorry.

Alignment of continued lines, order of properties.

Best regards,
Krzysztof


2024-02-27 15:09:42

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH 00/18] Add audio support for the MediaTek Genio 350-evk board

On Mon, Feb 26, 2024 at 03:01:38PM +0100, Alexandre Mergnat wrote:
> This serie aim to add the following audio support for the Genio 350-evk:
> - Playback
> - 2ch Headset Jack (Earphone)
> - 1ch Line-out Jack (Speaker)
> - 8ch HDMI Tx
> - Capture
> - 1ch DMIC (On-board Digital Microphone)
> - 1ch AMIC (On-board Analogic Microphone)
> - 1ch Headset Jack (External Analogic Microphone)
>
> Of course, HDMI playback need the MT8365 display patches [1] and a DTS
> change documented in "mediatek,mt8365-mt6357.yaml".

Given the number of custom controls here could you please post the
output of mixer-test and pcm-test from a system with this driver running
next time you post, this will help with review since it checks a bunch
of things around the new controls.


Attachments:
(No filename) (794.00 B)
signature.asc (499.00 B)
Download all attachments

2024-02-27 15:20:01

by Alexandre Mergnat

[permalink] [raw]
Subject: Re: [PATCH 01/18] ASoC: dt-bindings: mediatek,mt8365-afe: Add audio afe document



On 27/02/2024 10:01, Krzysztof Kozlowski wrote:
> On 26/02/2024 15:01, Alexandre Mergnat wrote:
>> Add MT8365 audio front-end bindings
>>
>> Signed-off-by: Alexandre Mergnat <[email protected]>
>> ---
>> .../bindings/sound/mediatek,mt8365-afe.yaml | 164 +++++++++++++++++++++
>> 1 file changed, 164 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8365-afe.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8365-afe.yaml
>> new file mode 100644
>> index 000000000000..1d7eb2532ad2
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/sound/mediatek,mt8365-afe.yaml
>> @@ -0,0 +1,164 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/sound/mediatek,mt8365-afe.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: MediaTek AFE PCM controller for MT8365
>> +
>> +maintainers:
>> + - Alexandre Mergnat <[email protected]>
>> +
>> +properties:
>> + compatible:
>> + const: mediatek,mt8365-afe-pcm
>> +
>> + reg:
>> + maxItems: 2
>
> You must describe the items.

Actually, I've took downstream code that I'm not able to explain because
the second reg isn't on my MTK documentation.
So I've remove the second reg and passed all functional tests
successfully. Then I will remove the extra reg for v2.

>
>> +
>> + interrupts:
>> + maxItems: 1
>> +
>> + mediatek,topckgen:
>> + $ref: /schemas/types.yaml#/definitions/phandle
>> + description: The phandle of the mediatek topckgen controller
>
> What for? Don't repeat the property name. Say something useful.

got it

>
>> +
>> + power-domains:
>> + maxItems: 1
>> +
>> + "#sound-dai-cells":
>> + const: 0
>> +
>> + clocks:
>> + items:
>> + - description: 26M clock
>> + - description: mux for audio clock
>> + - description: audio i2s0 mck
>> + - description: audio i2s1 mck
>> + - description: audio i2s2 mck
>> + - description: audio i2s3 mck
>> + - description: engen 1 clock
>> + - description: engen 2 clock
>> + - description: audio 1 clock
>> + - description: audio 2 clock
>> + - description: mux for i2s0
>> + - description: mux for i2s1
>> + - description: mux for i2s2
>> + - description: mux for i2s3
>> +
>> + clock-names:
>> + items:
>> + - const: top_clk26m_clk
>> + - const: top_audio_sel
>> + - const: audio_i2s0_m
>> + - const: audio_i2s1_m
>> + - const: audio_i2s2_m
>> + - const: audio_i2s3_m
>> + - const: engen1
>> + - const: engen2
>> + - const: aud1
>> + - const: aud2
>> + - const: i2s0_m_sel
>> + - const: i2s1_m_sel
>> + - const: i2s2_m_sel
>> + - const: i2s3_m_sel
>> +
>> + mediatek,i2s-shared-clock:
>
> Why do you need this property? Linux (and other systems) handle sharing
> clocks properly.

Indeed, not needed. It was used by the downstream code driver but I
remove it for v2.

>
>> + description:
>> + i2s modules can share the same external clock pin.
>> + If this property is not present the clock mode is separrate.
>
> Typo
>
>> + type: boolean
>> +
>> + mediatek,dmic-iir-on:
>> + description:
>> + Boolean which specifies whether the DMIC IIR is enabled.
>> + If this property is not present the IIR is disabled.
>
> "is enabled" or "enable it"?
>
> You described the desired Linux feature or behavior, not the actual
> hardware. The bindings are about the latter, so instead you need to
> rephrase the property and its description to match actual hardware
> capabilities/features/configuration etc.

I will rephrase:

True to enable the Infinite Impulse Response (IIR) filter
on the digital microphone inputs.

>
>> + type: boolean
>> +
>> + mediatek,dmic-irr-mode:
>> + $ref: /schemas/types.yaml#/definitions/uint32
>> + description:
>> + Selects stop band of IIR DC-removal filter.
>> + 0 = Software programmable custom coeff loaded by the driver.
>
> Bindings are for hardware, not drivers. Why is this a property of board DTS?

Actually this is a hardware feature. Mode 1 t 5 are predefined filters.
Mode 0, the HW will read some "coef filter registers" to setup the
custom filter. the "coef filter regs" are written by the driver.
Currently the coef values are hardcoded in the driver.

>
>> + 1 = 5Hz if 48KHz mode.
>> + 2 = 10Hz if 48KHz mode.
>> + 3 = 25Hz if 48KHz mode.
>> + 4 = 50Hz if 48KHz mode.
>> + 5 = 65Hz if 48KHz mode.
>
> Use proper unit suffixes - hz.
>
>
>> + enum:
>> + - 0
>> + - 1
>> + - 2
>> + - 3
>> + - 4
>> + - 5
>> +
>> + mediatek,dmic-two-wire-mode:
>> + description:
>> + Boolean which turns on digital microphone for two wire mode.
>> + If this property is not present the two wire mode is disabled.
>
> This looks like hardware property, but the naming looks like SW. Again
> you instruct what driver should do. Standard disclaimer:
>
> You described the desired Linux feature or behavior, not the actual
> hardware. The bindings are about the latter, so instead you need to
> rephrase the property and its description to match actual hardware
> capabilities/features/configuration etc.

Actually this is a hardware feature. This is ALL I have to describe the
HW behavior from the datasheet:
"
bit name: ul_dmic_two_wire_ctl
Turns on digital microphone for two wire mode.
0: Turn off
1: Turn on
"

On the board schematic, SoC and DMIC and linked by 3 pins:
- clk
- data0
- data1

IMHO, "two-wire-mode" means the HW use 2 pins for data, and the SoC must
be aware of that by reading the register value written by the driver,
using the value found in the DTS.

I don't get why you think it wouldn't be hardware behavior.

Rephrase description:
"True to enable the two wire mode of the digital microphone"
Is it better ?

About the property name, "mediatek,dmic-two-wire-ctl" sound better for you ?

>
>
>> + type: boolean
>> +
>> +
>
> Just one blank line.
>
>> +required:
>> + - compatible
>> + - reg
>> + - interrupts
>> + - power-domains
>> + - mediatek,topckgen
>> + - clocks
>> + - clock-names
>> +
>> +additionalProperties: false
>> +
>> +examples:
>> + - |
>> + #include <dt-bindings/clock/mediatek,mt8365-clk.h>
>> + #include <dt-bindings/interrupt-controller/arm-gic.h>
>> + #include <dt-bindings/interrupt-controller/irq.h>
>> + #include <dt-bindings/power/mediatek,mt8365-power.h>
>> +
>> + soc {
>> + #address-cells = <2>;
>> + #size-cells = <2>;
>> +
>> + afe@11220000 {
>
> What is AFE?

Audio Front End, this is the same name used for other MTK SoC, to be
consistent.

Cook a new patch serie to change "afe" by "audio-controller" for all MTK
SoC would be great.

>
> https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation
>
>
>> + compatible = "mediatek,mt8365-afe-pcm";
>
>
> Best regards,
> Krzysztof
>

--
Regards,
Alexandre

2024-02-28 07:28:25

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH 01/18] ASoC: dt-bindings: mediatek,mt8365-afe: Add audio afe document

On 27/02/2024 16:18, Alexandre Mergnat wrote:
>>
>>> + type: boolean
>>> +
>>> + mediatek,dmic-iir-on:
>>> + description:
>>> + Boolean which specifies whether the DMIC IIR is enabled.
>>> + If this property is not present the IIR is disabled.
>>
>> "is enabled" or "enable it"?
>>
>> You described the desired Linux feature or behavior, not the actual
>> hardware. The bindings are about the latter, so instead you need to
>> rephrase the property and its description to match actual hardware
>> capabilities/features/configuration etc.
>
> I will rephrase:
>
> True to enable the Infinite Impulse Response (IIR) filter
> on the digital microphone inputs.

I still don't know why this is DT-specific. You still tell driver what
to do...

>
>>
>>> + type: boolean
>>> +
>>> + mediatek,dmic-irr-mode:
>>> + $ref: /schemas/types.yaml#/definitions/uint32
>>> + description:
>>> + Selects stop band of IIR DC-removal filter.
>>> + 0 = Software programmable custom coeff loaded by the driver.
>>
>> Bindings are for hardware, not drivers. Why is this a property of board DTS?
>
> Actually this is a hardware feature. Mode 1 t 5 are predefined filters.
> Mode 0, the HW will read some "coef filter registers" to setup the
> custom filter. the "coef filter regs" are written by the driver.
> Currently the coef values are hardcoded in the driver.

You don't get the point. Just because you choose some mode it does not
mean is hardware feature for DT. Sampling frequency done by hardware is
also "hardware feature", but do you put it to DT? No.

Explain why this is board-specific, not runtime configuration.

>
>>
>>> + 1 = 5Hz if 48KHz mode.
>>> + 2 = 10Hz if 48KHz mode.
>>> + 3 = 25Hz if 48KHz mode.
>>> + 4 = 50Hz if 48KHz mode.
>>> + 5 = 65Hz if 48KHz mode.
>>
>> Use proper unit suffixes - hz.
>>
>>
>>> + enum:
>>> + - 0
>>> + - 1
>>> + - 2
>>> + - 3
>>> + - 4
>>> + - 5
>>> +
>>> + mediatek,dmic-two-wire-mode:
>>> + description:
>>> + Boolean which turns on digital microphone for two wire mode.
>>> + If this property is not present the two wire mode is disabled.
>>
>> This looks like hardware property, but the naming looks like SW. Again
>> you instruct what driver should do. Standard disclaimer:
>>
>> You described the desired Linux feature or behavior, not the actual
>> hardware. The bindings are about the latter, so instead you need to
>> rephrase the property and its description to match actual hardware
>> capabilities/features/configuration etc.
>
> Actually this is a hardware feature. This is ALL I have to describe the
> HW behavior from the datasheet:
> "
> bit name: ul_dmic_two_wire_ctl
> Turns on digital microphone for two wire mode.
> 0: Turn off
> 1: Turn on

That's rather suggestion it is not a description of hardware but you
want driver to do something...

> "
>
> On the board schematic, SoC and DMIC and linked by 3 pins:
> - clk
> - data0
> - data1
>
> IMHO, "two-wire-mode" means the HW use 2 pins for data, and the SoC must
> be aware of that by reading the register value written by the driver,
> using the value found in the DTS.

So this depends on type of connection of DMIC? Then rephrase description
property like this.

>
> I don't get why you think it wouldn't be hardware behavior.

Because telling what to write to the registers which is typical sign of
people stuffing to DT whatever they need to configure the hardware.

>
> Rephrase description:
> "True to enable the two wire mode of the digital microphone"
> Is it better ?

No, because again you describe some sort of mode. If you insist on such
description, then my answer is: it's runtime, so not suitable for DT.
Instead describe what is the hardware problem/configuration, e.g. "DMIC
is connected with only CLK and DATA0, without third pin" etc.

>
> About the property name, "mediatek,dmic-two-wire-ctl" sound better for you ?

To sound more like a register less like physical characteristic of the
board? No. The name can stay, I don't have better ideas.


Best regards,
Krzysztof


2024-02-28 09:18:54

by Alexandre Mergnat

[permalink] [raw]
Subject: Re: [PATCH 02/18] ASoC: dt-bindings: mediatek,mt8365-mt6357: Add audio sound card document



On 27/02/2024 13:38, AngeloGioacchino Del Regno wrote:
> Il 27/02/24 11:23, Alexandre Mergnat ha scritto:
>>
>>
>> On 26/02/2024 16:30, AngeloGioacchino Del Regno wrote:
>>> Il 26/02/24 15:01, Alexandre Mergnat ha scritto:
>>>> Add soundcard bindings for the MT8365 SoC with the MT6357 audio codec.
>>>>
>>>> Signed-off-by: Alexandre Mergnat <[email protected]>
>>>> ---
>>>>   .../bindings/sound/mediatek,mt8365-mt6357.yaml     | 127
>>>> +++++++++++++++++++++
>>>>   1 file changed, 127 insertions(+)
>>>>
>>>> diff --git
>>>> a/Documentation/devicetree/bindings/sound/mediatek,mt8365-mt6357.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8365-mt6357.yaml
>>>> new file mode 100644
>>>> index 000000000000..f469611ec6b6
>>>> --- /dev/null
>>>> +++
>>>> b/Documentation/devicetree/bindings/sound/mediatek,mt8365-mt6357.yaml
>>>> @@ -0,0 +1,127 @@
>>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>>>> +%YAML 1.2
>>>> +---
>>>> +$id: http://devicetree.org/schemas/sound/mediatek,mt8365-mt6357.yaml#
>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>>> +
>>>> +title: Mediatek MT8365 sound card with MT6357 sound codec.
>>>> +
>>>> +maintainers:
>>>> +  - Alexandre Mergnat <[email protected]>
>>>> +
>>>> +description:
>>>> +  This binding describes the MT8365 sound card.
>>>> +
>>>> +properties:
>>>> +  compatible:
>>>> +    const: mediatek,mt8365-mt6357
>>>> +
>>>> +  mediatek,hp-pull-down:
>>>> +    description:
>>>> +      Earphone driver positive output stage short to the
>>>> +      audio reference ground.
>>>> +      Default value is false.
>>>> +    type: boolean
>>>> +
>>>> +  mediatek,micbias0-microvolt:
>>>> +    description: |
>>>
>>> description: Selects MIC Bias 0 output voltage
>>>
>>>> +      Selects MIC Bias 0 output voltage.
>>>> +      [1.7v, 1.8v, 1.9v, 2.0v, 2.1v, 2.5v, 2.6v, 2.7v]
>>>> +    enum: [0, 1, 2, 3, 4, 5, 6, 7]
>>>
>>> No, you don't say 0 1 2 3 4 to a property that says "microvolt",
>>> that's simply
>>> wrong.
>>>
>>> mediatek,micbias0-microvolt = <2100000>;
>>>
>>> ...so you want a binding that says
>>> enum: [ 1700000, 1800000, this, that, 2700000]
>>>
>>
>> Is it correct if I put "description: Selects MIC Bias 0 output voltage
>> index" ?
>>
>
> No, it's still not correct. You have to pass microvolt values.
>
> The driver will then transform the microvolt values to the index and
> subsequently
> write the index value to the hardware registers.
>
> The bindings shall be generic, in the sense that they shall not express
> hardware
> register values... and this is especially true when we have a value that
> *does*
> actually have means to be expressed in common units.
>
> Besides, in the cases in which there's no common units involved, the
> values most
> probably won't be suited for devicetree//bindings, so those would be
> hardcoded in
> the driver as platform data.
>
> This is not the case, so, please keep this property but specify
> microvolts in the
> bindings (and obviously in devicetree).

Got it, thx !

>
>>>> +
>>>> +  mediatek,micbias1-microvolt:
>>>> +    description: |
>>>> +      Selects MIC Bias 1 output voltage.
>>>> +      [1.7v, 1.8v, 1.9v, 2.0v, 2.1v, 2.5v, 2.6v, 2.7v]
>>>> +    enum: [0, 1, 2, 3, 4, 5, 6, 7]
>>>
>>> same here.
>>>
>>>> +
>>>> +  mediatek,platform:
>>>> +    $ref: /schemas/types.yaml#/definitions/phandle
>>>> +    description: The phandle of MT8365 ASoC platform.
>>>> +
>>>> +  pinctrl-names:
>>>> +    minItems: 1
>>>> +    items:
>>>> +      - const: aud_default
>>>> +      - const: aud_dmic
>>>> +      - const: aud_miso_off
>>>> +      - const: aud_miso_on
>>>> +      - const: aud_mosi_off
>>>> +      - const: aud_mosi_on
>>>> +
>>>> +  vaud28-supply:
>>>> +    description:
>>>> +      2.8 volt supply for the audio codec
>>>> +
>>>> +patternProperties:
>>>> +  "^dai-link-[0-9]+$":
>>>> +    type: object
>>>> +    description:
>>>> +      Container for dai-link level properties and CODEC sub-nodes.
>>>> +
>>>> +    properties:
>>>> +      codec:
>>>> +        type: object
>>>> +        description: Holds subnode which indicates codec dai.
>>>> +
>>>> +        properties:
>>>> +          sound-dai:
>>>> +            maxItems: 1
>>>> +            description: phandle of the codec DAI
>>>> +
>>>> +        additionalProperties: false
>>>> +
>>>> +      link-name:
>>>> +        description:
>>>> +          This property corresponds to the name of the BE dai-link
>>>> to which
>>>> +          we are going to update parameters in this node.
>>>> +        items:
>>>> +          const: 2ND I2S BE
>>>> +
>>>> +      sound-dai:
>>>> +        maxItems: 1
>>>> +        description: phandle of the CPU DAI
>>>> +
>>>> +    additionalProperties: false
>>>> +
>>>> +    required:
>>>> +      - link-name
>>>> +      - sound-dai
>>>> +
>>>> +additionalProperties: false
>>>> +
>>>> +required:
>>>> +  - compatible
>>>> +  - mediatek,platform
>>>> +  - pinctrl-names
>>>> +  - vaud28-supply
>>>> +
>>>> +examples:
>>>> +  - |
>>>> +    sound {
>>>> +        compatible = "mediatek,mt8365-mt6357";
>>>> +        mediatek,platform = <&afe>;
>>>
>>> Please:
>>>
>>> https://docs.kernel.org/devicetree/bindings/dts-coding-style.html
>>
>> Is it about the wrong pinctrl-names tab alignment ?
>> Also, 2ND I2S BE => 2ND_I2S_BE ?
>> Otherwise, I don't get it sorry.
>>
>
> ...as Krzysztof already clarified, won't repeat :-P

Yes it is, I will fix that.

>
> Cheers!
>
>>>
>>> Regards,
>>> Angelo
>>>
>>>> +        pinctrl-names = "aud_default",
>>>> +            "aud_dmic",
>>>> +            "aud_miso_off",
>>>> +            "aud_miso_on",
>>>> +            "aud_mosi_off",
>>>> +            "aud_mosi_on";
>>>> +        pinctrl-0 = <&aud_default_pins>;
>>>> +        pinctrl-1 = <&aud_dmic_pins>;
>>>> +        pinctrl-2 = <&aud_miso_off_pins>;
>>>> +        pinctrl-3 = <&aud_miso_on_pins>;
>>>> +        pinctrl-4 = <&aud_mosi_off_pins>;
>>>> +        pinctrl-5 = <&aud_mosi_on_pins>;
>>>> +        vaud28-supply = <&mt6357_vaud28_reg>;
>>>> +
>>>> +        /* hdmi interface */
>>>> +        dai-link-0 {
>>>> +            sound-dai = <&afe>;
>>>> +            link-name = "2ND I2S BE";
>>>> +
>>>> +            codec {
>>>> +                sound-dai = <&it66121hdmitx>;
>>>> +            };
>>>> +        };
>>>> +    };
>>>>
>>>
>>
>
>

--
Regards,
Alexandre

2024-02-28 09:57:41

by Alexandre Mergnat

[permalink] [raw]
Subject: Re: [PATCH 01/18] ASoC: dt-bindings: mediatek,mt8365-afe: Add audio afe document

I think I got it.

- mediatek,i2s-shared-clock: will be remove from DT
- mediatek,dmic-iir-on: will be remove from DT
- mediatek,dmic-irr-mode: will be remove from DT
- mediatek,dmic-two-wire-mode: rephrase description needed

I've did abstraction (despite me) that IIR settings are runtime config
because the driver implement its usage like a one-time-setup -_-'

Thanks for the explanations, that help.

Regards,
Alexandre

On 28/02/2024 08:28, Krzysztof Kozlowski wrote:
> On 27/02/2024 16:18, Alexandre Mergnat wrote:
>>>
>>>> + type: boolean
>>>> +
>>>> + mediatek,dmic-iir-on:
>>>> + description:
>>>> + Boolean which specifies whether the DMIC IIR is enabled.
>>>> + If this property is not present the IIR is disabled.
>>>
>>> "is enabled" or "enable it"?
>>>
>>> You described the desired Linux feature or behavior, not the actual
>>> hardware. The bindings are about the latter, so instead you need to
>>> rephrase the property and its description to match actual hardware
>>> capabilities/features/configuration etc.
>>
>> I will rephrase:
>>
>> True to enable the Infinite Impulse Response (IIR) filter
>> on the digital microphone inputs.
>
> I still don't know why this is DT-specific. You still tell driver what
> to do...
>
>>
>>>
>>>> + type: boolean
>>>> +
>>>> + mediatek,dmic-irr-mode:
>>>> + $ref: /schemas/types.yaml#/definitions/uint32
>>>> + description:
>>>> + Selects stop band of IIR DC-removal filter.
>>>> + 0 = Software programmable custom coeff loaded by the driver.
>>>
>>> Bindings are for hardware, not drivers. Why is this a property of board DTS?
>>
>> Actually this is a hardware feature. Mode 1 t 5 are predefined filters.
>> Mode 0, the HW will read some "coef filter registers" to setup the
>> custom filter. the "coef filter regs" are written by the driver.
>> Currently the coef values are hardcoded in the driver.
>
> You don't get the point. Just because you choose some mode it does not
> mean is hardware feature for DT. Sampling frequency done by hardware is
> also "hardware feature", but do you put it to DT? No.
>
> Explain why this is board-specific, not runtime configuration.
>
>>
>>>
>>>> + 1 = 5Hz if 48KHz mode.
>>>> + 2 = 10Hz if 48KHz mode.
>>>> + 3 = 25Hz if 48KHz mode.
>>>> + 4 = 50Hz if 48KHz mode.
>>>> + 5 = 65Hz if 48KHz mode.
>>>
>>> Use proper unit suffixes - hz.
>>>
>>>
>>>> + enum:
>>>> + - 0
>>>> + - 1
>>>> + - 2
>>>> + - 3
>>>> + - 4
>>>> + - 5
>>>> +
>>>> + mediatek,dmic-two-wire-mode:
>>>> + description:
>>>> + Boolean which turns on digital microphone for two wire mode.
>>>> + If this property is not present the two wire mode is disabled.
>>>
>>> This looks like hardware property, but the naming looks like SW. Again
>>> you instruct what driver should do. Standard disclaimer:
>>>
>>> You described the desired Linux feature or behavior, not the actual
>>> hardware. The bindings are about the latter, so instead you need to
>>> rephrase the property and its description to match actual hardware
>>> capabilities/features/configuration etc.
>>
>> Actually this is a hardware feature. This is ALL I have to describe the
>> HW behavior from the datasheet:
>> "
>> bit name: ul_dmic_two_wire_ctl
>> Turns on digital microphone for two wire mode.
>> 0: Turn off
>> 1: Turn on
>
> That's rather suggestion it is not a description of hardware but you
> want driver to do something...
>
>> "
>>
>> On the board schematic, SoC and DMIC and linked by 3 pins:
>> - clk
>> - data0
>> - data1
>>
>> IMHO, "two-wire-mode" means the HW use 2 pins for data, and the SoC must
>> be aware of that by reading the register value written by the driver,
>> using the value found in the DTS.
>
> So this depends on type of connection of DMIC? Then rephrase description
> property like this.
>
>>
>> I don't get why you think it wouldn't be hardware behavior.
>
> Because telling what to write to the registers which is typical sign of
> people stuffing to DT whatever they need to configure the hardware.
>
>>
>> Rephrase description:
>> "True to enable the two wire mode of the digital microphone"
>> Is it better ?
>
> No, because again you describe some sort of mode. If you insist on such
> description, then my answer is: it's runtime, so not suitable for DT.
> Instead describe what is the hardware problem/configuration, e.g. "DMIC
> is connected with only CLK and DATA0, without third pin" etc.
>
>>
>> About the property name, "mediatek,dmic-two-wire-ctl" sound better for you ?
>
> To sound more like a register less like physical characteristic of the
> board? No. The name can stay, I don't have better ideas.
>
>
> Best regards,
> Krzysztof
>


Subject: Re: [PATCH 01/18] ASoC: dt-bindings: mediatek,mt8365-afe: Add audio afe document

Il 28/02/24 10:57, Alexandre Mergnat ha scritto:
> I think I got it.
>
> - mediatek,i2s-shared-clock: will be remove from DT
> - mediatek,dmic-iir-on: will be remove from DT
> - mediatek,dmic-irr-mode: will be remove from DT
> - mediatek,dmic-two-wire-mode: rephrase description needed
>
> I've did abstraction (despite me) that IIR settings are runtime config because the
> driver implement its usage like a one-time-setup -_-'
>

Yes but just one more thing I just noticed: `mediatek,dmic-two-wire-mode` - can we
please rename this to `mediatek,dmic-mode` ?

That'd be for consistency check mt6359.yaml and mt6358.txt

mediatek,dmic-mode:
$ref: /schemas/types.yaml#/definitions/uint32
description: |
Indicates how many data pins are used to transmit two channels of PDM
signal. 0 means two wires, 1 means one wire. Default value is 0.
enum:
- 0 # one wire
- 1 # two wires

Cheers,
Angelo



> Thanks for the explanations, that help.
>
> Regards,
> Alexandre
>
> On 28/02/2024 08:28, Krzysztof Kozlowski wrote:
>> On 27/02/2024 16:18, Alexandre Mergnat wrote:
>>>>
>>>>> +    type: boolean
>>>>> +
>>>>> +  mediatek,dmic-iir-on:
>>>>> +    description:
>>>>> +      Boolean which specifies whether the DMIC IIR is enabled.
>>>>> +      If this property is not present the IIR is disabled.
>>>>
>>>> "is enabled" or "enable it"?
>>>>
>>>> You described the desired Linux feature or behavior, not the actual
>>>> hardware. The bindings are about the latter, so instead you need to
>>>> rephrase the property and its description to match actual hardware
>>>> capabilities/features/configuration etc.
>>>
>>> I will rephrase:
>>>
>>> True to enable the Infinite Impulse Response (IIR) filter
>>> on the digital microphone inputs.
>>
>> I still don't know why this is DT-specific. You still tell driver what
>> to do...
>>
>>>
>>>>
>>>>> +    type: boolean
>>>>> +
>>>>> +  mediatek,dmic-irr-mode:
>>>>> +    $ref: /schemas/types.yaml#/definitions/uint32
>>>>> +    description:
>>>>> +      Selects stop band of IIR DC-removal filter.
>>>>> +      0 = Software programmable custom coeff loaded by the driver.
>>>>
>>>> Bindings are for hardware, not drivers. Why is this a property of board DTS?
>>>
>>> Actually this is a hardware feature. Mode 1 t 5 are predefined filters.
>>> Mode 0, the HW will read some "coef filter registers" to setup the
>>> custom filter. the "coef filter regs" are written by the driver.
>>> Currently the coef values are hardcoded in the driver.
>>
>> You don't get the point. Just because you choose some mode it does not
>> mean is hardware feature for DT. Sampling frequency done by hardware is
>> also "hardware feature", but do you put it to DT? No.
>>
>> Explain why this is board-specific, not runtime configuration.
>>
>>>
>>>>
>>>>> +      1 = 5Hz if 48KHz mode.
>>>>> +      2 = 10Hz if 48KHz mode.
>>>>> +      3 = 25Hz if 48KHz mode.
>>>>> +      4 = 50Hz if 48KHz mode.
>>>>> +      5 = 65Hz if 48KHz mode.
>>>>
>>>> Use proper unit suffixes - hz.
>>>>
>>>>
>>>>> +    enum:
>>>>> +      - 0
>>>>> +      - 1
>>>>> +      - 2
>>>>> +      - 3
>>>>> +      - 4
>>>>> +      - 5
>>>>> +
>>>>> +  mediatek,dmic-two-wire-mode:
>>>>> +    description:
>>>>> +      Boolean which turns on digital microphone for two wire mode.
>>>>> +      If this property is not present the two wire mode is disabled.
>>>>
>>>> This looks like hardware property, but the naming looks like SW. Again
>>>> you instruct what driver should do. Standard disclaimer:
>>>>
>>>> You described the desired Linux feature or behavior, not the actual
>>>> hardware. The bindings are about the latter, so instead you need to
>>>> rephrase the property and its description to match actual hardware
>>>> capabilities/features/configuration etc.
>>>
>>> Actually this is a hardware feature. This is ALL I have to describe the
>>> HW behavior from the datasheet:
>>> "
>>> bit name: ul_dmic_two_wire_ctl
>>> Turns on digital microphone for two wire mode.
>>> 0: Turn off
>>> 1: Turn on
>>
>> That's rather suggestion it is not a description of hardware but you
>> want driver to do something...
>>
>>> "
>>>
>>> On the board schematic, SoC and DMIC and linked by 3 pins:
>>> - clk
>>> - data0
>>> - data1
>>>
>>> IMHO, "two-wire-mode" means the HW use 2 pins for data, and the SoC must
>>> be aware of that by reading the register value written by the driver,
>>> using the value found in the DTS.
>>
>> So this depends on type of connection of DMIC? Then rephrase description
>> property like this.
>>
>>>
>>> I don't get why you think it wouldn't be hardware behavior.
>>
>> Because telling what to write to the registers which is typical sign of
>> people stuffing to DT whatever they need to configure the hardware.
>>
>>>
>>> Rephrase description:
>>> "True to enable the two wire mode of the digital microphone"
>>> Is it better ?
>>
>> No, because again you describe some sort of mode. If you insist on such
>> description, then my answer is: it's runtime, so not suitable for DT.
>> Instead describe what is the hardware problem/configuration, e.g. "DMIC
>> is connected with only CLK and DATA0, without third pin" etc.
>>
>>>
>>> About the property name, "mediatek,dmic-two-wire-ctl" sound better for you ?
>>
>> To sound more like a register less like physical characteristic of the
>> board? No. The name can stay, I don't have better ideas.
>>
>>
>> Best regards,
>> Krzysztof
>>
>


2024-02-28 12:06:34

by Alexandre Mergnat

[permalink] [raw]
Subject: Re: [PATCH 01/18] ASoC: dt-bindings: mediatek,mt8365-afe: Add audio afe document



On 28/02/2024 11:25, AngeloGioacchino Del Regno wrote:
> Il 28/02/24 10:57, Alexandre Mergnat ha scritto:
>> I think I got it.
>>
>> - mediatek,i2s-shared-clock: will be remove from DT
>> - mediatek,dmic-iir-on: will be remove from DT
>> - mediatek,dmic-irr-mode: will be remove from DT
>> - mediatek,dmic-two-wire-mode: rephrase description needed
>>
>> I've did abstraction (despite me) that IIR settings are runtime config
>> because the driver implement its usage like a one-time-setup -_-'
>>
>
> Yes but just one more thing I just noticed:
> `mediatek,dmic-two-wire-mode` - can we
> please rename this to `mediatek,dmic-mode` ?

Sure, I wasn't aware of this property. I will do it.

Note: the description isn't consistent with the enum comments
"
0 means two wires, 1 means one wire.
..
- 0 # one wire
- 1 # two wires
"

>
> That'd be for consistency check mt6359.yaml and mt6358.txt
>
>   mediatek,dmic-mode:
>     $ref: /schemas/types.yaml#/definitions/uint32
>     description: |
>       Indicates how many data pins are used to transmit two channels of
> PDM
>       signal. 0 means two wires, 1 means one wire. Default value is 0.
>     enum:
>       - 0 # one wire
>       - 1 # two wires
>
> Cheers,
> Angelo
>
>
>
>> Thanks for the explanations, that help.
>>
>> Regards,
>> Alexandre
>>
>> On 28/02/2024 08:28, Krzysztof Kozlowski wrote:
>>> On 27/02/2024 16:18, Alexandre Mergnat wrote:
>>>>>
>>>>>> +    type: boolean
>>>>>> +
>>>>>> +  mediatek,dmic-iir-on:
>>>>>> +    description:
>>>>>> +      Boolean which specifies whether the DMIC IIR is enabled.
>>>>>> +      If this property is not present the IIR is disabled.
>>>>>
>>>>> "is enabled" or "enable it"?
>>>>>
>>>>> You described the desired Linux feature or behavior, not the actual
>>>>> hardware. The bindings are about the latter, so instead you need to
>>>>> rephrase the property and its description to match actual hardware
>>>>> capabilities/features/configuration etc.
>>>>
>>>> I will rephrase:
>>>>
>>>> True to enable the Infinite Impulse Response (IIR) filter
>>>> on the digital microphone inputs.
>>>
>>> I still don't know why this is DT-specific. You still tell driver what
>>> to do...
>>>
>>>>
>>>>>
>>>>>> +    type: boolean
>>>>>> +
>>>>>> +  mediatek,dmic-irr-mode:
>>>>>> +    $ref: /schemas/types.yaml#/definitions/uint32
>>>>>> +    description:
>>>>>> +      Selects stop band of IIR DC-removal filter.
>>>>>> +      0 = Software programmable custom coeff loaded by the driver.
>>>>>
>>>>> Bindings are for hardware, not drivers. Why is this a property of
>>>>> board DTS?
>>>>
>>>> Actually this is a hardware feature. Mode 1 t 5 are predefined filters.
>>>> Mode 0, the HW will read some "coef filter registers" to setup the
>>>> custom filter. the "coef filter regs" are written by the driver.
>>>> Currently the coef values are hardcoded in the driver.
>>>
>>> You don't get the point. Just because you choose some mode it does not
>>> mean is hardware feature for DT. Sampling frequency done by hardware is
>>> also "hardware feature", but do you put it to DT? No.
>>>
>>> Explain why this is board-specific, not runtime configuration.
>>>
>>>>
>>>>>
>>>>>> +      1 = 5Hz if 48KHz mode.
>>>>>> +      2 = 10Hz if 48KHz mode.
>>>>>> +      3 = 25Hz if 48KHz mode.
>>>>>> +      4 = 50Hz if 48KHz mode.
>>>>>> +      5 = 65Hz if 48KHz mode.
>>>>>
>>>>> Use proper unit suffixes - hz.
>>>>>
>>>>>
>>>>>> +    enum:
>>>>>> +      - 0
>>>>>> +      - 1
>>>>>> +      - 2
>>>>>> +      - 3
>>>>>> +      - 4
>>>>>> +      - 5
>>>>>> +
>>>>>> +  mediatek,dmic-two-wire-mode:
>>>>>> +    description:
>>>>>> +      Boolean which turns on digital microphone for two wire mode.
>>>>>> +      If this property is not present the two wire mode is disabled.
>>>>>
>>>>> This looks like hardware property, but the naming looks like SW. Again
>>>>> you instruct what driver should do. Standard disclaimer:
>>>>>
>>>>> You described the desired Linux feature or behavior, not the actual
>>>>> hardware. The bindings are about the latter, so instead you need to
>>>>> rephrase the property and its description to match actual hardware
>>>>> capabilities/features/configuration etc.
>>>>
>>>> Actually this is a hardware feature. This is ALL I have to describe the
>>>> HW behavior from the datasheet:
>>>> "
>>>> bit name: ul_dmic_two_wire_ctl
>>>> Turns on digital microphone for two wire mode.
>>>> 0: Turn off
>>>> 1: Turn on
>>>
>>> That's rather suggestion it is not a description of hardware but you
>>> want driver to do something...
>>>
>>>> "
>>>>
>>>> On the board schematic, SoC and DMIC and linked by 3 pins:
>>>> - clk
>>>> - data0
>>>> - data1
>>>>
>>>> IMHO, "two-wire-mode" means the HW use 2 pins for data, and the SoC
>>>> must
>>>> be aware of that by reading the register value written by the driver,
>>>> using the value found in the DTS.
>>>
>>> So this depends on type of connection of DMIC? Then rephrase description
>>> property like this.
>>>
>>>>
>>>> I don't get why you think it wouldn't be hardware behavior.
>>>
>>> Because telling what to write to the registers which is typical sign of
>>> people stuffing to DT whatever they need to configure the hardware.
>>>
>>>>
>>>> Rephrase description:
>>>> "True to enable the two wire mode of the digital microphone"
>>>> Is it better ?
>>>
>>> No, because again you describe some sort of mode. If you insist on such
>>> description, then my answer is: it's runtime, so not suitable for DT.
>>> Instead describe what is the hardware problem/configuration, e.g. "DMIC
>>> is connected with only CLK and DATA0, without third pin" etc.
>>>
>>>>
>>>> About the property name, "mediatek,dmic-two-wire-ctl" sound better
>>>> for you ?
>>>
>>> To sound more like a register less like physical characteristic of the
>>> board? No. The name can stay, I don't have better ideas.
>>>
>>>
>>> Best regards,
>>> Krzysztof
>>>
>>
>

--
Regards,
Alexandre

2024-02-28 12:24:33

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH 01/18] ASoC: dt-bindings: mediatek,mt8365-afe: Add audio afe document

On 28/02/2024 11:25, AngeloGioacchino Del Regno wrote:
> Il 28/02/24 10:57, Alexandre Mergnat ha scritto:
>> I think I got it.
>>
>> - mediatek,i2s-shared-clock: will be remove from DT
>> - mediatek,dmic-iir-on: will be remove from DT
>> - mediatek,dmic-irr-mode: will be remove from DT
>> - mediatek,dmic-two-wire-mode: rephrase description needed
>>
>> I've did abstraction (despite me) that IIR settings are runtime config because the
>> driver implement its usage like a one-time-setup -_-'
>>
>
> Yes but just one more thing I just noticed: `mediatek,dmic-two-wire-mode` - can we
> please rename this to `mediatek,dmic-mode` ?
>
> That'd be for consistency check mt6359.yaml and mt6358.txt
>
> mediatek,dmic-mode:
> $ref: /schemas/types.yaml#/definitions/uint32
> description: |
> Indicates how many data pins are used to transmit two channels of PDM
> signal. 0 means two wires, 1 means one wire. Default value is 0.
> enum:
> - 0 # one wire
> - 1 # two wires

Thanks for checking. Now I wonder if entire binding just ignored
existing work and started doing things from scratch...

Best regards,
Krzysztof


2024-02-29 17:45:16

by Lee Jones

[permalink] [raw]
Subject: Re: (subset) [PATCH 13/18] mfd: mt6397-core: register mt6357 sound codec

On Mon, 26 Feb 2024 15:01:51 +0100, [email protected] wrote:
> Add MT6357 codec entry in the MFD driver.
>
>

Applied, thanks!

[13/18] mfd: mt6397-core: register mt6357 sound codec
commit: 79d98102a31ab777b4a6632d799ab2bc63654cf8

--
Lee Jones [李琼斯]


Subject: Re: [PATCH 02/18] ASoC: dt-bindings: mediatek,mt8365-mt6357: Add audio sound card document

Il 27/02/24 11:23, Alexandre Mergnat ha scritto:
>
>
> On 26/02/2024 16:30, AngeloGioacchino Del Regno wrote:
>> Il 26/02/24 15:01, Alexandre Mergnat ha scritto:
>>> Add soundcard bindings for the MT8365 SoC with the MT6357 audio codec.
>>>
>>> Signed-off-by: Alexandre Mergnat <[email protected]>
>>> ---
>>>   .../bindings/sound/mediatek,mt8365-mt6357.yaml     | 127 +++++++++++++++++++++
>>>   1 file changed, 127 insertions(+)
>>>
>>> diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8365-mt6357.yaml
>>> b/Documentation/devicetree/bindings/sound/mediatek,mt8365-mt6357.yaml
>>> new file mode 100644
>>> index 000000000000..f469611ec6b6
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/sound/mediatek,mt8365-mt6357.yaml
>>> @@ -0,0 +1,127 @@
>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>>> +%YAML 1.2
>>> +---
>>> +$id: http://devicetree.org/schemas/sound/mediatek,mt8365-mt6357.yaml#
>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>> +
>>> +title: Mediatek MT8365 sound card with MT6357 sound codec.
>>> +
>>> +maintainers:
>>> +  - Alexandre Mergnat <[email protected]>
>>> +
>>> +description:
>>> +  This binding describes the MT8365 sound card.
>>> +
>>> +properties:
>>> +  compatible:
>>> +    const: mediatek,mt8365-mt6357
>>> +
>>> +  mediatek,hp-pull-down:
>>> +    description:
>>> +      Earphone driver positive output stage short to the
>>> +      audio reference ground.
>>> +      Default value is false.
>>> +    type: boolean
>>> +
>>> +  mediatek,micbias0-microvolt:
>>> +    description: |
>>
>> description: Selects MIC Bias 0 output voltage
>>
>>> +      Selects MIC Bias 0 output voltage.
>>> +      [1.7v, 1.8v, 1.9v, 2.0v, 2.1v, 2.5v, 2.6v, 2.7v]
>>> +    enum: [0, 1, 2, 3, 4, 5, 6, 7]
>>
>> No, you don't say 0 1 2 3 4 to a property that says "microvolt", that's simply
>> wrong.
>>
>> mediatek,micbias0-microvolt = <2100000>;
>>
>> ...so you want a binding that says
>> enum: [ 1700000, 1800000, this, that, 2700000]
>>
>
> Is it correct if I put "description: Selects MIC Bias 0 output voltage index" ?
>

No, it's still not correct. You have to pass microvolt values.

The driver will then transform the microvolt values to the index and subsequently
write the index value to the hardware registers.

The bindings shall be generic, in the sense that they shall not express hardware
register values... and this is especially true when we have a value that *does*
actually have means to be expressed in common units.

Besides, in the cases in which there's no common units involved, the values most
probably won't be suited for devicetree//bindings, so those would be hardcoded in
the driver as platform data.

This is not the case, so, please keep this property but specify microvolts in the
bindings (and obviously in devicetree).

>>> +
>>> +  mediatek,micbias1-microvolt:
>>> +    description: |
>>> +      Selects MIC Bias 1 output voltage.
>>> +      [1.7v, 1.8v, 1.9v, 2.0v, 2.1v, 2.5v, 2.6v, 2.7v]
>>> +    enum: [0, 1, 2, 3, 4, 5, 6, 7]
>>
>> same here.
>>
>>> +
>>> +  mediatek,platform:
>>> +    $ref: /schemas/types.yaml#/definitions/phandle
>>> +    description: The phandle of MT8365 ASoC platform.
>>> +
>>> +  pinctrl-names:
>>> +    minItems: 1
>>> +    items:
>>> +      - const: aud_default
>>> +      - const: aud_dmic
>>> +      - const: aud_miso_off
>>> +      - const: aud_miso_on
>>> +      - const: aud_mosi_off
>>> +      - const: aud_mosi_on
>>> +
>>> +  vaud28-supply:
>>> +    description:
>>> +      2.8 volt supply for the audio codec
>>> +
>>> +patternProperties:
>>> +  "^dai-link-[0-9]+$":
>>> +    type: object
>>> +    description:
>>> +      Container for dai-link level properties and CODEC sub-nodes.
>>> +
>>> +    properties:
>>> +      codec:
>>> +        type: object
>>> +        description: Holds subnode which indicates codec dai.
>>> +
>>> +        properties:
>>> +          sound-dai:
>>> +            maxItems: 1
>>> +            description: phandle of the codec DAI
>>> +
>>> +        additionalProperties: false
>>> +
>>> +      link-name:
>>> +        description:
>>> +          This property corresponds to the name of the BE dai-link to which
>>> +          we are going to update parameters in this node.
>>> +        items:
>>> +          const: 2ND I2S BE
>>> +
>>> +      sound-dai:
>>> +        maxItems: 1
>>> +        description: phandle of the CPU DAI
>>> +
>>> +    additionalProperties: false
>>> +
>>> +    required:
>>> +      - link-name
>>> +      - sound-dai
>>> +
>>> +additionalProperties: false
>>> +
>>> +required:
>>> +  - compatible
>>> +  - mediatek,platform
>>> +  - pinctrl-names
>>> +  - vaud28-supply
>>> +
>>> +examples:
>>> +  - |
>>> +    sound {
>>> +        compatible = "mediatek,mt8365-mt6357";
>>> +        mediatek,platform = <&afe>;
>>
>> Please:
>>
>> https://docs.kernel.org/devicetree/bindings/dts-coding-style.html
>
> Is it about the wrong pinctrl-names tab alignment ?
> Also, 2ND I2S BE => 2ND_I2S_BE ?
> Otherwise, I don't get it sorry.
>

..as Krzysztof already clarified, won't repeat :-P

Cheers!

>>
>> Regards,
>> Angelo
>>
>>> +        pinctrl-names = "aud_default",
>>> +            "aud_dmic",
>>> +            "aud_miso_off",
>>> +            "aud_miso_on",
>>> +            "aud_mosi_off",
>>> +            "aud_mosi_on";
>>> +        pinctrl-0 = <&aud_default_pins>;
>>> +        pinctrl-1 = <&aud_dmic_pins>;
>>> +        pinctrl-2 = <&aud_miso_off_pins>;
>>> +        pinctrl-3 = <&aud_miso_on_pins>;
>>> +        pinctrl-4 = <&aud_mosi_off_pins>;
>>> +        pinctrl-5 = <&aud_mosi_on_pins>;
>>> +        vaud28-supply = <&mt6357_vaud28_reg>;
>>> +
>>> +        /* hdmi interface */
>>> +        dai-link-0 {
>>> +            sound-dai = <&afe>;
>>> +            link-name = "2ND I2S BE";
>>> +
>>> +            codec {
>>> +                sound-dai = <&it66121hdmitx>;
>>> +            };
>>> +        };
>>> +    };
>>>
>>
>



Subject: Re: [PATCH 10/18] ASoc: mediatek: mt8365: Add a specific soundcard for EVK

Il 26/02/24 15:01, [email protected] ha scritto:
> From: Nicolas Belin <[email protected]>
>
> Add a specific soundcard for mt8365-evk. It supports audio jack
> in/out, dmics, the amic and lineout.
>
> Signed-off-by: Nicolas Belin <[email protected]>
> Signed-off-by: Alexandre Mergnat <[email protected]>
> ---
> sound/soc/mediatek/mt8365/mt8365-mt6357.c | 379 ++++++++++++++++++++++++++++++
> 1 file changed, 379 insertions(+)
>
> diff --git a/sound/soc/mediatek/mt8365/mt8365-mt6357.c b/sound/soc/mediatek/mt8365/mt8365-mt6357.c
> new file mode 100644
> index 000000000000..5192b35458e6
> --- /dev/null
> +++ b/sound/soc/mediatek/mt8365/mt8365-mt6357.c
> @@ -0,0 +1,379 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Mediatek MT8365 Sound Card driver
> + *
> + * Copyright (c) 2024 MediaTek Inc.
> + * Authors: Nicolas Belin <[email protected]>
> + */
> +
> +#include <linux/module.h>
> +#include <linux/of_gpio.h>
> +#include <sound/soc.h>
> +#include <sound/pcm_params.h>
> +#include "mt8365-afe-common.h"
> +#include <linux/pinctrl/consumer.h>
> +#include "../common/mtk-soundcard-driver.h"
> +
> +enum PINCTRL_PIN_STATE {

Aren't those supposed to be AFE pin states?

Anyway, lower case name for enums please, and no zero initializer for the first
entry.

enum mt8365_pin_state {
PIN_STATE_DEFAULT,
....
};

> + PIN_STATE_DEFAULT = 0,
> + PIN_STATE_DMIC,
> + PIN_STATE_MISO_OFF,
> + PIN_STATE_MISO_ON,
> + PIN_STATE_MOSI_OFF,
> + PIN_STATE_MOSI_ON,
> + PIN_STATE_MAX
> +};
> +
> +static const char * const mt8365_mt6357_pin_str[PIN_STATE_MAX] = {
> + "aud_default",
> + "aud_dmic",
> + "aud_miso_off",
> + "aud_miso_on",
> + "aud_mosi_off",
> + "aud_mosi_on",
> +};
> +
> +struct mt8365_mt6357_priv {
> + struct pinctrl *pinctrl;
> + struct pinctrl_state *pin_states[PIN_STATE_MAX];
> +};
> +
> +struct mt8365_dai_link_prop {
> + char *name;
> + unsigned int link_id;
> +};

This structure is unused.

> +
> +enum {
> + /* FE */
> + DAI_LINK_DL1_PLAYBACK = 0,
> + DAI_LINK_DL2_PLAYBACK,
> + DAI_LINK_AWB_CAPTURE,
> + DAI_LINK_VUL_CAPTURE,
> + /* BE */
> + DAI_LINK_2ND_I2S_INTF,
> + DAI_LINK_DMIC,
> + DAI_LINK_INT_ADDA,
> + DAI_LINK_NUM
> +};
> +
> +static const struct snd_soc_dapm_widget mt8365_mt6357_widgets[] = {
> + SND_SOC_DAPM_OUTPUT("HDMI Out"),
> +};
> +
> +static const struct snd_soc_dapm_route mt8365_mt6357_routes[] = {
> + {"HDMI Out", NULL, "2ND I2S Playback"},
> + {"DMIC In", NULL, "MICBIAS0"},
> +};
> +
> +static int mt8365_mt6357_int_adda_startup(struct snd_pcm_substream *substream)
> +{
> + struct snd_soc_pcm_runtime *rtd = substream->private_data;
> + struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(rtd->card);
> + int ret = 0;
> +
> + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
> + if (IS_ERR(priv->pin_states[PIN_STATE_MOSI_ON]))
> + return ret;
> +
> + ret = pinctrl_select_state(priv->pinctrl,
> + priv->pin_states[PIN_STATE_MOSI_ON]);
> + if (ret)
> + dev_err(rtd->card->dev, "%s failed to select state %d\n",
> + __func__, ret);
> + }
> +
> + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
> + if (IS_ERR(priv->pin_states[PIN_STATE_MISO_ON]))
> + return ret;
> +
> + ret = pinctrl_select_state(priv->pinctrl,
> + priv->pin_states[PIN_STATE_MISO_ON]);
> + if (ret)
> + dev_err(rtd->card->dev, "%s failed to select state %d\n",
> + __func__, ret);
> + }
> +
> + return 0;
> +}
> +
> +static void mt8365_mt6357_int_adda_shutdown(struct snd_pcm_substream *substream)
> +{
> + struct snd_soc_pcm_runtime *rtd = substream->private_data;
> + struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(rtd->card);
> + int ret = 0;
> +
> + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
> + if (IS_ERR(priv->pin_states[PIN_STATE_MOSI_OFF]))
> + return;
> +
> + ret = pinctrl_select_state(priv->pinctrl,
> + priv->pin_states[PIN_STATE_MOSI_OFF]);
> + if (ret)
> + dev_err(rtd->card->dev, "%s failed to select state %d\n",
> + __func__, ret);
> + }
> +
> + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
> + if (IS_ERR(priv->pin_states[PIN_STATE_MISO_OFF]))
> + return;
> +
> + ret = pinctrl_select_state(priv->pinctrl,
> + priv->pin_states[PIN_STATE_MISO_OFF]);
> + if (ret)
> + dev_err(rtd->card->dev, "%s failed to select state %d\n",
> + __func__, ret);
> + }
> +
> +}
> +
> +static const struct snd_soc_ops mt8365_mt6357_int_adda_ops = {
> + .startup = mt8365_mt6357_int_adda_startup,
> + .shutdown = mt8365_mt6357_int_adda_shutdown,
> +};
> +
> +SND_SOC_DAILINK_DEFS(playback1,
> + DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
> + DAILINK_COMP_ARRAY(COMP_DUMMY()),
> + DAILINK_COMP_ARRAY(COMP_EMPTY()));
> +SND_SOC_DAILINK_DEFS(playback2,
> + DAILINK_COMP_ARRAY(COMP_CPU("DL2")),
> + DAILINK_COMP_ARRAY(COMP_DUMMY()),
> + DAILINK_COMP_ARRAY(COMP_EMPTY()));
> +SND_SOC_DAILINK_DEFS(awb_capture,
> + DAILINK_COMP_ARRAY(COMP_CPU("AWB")),
> + DAILINK_COMP_ARRAY(COMP_DUMMY()),
> + DAILINK_COMP_ARRAY(COMP_EMPTY()));
> +SND_SOC_DAILINK_DEFS(vul,
> + DAILINK_COMP_ARRAY(COMP_CPU("VUL")),
> + DAILINK_COMP_ARRAY(COMP_DUMMY()),
> + DAILINK_COMP_ARRAY(COMP_EMPTY()));
> +
> +SND_SOC_DAILINK_DEFS(i2s3,
> + DAILINK_COMP_ARRAY(COMP_CPU("2ND I2S")),
> + DAILINK_COMP_ARRAY(COMP_DUMMY()),
> + DAILINK_COMP_ARRAY(COMP_EMPTY()));
> +SND_SOC_DAILINK_DEFS(dmic,
> + DAILINK_COMP_ARRAY(COMP_CPU("DMIC")),
> + DAILINK_COMP_ARRAY(COMP_DUMMY()),
> + DAILINK_COMP_ARRAY(COMP_EMPTY()));
> +SND_SOC_DAILINK_DEFS(primary_codec,
> + DAILINK_COMP_ARRAY(COMP_CPU("INT ADDA")),
> + DAILINK_COMP_ARRAY(COMP_CODEC("mt6357-sound", "mt6357-snd-codec-aif1")),
> + DAILINK_COMP_ARRAY(COMP_EMPTY()));
> +
> +/* Digital audio interface glue - connects codec <---> CPU */
> +static struct snd_soc_dai_link mt8365_mt6357_dais[] = {
> + /* Front End DAI links */
> + [DAI_LINK_DL1_PLAYBACK] = {
> + .name = "DL1_FE",
> + .stream_name = "MultiMedia1_PLayback",
> + .id = DAI_LINK_DL1_PLAYBACK,
> + .trigger = {
> + SND_SOC_DPCM_TRIGGER_POST,
> + SND_SOC_DPCM_TRIGGER_POST
> + },
> + .dynamic = 1,
> + .dpcm_playback = 1,
> + .dpcm_merged_rate = 1,
> + SND_SOC_DAILINK_REG(playback1),
> + },
> + [DAI_LINK_DL2_PLAYBACK] = {
> + .name = "DL2_FE",
> + .stream_name = "MultiMedia2_PLayback",
> + .id = DAI_LINK_DL2_PLAYBACK,
> + .trigger = {
> + SND_SOC_DPCM_TRIGGER_POST,
> + SND_SOC_DPCM_TRIGGER_POST
> + },
> + .dynamic = 1,
> + .dpcm_playback = 1,
> + .dpcm_merged_rate = 1,
> + SND_SOC_DAILINK_REG(playback2),
> + },
> + [DAI_LINK_AWB_CAPTURE] = {
> + .name = "AWB_FE",
> + .stream_name = "DL1_AWB_Record",
> + .id = DAI_LINK_AWB_CAPTURE,
> + .trigger = {
> + SND_SOC_DPCM_TRIGGER_POST,
> + SND_SOC_DPCM_TRIGGER_POST
> + },
> + .dynamic = 1,
> + .dpcm_capture = 1,
> + .dpcm_merged_rate = 1,
> + SND_SOC_DAILINK_REG(awb_capture),
> + },
> + [DAI_LINK_VUL_CAPTURE] = {
> + .name = "VUL_FE",
> + .stream_name = "MultiMedia1_Capture",
> + .id = DAI_LINK_VUL_CAPTURE,
> + .trigger = {
> + SND_SOC_DPCM_TRIGGER_POST,
> + SND_SOC_DPCM_TRIGGER_POST
> + },
> + .dynamic = 1,
> + .dpcm_capture = 1,
> + .dpcm_merged_rate = 1,
> + SND_SOC_DAILINK_REG(vul),
> + },
> + /* Back End DAI links */
> + [DAI_LINK_2ND_I2S_INTF] = {
> + .name = "2ND I2S BE",
> + .no_pcm = 1,
> + .id = DAI_LINK_2ND_I2S_INTF,
> + .dai_fmt = SND_SOC_DAIFMT_I2S |
> + SND_SOC_DAIFMT_NB_NF |
> + SND_SOC_DAIFMT_CBS_CFS,
> + .dpcm_playback = 1,
> + .dpcm_capture = 1,
> + SND_SOC_DAILINK_REG(i2s3),
> + },
> + [DAI_LINK_DMIC] = {
> + .name = "DMIC BE",
> + .no_pcm = 1,
> + .id = DAI_LINK_DMIC,
> + .dpcm_capture = 1,
> + SND_SOC_DAILINK_REG(dmic),
> + },
> + [DAI_LINK_INT_ADDA] = {
> + .name = "MTK Codec",
> + .no_pcm = 1,
> + .id = DAI_LINK_INT_ADDA,
> + .dpcm_playback = 1,
> + .dpcm_capture = 1,
> + .ops = &mt8365_mt6357_int_adda_ops,
> + SND_SOC_DAILINK_REG(primary_codec),
> + },
> +};
> +
> +static int pinctrl_setup(struct snd_soc_card *card,
> + struct mt8365_mt6357_priv *priv,
> + unsigned int pin_id)
> +{
> + int ret = 0;
> + /* if pin exist */
> + if (!IS_ERR(priv->pin_states[pin_id])) {
> + ret = pinctrl_select_state(priv->pinctrl,
> + priv->pin_states[pin_id]);
> + if (ret)
> + dev_err(card->dev,
> + "%s failed to select state %d\n",
> + __func__, ret);
> + }
> + return ret;
> +}
> +
> +static int mt8365_mt6357_gpio_probe(struct snd_soc_card *card)
> +{
> + struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(card);
> + int ret = 0;
> + int i;
> +
> + priv->pinctrl = devm_pinctrl_get(card->dev);
> + if (IS_ERR(priv->pinctrl)) {
> + ret = PTR_ERR(priv->pinctrl);
> + dev_err(card->dev, "%s devm_pinctrl_get failed %d\n",
> + __func__, ret);
> + return ret;
> + }
> +
> + for (i = 0 ; i < PIN_STATE_MAX ; i++) {
> + priv->pin_states[i] = pinctrl_lookup_state(priv->pinctrl,
> + mt8365_mt6357_pin_str[i]);
> + if (IS_ERR(priv->pin_states[i])) {
> + ret = PTR_ERR(priv->pin_states[i]);
> + dev_err(card->dev, "%s Can't find pin state %s %d\n",
> + __func__, mt8365_mt6357_pin_str[i], ret);
> + }
> + }
> +
> + /* Setup pins */

for (i = PIN_STATE_DEFAULT; i < PIN_STATE_MAX; i++) {
/* Are you sure about that?!?! */
if (IS_ERR(priv->pin_states[i]))
continue;

ret = pinctrl_select_state(...)
if (ret) {
/* Should you go back to default? */
pinctrl_select_state(card, priv, PIN_STATE_DEFAULT);
return dev_err_probe(card->dev, ret, "ARGH!\n"); /* :-) */
}
};

> + ret |= pinctrl_setup(card, priv, PIN_STATE_DEFAULT);

...because OR'in return values is a big no.

> + ret |= pinctrl_setup(card, priv, PIN_STATE_DMIC);
> + ret |= pinctrl_setup(card, priv, PIN_STATE_MISO_OFF);
> + ret |= pinctrl_setup(card, priv, PIN_STATE_MOSI_OFF);
> +

return 0;

> + return ret;
> +}
> +
> +static struct snd_soc_card mt8365_mt6357_card = {
> + .name = "mt8365-evk",
> + .owner = THIS_MODULE,
> + .dai_link = mt8365_mt6357_dais,
> + .num_links = ARRAY_SIZE(mt8365_mt6357_dais),
> + .dapm_widgets = mt8365_mt6357_widgets,
> + .num_dapm_widgets = ARRAY_SIZE(mt8365_mt6357_widgets),
> + .dapm_routes = mt8365_mt6357_routes,
> + .num_dapm_routes = ARRAY_SIZE(mt8365_mt6357_routes),
> +};
> +
> +static int mt8365_mt6357_dev_probe(struct platform_device *pdev)
> +{
> + struct snd_soc_card *card = &mt8365_mt6357_card;
> + struct device *dev = &pdev->dev;
> + struct device_node *platform_node;
> + struct mt8365_mt6357_priv *priv;
> + int i, ret;
> +
> + card->dev = dev;
> + ret = parse_dai_link_info(card);
> + if (ret)
> + goto err;
> +
> + platform_node = of_parse_phandle(dev->of_node, "mediatek,platform", 0);
> + if (!platform_node) {
> + dev_err(dev, "Property 'platform' missing or invalid\n");
> + return -EINVAL;
> + }
> +
> + for (i = 0; i < card->num_links; i++) {
> + if (mt8365_mt6357_dais[i].platforms->name)
> + continue;
> + mt8365_mt6357_dais[i].platforms->of_node = platform_node;
> + }
> +
> + priv = devm_kzalloc(dev, sizeof(struct mt8365_mt6357_priv),
> + GFP_KERNEL);
> + if (!priv) {
> + ret = -ENOMEM;
> + dev_err(dev, "%s allocate card private data fail %d\n",
> + __func__, ret);
> + return ret;
> + }
> +
> + snd_soc_card_set_drvdata(card, priv);
> +
> + mt8365_mt6357_gpio_probe(card);

P.S.: with my cleanup this function would not need any parse_dai_link_info() call,
nor phandle parsing, nor platform_node assignment, nor any call to
devm_snd_soc_register_card(), nor....

..practically you'd need to only allocate your priv (granted that you are not
moving the gpio_probe() to the AFE driver) and the actual gpio_probe() call.

But I'm not pressing to wait, anyway.

Cheers,
Angelo


Subject: Re: [PATCH 02/18] ASoC: dt-bindings: mediatek,mt8365-mt6357: Add audio sound card document

Il 26/02/24 15:01, Alexandre Mergnat ha scritto:
> Add soundcard bindings for the MT8365 SoC with the MT6357 audio codec.
>
> Signed-off-by: Alexandre Mergnat <[email protected]>
> ---
> .../bindings/sound/mediatek,mt8365-mt6357.yaml | 127 +++++++++++++++++++++
> 1 file changed, 127 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8365-mt6357.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8365-mt6357.yaml
> new file mode 100644
> index 000000000000..f469611ec6b6
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/mediatek,mt8365-mt6357.yaml
> @@ -0,0 +1,127 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/sound/mediatek,mt8365-mt6357.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Mediatek MT8365 sound card with MT6357 sound codec.
> +
> +maintainers:
> + - Alexandre Mergnat <[email protected]>
> +
> +description:
> + This binding describes the MT8365 sound card.
> +
> +properties:
> + compatible:
> + const: mediatek,mt8365-mt6357
> +
> + mediatek,hp-pull-down:
> + description:
> + Earphone driver positive output stage short to the
> + audio reference ground.
> + Default value is false.
> + type: boolean
> +
> + mediatek,micbias0-microvolt:
> + description: |

description: Selects MIC Bias 0 output voltage

> + Selects MIC Bias 0 output voltage.
> + [1.7v, 1.8v, 1.9v, 2.0v, 2.1v, 2.5v, 2.6v, 2.7v]
> + enum: [0, 1, 2, 3, 4, 5, 6, 7]

No, you don't say 0 1 2 3 4 to a property that says "microvolt", that's simply
wrong.

mediatek,micbias0-microvolt = <2100000>;

..so you want a binding that says
enum: [ 1700000, 1800000, this, that, 2700000]

> +
> + mediatek,micbias1-microvolt:
> + description: |
> + Selects MIC Bias 1 output voltage.
> + [1.7v, 1.8v, 1.9v, 2.0v, 2.1v, 2.5v, 2.6v, 2.7v]
> + enum: [0, 1, 2, 3, 4, 5, 6, 7]

same here.

> +
> + mediatek,platform:
> + $ref: /schemas/types.yaml#/definitions/phandle
> + description: The phandle of MT8365 ASoC platform.
> +
> + pinctrl-names:
> + minItems: 1
> + items:
> + - const: aud_default
> + - const: aud_dmic
> + - const: aud_miso_off
> + - const: aud_miso_on
> + - const: aud_mosi_off
> + - const: aud_mosi_on
> +
> + vaud28-supply:
> + description:
> + 2.8 volt supply for the audio codec
> +
> +patternProperties:
> + "^dai-link-[0-9]+$":
> + type: object
> + description:
> + Container for dai-link level properties and CODEC sub-nodes.
> +
> + properties:
> + codec:
> + type: object
> + description: Holds subnode which indicates codec dai.
> +
> + properties:
> + sound-dai:
> + maxItems: 1
> + description: phandle of the codec DAI
> +
> + additionalProperties: false
> +
> + link-name:
> + description:
> + This property corresponds to the name of the BE dai-link to which
> + we are going to update parameters in this node.
> + items:
> + const: 2ND I2S BE
> +
> + sound-dai:
> + maxItems: 1
> + description: phandle of the CPU DAI
> +
> + additionalProperties: false
> +
> + required:
> + - link-name
> + - sound-dai
> +
> +additionalProperties: false
> +
> +required:
> + - compatible
> + - mediatek,platform
> + - pinctrl-names
> + - vaud28-supply
> +
> +examples:
> + - |
> + sound {
> + compatible = "mediatek,mt8365-mt6357";
> + mediatek,platform = <&afe>;

Please:

https://docs.kernel.org/devicetree/bindings/dts-coding-style.html

Regards,
Angelo

> + pinctrl-names = "aud_default",
> + "aud_dmic",
> + "aud_miso_off",
> + "aud_miso_on",
> + "aud_mosi_off",
> + "aud_mosi_on";
> + pinctrl-0 = <&aud_default_pins>;
> + pinctrl-1 = <&aud_dmic_pins>;
> + pinctrl-2 = <&aud_miso_off_pins>;
> + pinctrl-3 = <&aud_miso_on_pins>;
> + pinctrl-4 = <&aud_mosi_off_pins>;
> + pinctrl-5 = <&aud_mosi_on_pins>;
> + vaud28-supply = <&mt6357_vaud28_reg>;
> +
> + /* hdmi interface */
> + dai-link-0 {
> + sound-dai = <&afe>;
> + link-name = "2ND I2S BE";
> +
> + codec {
> + sound-dai = <&it66121hdmitx>;
> + };
> + };
> + };
>


Subject: Re: [PATCH 12/18] ASoC: codecs: mt6357: add MT6357 codec

Il 26/02/24 15:01, [email protected] ha scritto:
> From: Nicolas Belin <[email protected]>
>
> Add the support of MT6357 PMIC audio codec.
>
> Signed-off-by: Nicolas Belin <[email protected]>
> Signed-off-by: Alexandre Mergnat <[email protected]>
> ---
> sound/soc/codecs/Kconfig | 7 +
> sound/soc/codecs/Makefile | 2 +
> sound/soc/codecs/mt6357.c | 1805 +++++++++++++++++++++++++++++++++++++++++++++
> sound/soc/codecs/mt6357.h | 674 +++++++++++++++++
> 4 files changed, 2488 insertions(+)
>
> diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
> index 59f9742e9ff4..9cf2b9b70472 100644
> --- a/sound/soc/codecs/Kconfig
> +++ b/sound/soc/codecs/Kconfig
> @@ -153,6 +153,7 @@ config SND_SOC_ALL_CODECS
> imply SND_SOC_MC13783
> imply SND_SOC_ML26124
> imply SND_SOC_MT6351
> + imply SND_SOC_MT6357
> imply SND_SOC_MT6358
> imply SND_SOC_MT6359
> imply SND_SOC_MT6660
> @@ -2361,6 +2362,12 @@ config SND_SOC_ML26124
> config SND_SOC_MT6351
> tristate "MediaTek MT6351 Codec"
>
> +config SND_SOC_MT6357
> + tristate "MediaTek MT6357 Codec"
> + help
> + Enable support for the platform which uses MT6357 as
> + external codec device.
> +
> config SND_SOC_MT6358
> tristate "MediaTek MT6358 Codec"
> help
> diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
> index f53baa2b9565..33e27612867e 100644
> --- a/sound/soc/codecs/Makefile
> +++ b/sound/soc/codecs/Makefile
> @@ -169,6 +169,7 @@ snd-soc-ml26124-objs := ml26124.o
> snd-soc-msm8916-analog-objs := msm8916-wcd-analog.o
> snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o
> snd-soc-mt6351-objs := mt6351.o
> +snd-soc-mt6357-objs := mt6357.o
> snd-soc-mt6358-objs := mt6358.o
> snd-soc-mt6359-objs := mt6359.o
> snd-soc-mt6359-accdet-objs := mt6359-accdet.o
> @@ -554,6 +555,7 @@ obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o
> obj-$(CONFIG_SND_SOC_MSM8916_WCD_ANALOG) +=snd-soc-msm8916-analog.o
> obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o
> obj-$(CONFIG_SND_SOC_MT6351) += snd-soc-mt6351.o
> +obj-$(CONFIG_SND_SOC_MT6357) += snd-soc-mt6357.o
> obj-$(CONFIG_SND_SOC_MT6358) += snd-soc-mt6358.o
> obj-$(CONFIG_SND_SOC_MT6359) += snd-soc-mt6359.o
> obj-$(CONFIG_SND_SOC_MT6359_ACCDET) += mt6359-accdet.o
> diff --git a/sound/soc/codecs/mt6357.c b/sound/soc/codecs/mt6357.c
> new file mode 100644
> index 000000000000..13e95c227114
> --- /dev/null
> +++ b/sound/soc/codecs/mt6357.c
> @@ -0,0 +1,1805 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * MT6357 ALSA SoC audio codec driver
> + *
> + * Copyright (c) 2024 Baylibre
> + * Author: Nicolas Belin <[email protected]>
> + */
> +
> +#include <linux/dma-mapping.h>
> +#include <sound/soc.h>
> +#include <sound/tlv.h>
> +#include <linux/mfd/mt6397/core.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include "mt6357.h"
> +
> +static void set_playback_gpio(struct mt6357_priv *priv, bool enable)
> +{

you're anyway always doing CLEAR_ALL, so you can do it outside of the if branch.


regmap_write( ... CLEAR_ALL);

if (enable) {
..
} else {
..
}


> + if (enable) {
> + /* set gpio mosi mode */
> + regmap_write(priv->regmap, MT6357_GPIO_MODE2_CLR, GPIO_MODE2_CLEAR_ALL);
> + regmap_write(priv->regmap, MT6357_GPIO_MODE2_SET, GPIO8_MODE_SET_AUD_CLK_MOSI |
> + GPIO9_MODE_SET_AUD_DAT_MOSI0 |
> + GPIO10_MODE_SET_AUD_DAT_MOSI1 |
> + GPIO11_MODE_SET_AUD_SYNC_MOSI);

Are you sure that you need to write to MODE2_SET *and* to MODE2?!

> + regmap_write(priv->regmap, MT6357_GPIO_MODE2, GPIO8_MODE_AUD_CLK_MOSI |
> + GPIO9_MODE_AUD_DAT_MOSI0 |
> + GPIO10_MODE_AUD_DAT_MOSI1 |
> + GPIO11_MODE_AUD_SYNC_MOSI);
> + } else {
> + /* set pad_aud_*_mosi to GPIO mode and dir input
> + * reason:
> + * pad_aud_dat_mosi*, because the pin is used as boot strap
> + */
> + regmap_write(priv->regmap, MT6357_GPIO_MODE2_CLR, GPIO_MODE2_CLEAR_ALL);
> + regmap_write(priv->regmap, MT6357_GPIO_MODE2, GPIO8_MODE_GPIO |
> + GPIO9_MODE_GPIO |
> + GPIO10_MODE_GPIO |
> + GPIO11_MODE_GPIO);
> + regmap_update_bits(priv->regmap, MT6357_GPIO_DIR0, GPIO8_DIR_MASK |
> + GPIO9_DIR_MASK |
> + GPIO10_DIR_MASK |
> + GPIO11_DIR_MASK,
> + GPIO8_DIR_INPUT |
> + GPIO9_DIR_INPUT |
> + GPIO10_DIR_INPUT |
> + GPIO11_DIR_INPUT);
> + }
> +}
> +
> +static void set_capture_gpio(struct mt6357_priv *priv, bool enable)
> +{

same comment applies here.

> + if (enable) {
> + /* set gpio miso mode */
> + regmap_write(priv->regmap, MT6357_GPIO_MODE3_CLR, GPIO_MODE3_CLEAR_ALL);
> + regmap_write(priv->regmap, MT6357_GPIO_MODE3_SET, GPIO12_MODE_SET_AUD_CLK_MISO |
> + GPIO13_MODE_SET_AUD_DAT_MISO0 |
> + GPIO14_MODE_SET_AUD_DAT_MISO1 |
> + GPIO15_MODE_SET_AUD_SYNC_MISO);
> + regmap_write(priv->regmap, MT6357_GPIO_MODE3, GPIO12_MODE_AUD_CLK_MISO |
> + GPIO13_MODE_AUD_DAT_MISO0 |
> + GPIO14_MODE_AUD_DAT_MISO1 |
> + GPIO15_MODE_AUD_SYNC_MISO);
> + } else {
> + /* set pad_aud_*_miso to GPIO mode and dir input
> + * reason:
> + * pad_aud_clk_miso, because when playback only the miso_clk
> + * will also have 26m, so will have power leak
> + * pad_aud_dat_miso*, because the pin is used as boot strap
> + */
> + regmap_write(priv->regmap, MT6357_GPIO_MODE3_CLR, GPIO_MODE3_CLEAR_ALL);
> + regmap_write(priv->regmap, MT6357_GPIO_MODE3, GPIO12_MODE_GPIO |
> + GPIO13_MODE_GPIO |
> + GPIO14_MODE_GPIO |
> + GPIO15_MODE_GPIO);
> + regmap_update_bits(priv->regmap, MT6357_GPIO_DIR0, GPIO12_DIR_MASK |
> + GPIO13_DIR_MASK |
> + GPIO14_DIR_MASK |
> + GPIO15_DIR_MASK,
> + GPIO12_DIR_INPUT |
> + GPIO13_DIR_INPUT |
> + GPIO14_DIR_INPUT |
> + GPIO15_DIR_INPUT);
> + }
> +}
> +
> +static void hp_main_output_ramp(struct mt6357_priv *priv, bool up)
> +{
> + int i = 0, stage = 0;
> + int target = 7;
> + /* Enable/Reduce HPL/R main output stage step by step */
> + for (i = 0; i <= target; i++) {

double 'i` initialization.

> + stage = up ? i : target - i;
> + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
> + HPLOUT_STG_CTRL_VAUDP15_MASK,
> + stage << HPLOUT_STG_CTRL_VAUDP15_SFT);
> + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
> + HPROUT_STG_CTRL_VAUDP15_MASK,
> + stage << HPROUT_STG_CTRL_VAUDP15_SFT);
> + usleep_range(600, 700);
> + }
> +}
> +
> +static void hp_aux_feedback_loop_gain_ramp(struct mt6357_priv *priv, bool up)
> +{
> + int i = 0, stage = 0;
> + /* Reduce HP aux feedback loop gain step by step */
> + for (i = 0; i <= 0xf; i++) {

same

> + stage = up ? i : 0xf - i;
> + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
> + HP_AUX_LOOP_GAIN_MASK, stage << HP_AUX_LOOP_GAIN_SFT);
> + usleep_range(600, 700);
> + }
> +}
> +
> +static void hp_pull_down(struct mt6357_priv *priv, bool enable)
> +{
> + if (enable)
> + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON2,
> + HPP_SHORT_2VCM_VAUDP15_MASK, HPP_SHORT_2VCM_VAUDP15_ENABLE);
> + else
> + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON2,
> + HPP_SHORT_2VCM_VAUDP15_MASK, HPP_SHORT_2VCM_VAUDP15_DISABLE);
> +}
> +
> +static bool is_valid_hp_pga_idx(int reg_idx)
> +{
> + return (reg_idx >= DL_GAIN_8DB && reg_idx <= DL_GAIN_N_12DB) || reg_idx == DL_GAIN_N_40DB;
> +}
> +
> +static void volume_ramp(struct mt6357_priv *priv, int lfrom, int lto,
> + int rfrom, int rto, unsigned int reg_addr)
> +{
> + int lcount, rcount, sleep = 0;
> +
> + if (!is_valid_hp_pga_idx(lfrom) || !is_valid_hp_pga_idx(lto))
> + pr_debug("%s(), invalid left volume index, from %d, to %d\n",
> + __func__, lfrom, lto);
> +
> + if (!is_valid_hp_pga_idx(rfrom) || !is_valid_hp_pga_idx(rto))
> + pr_debug("%s(), invalid right volume index, from %d, to %d\n",
> + __func__, rfrom, rto);
> +
> + if (lto > lfrom)
> + lcount = 1;
> + else
> + lcount = -1;
> +
> + if (rto > rfrom)
> + rcount = 1;
> + else
> + rcount = -1;
> +
> + while ((lto != lfrom) || (rto != rfrom)) {
> + if (lto != lfrom) {
> + lfrom += lcount;
> + if (is_valid_hp_pga_idx(lfrom)) {
> + regmap_update_bits(priv->regmap, reg_addr, DL_GAIN_REG_LEFT_MASK,
> + lfrom << DL_GAIN_REG_LEFT_SHIFT);
> + sleep = 1;
> + }
> + }
> + if (rto != rfrom) {
> + rfrom += rcount;
> + if (is_valid_hp_pga_idx(rfrom)) {
> + regmap_update_bits(priv->regmap, reg_addr, DL_GAIN_REG_RIGHT_MASK,
> + rfrom << DL_GAIN_REG_RIGHT_SHIFT);
> + sleep = 1;
> + }
> + }
> + if (sleep)
> + usleep_range(200, 300);
> + }
> +}
> +
> +static void lo_volume_ramp(struct mt6357_priv *priv, int lfrom, int lto, int rfrom, int rto)
> +{
> + volume_ramp(priv, lfrom, lto, rfrom, rto, MT6357_ZCD_CON1);
> +}
> +
> +static void hp_volume_ramp(struct mt6357_priv *priv, int lfrom, int lto, int rfrom, int rto)
> +{
> + volume_ramp(priv, lfrom, lto, rfrom, rto, MT6357_ZCD_CON2);
> +}
> +
> +static void hs_volume_ramp(struct mt6357_priv *priv, int from, int to)
> +{
> + volume_ramp(priv, from, to, 0, 0, MT6357_ZCD_CON3);
> +}
> +
> +static int mt6357_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
> +{
> + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
> + struct mt6357_priv *priv = snd_soc_component_get_drvdata(component);
> + struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
> + unsigned int reg;
> + int ret;
> +
> + ret = snd_soc_put_volsw(kcontrol, ucontrol);
> + if (ret < 0)
> + return ret;
> +

regmap_read(priv->regmap, mc->reg, &reg)
switch (mc->reg) {
..
};

return 0;

> + switch (mc->reg) {
> + case MT6357_ZCD_CON2:
> + regmap_read(priv->regmap, MT6357_ZCD_CON2, &reg);
> + priv->ana_gain[ANALOG_VOLUME_HPOUTL] =
> + (reg & AUD_HPL_GAIN_MASK) >> AUD_HPL_GAIN_SFT;
> + priv->ana_gain[ANALOG_VOLUME_HPOUTR] =
> + (reg & AUD_HPR_GAIN_MASK) >> AUD_HPR_GAIN_SFT;
> + break;
> + case MT6357_ZCD_CON1:
> + regmap_read(priv->regmap, MT6357_ZCD_CON1, &reg);
> + priv->ana_gain[ANALOG_VOLUME_LINEOUTL] =
> + (reg & AUD_LOL_GAIN_MASK) >> AUD_LOL_GAIN_SFT;
> + priv->ana_gain[ANALOG_VOLUME_LINEOUTR] =
> + (reg & AUD_LOR_GAIN_MASK) >> AUD_LOR_GAIN_SFT;
> + break;
> + case MT6357_ZCD_CON3:
> + regmap_read(priv->regmap, MT6357_ZCD_CON3, &reg);
> + priv->ana_gain[ANALOG_VOLUME_HSOUT] =
> + (reg & AUD_HS_GAIN_MASK) >> AUD_HS_GAIN_SFT;
> + break;
> + case MT6357_AUDENC_ANA_CON0:
> + case MT6357_AUDENC_ANA_CON1:
> + regmap_read(priv->regmap, MT6357_AUDENC_ANA_CON0, &reg);
> + priv->ana_gain[ANALOG_VOLUME_MIC1] =
> + (reg & AUDPREAMPLGAIN_MASK) >> AUDPREAMPLGAIN_SFT;
> + regmap_read(priv->regmap, MT6357_AUDENC_ANA_CON1, &reg);
> + priv->ana_gain[ANALOG_VOLUME_MIC2] =
> + (reg & AUDPREAMPRGAIN_MASK) >> AUDPREAMPRGAIN_SFT;
> + break;
> + }
> +
> + return ret;
> +}
> +

.snip..

> +
> +static int adc_enable_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
> +
> + dev_dbg(priv->dev, "%s(), event = 0x%x\n", __func__, event);
> + switch (event) {
> + case SND_SOC_DAPM_PRE_PMU:
> + /* enable aud_pad TX fifos */
> + regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
> + AUD_PAD_TX_FIFO_NORMAL_PATH_MASK,
> + AUD_PAD_TX_FIFO_NORMAL_PATH_ENABLE);
> + /* UL turn on */
> + regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
> + UL_SRC_ON_TMP_CTL_MASK, UL_SRC_ENABLE);
> + /* Wait to avoid any pop noises */
> + msleep(100);
> + //set the mic gains to the stored values

Keep the comments style consistent please.

> + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, AUDPREAMPLGAIN_MASK,
> + priv->ana_gain[ANALOG_VOLUME_MIC1] << AUDPREAMPLGAIN_SFT);
> + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, AUDPREAMPRGAIN_MASK,
> + priv->ana_gain[ANALOG_VOLUME_MIC2] << AUDPREAMPRGAIN_SFT);
> + break;
> + case SND_SOC_DAPM_POST_PMD:
> + /* UL turn off */
> + regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
> + UL_SRC_ON_TMP_CTL_MASK, UL_SRC_DISABLE);
> + /* disable aud_pad TX fifos */
> + regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
> + AUD_PAD_TX_FIFO_NORMAL_PATH_MASK,
> + AUD_PAD_TX_FIFO_NORMAL_PATH_DISABLE);
> + break;
> + default:
> + break;
> + }
> +
> + return 0;
> +}
> +

.snip..

> +
> +static int lol_mux_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
> +
> + dev_dbg(priv->dev, "%s(), event 0x%x\n", __func__, event);
> + switch (event) {
> + case SND_SOC_DAPM_POST_PMU:
> + /* Set LO STB enhance circuits */
> + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
> + AUD_LOLOUT_STB_ENH_VAUDP15_MASK,
> + AUD_LOLOUT_STB_ENH_VAUDP15_ENABLE);
> + /* Enable LO driver bias circuits */
> + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
> + AUD_LOL_PWRUP_BIAS_VAUDP15_MASK,
> + AUD_LOL_PWRUP_BIAS_VAUDP15_ENABLE);
> + /* Enable LO driver core circuits */
> + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
> + AUD_LOL_PWRUP_VAUDP15_MASK, AUD_LOL_PWRUP_VAUDP15_ENABLE);
> + /* Set LOL gain to normal gain step by step */
> + lo_volume_ramp(priv, DL_GAIN_N_40DB, priv->ana_gain[ANALOG_VOLUME_LINEOUTL],
> + DL_GAIN_N_40DB, priv->ana_gain[ANALOG_VOLUME_LINEOUTR]);
> + break;
> + case SND_SOC_DAPM_PRE_PMD:
> +

Drop extra blank line.

> + /* decrease LOL gain to minimum gain step by step */
> + lo_volume_ramp(priv, priv->ana_gain[ANALOG_VOLUME_LINEOUTL], DL_GAIN_N_40DB,
> + priv->ana_gain[ANALOG_VOLUME_LINEOUTR], DL_GAIN_N_40DB);
> + /* Disable LO driver core circuits */
> + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
> + AUD_LOL_PWRUP_VAUDP15_MASK, AUD_LOL_PWRUP_VAUDP15_DISABLE);
> + /* Disable LO driver bias circuits */
> + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
> + AUD_LOL_PWRUP_BIAS_VAUDP15_MASK,
> + AUD_LOL_PWRUP_BIAS_VAUDP15_DISABLE);
> + /* Clear LO STB enhance circuits */
> + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
> + AUD_LOLOUT_STB_ENH_VAUDP15_MASK,
> + AUD_LOLOUT_STB_ENH_VAUDP15_DISABLE);
> + break;
> + default:
> + break;
> + }
> +
> + return 0;
> +}
> +
> +static int hs_mux_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
> +
> + dev_dbg(priv->dev, "%s(), event 0x%x\n", __func__, event);
> + switch (event) {
> + case SND_SOC_DAPM_POST_PMU:
> +
> + /* Set HS STB enhance circuits */
> + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
> + AUD_HSOUT_STB_ENH_VAUDP15_MASK,
> + AUD_HSOUT_STB_ENH_VAUDP15_ENABLE);
> + /* Enable HS driver bias circuits */
> + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
> + AUD_HS_PWRUP_BIAS_VAUDP15_MASK,
> + AUD_HS_PWRUP_BIAS_VAUDP15_ENABLE);
> + /* Enable HS driver core circuits */
> + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
> + AUD_HS_PWRUP_VAUDP15_MASK, AUD_HS_PWRUP_VAUDP15_ENABLE);
> + /* Set HS gain to normal gain step by step */
> + hs_volume_ramp(priv, DL_GAIN_N_40DB, priv->ana_gain[ANALOG_VOLUME_HSOUT]);
> + break;
> + case SND_SOC_DAPM_PRE_PMD:
> +

same

> + /* decrease HS gain to minimum gain step by step */
> + hs_volume_ramp(priv, priv->ana_gain[ANALOG_VOLUME_HSOUT], DL_GAIN_N_40DB);
> + /* Disable HS driver core circuits */
> + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
> + AUD_HS_PWRUP_VAUDP15_MASK, AUD_HS_PWRUP_VAUDP15_DISABLE);
> + /* Disable HS driver bias circuits */
> + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
> + AUD_HS_PWRUP_BIAS_VAUDP15_MASK,
> + AUD_HS_PWRUP_BIAS_VAUDP15_ENABLE);
> + /* Clear HS STB enhance circuits */
> + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
> + AUD_HSOUT_STB_ENH_VAUDP15_MASK,
> + AUD_HSOUT_STB_ENH_VAUDP15_DISABLE);
> + break;
> + default:
> + break;
> + }
> +
> + return 0;
> +}
> +

.snip..

> +
> +static unsigned int mt6357_read(struct snd_soc_component *codec, unsigned int reg)
> +{
> + struct mt6357_priv *priv = snd_soc_component_get_drvdata(codec);
> + unsigned int val;
> +
> + pr_debug("%s() reg = 0x%x", __func__, reg);

I'm not sure that you really need that pr_debug()....

> + regmap_read(priv->regmap, reg, &val);
> + return val;
> +}
> +
> +static int mt6357_write(struct snd_soc_component *codec, unsigned int reg, unsigned int value)
> +{
> + struct mt6357_priv *priv = snd_soc_component_get_drvdata(codec);
> +
> + pr_debug("%s() reg = 0x%x value= 0x%x\n", __func__, reg, value);

..nor this one.

> + regmap_update_bits(priv->regmap, reg, 0xffff, value);
> + return 0;

return regmap_update_bits(...);

> +}
> +
> +static const struct snd_soc_component_driver mt6357_soc_component_driver = {
> + .probe = mt6357_codec_probe,
> + .read = mt6357_read,
> + .write = mt6357_write,
> + .controls = mt6357_controls,
> + .num_controls = ARRAY_SIZE(mt6357_controls),
> + .dapm_widgets = mt6357_dapm_widgets,
> + .num_dapm_widgets = ARRAY_SIZE(mt6357_dapm_widgets),
> + .dapm_routes = mt6357_dapm_routes,
> + .num_dapm_routes = ARRAY_SIZE(mt6357_dapm_routes),
> +};
> +
> +static void mt6357_parse_dt(struct mt6357_priv *priv)
> +{
> + int ret, voltage_index;
> + u32 micbias_voltage_index = 0;
> + struct device *dev = priv->dev;
> +
> + priv->pull_down_needed = false;
> + if (of_property_read_bool(dev->of_node, "mediatek,hp-pull-down"))
> + priv->pull_down_needed = true;
> +
> + micbias_voltage_index = MT6357_MICBIAS0_DEFAULT_VOLTAGE_INDEX;
> + ret = of_property_read_u32(dev->of_node, "mediatek,micbias0-microvolt", &voltage_index);
> + if (!ret)
> + micbias_voltage_index = voltage_index;
> +
> + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON8, AUD_MICBIAS0_VREF_MASK,
> + micbias_voltage_index << AUD_MICBIAS0_VREF_SFT);
> +
> + micbias_voltage_index = MT6357_MICBIAS1_DEFAULT_VOLTAGE_INDEX;
> + ret = of_property_read_u32(dev->of_node, "mediatek,micbias1-microvolt", &voltage_index);
> + if (!ret)
> + micbias_voltage_index = voltage_index;
> +
> + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON9, AUD_MICBIAS1_VREF_MASK,
> + micbias_voltage_index << AUD_MICBIAS1_VREF_SFT);
> +}
> +
> +static int mt6357_platform_driver_probe(struct platform_device *pdev)
> +{
> + struct mt6357_priv *priv;
> + struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent);

struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent);
struct mt6357_priv *priv;
int ret;

looks better :-)


> + int ret;
> +
> + ret = devm_regulator_get_enable(&pdev->dev, "vaud28");
> + if (ret)
> + return dev_err_probe(&pdev->dev, ret, "failed to enable vaud28 regulator\n");
> +
> + priv = devm_kzalloc(&pdev->dev,
> + sizeof(struct mt6357_priv),
> + GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + dev_set_drvdata(&pdev->dev, priv);
> + priv->dev = &pdev->dev;
> +
> + priv->regmap = mt6397->regmap;
> + if (IS_ERR(priv->regmap))
> + return PTR_ERR(priv->regmap);
> +
> + mt6357_parse_dt(priv);
> +
> + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(64);
> + if (!pdev->dev.dma_mask)
> + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
> +
> + return devm_snd_soc_register_component(&pdev->dev,
> + &mt6357_soc_component_driver,
> + mtk_6357_dai_codecs,
> + ARRAY_SIZE(mtk_6357_dai_codecs));
> +}
> +
> +static const struct of_device_id mt6357_of_match[] = {
> + {.compatible = "mediatek,mt6357-sound",},
> + {}

{ /* sentinel */ }

> +};
> +MODULE_DEVICE_TABLE(of, mt6357_of_match);
> +
> +static struct platform_driver mt6357_platform_driver = {
> + .driver = {
> + .name = "mt6357-sound",
> + .of_match_table = mt6357_of_match,
> + },
> + .probe = mt6357_platform_driver_probe,
> +};
> +
> +module_platform_driver(mt6357_platform_driver)
> +
> +MODULE_DESCRIPTION("MT6357 ALSA SoC codec driver");
> +MODULE_AUTHOR("Nicolas Belin <[email protected]>");
> +MODULE_LICENSE("GPL");


Cheers,
Angelo



2024-03-12 08:58:31

by Alexandre Mergnat

[permalink] [raw]
Subject: Re: [PATCH 00/18] Add audio support for the MediaTek Genio 350-evk board



On 27/02/2024 16:06, Mark Brown wrote:
> On Mon, Feb 26, 2024 at 03:01:38PM +0100, Alexandre Mergnat wrote:
>> This serie aim to add the following audio support for the Genio 350-evk:
>> - Playback
>> - 2ch Headset Jack (Earphone)
>> - 1ch Line-out Jack (Speaker)
>> - 8ch HDMI Tx
>> - Capture
>> - 1ch DMIC (On-board Digital Microphone)
>> - 1ch AMIC (On-board Analogic Microphone)
>> - 1ch Headset Jack (External Analogic Microphone)
>>
>> Of course, HDMI playback need the MT8365 display patches [1] and a DTS
>> change documented in "mediatek,mt8365-mt6357.yaml".
>
> Given the number of custom controls here could you please post the
> output of mixer-test and pcm-test from a system with this driver running
> next time you post, this will help with review since it checks a bunch
> of things around the new controls.

Hi Mark,

I'm a bit lost for mixer-test and pcm-test.
Currently, I cross-compile the alsa lib project to be able to build the
tests and put it on my board.

I can execute it, but I still have 2 issues:

1) I've a lot of missing module in my environment (Encode.so, Encode.pm,
Symbol.pm, IO/Handle.pm, ...). AFAII, I've to cross compile the missing
perl modules and install them in the rootfs

2) I don't know how to configure pcm-test.conf &
Lenovo_ThinkPad_P1_Gen2.conf (or new file to match with my board).

My test cmd:
/run_kselftest.sh -c alsa

I'm wondering if I'm going to the wrong way because I don't find
guide/readme whereas it's not trivial at all.

--
Regards,
Alexandre

2024-03-12 14:50:34

by Alexandre Mergnat

[permalink] [raw]
Subject: Re: [PATCH 12/18] ASoC: codecs: mt6357: add MT6357 codec



On 26/02/2024 16:25, AngeloGioacchino Del Regno wrote:
>> +    if (enable) {
>> +        /* set gpio mosi mode */
>> +        regmap_write(priv->regmap, MT6357_GPIO_MODE2_CLR,
>> GPIO_MODE2_CLEAR_ALL);
>> +        regmap_write(priv->regmap, MT6357_GPIO_MODE2_SET,
>> GPIO8_MODE_SET_AUD_CLK_MOSI |
>> +                                  GPIO9_MODE_SET_AUD_DAT_MOSI0 |
>> +                                  GPIO10_MODE_SET_AUD_DAT_MOSI1 |
>> +                                  GPIO11_MODE_SET_AUD_SYNC_MOSI);
>
> Are you sure that you need to write to MODE2_SET *and* to MODE2?!

This is downstream code and these registers aren't in my documentation.
I've removed the MODE2_SET write and test the audio: it's still working.

So I will keep the spurious write removed for v2. :)

--
Regards,
Alexandre

Subject: Re: [PATCH 12/18] ASoC: codecs: mt6357: add MT6357 codec

Il 12/03/24 15:50, Alexandre Mergnat ha scritto:
>
>
> On 26/02/2024 16:25, AngeloGioacchino Del Regno wrote:
>>> +    if (enable) {
>>> +        /* set gpio mosi mode */
>>> +        regmap_write(priv->regmap, MT6357_GPIO_MODE2_CLR, GPIO_MODE2_CLEAR_ALL);
>>> +        regmap_write(priv->regmap, MT6357_GPIO_MODE2_SET,
>>> GPIO8_MODE_SET_AUD_CLK_MOSI |
>>> +                                  GPIO9_MODE_SET_AUD_DAT_MOSI0 |
>>> +                                  GPIO10_MODE_SET_AUD_DAT_MOSI1 |
>>> +                                  GPIO11_MODE_SET_AUD_SYNC_MOSI);
>>
>> Are you sure that you need to write to MODE2_SET *and* to MODE2?!
>
> This is downstream code and these registers aren't in my documentation.
> I've removed the MODE2_SET write and test the audio: it's still working.
>
> So I will keep the spurious write removed for v2. :)
>

Usually, MediaTek registers are laid out like "REG" being R/legacy-W and
"REG_SET/CLR" for setting and clearing bits in "REG" internally, and that
might account for internal latencies and such.

Can you please try to remove the MODE2 write instead of the MODE2_SET one
and check if that works?

You're already using the SETCLR way when manipulating registers in here,
so I would confidently expect that to work.

Cheers,
Angelo

2024-03-12 18:03:47

by Alexandre Mergnat

[permalink] [raw]
Subject: Re: [PATCH 12/18] ASoC: codecs: mt6357: add MT6357 codec



On 26/02/2024 17:09, Mark Brown wrote:
> On Mon, Feb 26, 2024 at 03:01:50PM +0100, [email protected] wrote:
>
>> index 000000000000..13e95c227114
>> --- /dev/null
>> +++ b/sound/soc/codecs/mt6357.c
>> @@ -0,0 +1,1805 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * MT6357 ALSA SoC audio codec driver
>> + *
>
> Please use a C++ comment for the whole comment to make it clearer that
> this is intentional.

ok

>
>> +static void set_playback_gpio(struct mt6357_priv *priv, bool enable)
>> +{
>> + if (enable) {
>> + /* set gpio mosi mode */
>> + regmap_write(priv->regmap, MT6357_GPIO_MODE2_CLR, GPIO_MODE2_CLEAR_ALL);
>> + regmap_write(priv->regmap, MT6357_GPIO_MODE2_SET, GPIO8_MODE_SET_AUD_CLK_MOSI |
>> + GPIO9_MODE_SET_AUD_DAT_MOSI0 |
>> + GPIO10_MODE_SET_AUD_DAT_MOSI1 |
>> + GPIO11_MODE_SET_AUD_SYNC_MOSI);
>
> This would be a lot more legible if you worked out the values to set and
> then had a single set of writes, currently the indentation makes it very
> hard to read. Similarly for other similar functions.

ok

>
>> +static int mt6357_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
>> +{
>> + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
>> + struct mt6357_priv *priv = snd_soc_component_get_drvdata(component);
>> + struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
>> + unsigned int reg;
>> + int ret;
>> +
>> + ret = snd_soc_put_volsw(kcontrol, ucontrol);
>> + if (ret < 0)
>> + return ret;
>> +
>> + switch (mc->reg) {
>> + case MT6357_ZCD_CON2:
>> + regmap_read(priv->regmap, MT6357_ZCD_CON2, &reg);
>> + priv->ana_gain[ANALOG_VOLUME_HPOUTL] =
>> + (reg & AUD_HPL_GAIN_MASK) >> AUD_HPL_GAIN_SFT;
>> + priv->ana_gain[ANALOG_VOLUME_HPOUTR] =
>> + (reg & AUD_HPR_GAIN_MASK) >> AUD_HPR_GAIN_SFT;
>> + break;
>
> It would probably be less code and would definitely be clearer and
> simpler to just read the values when we need them rather than constatly
> keeping a cache separate to the register cache.

Actually you must save the values because the gain selected by the user
will be override to do a ramp => volume_ramp(.....):
- When you switch on the HP, you start from gain=-40db to final_gain
(selected by user).
- When you switch off the HP, you start from final_gain (selected by
user) to gain=-40db.

Also, the microphone's gain change when it's enabled/disabled.

So, it can implemented differently but currently it's aligned with the
other MTK codecs and I don't see any resource wasted here.

>
>> + /* ul channel swap */
>> + SOC_SINGLE("UL LR Swap", MT6357_AFE_UL_DL_CON0, AFE_UL_LR_SWAP_SFT, 1, 0),
>
> On/off controls should end in Switch.

Sorry, I don't understand your comment. Can you reword it please ?

>
>> +static const char * const hslo_mux_map[] = {
>> + "Open", "DACR", "Playback", "Test mode"
>> +};
>> +
>> +static int hslo_mux_map_value[] = {
>> + 0x0, 0x1, 0x2, 0x3,
>> +};
>
> Why not just use a normal mux here, there's no missing values or
> reordering? Similarly for other muxes.

I've dug into some other codecs and it's done like that, but I've
probably misunderstood something.

The only bad thing I see is enum is missing currently:

enum {
PGA_MUX_OPEN = 0,
PGA_MUX_DACR,
PGA_MUX_PB,
PGA_MUX_TM,
PGA_MUX_MASK = 0x3,
};

static const char * const hslo_mux_map[] = {
"Open", "DACR", "Playback", "Test mode"
};

static int hslo_mux_map_value[] = {
PGA_MUX_OPEN, PGA_MUX_DACR, PGA_MUX_PB, PGA_MUX_TM,
};

>
>> +static unsigned int mt6357_read(struct snd_soc_component *codec, unsigned int reg)
>> +{
>> + struct mt6357_priv *priv = snd_soc_component_get_drvdata(codec);
>> + unsigned int val;
>> +
>> + pr_debug("%s() reg = 0x%x", __func__, reg);
>> + regmap_read(priv->regmap, reg, &val);
>> + return val;
>> +}
>
> Remove these, there are vastly more logging facilities as standard in
> the regmap core.

ok

>
>> +/* Reg bit defines */
>> +/* MT6357_GPIO_DIR0 */
>> +#define GPIO8_DIR_MASK BIT(8)
>> +#define GPIO8_DIR_INPUT 0
>
> Please namespace your defines, these look very generic.

ok

--
Regards,
Alexandre

2024-03-13 18:36:32

by Alexandre Mergnat

[permalink] [raw]
Subject: Re: [PATCH 12/18] ASoC: codecs: mt6357: add MT6357 codec



On 26/02/2024 17:09, Mark Brown wrote:
>> index 000000000000..13e95c227114
>> --- /dev/null
>> +++ b/sound/soc/codecs/mt6357.c
>> @@ -0,0 +1,1805 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * MT6357 ALSA SoC audio codec driver
>> + *
> Please use a C++ comment for the whole comment to make it clearer that
> this is intentional.

If I do that, the checkpatch raise a warning:

WARNING: Improper SPDX comment style for
'sound/soc/mediatek/mt8365/mt8365-afe-clk.c', please use '//' instead
#22: FILE: sound/soc/mediatek/mt8365/mt8365-afe-clk.c:1:
+/* SPDX-License-Identifier: GPL-2.0

WARNING: Missing or malformed SPDX-License-Identifier tag in line 1
#22: FILE: sound/soc/mediatek/mt8365/mt8365-afe-clk.c:1:
+/* SPDX-License-Identifier: GPL-2.0

even if I put:
/* SPDX-License-Identifier: GPL-2.0 */

IMO, the checkpatch tool should be fixed/update first.

--
Regards,
Alexandre

2024-03-13 18:41:43

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH 12/18] ASoC: codecs: mt6357: add MT6357 codec

On Tue, Mar 12, 2024 at 07:03:25PM +0100, Alexandre Mergnat wrote:
> On 26/02/2024 17:09, Mark Brown wrote:

> > > + case MT6357_ZCD_CON2:
> > > + regmap_read(priv->regmap, MT6357_ZCD_CON2, &reg);
> > > + priv->ana_gain[ANALOG_VOLUME_HPOUTL] =
> > > + (reg & AUD_HPL_GAIN_MASK) >> AUD_HPL_GAIN_SFT;
> > > + priv->ana_gain[ANALOG_VOLUME_HPOUTR] =
> > > + (reg & AUD_HPR_GAIN_MASK) >> AUD_HPR_GAIN_SFT;
> > > + break;

> > It would probably be less code and would definitely be clearer and
> > simpler to just read the values when we need them rather than constatly
> > keeping a cache separate to the register cache.

> Actually you must save the values because the gain selected by the user will
> be override to do a ramp => volume_ramp(.....):
> - When you switch on the HP, you start from gain=-40db to final_gain
> (selected by user).
> - When you switch off the HP, you start from final_gain (selected by user)
> to gain=-40db.

You can just read the value back when you need to do a ramp?

> Also, the microphone's gain change when it's enabled/disabled.

I don't understand what this means?

> > > + /* ul channel swap */
> > > + SOC_SINGLE("UL LR Swap", MT6357_AFE_UL_DL_CON0, AFE_UL_LR_SWAP_SFT, 1, 0),

> > On/off controls should end in Switch.

> Sorry, I don't understand your comment. Can you reword it please ?

See control-names.rst. Run mixer-test on a card with this driver and
fix all the issues it reports.

> > > +static int hslo_mux_map_value[] = {
> > > + 0x0, 0x1, 0x2, 0x3,
> > > +};

> > Why not just use a normal mux here, there's no missing values or
> > reordering? Similarly for other muxes.

> I've dug into some other codecs and it's done like that, but I've probably
> misunderstood something.

> The only bad thing I see is enum is missing currently:
>
> enum {
> PGA_MUX_OPEN = 0,
> PGA_MUX_DACR,
> PGA_MUX_PB,
> PGA_MUX_TM,
> PGA_MUX_MASK = 0x3,
> };

The whole thing with explicitly specfying the mapping is just completely
redundant, you may as well remove it.


Attachments:
(No filename) (2.03 kB)
signature.asc (499.00 B)
Download all attachments

2024-03-13 18:42:03

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH 12/18] ASoC: codecs: mt6357: add MT6357 codec

On Wed, Mar 13, 2024 at 06:11:50PM +0100, Alexandre Mergnat wrote:
> On 26/02/2024 17:09, Mark Brown wrote:
> > > index 000000000000..13e95c227114
> > > --- /dev/null
> > > +++ b/sound/soc/codecs/mt6357.c
> > > @@ -0,0 +1,1805 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +/*
> > > + * MT6357 ALSA SoC audio codec driver

> > Please use a C++ comment for the whole comment to make it clearer that
> > this is intentional.

> If I do that, the checkpatch raise a warning:

> WARNING: Improper SPDX comment style for
> 'sound/soc/mediatek/mt8365/mt8365-afe-clk.c', please use '//' instead
> #22: FILE: sound/soc/mediatek/mt8365/mt8365-afe-clk.c:1:
> +/* SPDX-License-Identifier: GPL-2.0

That's not a C++ comment so checkpatch is correctly warning?


Attachments:
(No filename) (775.00 B)
signature.asc (499.00 B)
Download all attachments

2024-03-15 11:01:34

by Alexandre Mergnat

[permalink] [raw]
Subject: Re: [PATCH 12/18] ASoC: codecs: mt6357: add MT6357 codec



On 13/03/2024 18:23, Mark Brown wrote:
> On Tue, Mar 12, 2024 at 07:03:25PM +0100, Alexandre Mergnat wrote:
>> On 26/02/2024 17:09, Mark Brown wrote:
>
>>>> + case MT6357_ZCD_CON2:
>>>> + regmap_read(priv->regmap, MT6357_ZCD_CON2, &reg);
>>>> + priv->ana_gain[ANALOG_VOLUME_HPOUTL] =
>>>> + (reg & AUD_HPL_GAIN_MASK) >> AUD_HPL_GAIN_SFT;
>>>> + priv->ana_gain[ANALOG_VOLUME_HPOUTR] =
>>>> + (reg & AUD_HPR_GAIN_MASK) >> AUD_HPR_GAIN_SFT;
>>>> + break;
>
>>> It would probably be less code and would definitely be clearer and
>>> simpler to just read the values when we need them rather than constatly
>>> keeping a cache separate to the register cache.
>
>> Actually you must save the values because the gain selected by the user will
>> be override to do a ramp => volume_ramp(.....):
>> - When you switch on the HP, you start from gain=-40db to final_gain
>> (selected by user).
>> - When you switch off the HP, you start from final_gain (selected by user)
>> to gain=-40db.
>
> You can just read the value back when you need to do a ramp?

You can't. Because you will read -40db when HP isn't playing sound. That
is why the gain is saved into the struct.

Let me know, when you change de gain to do a ramp down (start from user
gain to gain=-40db), next time for the ramp up, how/where do you find
the user gain ?


>
>> Also, the microphone's gain change when it's enabled/disabled.
>
> I don't understand what this means?

When microphone isn't capturing, the gain read back from the register is
0dB. I've put some logs in my code and do capture to show how it works:

root@i350-evk:~# arecord -D hw:mt8365evk,2,0 -r 48000 -c2 -f s32_le -d
10 recorded_file.wav
[Mar15 09:31] mt8365-afe-pcm 11220000.audio-controller:
mt8365_afe_fe_hw_params AWB period = 6000 rate = 48000 channels = 2
[ +0.000126] mt8365-afe-pcm 11220000.audio-controller:
mt8365_dai_int_adda_prepare 'Capture' rate = 48000
[ +0.107688] mt6357-sound mt6357-sound: TOTO set mic to stored value
[ +10.072648] mt6357-sound mt6357-sound: TOTO set mic to 0dB

root@i350-evk:~# arecord -D hw:mt8365evk,2,0 -r 48000 -c2 -f s32_le -d
10 recorded_file.wav
[Mar15 09:32] mt8365-afe-pcm 11220000.audio-controller:
mt8365_afe_fe_hw_params AWB period = 6000 rate = 48000 channels = 2
[ +0.000133] mt8365-afe-pcm 11220000.audio-controller:
mt8365_dai_int_adda_prepare 'Capture' rate = 48000
[ +0.109418] mt6357-sound mt6357-sound: TOTO set mic to stored value
[ +10.164197] mt6357-sound mt6357-sound: TOTO set mic to 0dB


>
>>>> + /* ul channel swap */
>>>> + SOC_SINGLE("UL LR Swap", MT6357_AFE_UL_DL_CON0, AFE_UL_LR_SWAP_SFT, 1, 0),
>
>>> On/off controls should end in Switch.
>
>> Sorry, I don't understand your comment. Can you reword it please ?
>
> See control-names.rst. Run mixer-test on a card with this driver and
> fix all the issues it reports.

Ok the name is the issue for you AFAII.
This control isn't for on/off but swap Left and Right.
From the codec documentation:
"Swaps audio UL L/R channel before UL SRC"
This control is overkill, I will remove it

I'm stuck to run mixer-test, please check the following message:
https://lore.kernel.org/all/[email protected]/


--
Regards,
Alexandre

2024-03-15 14:32:10

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH 12/18] ASoC: codecs: mt6357: add MT6357 codec

On Fri, Mar 15, 2024 at 12:01:12PM +0100, Alexandre Mergnat wrote:
> On 13/03/2024 18:23, Mark Brown wrote:
> > On Tue, Mar 12, 2024 at 07:03:25PM +0100, Alexandre Mergnat wrote:

> > > Actually you must save the values because the gain selected by the user will
> > > be override to do a ramp => volume_ramp(.....):
> > > - When you switch on the HP, you start from gain=-40db to final_gain
> > > (selected by user).
> > > - When you switch off the HP, you start from final_gain (selected by user)
> > > to gain=-40db.

> > You can just read the value back when you need to do a ramp?

> You can't. Because you will read -40db when HP isn't playing sound. That is
> why the gain is saved into the struct.

> Let me know, when you change de gain to do a ramp down (start from user gain
> to gain=-40db), next time for the ramp up, how/where do you find the user
> gain ?

In the register. You only need to reset the gain to -40dB at the start
of the ramp.

> > > Also, the microphone's gain change when it's enabled/disabled.

> > I don't understand what this means?

> When microphone isn't capturing, the gain read back from the register is
> 0dB. I've put some logs in my code and do capture to show how it works:

Is this a property of the hardware or a property of your driver?

> > > > > + /* ul channel swap */
> > > > > + SOC_SINGLE("UL LR Swap", MT6357_AFE_UL_DL_CON0, AFE_UL_LR_SWAP_SFT, 1, 0),

> > > > On/off controls should end in Switch.

> > > Sorry, I don't understand your comment. Can you reword it please ?

> > See control-names.rst. Run mixer-test on a card with this driver and
> > fix all the issues it reports.

> Ok the name is the issue for you AFAII.
> This control isn't for on/off but swap Left and Right.
> From the codec documentation:
> "Swaps audio UL L/R channel before UL SRC"
> This control is overkill, I will remove it

This is turning the swapping on and off.


Attachments:
(No filename) (1.90 kB)
signature.asc (499.00 B)
Download all attachments

2024-03-15 14:38:56

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH 00/18] Add audio support for the MediaTek Genio 350-evk board

On Tue, Mar 12, 2024 at 09:58:05AM +0100, Alexandre Mergnat wrote:

> I'm a bit lost for mixer-test and pcm-test.
> Currently, I cross-compile the alsa lib project to be able to build the
> tests and put it on my board.

> I can execute it, but I still have 2 issues:

> 1) I've a lot of missing module in my environment (Encode.so, Encode.pm,
> Symbol.pm, IO/Handle.pm, ...). AFAII, I've to cross compile the missing perl
> modules and install them in the rootfs

These tests are both simple C programs...

> 2) I don't know how to configure pcm-test.conf &
> Lenovo_ThinkPad_P1_Gen2.conf (or new file to match with my board).

The configuration is optional.

> My test cmd:
> ./run_kselftest.sh -c alsa

Just run the programs directly. I'm only asking for the output from two
of them anyway.


Attachments:
(No filename) (819.00 B)
signature.asc (499.00 B)
Download all attachments

2024-03-15 15:05:41

by Alexandre Mergnat

[permalink] [raw]
Subject: Re: [PATCH 12/18] ASoC: codecs: mt6357: add MT6357 codec



On 15/03/2024 15:30, Mark Brown wrote:
> On Fri, Mar 15, 2024 at 12:01:12PM +0100, Alexandre Mergnat wrote:
>> On 13/03/2024 18:23, Mark Brown wrote:
>>> On Tue, Mar 12, 2024 at 07:03:25PM +0100, Alexandre Mergnat wrote:
>
>>>> Actually you must save the values because the gain selected by the user will
>>>> be override to do a ramp => volume_ramp(.....):
>>>> - When you switch on the HP, you start from gain=-40db to final_gain
>>>> (selected by user).
>>>> - When you switch off the HP, you start from final_gain (selected by user)
>>>> to gain=-40db.
>
>>> You can just read the value back when you need to do a ramp?
>
>> You can't. Because you will read -40db when HP isn't playing sound. That is
>> why the gain is saved into the struct.
>
>> Let me know, when you change de gain to do a ramp down (start from user gain
>> to gain=-40db), next time for the ramp up, how/where do you find the user
>> gain ?
>
> In the register. You only need to reset the gain to -40dB at the start
> of the ramp.

Sorry but I don't understand your logic, I'm not able to implement it...
If I'm at -10dB and doing a ramp to reach -40dB, next time I will read
the register the value will be -40dB.

This implementation is also done in other MTK audio codec drivers.

>
>>>> Also, the microphone's gain change when it's enabled/disabled.
>
>>> I don't understand what this means?
>
>> When microphone isn't capturing, the gain read back from the register is
>> 0dB. I've put some logs in my code and do capture to show how it works:
>
> Is this a property of the hardware or a property of your driver?

At the end of the capture, the gain is set to 0dB by the driver.
At the start of the capture, the gain is set to the setup gain.

AFAII from the comment in the code, it's done to avoid the "pop noises".

>
>>>>>> + /* ul channel swap */
>>>>>> + SOC_SINGLE("UL LR Swap", MT6357_AFE_UL_DL_CON0, AFE_UL_LR_SWAP_SFT, 1, 0),
>
>>>>> On/off controls should end in Switch.
>
>>>> Sorry, I don't understand your comment. Can you reword it please ?
>
>>> See control-names.rst. Run mixer-test on a card with this driver and
>>> fix all the issues it reports.
>
>> Ok the name is the issue for you AFAII.
>> This control isn't for on/off but swap Left and Right.
>> From the codec documentation:
>> "Swaps audio UL L/R channel before UL SRC"
>> This control is overkill, I will remove it
>
> This is turning the swapping on and off.

--
Regards,
Alexandre

2024-03-15 15:17:09

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH 12/18] ASoC: codecs: mt6357: add MT6357 codec

On Fri, Mar 15, 2024 at 04:05:21PM +0100, Alexandre Mergnat wrote:
> On 15/03/2024 15:30, Mark Brown wrote:

> > > Let me know, when you change de gain to do a ramp down (start from user gain
> > > to gain=-40db), next time for the ramp up, how/where do you find the user
> > > gain ?

> > In the register. You only need to reset the gain to -40dB at the start
> > of the ramp.

> Sorry but I don't understand your logic, I'm not able to implement it...
> If I'm at -10dB and doing a ramp to reach -40dB, next time I will read the
> register the value will be -40dB.

After we've done the ramp and turned the amplifier off we can just
restore the desired value? The hardware is not going to care what the
volume is while it's not enabled.

> This implementation is also done in other MTK audio codec drivers.

Perhaps they should be updated too?

> > > When microphone isn't capturing, the gain read back from the register is
> > > 0dB. I've put some logs in my code and do capture to show how it works:

> > Is this a property of the hardware or a property of your driver?

> At the end of the capture, the gain is set to 0dB by the driver.
> At the start of the capture, the gain is set to the setup gain.

So that's a property of the driver then?

> AFAII from the comment in the code, it's done to avoid the "pop noises".

Yes, that's the usual reason to ramp gains. Though if you've just
copied the code without checking that it's needed it's possible that
this is something that's been fixed in current hardware.


Attachments:
(No filename) (1.52 kB)
signature.asc (499.00 B)
Download all attachments

2024-03-15 15:28:57

by Alexandre Mergnat

[permalink] [raw]
Subject: Re: [PATCH 00/18] Add audio support for the MediaTek Genio 350-evk board



On 15/03/2024 15:38, Mark Brown wrote:
> On Tue, Mar 12, 2024 at 09:58:05AM +0100, Alexandre Mergnat wrote:
>
>> I'm a bit lost for mixer-test and pcm-test.
>> Currently, I cross-compile the alsa lib project to be able to build the
>> tests and put it on my board.
>
>> I can execute it, but I still have 2 issues:
>
>> 1) I've a lot of missing module in my environment (Encode.so, Encode.pm,
>> Symbol.pm, IO/Handle.pm, ...). AFAII, I've to cross compile the missing perl
>> modules and install them in the rootfs
>
> These tests are both simple C programs...
>
>> 2) I don't know how to configure pcm-test.conf &
>> Lenovo_ThinkPad_P1_Gen2.conf (or new file to match with my board).
>
> The configuration is optional.
>
>> My test cmd:
>> ./run_kselftest.sh -c alsa
>
> Just run the programs directly. I'm only asking for the output from two
> of them anyway.

ok

--
Regards,
Alexandre

2024-03-15 18:11:03

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH 12/18] ASoC: codecs: mt6357: add MT6357 codec

On Fri, Mar 15, 2024 at 06:36:19PM +0100, Alexandre Mergnat wrote:
> On 15/03/2024 16:15, Mark Brown wrote:
> > On Fri, Mar 15, 2024 at 04:05:21PM +0100, Alexandre Mergnat wrote:

> > > > In the register. You only need to reset the gain to -40dB at the start
> > > > of the ramp.

> > > Sorry but I don't understand your logic, I'm not able to implement it...
> > > If I'm at -10dB and doing a ramp to reach -40dB, next time I will read the
> > > register the value will be -40dB.

> > After we've done the ramp and turned the amplifier off we can just
> > restore the desired value? The hardware is not going to care what the
> > volume is while it's not enabled.

> If you do that, HP will be enabled at the saved gain, and after that you
> will do the ramp. To avoid pop, the driver should be rewrite to:

So reset the volume to -40dB prior to turning the amplifier on...

> Read gain in the reg and save it locally
> Set -40dB in the reg
> Enable HP
> Do ramp

..as you yourself suggest?

> > > AFAII from the comment in the code, it's done to avoid the "pop noises".

> > Yes, that's the usual reason to ramp gains. Though if you've just
> > copied the code without checking that it's needed it's possible that
> > this is something that's been fixed in current hardware.

> I did the test at 24dB with and without the "pop filter". Isn't big but I
> ear the pop at the start of the record without the "pop filter".

OK, it probably is still doing something then.

> To be clear, the algo/behavior of this code is an implementation based on
> the 6k+ lines downstream code for this specific audio codec. But the
> shape/style is based on upstreamed drivers like mt6358.c.

The Mediatek code has a bunch of issues, I wouldn't read too much into
something being present in the code.


Attachments:
(No filename) (1.80 kB)
signature.asc (499.00 B)
Download all attachments

2024-03-15 17:36:39

by Alexandre Mergnat

[permalink] [raw]
Subject: Re: [PATCH 12/18] ASoC: codecs: mt6357: add MT6357 codec



On 15/03/2024 16:15, Mark Brown wrote:
> On Fri, Mar 15, 2024 at 04:05:21PM +0100, Alexandre Mergnat wrote:
>> On 15/03/2024 15:30, Mark Brown wrote:
>
>>>> Let me know, when you change de gain to do a ramp down (start from user gain
>>>> to gain=-40db), next time for the ramp up, how/where do you find the user
>>>> gain ?
>
>>> In the register. You only need to reset the gain to -40dB at the start
>>> of the ramp.
>
>> Sorry but I don't understand your logic, I'm not able to implement it...
>> If I'm at -10dB and doing a ramp to reach -40dB, next time I will read the
>> register the value will be -40dB.
>
> After we've done the ramp and turned the amplifier off we can just
> restore the desired value? The hardware is not going to care what the
> volume is while it's not enabled.

If you do that, HP will be enabled at the saved gain, and after that you
will do the ramp. To avoid pop, the driver should be rewrite to:

Read gain in the reg and save it locally
Set -40dB in the reg
Enable HP
Do ramp

And for the shutdown:

Read gain in the reg and save it locally
Do ramp
Disable HP
Set saved gain in the reg


To resume, that add 4 more steps to save 2 integers into the driver
structure.

IMHO, I don't think it make the code more readable or optimized, but I
don't have a strong opinion about that, so if you think it's better, I
will change it.


>
>> This implementation is also done in other MTK audio codec drivers.
>
> Perhaps they should be updated too?
>
>>>> When microphone isn't capturing, the gain read back from the register is
>>>> 0dB. I've put some logs in my code and do capture to show how it works:
>
>>> Is this a property of the hardware or a property of your driver?
>
>> At the end of the capture, the gain is set to 0dB by the driver.
>> At the start of the capture, the gain is set to the setup gain.
>
> So that's a property of the driver then?

Yes

>
>> AFAII from the comment in the code, it's done to avoid the "pop noises".
>
> Yes, that's the usual reason to ramp gains. Though if you've just
> copied the code without checking that it's needed it's possible that
> this is something that's been fixed in current hardware.

I did the test at 24dB with and without the "pop filter". Isn't big but
I ear the pop at the start of the record without the "pop filter".

To be clear, the algo/behavior of this code is an implementation based
on the 6k+ lines downstream code for this specific audio codec. But the
shape/style is based on upstreamed drivers like mt6358.c.

--
Regards,
Alexandre

2024-03-28 10:10:11

by Alexandre Mergnat

[permalink] [raw]
Subject: Re: [PATCH 00/18] Add audio support for the MediaTek Genio 350-evk board

Hi Angelo

On 26/02/2024 15:54, AngeloGioacchino Del Regno wrote:
> Il 26/02/24 15:01, Alexandre Mergnat ha scritto:
>> This serie aim to add the following audio support for the Genio 350-evk:
>> - Playback
>>    - 2ch Headset Jack (Earphone)
>>    - 1ch Line-out Jack (Speaker)
>>    - 8ch HDMI Tx
>> - Capture
>>    - 1ch DMIC (On-board Digital Microphone)
>>    - 1ch AMIC (On-board Analogic Microphone)
>>    - 1ch Headset Jack (External Analogic Microphone)
>>
>> Of course, HDMI playback need the MT8365 display patches [1] and a DTS
>> change documented in "mediatek,mt8365-mt6357.yaml".
>>
>> [1]:
>> https://lore.kernel.org/all/[email protected]/
>>
>> Signed-off-by: Alexandre Mergnat <[email protected]>
>
> Actually, I am cooking a series (I'm finishing the testing....) that
> brings quite
> a bit of cleanups in MTK ASoC, including the commonization of the
> machine driver
> probe, with the dai-link DT nodes, and which also modernizes most of the
> existing
> drivers to use that instead.
>
> If you wait for a day or two, your mt8365-mt6357.c driver's probe
> function can be
> shrunk to ~3 lines or something like that.. very easily :-)

Just to inform you. I'm aware of your serie. Currently, I've fixed my
patches according to the comments. The next step will be to rebase my
serie over yours and do the changes to be aligned with your new
implementation.

I've planned to review your serie during my last task, but it seems
already approved and already (partially) merged into linux-next, sorry.


--
Regards,
Alexandre