Commit 9a029545 authored by Mark Brown's avatar Mark Brown

Add audio support for the MediaTek Genio 350-evk

Merge series from Alexandre Mergnat <amergnat@baylibre.com>:

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".

Applied patch:
- mfd: mt6397-core: register mt6357 sound codec

Test passed:
- mixer-test log: [3]
- pcm-test log: [4]

[1]: https://lore.kernel.org/all/20231023-display-support-v1-0-5c860ed5c33b@baylibre.com/
[2]: https://lore.kernel.org/all/20240313110147.1267793-1-angelogioacchino.delregno@collabora.com/
[3]: https://pastebin.com/pc43AVrT
[4]: https://pastebin.com/cCtGhDpg
[5]: https://gitlab.baylibre.com/baylibre/mediatek/bsp/linux/-/commits/sound/for-next/add-i350-audio-support
parents 97688a9c e1991d10
......@@ -37,6 +37,24 @@ properties:
"#interrupt-cells":
const: 2
mediatek,hp-pull-down:
description:
Earphone driver positive output stage short to
the audio reference ground.
type: boolean
mediatek,micbias0-microvolt:
description: Selects MIC Bias 0 output voltage.
enum: [1700000, 1800000, 1900000, 2000000,
2100000, 2500000, 2600000, 2700000]
default: 1700000
mediatek,micbias1-microvolt:
description: Selects MIC Bias 1 output voltage.
enum: [1700000, 1800000, 1900000, 2000000,
2100000, 2500000, 2600000, 2700000]
default: 1700000
regulators:
type: object
$ref: /schemas/regulator/mediatek,mt6357-regulator.yaml
......@@ -83,6 +101,9 @@ examples:
interrupt-controller;
#interrupt-cells = <2>;
mediatek,micbias0-microvolt = <1700000>;
mediatek,micbias1-microvolt = <1700000>;
regulators {
mt6357_vproc_reg: buck-vproc {
regulator-name = "vproc";
......
# 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 Audio Front End PCM controller for MT8365
maintainers:
- Alexandre Mergnat <amergnat@baylibre.com>
properties:
compatible:
const: mediatek,mt8365-afe-pcm
reg:
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
interrupts:
maxItems: 1
power-domains:
maxItems: 1
mediatek,dmic-mode:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Indicates how many data pins are used to transmit two channels of PDM
signal. 1 means two wires, 0 means one wire. Default value is 0.
enum:
- 0 # one wire
- 1 # two wires
required:
- compatible
- reg
- clocks
- clock-names
- interrupts
- power-domains
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>;
audio-controller@11220000 {
compatible = "mediatek,mt8365-afe-pcm";
reg = <0 0x11220000 0 0x1000>;
#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";
interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_LOW>;
power-domains = <&spm MT8365_POWER_DOMAIN_AUDIO>;
mediatek,dmic-mode = <1>;
};
};
...
# 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 ASoC sound card
maintainers:
- Alexandre Mergnat <amergnat@baylibre.com>
properties:
compatible:
const: mediatek,mt8365-mt6357
pinctrl-names:
minItems: 1
items:
- const: default
- const: dmic
- const: miso_off
- const: miso_on
- const: mosi_off
- const: mosi_on
mediatek,platform:
$ref: /schemas/types.yaml#/definitions/phandle
description: The phandle of MT8365 ASoC platform.
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: Indicates dai-link name and PCM stream name
enum:
- I2S_IN_BE
- I2S_OUT_BE
- PCM1_BE
- PDM1_BE
- PDM2_BE
- PDM3_BE
- PDM4_BE
- SPDIF_IN_BE
- SPDIF_OUT_BE
- TDM_IN_BE
- TDM_OUT_BE
sound-dai:
maxItems: 1
description: phandle of the CPU DAI
required:
- link-name
- sound-dai
additionalProperties: false
required:
- compatible
- pinctrl-names
- mediatek,platform
additionalProperties: false
examples:
- |
sound {
compatible = "mediatek,mt8365-mt6357";
pinctrl-names = "default",
"dmic",
"miso_off",
"miso_on",
"mosi_off",
"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>;
mediatek,platform = <&afe>;
/* hdmi interface */
dai-link-0 {
link-name = "I2S_OUT_BE";
sound-dai = <&afe>;
codec {
sound-dai = <&it66121hdmitx>;
};
};
};
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0
*
* MediaTek 8365 AFE clock control definitions
*
* Copyright (c) 2024 MediaTek Inc.
* Authors: Jia Zeng <jia.zeng@mediatek.com>
* Alexandre Mergnat <amergnat@baylibre.com>
*/
#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);
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
/* SPDX-License-Identifier: GPL-2.0
*
* MediaTek 8365 audio driver common definitions
*
* Copyright (c) 2024 MediaTek Inc.
* Authors: Jia Zeng <jia.zeng@mediatek.com>
* Alexandre Mergnat <amergnat@baylibre.com>
*/
#ifndef _MT8365_AFE_COMMON_H_
#define _MT8365_AFE_COMMON_H_
#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"
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;
};
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];
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; /* Protect & sync APLL TUNER registers access*/
#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);
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
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0
/*
* MediaTek 8365 ALSA SoC Audio DAI ADDA Control
*
* Copyright (c) 2024 MediaTek Inc.
* Authors: Jia Zeng <jia.zeng@mediatek.com>
* Alexandre Mergnat <amergnat@baylibre.com>
*/
#include <linux/bitops.h>
#include <linux/regmap.h>
#include <sound/pcm_params.h>
#include "mt8365-afe-clk.h"
#include "mt8365-afe-common.h"
#include "../common/mtk-dai-adda-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;
if (rate == 8000 || rate == 16000)
val = AFE_ADDA_DL_VOICE_DATA;
else
val = 0;
val |= FIELD_PREP(AFE_ADDA_DL_SAMPLING_RATE,
mtk_adda_dl_rate_transform(afe, rate));
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;
val = FIELD_PREP(AFE_ADDA_UL_SAMPLING_RATE,
mtk_adda_ul_rate_transform(afe, rate));
regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0,
AFE_ADDA_UL_SAMPLING_RATE, 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;
dev_warn(afe->dev, "Abnormal adda_on ref count. Force it to 0\n");
}
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 */
usleep_range(150, 300);
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];
unsigned int rate = substream->runtime->rate;
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[substream->stream]) {
dev_info(afe->dev, "%s '%s' prepared already\n",
__func__, snd_pcm_stream_str(substream));
return 0;
}
if (substream->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[substream->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_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 Switch", AFE_CONN3,
10, 1, 0),
};
static const struct snd_kcontrol_new mtk_adda_dl_ch2_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2 Switch", 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;
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;
}
// SPDX-License-Identifier: GPL-2.0
/*
* MediaTek 8365 ALSA SoC Audio DAI DMIC Control
*
* Copyright (c) 2024 MediaTek Inc.
* Authors: Jia Zeng <jia.zeng@mediatek.com>
* Alexandre Mergnat <amergnat@baylibre.com>
*/
#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;
};
static int get_chan_reg(unsigned int channel)
{
switch (channel) {
case 8:
fallthrough;
case 7:
return AFE_DMIC3_UL_SRC_CON0;
case 6:
fallthrough;
case 5:
return AFE_DMIC2_UL_SRC_CON0;
case 4:
fallthrough;
case 3:
return AFE_DMIC1_UL_SRC_CON0;
case 2:
fallthrough;
case 1:
return AFE_DMIC0_UL_SRC_CON0;
default:
return -EINVAL;
}
}
/* 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;
int reg = get_chan_reg(dmic_data->dmic_channel);
if (reg < 0)
return;
/* 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;
regmap_update_bits(afe->regmap, reg, val_mask, val_mask);
}
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 mask;
int reg = get_chan_reg(dmic_data->dmic_channel);
if (reg < 0)
return;
dev_dbg(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;
/* Set all masked values to 0 */
regmap_update_bits(afe->regmap, reg, mask, 0);
}
static const struct reg_sequence mt8365_dmic_iir_coeff[] = {
{ 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_dmic_iir_coeff,
ARRAY_SIZE(mt8365_dmic_iir_coeff));
}
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;
unsigned int val = 0;
unsigned int rate = dai->rate;
int reg = get_chan_reg(dai->channels);
if (reg < 0)
return -EINVAL;
dmic_data->dmic_channel = dai->channels;
val |= DMIC_TOP_CON_SDM3_LEVEL_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;
}
regmap_update_bits(afe->regmap, reg, DMIC_TOP_CON_CONFIG_MASK, val);
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 125us before CG off */
usleep_range(125, 300);
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_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 */
/* Values for 48kHz mode */
static const char * const iir_mode_src[] = {
"SW custom", "5Hz", "10Hz", "25Hz", "50Hz", "65Hz"
};
static SOC_ENUM_SINGLE_DECL(iir_mode, AFE_DMIC0_UL_SRC_CON0, 7, iir_mode_src);
static const struct snd_kcontrol_new mtk_dai_dmic_controls[] = {
SOC_SINGLE("DMIC IIR Switch", AFE_DMIC0_UL_SRC_CON0, DMIC_TOP_CON_IIR_ON, 1, 0),
SOC_ENUM("DMIC IIR Mode", iir_mode),
};
/* 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(*dmic_priv), 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->two_wire_mode = !!temps[0];
if (!dmic_priv->two_wire_mode) {
dmic_priv->clk_phase_sel_ch1 = 0;
dmic_priv->clk_phase_sel_ch2 = 4;
}
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;
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);
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment