mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
ASoC: mediatek: Add support for MT8196 SoC
Cyril Chao <Cyril.Chao@mediatek.com> says: This series of patches adds support for Mediatek AFE of MT8196 SoC.
This commit is contained in:
commit
bf2831e4f4
113
Documentation/devicetree/bindings/sound/mediatek,mt8196-afe.yaml
Normal file
113
Documentation/devicetree/bindings/sound/mediatek,mt8196-afe.yaml
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/mediatek,mt8196-afe.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: MediaTek Audio Front End PCM controller for MT8196
|
||||
|
||||
maintainers:
|
||||
- Darren Ye <darren.ye@mediatek.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: mediatek,mt8196-afe
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
memory-region:
|
||||
maxItems: 1
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: mux for audio intbus
|
||||
- description: mux for audio engen1
|
||||
- description: mux for audio engen2
|
||||
- description: mux for audio h
|
||||
- description: audio apll1 clock
|
||||
- description: audio apll2 clock
|
||||
- description: audio apll12 divide for i2sin0
|
||||
- description: audio apll12 divide for i2sin1
|
||||
- description: audio apll12 divide for fmi2s
|
||||
- description: audio apll12 divide for tdmout mck
|
||||
- description: audio apll12 divide for tdmout bck
|
||||
- description: mux for adsp clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: top_aud_intbus
|
||||
- const: top_aud_eng1
|
||||
- const: top_aud_eng2
|
||||
- const: top_aud_h
|
||||
- const: apll1
|
||||
- const: apll2
|
||||
- const: apll12_div_i2sin0
|
||||
- const: apll12_div_i2sin1
|
||||
- const: apll12_div_fmi2s
|
||||
- const: apll12_div_tdmout_m
|
||||
- const: apll12_div_tdmout_b
|
||||
- const: top_adsp
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- memory-region
|
||||
- power-domains
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
afe@1a110000 {
|
||||
compatible = "mediatek,mt8196-afe";
|
||||
reg = <0 0x1a110000 0 0x9000>;
|
||||
interrupts = <GIC_SPI 351 IRQ_TYPE_LEVEL_HIGH 0>;
|
||||
memory-region = <&afe_dma_mem_reserved>;
|
||||
power-domains = <&scpsys 14>; //MT8196_POWER_DOMAIN_AUDIO
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&aud_pins_default>;
|
||||
clocks = <&vlp_cksys_clk 40>, //CLK_VLP_CK_AUD_INTBUS_SEL
|
||||
<&vlp_cksys_clk 38>, //CLK_VLP_CK_AUD_ENGEN1_SEL
|
||||
<&vlp_cksys_clk 39>, //CLK_VLP_CK_AUD_ENGEN2_SEL
|
||||
<&vlp_cksys_clk 37>, //CLK_VLP_CK_AUDIO_H_SEL
|
||||
<&vlp_cksys_clk 0>, //CLK_VLP_CK_VLP_APLL1
|
||||
<&vlp_cksys_clk 1>, //CLK_VLP_CK_VLP_APLL2
|
||||
<&cksys_clk 80>, //CLK_CK_APLL12_CK_DIV_I2SIN0
|
||||
<&cksys_clk 81>, //CLK_CK_APLL12_CK_DIV_I2SIN1
|
||||
<&cksys_clk 92>, //CLK_CK_APLL12_CK_DIV_FMI2S
|
||||
<&cksys_clk 93>, //CLK_CK_APLL12_CK_DIV_TDMOUT_M
|
||||
<&cksys_clk 94>, //CLK_CK_APLL12_CK_DIV_TDMOUT_B
|
||||
<&cksys_clk 45>; //CLK_CK_ADSP_SEL
|
||||
clock-names = "top_aud_intbus",
|
||||
"top_aud_eng1",
|
||||
"top_aud_eng2",
|
||||
"top_aud_h",
|
||||
"apll1",
|
||||
"apll2",
|
||||
"apll12_div_i2sin0",
|
||||
"apll12_div_i2sin1",
|
||||
"apll12_div_fmi2s",
|
||||
"apll12_div_tdmout_m",
|
||||
"apll12_div_tdmout_b",
|
||||
"top_adsp";
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/mediatek,mt8196-nau8825.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: MediaTek MT8196 ASoC sound card
|
||||
|
||||
maintainers:
|
||||
- Darren Ye <darren.ye@mediatek.com>
|
||||
|
||||
allOf:
|
||||
- $ref: sound-card-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- mediatek,mt8196-nau8825-sound
|
||||
- mediatek,mt8196-rt5682s-sound
|
||||
- mediatek,mt8196-rt5650-sound
|
||||
|
||||
mediatek,platform:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: The phandle of MT8188 ASoC platform.
|
||||
|
||||
patternProperties:
|
||||
"^dai-link-[0-9]+$":
|
||||
type: object
|
||||
description:
|
||||
Container for dai-link level properties and CODEC sub-nodes.
|
||||
|
||||
properties:
|
||||
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:
|
||||
enum:
|
||||
- TDM_DPTX_BE
|
||||
- I2SOUT6_BE
|
||||
- I2SIN6_BE
|
||||
- I2SOUT4_BE
|
||||
- I2SOUT3_BE
|
||||
|
||||
codec:
|
||||
description: Holds subnode which indicates codec dai.
|
||||
type: object
|
||||
additionalProperties: false
|
||||
properties:
|
||||
sound-dai:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
required:
|
||||
- sound-dai
|
||||
|
||||
dai-format:
|
||||
description: audio format.
|
||||
items:
|
||||
enum:
|
||||
- i2s
|
||||
- right_j
|
||||
- left_j
|
||||
- dsp_a
|
||||
- dsp_b
|
||||
|
||||
mediatek,clk-provider:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
description: Indicates dai-link clock master.
|
||||
enum:
|
||||
- cpu
|
||||
- codec
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- link-name
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- mediatek,platform
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
sound {
|
||||
compatible = "mediatek,mt8196-nau8825-sound";
|
||||
model = "mt8196-nau8825";
|
||||
mediatek,platform = <&afe>;
|
||||
dai-link-0 {
|
||||
link-name = "I2SOUT6_BE";
|
||||
dai-format = "i2s";
|
||||
mediatek,clk-provider = "cpu";
|
||||
codec {
|
||||
sound-dai = <&nau8825>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
|
|
@ -363,4 +363,34 @@ config SND_SOC_MT8365_MT6357
|
|||
Select Y if you have such device.
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SOC_MT8196
|
||||
tristate "ASoC support for Mediatek MT8196 chip"
|
||||
depends on ARCH_MEDIATEK
|
||||
select SND_SOC_MEDIATEK
|
||||
help
|
||||
This adds ASoC driver for Mediatek MT8196 boards
|
||||
that can be used with other codecs.
|
||||
Select Y if you have such device.
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SOC_MT8196_NAU8825
|
||||
tristate "ASoc Audio driver for MT8196 with NAU8825 and I2S codec"
|
||||
depends on SND_SOC_MT8196
|
||||
depends on I2C
|
||||
select SND_SOC_HDMI_CODEC
|
||||
select SND_SOC_DMIC
|
||||
select SND_SOC_NAU8315
|
||||
select SND_SOC_NAU8825
|
||||
select SND_SOC_RT5645
|
||||
select SND_SOC_RT5682_I2C
|
||||
select SND_SOC_RT5682S
|
||||
select SND_SOC_TAS2781_COMLIB
|
||||
select SND_SOC_TAS2781_FMWLIB
|
||||
select SND_SOC_TAS2781_I2C
|
||||
help
|
||||
This adds support for ASoC machine driver for MediaTek MT8196
|
||||
boards with the NAU8825 and other I2S audio codecs.
|
||||
Select Y if you have such device.
|
||||
If unsure select "N".
|
||||
|
||||
endmenu
|
||||
|
|
|
|||
|
|
@ -11,3 +11,4 @@ obj-$(CONFIG_SND_SOC_MT8192) += mt8192/
|
|||
obj-$(CONFIG_SND_SOC_MT8195) += mt8195/
|
||||
obj-$(CONFIG_SND_SOC_MT8365) += mt8365/
|
||||
obj-$(CONFIG_SND_SOC_MT8189) += mt8189/
|
||||
obj-$(CONFIG_SND_SOC_MT8196) += mt8196/
|
||||
|
|
|
|||
|
|
@ -87,29 +87,49 @@ snd_pcm_uframes_t mtk_afe_pcm_pointer(struct snd_soc_component *component,
|
|||
const struct mtk_base_memif_data *memif_data = memif->data;
|
||||
struct regmap *regmap = afe->regmap;
|
||||
struct device *dev = afe->dev;
|
||||
int reg_ofs_base = memif_data->reg_ofs_base;
|
||||
int reg_ofs_cur = memif_data->reg_ofs_cur;
|
||||
unsigned int hw_ptr = 0, hw_base = 0;
|
||||
int ret, pcm_ptr_bytes;
|
||||
unsigned int hw_ptr_lower32 = 0, hw_ptr_upper32 = 0;
|
||||
unsigned int hw_base_lower32 = 0, hw_base_upper32 = 0;
|
||||
unsigned long long hw_ptr = 0, hw_base = 0;
|
||||
int ret;
|
||||
unsigned long long pcm_ptr_bytes = 0;
|
||||
|
||||
ret = regmap_read(regmap, reg_ofs_cur, &hw_ptr);
|
||||
if (ret || hw_ptr == 0) {
|
||||
dev_err(dev, "%s hw_ptr err\n", __func__);
|
||||
pcm_ptr_bytes = 0;
|
||||
goto POINTER_RETURN_FRAMES;
|
||||
ret = regmap_read(regmap, memif_data->reg_ofs_cur, &hw_ptr_lower32);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s hw_ptr_lower32 err\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = regmap_read(regmap, reg_ofs_base, &hw_base);
|
||||
if (ret || hw_base == 0) {
|
||||
dev_err(dev, "%s hw_ptr err\n", __func__);
|
||||
pcm_ptr_bytes = 0;
|
||||
goto POINTER_RETURN_FRAMES;
|
||||
if (memif_data->reg_ofs_cur_msb) {
|
||||
ret = regmap_read(regmap, memif_data->reg_ofs_cur_msb, &hw_ptr_upper32);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s hw_ptr_upper32 err\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
pcm_ptr_bytes = hw_ptr - hw_base;
|
||||
ret = regmap_read(regmap, memif_data->reg_ofs_base, &hw_base_lower32);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s hw_base_lower32 err\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
if (memif_data->reg_ofs_base_msb) {
|
||||
ret = regmap_read(regmap, memif_data->reg_ofs_base_msb, &hw_base_upper32);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s hw_base_upper32 err\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
POINTER_RETURN_FRAMES:
|
||||
return bytes_to_frames(substream->runtime, pcm_ptr_bytes);
|
||||
hw_ptr = ((unsigned long long)hw_ptr_upper32 << 32) | hw_ptr_lower32;
|
||||
hw_base = ((unsigned long long)hw_base_upper32 << 32) | hw_base_lower32;
|
||||
|
||||
if (!hw_ptr || !hw_base) {
|
||||
dev_err(dev, "hw_ptr or hw_base = 0 err\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pcm_ptr_bytes = MTK_ALIGN_16BYTES(hw_ptr - hw_base);
|
||||
return bytes_to_frames(substream->runtime, (ssize_t)pcm_ptr_bytes);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_afe_pcm_pointer);
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
#define AFE_PCM_NAME "mtk-afe-pcm"
|
||||
extern const struct snd_soc_component_driver mtk_afe_pcm_platform;
|
||||
|
||||
#define MTK_ALIGN_16BYTES(x) ((x) & GENMASK_ULL(39, 4))
|
||||
|
||||
struct mtk_base_afe;
|
||||
struct snd_pcm;
|
||||
struct snd_soc_component;
|
||||
|
|
|
|||
14
sound/soc/mediatek/mt8196/Makefile
Normal file
14
sound/soc/mediatek/mt8196/Makefile
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# platform driver
|
||||
snd-soc-mt8196-afe-objs += \
|
||||
mt8196-afe-pcm.o \
|
||||
mt8196-afe-clk.o \
|
||||
mt8196-dai-adda.o \
|
||||
mt8196-dai-i2s.o \
|
||||
mt8196-dai-tdm.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_MT8196) += snd-soc-mt8196-afe.o
|
||||
|
||||
# machine driver
|
||||
obj-$(CONFIG_SND_SOC_MT8196_NAU8825) += mt8196-nau8825.o
|
||||
581
sound/soc/mediatek/mt8196/mt8196-afe-clk.c
Normal file
581
sound/soc/mediatek/mt8196/mt8196-afe-clk.c
Normal file
|
|
@ -0,0 +1,581 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* mt8196-afe-clk.c -- Mediatek 8196 afe clock ctrl
|
||||
*
|
||||
* Copyright (c) 2025 MediaTek Inc.
|
||||
* Author: Darren Ye <darren.ye@mediatek.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
|
||||
#include "mt8196-afe-clk.h"
|
||||
#include "mt8196-afe-common.h"
|
||||
|
||||
static const char *aud_clks[MT8196_CLK_NUM] = {
|
||||
/* vlp clk */
|
||||
[MT8196_CLK_VLP_MUX_AUDIOINTBUS] = "top_aud_intbus",
|
||||
[MT8196_CLK_VLP_MUX_AUD_ENG1] = "top_aud_eng1",
|
||||
[MT8196_CLK_VLP_MUX_AUD_ENG2] = "top_aud_eng2",
|
||||
[MT8196_CLK_VLP_MUX_AUDIO_H] = "top_aud_h",
|
||||
/* pll */
|
||||
[MT8196_CLK_TOP_APLL1_CK] = "apll1",
|
||||
[MT8196_CLK_TOP_APLL2_CK] = "apll2",
|
||||
/* divider */
|
||||
[MT8196_CLK_TOP_APLL12_DIV_I2SIN0] = "apll12_div_i2sin0",
|
||||
[MT8196_CLK_TOP_APLL12_DIV_I2SIN1] = "apll12_div_i2sin1",
|
||||
[MT8196_CLK_TOP_APLL12_DIV_FMI2S] = "apll12_div_fmi2s",
|
||||
[MT8196_CLK_TOP_APLL12_DIV_TDMOUT_M] = "apll12_div_tdmout_m",
|
||||
[MT8196_CLK_TOP_APLL12_DIV_TDMOUT_B] = "apll12_div_tdmout_b",
|
||||
/* mux */
|
||||
[MT8196_CLK_TOP_ADSP_SEL] = "top_adsp",
|
||||
};
|
||||
|
||||
int mt8196_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(clk);
|
||||
if (ret) {
|
||||
dev_err(afe->dev, "failed to enable clk\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt8196_afe_enable_clk);
|
||||
|
||||
void mt8196_afe_disable_clk(struct mtk_base_afe *afe, struct clk *clk)
|
||||
{
|
||||
if (clk)
|
||||
clk_disable_unprepare(clk);
|
||||
else
|
||||
dev_err(afe->dev, "NULL clk\n");
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt8196_afe_disable_clk);
|
||||
|
||||
static int mt8196_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 clk rate\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int get_top_cg_reg(unsigned int cg_type)
|
||||
{
|
||||
switch (cg_type) {
|
||||
case MT8196_AUDIO_26M_EN_ON:
|
||||
case MT8196_AUDIO_F3P25M_EN_ON:
|
||||
case MT8196_AUDIO_APLL1_EN_ON:
|
||||
case MT8196_AUDIO_APLL2_EN_ON:
|
||||
return AUDIO_ENGEN_CON0;
|
||||
case MT8196_CG_AUDIO_HOPPING_CK:
|
||||
case MT8196_CG_AUDIO_F26M_CK:
|
||||
case MT8196_CG_APLL1_CK:
|
||||
case MT8196_CG_APLL2_CK:
|
||||
case MT8196_PDN_APLL_TUNER2:
|
||||
case MT8196_PDN_APLL_TUNER1:
|
||||
return AUDIO_TOP_CON4;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int get_top_cg_mask(unsigned int cg_type)
|
||||
{
|
||||
switch (cg_type) {
|
||||
case MT8196_AUDIO_26M_EN_ON:
|
||||
return AUDIO_26M_EN_ON_MASK_SFT;
|
||||
case MT8196_AUDIO_F3P25M_EN_ON:
|
||||
return AUDIO_F3P25M_EN_ON_MASK_SFT;
|
||||
case MT8196_AUDIO_APLL1_EN_ON:
|
||||
return AUDIO_APLL1_EN_ON_MASK_SFT;
|
||||
case MT8196_AUDIO_APLL2_EN_ON:
|
||||
return AUDIO_APLL2_EN_ON_MASK_SFT;
|
||||
case MT8196_CG_AUDIO_HOPPING_CK:
|
||||
return CG_AUDIO_HOPPING_CK_MASK_SFT;
|
||||
case MT8196_CG_AUDIO_F26M_CK:
|
||||
return CG_AUDIO_F26M_CK_MASK_SFT;
|
||||
case MT8196_CG_APLL1_CK:
|
||||
return CG_APLL1_CK_MASK_SFT;
|
||||
case MT8196_CG_APLL2_CK:
|
||||
return CG_APLL2_CK_MASK_SFT;
|
||||
case MT8196_PDN_APLL_TUNER2:
|
||||
return PDN_APLL_TUNER2_MASK_SFT;
|
||||
case MT8196_PDN_APLL_TUNER1:
|
||||
return PDN_APLL_TUNER1_MASK_SFT;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int get_top_cg_on_val(unsigned int cg_type)
|
||||
{
|
||||
switch (cg_type) {
|
||||
case MT8196_AUDIO_26M_EN_ON:
|
||||
case MT8196_AUDIO_F3P25M_EN_ON:
|
||||
case MT8196_AUDIO_APLL1_EN_ON:
|
||||
case MT8196_AUDIO_APLL2_EN_ON:
|
||||
return get_top_cg_mask(cg_type);
|
||||
case MT8196_CG_AUDIO_HOPPING_CK:
|
||||
case MT8196_CG_AUDIO_F26M_CK:
|
||||
case MT8196_CG_APLL1_CK:
|
||||
case MT8196_CG_APLL2_CK:
|
||||
case MT8196_PDN_APLL_TUNER2:
|
||||
case MT8196_PDN_APLL_TUNER1:
|
||||
return 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int get_top_cg_off_val(unsigned int cg_type)
|
||||
{
|
||||
switch (cg_type) {
|
||||
case MT8196_AUDIO_26M_EN_ON:
|
||||
case MT8196_AUDIO_F3P25M_EN_ON:
|
||||
case MT8196_AUDIO_APLL1_EN_ON:
|
||||
case MT8196_AUDIO_APLL2_EN_ON:
|
||||
return 0;
|
||||
case MT8196_CG_AUDIO_HOPPING_CK:
|
||||
case MT8196_CG_AUDIO_F26M_CK:
|
||||
case MT8196_CG_APLL1_CK:
|
||||
case MT8196_CG_APLL2_CK:
|
||||
case MT8196_PDN_APLL_TUNER2:
|
||||
case MT8196_PDN_APLL_TUNER1:
|
||||
return get_top_cg_mask(cg_type);
|
||||
default:
|
||||
return get_top_cg_mask(cg_type);
|
||||
}
|
||||
}
|
||||
|
||||
static int mt8196_afe_enable_top_cg(struct mtk_base_afe *afe, unsigned int cg_type)
|
||||
{
|
||||
int ret;
|
||||
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);
|
||||
|
||||
if (!afe->regmap) {
|
||||
dev_err(afe->dev, "afe regmap is null !!!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_dbg(afe->dev, "reg: 0x%x, mask: 0x%x, val: 0x%x\n", reg, mask, val);
|
||||
|
||||
ret = regmap_update_bits(afe->regmap, reg, mask, val);
|
||||
if (ret)
|
||||
dev_err(afe->dev, "regmap_update_bits failed: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mt8196_afe_disable_top_cg(struct mtk_base_afe *afe, unsigned int cg_type)
|
||||
{
|
||||
int ret;
|
||||
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);
|
||||
|
||||
if (!afe->regmap) {
|
||||
dev_err(afe->dev, "afe regmap is null !!!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_dbg(afe->dev, "reg: 0x%x, mask: 0x%x, val: 0x%x\n", reg, mask, val);
|
||||
|
||||
ret = regmap_update_bits(afe->regmap, reg, mask, val);
|
||||
if (ret)
|
||||
dev_err(afe->dev, "regmap_update_bits failed: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable)
|
||||
{
|
||||
struct mt8196_afe_private *afe_priv = afe->platform_priv;
|
||||
int apll_rate;
|
||||
int ret;
|
||||
|
||||
dev_dbg(afe->dev, "enable: %d\n", enable);
|
||||
|
||||
if (enable) {
|
||||
apll_rate = mt8196_get_apll_rate(afe, MT8196_APLL1);
|
||||
|
||||
/* 180.6336 / 4 = 45.1584MHz */
|
||||
ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG1]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG1],
|
||||
MT8196_AUD_ENG1_CLK);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H],
|
||||
apll_rate);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG1],
|
||||
MT8196_AFE_26M);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG1]);
|
||||
|
||||
ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H],
|
||||
MT8196_AFE_26M);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable)
|
||||
{
|
||||
struct mt8196_afe_private *afe_priv = afe->platform_priv;
|
||||
int apll_rate;
|
||||
int ret;
|
||||
|
||||
dev_dbg(afe->dev, "enable: %d\n", enable);
|
||||
|
||||
if (enable) {
|
||||
apll_rate = mt8196_get_apll_rate(afe, MT8196_APLL2);
|
||||
|
||||
/* 196.608 / 4 = 49.152MHz */
|
||||
ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG2]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG2],
|
||||
MT8196_AUD_ENG2_CLK);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H],
|
||||
apll_rate);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG2],
|
||||
MT8196_AFE_26M);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUD_ENG2]);
|
||||
|
||||
ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H],
|
||||
MT8196_AFE_26M);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mt8196_apll1_enable(struct mtk_base_afe *afe)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* setting for APLL */
|
||||
apll1_mux_setting(afe, true);
|
||||
|
||||
ret = mt8196_afe_enable_top_cg(afe, MT8196_CG_APLL1_CK);
|
||||
if (ret)
|
||||
goto err_clk_apll1;
|
||||
|
||||
ret = mt8196_afe_enable_top_cg(afe, MT8196_PDN_APLL_TUNER1);
|
||||
if (ret)
|
||||
goto err_clk_apll1_tuner;
|
||||
|
||||
/* sel 44.1kHz:1, apll_div:7, upper bound:3 */
|
||||
regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG,
|
||||
XTAL_EN_128FS_SEL_MASK_SFT | APLL_DIV_MASK_SFT | UPPER_BOUND_MASK_SFT,
|
||||
(0x1 << XTAL_EN_128FS_SEL_SFT) | (7 << APLL_DIV_SFT) |
|
||||
(3 << UPPER_BOUND_SFT));
|
||||
|
||||
/* apll1 freq tuner enable */
|
||||
regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG,
|
||||
FREQ_TUNER_EN_MASK_SFT,
|
||||
0x1 << FREQ_TUNER_EN_SFT);
|
||||
|
||||
/* audio apll1 on */
|
||||
mt8196_afe_enable_top_cg(afe, MT8196_AUDIO_APLL1_EN_ON);
|
||||
|
||||
return 0;
|
||||
|
||||
err_clk_apll1_tuner:
|
||||
mt8196_afe_disable_top_cg(afe, MT8196_PDN_APLL_TUNER1);
|
||||
err_clk_apll1:
|
||||
mt8196_afe_disable_top_cg(afe, MT8196_CG_APLL1_CK);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void mt8196_apll1_disable(struct mtk_base_afe *afe)
|
||||
{
|
||||
/* audio apll1 off */
|
||||
mt8196_afe_disable_top_cg(afe, MT8196_AUDIO_APLL1_EN_ON);
|
||||
|
||||
/* apll1 freq tuner disable */
|
||||
regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG,
|
||||
FREQ_TUNER_EN_MASK_SFT,
|
||||
0x0);
|
||||
|
||||
mt8196_afe_disable_top_cg(afe, MT8196_PDN_APLL_TUNER1);
|
||||
mt8196_afe_disable_top_cg(afe, MT8196_CG_APLL1_CK);
|
||||
apll1_mux_setting(afe, false);
|
||||
}
|
||||
|
||||
int mt8196_apll2_enable(struct mtk_base_afe *afe)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* setting for APLL */
|
||||
apll2_mux_setting(afe, true);
|
||||
|
||||
ret = mt8196_afe_enable_top_cg(afe, MT8196_CG_APLL2_CK);
|
||||
if (ret)
|
||||
goto err_clk_apll2;
|
||||
|
||||
ret = mt8196_afe_enable_top_cg(afe, MT8196_PDN_APLL_TUNER2);
|
||||
if (ret)
|
||||
goto err_clk_apll2_tuner;
|
||||
|
||||
/* sel 48kHz: 2, apll_div: 7, upper bound: 3*/
|
||||
regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG,
|
||||
XTAL_EN_128FS_SEL_MASK_SFT | APLL_DIV_MASK_SFT | UPPER_BOUND_MASK_SFT,
|
||||
(0x2 << XTAL_EN_128FS_SEL_SFT) | (7 << APLL_DIV_SFT) |
|
||||
(3 << UPPER_BOUND_SFT));
|
||||
|
||||
/* apll2 freq tuner enable */
|
||||
regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG,
|
||||
FREQ_TUNER_EN_MASK_SFT,
|
||||
0x1 << FREQ_TUNER_EN_SFT);
|
||||
|
||||
/* audio apll2 on */
|
||||
mt8196_afe_enable_top_cg(afe, MT8196_AUDIO_APLL2_EN_ON);
|
||||
return 0;
|
||||
|
||||
err_clk_apll2_tuner:
|
||||
mt8196_afe_disable_top_cg(afe, MT8196_PDN_APLL_TUNER2);
|
||||
err_clk_apll2:
|
||||
mt8196_afe_disable_top_cg(afe, MT8196_CG_APLL2_CK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mt8196_apll2_disable(struct mtk_base_afe *afe)
|
||||
{
|
||||
/* audio apll2 off */
|
||||
mt8196_afe_disable_top_cg(afe, MT8196_AUDIO_APLL2_EN_ON);
|
||||
|
||||
/* apll2 freq tuner disable */
|
||||
regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG,
|
||||
FREQ_TUNER_EN_MASK_SFT,
|
||||
0x0);
|
||||
|
||||
mt8196_afe_disable_top_cg(afe, MT8196_PDN_APLL_TUNER2);
|
||||
mt8196_afe_disable_top_cg(afe, MT8196_CG_APLL2_CK);
|
||||
apll2_mux_setting(afe, false);
|
||||
}
|
||||
|
||||
int mt8196_get_apll_rate(struct mtk_base_afe *afe, int apll)
|
||||
{
|
||||
struct mt8196_afe_private *afe_priv = afe->platform_priv;
|
||||
int clk_id = 0;
|
||||
|
||||
if (apll < MT8196_APLL1 || apll > MT8196_APLL2) {
|
||||
dev_warn(afe->dev, "invalid clk id %d\n", apll);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (apll == MT8196_APLL1)
|
||||
clk_id = MT8196_CLK_TOP_APLL1_CK;
|
||||
else
|
||||
clk_id = MT8196_CLK_TOP_APLL2_CK;
|
||||
|
||||
return clk_get_rate(afe_priv->clk[clk_id]);
|
||||
}
|
||||
|
||||
/* 48K: select APLL2; 44.1k: select APLL1 */
|
||||
int mt8196_get_apll_by_rate(struct mtk_base_afe *afe, int rate)
|
||||
{
|
||||
return (rate % 8000) ? MT8196_APLL1 : MT8196_APLL2;
|
||||
}
|
||||
|
||||
int mt8196_get_apll_by_name(struct mtk_base_afe *afe, const char *name)
|
||||
{
|
||||
if (strcmp(name, APLL1_W_NAME) == 0)
|
||||
return MT8196_APLL1;
|
||||
|
||||
return MT8196_APLL2;
|
||||
}
|
||||
|
||||
static const int mck_div[MT8196_MCK_NUM] = {
|
||||
[MT8196_I2SIN0_MCK] = MT8196_CLK_TOP_APLL12_DIV_I2SIN0,
|
||||
[MT8196_I2SIN1_MCK] = MT8196_CLK_TOP_APLL12_DIV_I2SIN1,
|
||||
[MT8196_FMI2S_MCK] = MT8196_CLK_TOP_APLL12_DIV_FMI2S,
|
||||
[MT8196_TDMOUT_MCK] = MT8196_CLK_TOP_APLL12_DIV_TDMOUT_M,
|
||||
[MT8196_TDMOUT_BCK] = MT8196_CLK_TOP_APLL12_DIV_TDMOUT_B,
|
||||
};
|
||||
|
||||
int mt8196_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate)
|
||||
{
|
||||
struct mt8196_afe_private *afe_priv = afe->platform_priv;
|
||||
int div_clk_id;
|
||||
int ret;
|
||||
|
||||
dev_dbg(afe->dev, "mck_id: %d, rate: %d\n", mck_id, rate);
|
||||
|
||||
if (mck_id >= MT8196_MCK_NUM || mck_id < 0)
|
||||
return -EINVAL;
|
||||
|
||||
div_clk_id = mck_div[mck_id];
|
||||
|
||||
/* enable div, set rate */
|
||||
if (div_clk_id < 0) {
|
||||
dev_err(afe->dev, "invalid div_clk_id %d\n", div_clk_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (div_clk_id == MT8196_CLK_TOP_APLL12_DIV_TDMOUT_B)
|
||||
rate *= 16;
|
||||
|
||||
ret = mt8196_afe_enable_clk(afe, afe_priv->clk[div_clk_id]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[div_clk_id], rate);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mt8196_mck_disable(struct mtk_base_afe *afe, int mck_id)
|
||||
{
|
||||
struct mt8196_afe_private *afe_priv = afe->platform_priv;
|
||||
int div_clk_id;
|
||||
int ret;
|
||||
|
||||
dev_dbg(afe->dev, "mck_id: %d.\n", mck_id);
|
||||
|
||||
if (mck_id < 0) {
|
||||
dev_err(afe->dev, "mck_id = %d < 0\n", mck_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
div_clk_id = mck_div[mck_id];
|
||||
|
||||
if (div_clk_id < 0) {
|
||||
dev_err(afe->dev, "div_clk_id = %d < 0\n",
|
||||
div_clk_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[div_clk_id], MT8196_AFE_26M);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mt8196_afe_disable_clk(afe, afe_priv->clk[div_clk_id]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mt8196_afe_enable_reg_rw_clk(struct mtk_base_afe *afe)
|
||||
{
|
||||
struct mt8196_afe_private *afe_priv = afe->platform_priv;
|
||||
int ret;
|
||||
|
||||
/* bus clock for AFE external access, like DRAM */
|
||||
mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_ADSP_SEL]);
|
||||
|
||||
/* bus clock for AFE internal access, like AFE SRAM */
|
||||
mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIOINTBUS]);
|
||||
ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIOINTBUS],
|
||||
MT8196_AFE_26M);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* enable audio h clock */
|
||||
mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
|
||||
ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H],
|
||||
MT8196_AFE_26M);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* AFE hw clock */
|
||||
/* IPM2.0: USE HOPPING & 26M */
|
||||
/* set in the regmap_register_patch */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mt8196_afe_disable_reg_rw_clk(struct mtk_base_afe *afe)
|
||||
{
|
||||
struct mt8196_afe_private *afe_priv = afe->platform_priv;
|
||||
|
||||
/* IPM2.0: Use HOPPING & 26M */
|
||||
/* set in the regmap_register_patch */
|
||||
|
||||
mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
|
||||
mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIOINTBUS]);
|
||||
mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_ADSP_SEL]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mt8196_afe_enable_main_clock(struct mtk_base_afe *afe)
|
||||
{
|
||||
mt8196_afe_enable_top_cg(afe, MT8196_AUDIO_26M_EN_ON);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mt8196_afe_disable_main_clock(struct mtk_base_afe *afe)
|
||||
{
|
||||
mt8196_afe_disable_top_cg(afe, MT8196_AUDIO_26M_EN_ON);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mt8196_init_clock(struct mtk_base_afe *afe)
|
||||
{
|
||||
struct mt8196_afe_private *afe_priv = afe->platform_priv;
|
||||
int i;
|
||||
|
||||
afe_priv->clk = devm_kcalloc(afe->dev, MT8196_CLK_NUM, sizeof(*afe_priv->clk),
|
||||
GFP_KERNEL);
|
||||
if (!afe_priv->clk)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < MT8196_CLK_NUM; i++) {
|
||||
afe_priv->clk[i] = devm_clk_get(afe->dev, aud_clks[i]);
|
||||
if (IS_ERR(afe_priv->clk[i])) {
|
||||
dev_err(afe->dev, "devm_clk_get %s fail\n", aud_clks[i]);
|
||||
return PTR_ERR(afe_priv->clk[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
64
sound/soc/mediatek/mt8196/mt8196-afe-clk.h
Normal file
64
sound/soc/mediatek/mt8196/mt8196-afe-clk.h
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* mt8196-afe-clk.h -- Mediatek MT8196 AFE Clock Control definitions
|
||||
*
|
||||
* Copyright (c) 2025 MediaTek Inc.
|
||||
* Author: Darren Ye <darren.ye@mediatek.com>
|
||||
*/
|
||||
|
||||
#ifndef _MT8196_AFE_CLOCK_CTRL_H_
|
||||
#define _MT8196_AFE_CLOCK_CTRL_H_
|
||||
|
||||
#define MT8196_AFE_26M 26000000
|
||||
#define MT8196_AUD_ENG1_CLK 45158400
|
||||
#define MT8196_AUD_ENG2_CLK 49152000
|
||||
|
||||
/* APLL */
|
||||
#define APLL1_W_NAME "APLL1"
|
||||
#define APLL2_W_NAME "APLL2"
|
||||
|
||||
enum {
|
||||
MT8196_APLL1 = 0,
|
||||
MT8196_APLL2,
|
||||
};
|
||||
|
||||
enum {
|
||||
/* vlp clk */
|
||||
MT8196_CLK_VLP_MUX_AUDIOINTBUS,
|
||||
MT8196_CLK_VLP_MUX_AUD_ENG1,
|
||||
MT8196_CLK_VLP_MUX_AUD_ENG2,
|
||||
MT8196_CLK_VLP_MUX_AUDIO_H,
|
||||
/* pll */
|
||||
MT8196_CLK_TOP_APLL1_CK,
|
||||
MT8196_CLK_TOP_APLL2_CK,
|
||||
/* divider */
|
||||
MT8196_CLK_TOP_APLL12_DIV_I2SIN0,
|
||||
MT8196_CLK_TOP_APLL12_DIV_I2SIN1,
|
||||
MT8196_CLK_TOP_APLL12_DIV_FMI2S,
|
||||
MT8196_CLK_TOP_APLL12_DIV_TDMOUT_M,
|
||||
MT8196_CLK_TOP_APLL12_DIV_TDMOUT_B,
|
||||
/* mux */
|
||||
MT8196_CLK_TOP_ADSP_SEL,
|
||||
MT8196_CLK_NUM,
|
||||
};
|
||||
|
||||
struct mtk_base_afe;
|
||||
|
||||
int mt8196_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate);
|
||||
int mt8196_mck_disable(struct mtk_base_afe *afe, int mck_id);
|
||||
int mt8196_get_apll_rate(struct mtk_base_afe *afe, int apll);
|
||||
int mt8196_get_apll_by_rate(struct mtk_base_afe *afe, int rate);
|
||||
int mt8196_get_apll_by_name(struct mtk_base_afe *afe, const char *name);
|
||||
int mt8196_init_clock(struct mtk_base_afe *afe);
|
||||
int mt8196_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk);
|
||||
void mt8196_afe_disable_clk(struct mtk_base_afe *afe, struct clk *clk);
|
||||
int mt8196_apll1_enable(struct mtk_base_afe *afe);
|
||||
void mt8196_apll1_disable(struct mtk_base_afe *afe);
|
||||
int mt8196_apll2_enable(struct mtk_base_afe *afe);
|
||||
void mt8196_apll2_disable(struct mtk_base_afe *afe);
|
||||
int mt8196_afe_enable_main_clock(struct mtk_base_afe *afe);
|
||||
int mt8196_afe_disable_main_clock(struct mtk_base_afe *afe);
|
||||
int mt8196_afe_enable_reg_rw_clk(struct mtk_base_afe *afe);
|
||||
int mt8196_afe_disable_reg_rw_clk(struct mtk_base_afe *afe);
|
||||
|
||||
#endif
|
||||
205
sound/soc/mediatek/mt8196/mt8196-afe-common.h
Normal file
205
sound/soc/mediatek/mt8196/mt8196-afe-common.h
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* mt8196-afe-common.h -- Mediatek 8196 audio driver definitions
|
||||
*
|
||||
* Copyright (c) 2025 MediaTek Inc.
|
||||
* Author: Darren Ye <darren.ye@mediatek.com>
|
||||
*/
|
||||
|
||||
#ifndef _MT_8196_AFE_COMMON_H_
|
||||
#define _MT_8196_AFE_COMMON_H_
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "mt8196-reg.h"
|
||||
#include "../common/mtk-base-afe.h"
|
||||
|
||||
/* HW IPM 2.0 */
|
||||
enum {
|
||||
MTK_AFE_IPM2P0_RATE_8K = 0x0,
|
||||
MTK_AFE_IPM2P0_RATE_11K = 0x1,
|
||||
MTK_AFE_IPM2P0_RATE_12K = 0x2,
|
||||
MTK_AFE_IPM2P0_RATE_16K = 0x4,
|
||||
MTK_AFE_IPM2P0_RATE_22K = 0x5,
|
||||
MTK_AFE_IPM2P0_RATE_24K = 0x6,
|
||||
MTK_AFE_IPM2P0_RATE_32K = 0x8,
|
||||
MTK_AFE_IPM2P0_RATE_44K = 0x9,
|
||||
MTK_AFE_IPM2P0_RATE_48K = 0xa,
|
||||
MTK_AFE_IPM2P0_RATE_88K = 0xd,
|
||||
MTK_AFE_IPM2P0_RATE_96K = 0xe,
|
||||
MTK_AFE_IPM2P0_RATE_176K = 0x11,
|
||||
MTK_AFE_IPM2P0_RATE_192K = 0x12,
|
||||
MTK_AFE_IPM2P0_RATE_352K = 0x15,
|
||||
MTK_AFE_IPM2P0_RATE_384K = 0x16,
|
||||
};
|
||||
|
||||
enum {
|
||||
MTKAIF_PROTOCOL_1,
|
||||
MTKAIF_PROTOCOL_2,
|
||||
MTKAIF_PROTOCOL_2_CLK_P2,
|
||||
};
|
||||
|
||||
enum {
|
||||
MT8196_MEMIF_DL0,
|
||||
MT8196_MEMIF_DL1,
|
||||
MT8196_MEMIF_DL2,
|
||||
MT8196_MEMIF_DL3,
|
||||
MT8196_MEMIF_DL4,
|
||||
MT8196_MEMIF_DL5,
|
||||
MT8196_MEMIF_DL6,
|
||||
MT8196_MEMIF_DL7,
|
||||
MT8196_MEMIF_DL8,
|
||||
MT8196_MEMIF_DL23,
|
||||
MT8196_MEMIF_DL24,
|
||||
MT8196_MEMIF_DL25,
|
||||
MT8196_MEMIF_DL26,
|
||||
MT8196_MEMIF_DL_4CH,
|
||||
MT8196_MEMIF_DL_24CH,
|
||||
MT8196_MEMIF_VUL0,
|
||||
MT8196_MEMIF_VUL1,
|
||||
MT8196_MEMIF_VUL2,
|
||||
MT8196_MEMIF_VUL3,
|
||||
MT8196_MEMIF_VUL4,
|
||||
MT8196_MEMIF_VUL5,
|
||||
MT8196_MEMIF_VUL6,
|
||||
MT8196_MEMIF_VUL7,
|
||||
MT8196_MEMIF_VUL8,
|
||||
MT8196_MEMIF_VUL9,
|
||||
MT8196_MEMIF_VUL10,
|
||||
MT8196_MEMIF_VUL24,
|
||||
MT8196_MEMIF_VUL25,
|
||||
MT8196_MEMIF_VUL26,
|
||||
MT8196_MEMIF_VUL_CM0,
|
||||
MT8196_MEMIF_VUL_CM1,
|
||||
MT8196_MEMIF_VUL_CM2,
|
||||
MT8196_MEMIF_ETDM_IN0,
|
||||
MT8196_MEMIF_ETDM_IN1,
|
||||
MT8196_MEMIF_ETDM_IN2,
|
||||
MT8196_MEMIF_ETDM_IN3,
|
||||
MT8196_MEMIF_ETDM_IN4,
|
||||
MT8196_MEMIF_ETDM_IN6,
|
||||
MT8196_MEMIF_HDMI,
|
||||
MT8196_MEMIF_NUM,
|
||||
MT8196_DAI_ADDA = MT8196_MEMIF_NUM,
|
||||
MT8196_DAI_ADDA_CH34,
|
||||
MT8196_DAI_ADDA_CH56,
|
||||
MT8196_DAI_AP_DMIC,
|
||||
MT8196_DAI_AP_DMIC_CH34,
|
||||
MT8196_DAI_AP_DMIC_MULTICH,
|
||||
MT8196_DAI_I2S_IN0,
|
||||
MT8196_DAI_I2S_IN1,
|
||||
MT8196_DAI_I2S_IN2,
|
||||
MT8196_DAI_I2S_IN3,
|
||||
MT8196_DAI_I2S_IN4,
|
||||
MT8196_DAI_I2S_IN6,
|
||||
MT8196_DAI_I2S_OUT0,
|
||||
MT8196_DAI_I2S_OUT1,
|
||||
MT8196_DAI_I2S_OUT2,
|
||||
MT8196_DAI_I2S_OUT3,
|
||||
MT8196_DAI_I2S_OUT4,
|
||||
MT8196_DAI_I2S_OUT6,
|
||||
MT8196_DAI_FM_I2S_MASTER,
|
||||
MT8196_DAI_TDM,
|
||||
MT8196_DAI_TDM_DPTX,
|
||||
MT8196_DAI_NUM,
|
||||
};
|
||||
|
||||
#define MT8196_DAI_I2S_MAX_NUM 13 //depends each platform's max i2s num
|
||||
|
||||
/* update irq ID (= enum) from AFE_IRQ_MCU_STATUS */
|
||||
enum {
|
||||
MT8196_IRQ_0,
|
||||
MT8196_IRQ_1,
|
||||
MT8196_IRQ_2,
|
||||
MT8196_IRQ_3,
|
||||
MT8196_IRQ_4,
|
||||
MT8196_IRQ_5,
|
||||
MT8196_IRQ_6,
|
||||
MT8196_IRQ_7,
|
||||
MT8196_IRQ_8,
|
||||
MT8196_IRQ_9,
|
||||
MT8196_IRQ_10,
|
||||
MT8196_IRQ_11,
|
||||
MT8196_IRQ_12,
|
||||
MT8196_IRQ_13,
|
||||
MT8196_IRQ_14,
|
||||
MT8196_IRQ_15,
|
||||
MT8196_IRQ_16,
|
||||
MT8196_IRQ_17,
|
||||
MT8196_IRQ_18,
|
||||
MT8196_IRQ_19,
|
||||
MT8196_IRQ_20,
|
||||
MT8196_IRQ_21,
|
||||
MT8196_IRQ_22,
|
||||
MT8196_IRQ_23,
|
||||
MT8196_IRQ_24,
|
||||
MT8196_IRQ_25,
|
||||
MT8196_IRQ_26,
|
||||
MT8196_IRQ_31, /* used only for TDM */
|
||||
MT8196_IRQ_NUM,
|
||||
};
|
||||
|
||||
/* update irq ID (= enum) from AFE_IRQ_MCU_STATUS */
|
||||
enum {
|
||||
MT8196_CUS_IRQ_TDM, /* used only for TDM */
|
||||
MT8196_CUS_IRQ_NUM,
|
||||
};
|
||||
|
||||
enum {
|
||||
/* AUDIO_ENGEN_CON0 */
|
||||
MT8196_AUDIO_26M_EN_ON,
|
||||
MT8196_AUDIO_F3P25M_EN_ON,
|
||||
MT8196_AUDIO_APLL1_EN_ON,
|
||||
MT8196_AUDIO_APLL2_EN_ON,
|
||||
MT8196_AUDIO_F26M_EN_RST,
|
||||
MT8196_MULTI_USER_RST,
|
||||
MT8196_MULTI_USER_BYPASS,
|
||||
/* AUDIO_TOP_CON4 */
|
||||
MT8196_CG_AUDIO_HOPPING_CK,
|
||||
MT8196_CG_AUDIO_F26M_CK,
|
||||
MT8196_CG_APLL1_CK,
|
||||
MT8196_CG_APLL2_CK,
|
||||
MT8196_PDN_APLL_TUNER2,
|
||||
MT8196_PDN_APLL_TUNER1,
|
||||
MT8196_AUDIO_CG_NUM,
|
||||
};
|
||||
|
||||
/* MCLK */
|
||||
enum {
|
||||
MT8196_I2SIN0_MCK,
|
||||
MT8196_I2SIN1_MCK,
|
||||
MT8196_FMI2S_MCK,
|
||||
MT8196_TDMOUT_MCK,
|
||||
MT8196_TDMOUT_BCK,
|
||||
MT8196_MCK_NUM,
|
||||
};
|
||||
|
||||
/* CM*/
|
||||
enum {
|
||||
CM0,
|
||||
CM1,
|
||||
CM2,
|
||||
CM_NUM,
|
||||
};
|
||||
|
||||
struct clk;
|
||||
struct mtk_base_afe;
|
||||
|
||||
struct mt8196_afe_private {
|
||||
struct clk **clk;
|
||||
/* dai */
|
||||
void *dai_priv[MT8196_DAI_NUM];
|
||||
/* mck */
|
||||
int mck_rate[MT8196_MCK_NUM];
|
||||
/* channel merge */
|
||||
u32 cm_rate[CM_NUM];
|
||||
u32 cm_channels;
|
||||
};
|
||||
|
||||
int mt8196_dai_adda_register(struct mtk_base_afe *afe);
|
||||
int mt8196_dai_i2s_register(struct mtk_base_afe *afe);
|
||||
int mt8196_dai_tdm_register(struct mtk_base_afe *afe);
|
||||
int mt8196_dai_set_priv(struct mtk_base_afe *afe, int id,
|
||||
int priv_size, const void *priv_data);
|
||||
|
||||
#endif
|
||||
2503
sound/soc/mediatek/mt8196/mt8196-afe-pcm.c
Normal file
2503
sound/soc/mediatek/mt8196/mt8196-afe-pcm.c
Normal file
File diff suppressed because it is too large
Load Diff
845
sound/soc/mediatek/mt8196/mt8196-dai-adda.c
Normal file
845
sound/soc/mediatek/mt8196/mt8196-dai-adda.c
Normal file
|
|
@ -0,0 +1,845 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* MediaTek ALSA SoC Audio DAI ADDA Control
|
||||
*
|
||||
* Copyright (c) 2025 MediaTek Inc.
|
||||
* Author: Darren Ye <darren.ye@mediatek.com>
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "mt8196-afe-clk.h"
|
||||
#include "mt8196-afe-common.h"
|
||||
#include "mt8196-interconnection.h"
|
||||
|
||||
enum {
|
||||
UL_IIR_SW,
|
||||
UL_IIR_5HZ,
|
||||
UL_IIR_10HZ,
|
||||
UL_IIR_25HZ,
|
||||
UL_IIR_50HZ,
|
||||
UL_IIR_75HZ,
|
||||
};
|
||||
|
||||
enum {
|
||||
MTK_AFE_ADDA_UL_RATE_8K,
|
||||
MTK_AFE_ADDA_UL_RATE_16K,
|
||||
MTK_AFE_ADDA_UL_RATE_32K,
|
||||
MTK_AFE_ADDA_UL_RATE_48K,
|
||||
MTK_AFE_ADDA_UL_RATE_96K,
|
||||
MTK_AFE_ADDA_UL_RATE_192K,
|
||||
MTK_AFE_ADDA_UL_RATE_48K_HD,
|
||||
};
|
||||
|
||||
enum {
|
||||
MTK_AFE_MTKAIF_RATE_8K,
|
||||
MTK_AFE_MTKAIF_RATE_12K,
|
||||
MTK_AFE_MTKAIF_RATE_16K,
|
||||
MTK_AFE_MTKAIF_RATE_24K,
|
||||
MTK_AFE_MTKAIF_RATE_32K,
|
||||
MTK_AFE_MTKAIF_RATE_48K,
|
||||
MTK_AFE_MTKAIF_RATE_64K,
|
||||
MTK_AFE_MTKAIF_RATE_96K,
|
||||
MTK_AFE_MTKAIF_RATE_128K,
|
||||
MTK_AFE_MTKAIF_RATE_192K,
|
||||
MTK_AFE_MTKAIF_RATE_256K,
|
||||
MTK_AFE_MTKAIF_RATE_384K,
|
||||
MTK_AFE_MTKAIF_RATE_11K = 0x10,
|
||||
MTK_AFE_MTKAIF_RATE_22K,
|
||||
MTK_AFE_MTKAIF_RATE_44K,
|
||||
MTK_AFE_MTKAIF_RATE_88K,
|
||||
MTK_AFE_MTKAIF_RATE_176K,
|
||||
MTK_AFE_MTKAIF_RATE_352K,
|
||||
};
|
||||
|
||||
struct mtk_afe_adda_priv {
|
||||
int dl_rate;
|
||||
int ul_rate;
|
||||
};
|
||||
|
||||
static unsigned int adda_ul_rate_transform(struct mtk_base_afe *afe,
|
||||
unsigned int rate)
|
||||
{
|
||||
switch (rate) {
|
||||
case 8000:
|
||||
return MTK_AFE_ADDA_UL_RATE_8K;
|
||||
case 16000:
|
||||
return MTK_AFE_ADDA_UL_RATE_16K;
|
||||
case 32000:
|
||||
return MTK_AFE_ADDA_UL_RATE_32K;
|
||||
case 48000:
|
||||
return MTK_AFE_ADDA_UL_RATE_48K;
|
||||
case 96000:
|
||||
return MTK_AFE_ADDA_UL_RATE_96K;
|
||||
case 192000:
|
||||
return MTK_AFE_ADDA_UL_RATE_192K;
|
||||
default:
|
||||
dev_warn(afe->dev, "rate %d invalid, use 48kHz!!!\n", rate);
|
||||
return MTK_AFE_ADDA_UL_RATE_48K;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int mtkaif_rate_transform(struct mtk_base_afe *afe,
|
||||
unsigned int rate)
|
||||
{
|
||||
switch (rate) {
|
||||
case 8000:
|
||||
return MTK_AFE_MTKAIF_RATE_8K;
|
||||
case 11025:
|
||||
return MTK_AFE_MTKAIF_RATE_11K;
|
||||
case 12000:
|
||||
return MTK_AFE_MTKAIF_RATE_12K;
|
||||
case 16000:
|
||||
return MTK_AFE_MTKAIF_RATE_16K;
|
||||
case 22050:
|
||||
return MTK_AFE_MTKAIF_RATE_22K;
|
||||
case 24000:
|
||||
return MTK_AFE_MTKAIF_RATE_24K;
|
||||
case 32000:
|
||||
return MTK_AFE_MTKAIF_RATE_32K;
|
||||
case 44100:
|
||||
return MTK_AFE_MTKAIF_RATE_44K;
|
||||
case 48000:
|
||||
return MTK_AFE_MTKAIF_RATE_48K;
|
||||
case 96000:
|
||||
return MTK_AFE_MTKAIF_RATE_96K;
|
||||
case 192000:
|
||||
return MTK_AFE_MTKAIF_RATE_192K;
|
||||
default:
|
||||
dev_warn(afe->dev, "rate %d invalid, use 48kHz!!!\n", rate);
|
||||
return MTK_AFE_MTKAIF_RATE_48K;
|
||||
}
|
||||
}
|
||||
|
||||
enum {
|
||||
SUPPLY_SEQ_ADDA_AFE_ON,
|
||||
SUPPLY_SEQ_ADDA_FIFO,
|
||||
SUPPLY_SEQ_ADDA_AP_DMIC,
|
||||
SUPPLY_SEQ_ADDA_UL_ON,
|
||||
};
|
||||
|
||||
static int mtk_adda_ul_src_set_dmic_phase_sync(struct mtk_base_afe *afe)
|
||||
{
|
||||
dev_dbg(afe->dev, "set dmic phase sync\n");
|
||||
// ul0~1
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1,
|
||||
UL0_PHASE_SYNC_HCLK_SET_MASK_SFT,
|
||||
0x1 << UL0_PHASE_SYNC_HCLK_SET_SFT);
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1,
|
||||
UL0_PHASE_SYNC_FCLK_SET_MASK_SFT,
|
||||
0x1 << UL0_PHASE_SYNC_FCLK_SET_SFT);
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1,
|
||||
UL1_PHASE_SYNC_HCLK_SET_MASK_SFT,
|
||||
0x1 << UL1_PHASE_SYNC_HCLK_SET_SFT);
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1,
|
||||
UL1_PHASE_SYNC_FCLK_SET_MASK_SFT,
|
||||
0x1 << UL1_PHASE_SYNC_FCLK_SET_SFT);
|
||||
// dmic 0
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1,
|
||||
DMIC0_PHASE_SYNC_FCLK_SET_MASK_SFT,
|
||||
0x1 << DMIC0_PHASE_SYNC_FCLK_SET_SFT);
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1,
|
||||
DMIC0_PHASE_SYNC_HCLK_SET_MASK_SFT,
|
||||
0x1 << DMIC0_PHASE_SYNC_HCLK_SET_SFT);
|
||||
// dmic 1
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1,
|
||||
DMIC1_PHASE_SYNC_FCLK_SET_MASK_SFT,
|
||||
0x1 << DMIC1_PHASE_SYNC_FCLK_SET_SFT);
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1,
|
||||
DMIC1_PHASE_SYNC_HCLK_SET_MASK_SFT,
|
||||
0x1 << DMIC1_PHASE_SYNC_HCLK_SET_SFT);
|
||||
// ul0~1 phase sync clock
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
|
||||
DMIC1_PHASE_HCLK_SEL_MASK_SFT,
|
||||
0x1 << DMIC1_PHASE_HCLK_SEL_SFT);
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
|
||||
DMIC1_PHASE_FCLK_SEL_MASK_SFT,
|
||||
0x1 << DMIC1_PHASE_FCLK_SEL_SFT);
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
|
||||
DMIC0_PHASE_HCLK_SEL_MASK_SFT,
|
||||
0x1 << DMIC0_PHASE_HCLK_SEL_SFT);
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
|
||||
DMIC0_PHASE_FCLK_SEL_MASK_SFT,
|
||||
0x1 << DMIC0_PHASE_FCLK_SEL_SFT);
|
||||
// dmic 0
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
|
||||
UL1_PHASE_HCLK_SEL_MASK_SFT,
|
||||
0x2 << UL1_PHASE_HCLK_SEL_SFT);
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
|
||||
UL1_PHASE_FCLK_SEL_MASK_SFT,
|
||||
0x2 << UL1_PHASE_FCLK_SEL_SFT);
|
||||
// dmic 1
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
|
||||
UL0_PHASE_HCLK_SEL_MASK_SFT,
|
||||
0x2 << UL0_PHASE_HCLK_SEL_SFT);
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
|
||||
UL0_PHASE_FCLK_SEL_MASK_SFT,
|
||||
0x2 << UL0_PHASE_FCLK_SEL_SFT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_adda_ul_src_set_dmic_phase_sync_clock(struct mtk_base_afe *afe)
|
||||
{
|
||||
dev_dbg(afe->dev, "dmic turn on phase sync clk\n");
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
|
||||
UL_PHASE_SYNC_HCLK_1_ON_MASK_SFT,
|
||||
0x1 << UL_PHASE_SYNC_HCLK_1_ON_SFT);
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
|
||||
UL_PHASE_SYNC_HCLK_0_ON_MASK_SFT,
|
||||
0x1 << UL_PHASE_SYNC_HCLK_0_ON_SFT);
|
||||
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
|
||||
UL_PHASE_SYNC_FCLK_1_ON_MASK_SFT,
|
||||
0x1 << UL_PHASE_SYNC_FCLK_1_ON_SFT);
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON0,
|
||||
UL_PHASE_SYNC_FCLK_0_ON_MASK_SFT,
|
||||
0x1 << UL_PHASE_SYNC_FCLK_0_ON_SFT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_adda_ul_src_enable_dmic(struct mtk_base_afe *afe, int id)
|
||||
{
|
||||
unsigned int reg_con0 = 0, reg_con1 = 0;
|
||||
|
||||
dev_dbg(afe->dev, "id: %d\n", id);
|
||||
|
||||
switch (id) {
|
||||
case MT8196_DAI_ADDA:
|
||||
case MT8196_DAI_AP_DMIC:
|
||||
reg_con0 = AFE_ADDA_UL0_SRC_CON0;
|
||||
reg_con1 = AFE_ADDA_UL0_SRC_CON1;
|
||||
break;
|
||||
case MT8196_DAI_ADDA_CH34:
|
||||
case MT8196_DAI_AP_DMIC_CH34:
|
||||
reg_con0 = AFE_ADDA_UL1_SRC_CON0;
|
||||
reg_con1 = AFE_ADDA_UL1_SRC_CON1;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (id) {
|
||||
case MT8196_DAI_AP_DMIC:
|
||||
dev_dbg(afe->dev, "clear mtkaifv4 ul ch1ch2 mux\n");
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
|
||||
MTKAIFV4_UL_CH1CH2_IN_EN_SEL_MASK_SFT,
|
||||
0x0 << MTKAIFV4_UL_CH1CH2_IN_EN_SEL_SFT);
|
||||
break;
|
||||
case MT8196_DAI_AP_DMIC_CH34:
|
||||
dev_dbg(afe->dev, "clear mtkaifv4 ul ch3ch4 mux\n");
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
|
||||
MTKAIFV4_UL_CH3CH4_IN_EN_SEL_MASK_SFT,
|
||||
0x0 << MTKAIFV4_UL_CH3CH4_IN_EN_SEL_SFT);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* choose Phase */
|
||||
regmap_update_bits(afe->regmap, reg_con0,
|
||||
UL_DMIC_PHASE_SEL_CH1_MASK_SFT,
|
||||
0x0 << UL_DMIC_PHASE_SEL_CH1_SFT);
|
||||
regmap_update_bits(afe->regmap, reg_con0,
|
||||
UL_DMIC_PHASE_SEL_CH2_MASK_SFT,
|
||||
0x4 << UL_DMIC_PHASE_SEL_CH2_SFT);
|
||||
|
||||
/* dmic mode, 3.25M*/
|
||||
regmap_update_bits(afe->regmap, reg_con0,
|
||||
DIGMIC_3P25M_1P625M_SEL_CTL_MASK_SFT,
|
||||
0x0);
|
||||
regmap_update_bits(afe->regmap, reg_con0,
|
||||
DMIC_LOW_POWER_MODE_CTL_MASK_SFT,
|
||||
0x0);
|
||||
|
||||
/* turn on dmic, ch1, ch2 */
|
||||
regmap_update_bits(afe->regmap, reg_con0,
|
||||
UL_SDM_3_LEVEL_CTL_MASK_SFT,
|
||||
0x1 << UL_SDM_3_LEVEL_CTL_SFT);
|
||||
regmap_update_bits(afe->regmap, reg_con0,
|
||||
UL_MODE_3P25M_CH1_CTL_MASK_SFT,
|
||||
0x1 << UL_MODE_3P25M_CH1_CTL_SFT);
|
||||
regmap_update_bits(afe->regmap, reg_con0,
|
||||
UL_MODE_3P25M_CH2_CTL_MASK_SFT,
|
||||
0x1 << UL_MODE_3P25M_CH2_CTL_SFT);
|
||||
|
||||
/* ul gain: gain = 0x7fff/positive_gain = 0x0/gain_mode = 0x10 */
|
||||
regmap_update_bits(afe->regmap, reg_con1,
|
||||
ADDA_UL_GAIN_VALUE_MASK_SFT,
|
||||
0x7fff << ADDA_UL_GAIN_VALUE_SFT);
|
||||
regmap_update_bits(afe->regmap, reg_con1,
|
||||
ADDA_UL_POSTIVEGAIN_MASK_SFT,
|
||||
0x0 << ADDA_UL_POSTIVEGAIN_SFT);
|
||||
/* gain_mode = 0x10: Add 0.5 gain at CIC output */
|
||||
regmap_update_bits(afe->regmap, reg_con1,
|
||||
GAIN_MODE_MASK_SFT,
|
||||
0x02 << GAIN_MODE_SFT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_adda_sleep_on_pmd_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
|
||||
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
|
||||
|
||||
dev_dbg(afe->dev, "name %s, event 0x%x\n", w->name, event);
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
/* should delayed 1/fs(smallest is 8k) = 125us before afe off */
|
||||
usleep_range(120, 130);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ADDA UL MUX */
|
||||
#define ADDA_UL_MUX_MASK 0x3
|
||||
enum {
|
||||
ADDA_UL_MUX_MTKAIF = 0,
|
||||
ADDA_UL_MUX_AP_DMIC,
|
||||
ADDA_UL_MUX_AP_DMIC_MULTICH,
|
||||
};
|
||||
|
||||
static const char *const adda_ul_mux_map[] = {
|
||||
"MTKAIF", "AP_DMIC", "AP_DMIC_MULTI_CH",
|
||||
};
|
||||
|
||||
static int adda_ul_map_value[] = {
|
||||
ADDA_UL_MUX_MTKAIF,
|
||||
ADDA_UL_MUX_AP_DMIC,
|
||||
ADDA_UL_MUX_AP_DMIC_MULTICH,
|
||||
};
|
||||
|
||||
static SOC_VALUE_ENUM_SINGLE_DECL(adda_ul_mux_map_enum,
|
||||
SND_SOC_NOPM,
|
||||
0,
|
||||
ADDA_UL_MUX_MASK,
|
||||
adda_ul_mux_map,
|
||||
adda_ul_map_value);
|
||||
|
||||
static const struct snd_kcontrol_new adda_ul_mux_control =
|
||||
SOC_DAPM_ENUM("ADDA_UL_MUX Select", adda_ul_mux_map_enum);
|
||||
|
||||
static const struct snd_kcontrol_new adda_ch34_ul_mux_control =
|
||||
SOC_DAPM_ENUM("ADDA_CH34_UL_MUX Select", adda_ul_mux_map_enum);
|
||||
|
||||
static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = {
|
||||
/* inter-connections */
|
||||
SND_SOC_DAPM_SUPPLY_S("ADDA Enable", SUPPLY_SEQ_ADDA_AFE_ON,
|
||||
AUDIO_ENGEN_CON0, AUDIO_F3P25M_EN_ON_SFT, 0,
|
||||
NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY_S("ADDA Capture Enable", SUPPLY_SEQ_ADDA_UL_ON,
|
||||
AFE_ADDA_UL0_SRC_CON0,
|
||||
UL_SRC_ON_TMP_CTL_SFT, 0,
|
||||
mtk_adda_sleep_on_pmd_event,
|
||||
SND_SOC_DAPM_POST_PMD),
|
||||
SND_SOC_DAPM_SUPPLY_S("ADDA CH34 Capture Enable", SUPPLY_SEQ_ADDA_UL_ON,
|
||||
AFE_ADDA_UL1_SRC_CON0,
|
||||
UL_SRC_ON_TMP_CTL_SFT, 0,
|
||||
mtk_adda_sleep_on_pmd_event,
|
||||
SND_SOC_DAPM_POST_PMD),
|
||||
SND_SOC_DAPM_SUPPLY_S("AP_DMIC_EN", SUPPLY_SEQ_ADDA_AP_DMIC,
|
||||
AFE_ADDA_UL0_SRC_CON0,
|
||||
UL_AP_DMIC_ON_SFT, 0,
|
||||
mtk_adda_sleep_on_pmd_event,
|
||||
SND_SOC_DAPM_POST_PMD),
|
||||
SND_SOC_DAPM_SUPPLY_S("AP_DMIC_CH34_EN", SUPPLY_SEQ_ADDA_AP_DMIC,
|
||||
AFE_ADDA_UL1_SRC_CON0,
|
||||
UL_AP_DMIC_ON_SFT, 0,
|
||||
mtk_adda_sleep_on_pmd_event,
|
||||
SND_SOC_DAPM_POST_PMD),
|
||||
SND_SOC_DAPM_SUPPLY_S("ADDA_FIFO", SUPPLY_SEQ_ADDA_FIFO,
|
||||
AFE_ADDA_UL0_SRC_CON1,
|
||||
FIFO_SOFT_RST_SFT, 1,
|
||||
NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY_S("ADDA_CH34_FIFO", SUPPLY_SEQ_ADDA_FIFO,
|
||||
AFE_ADDA_UL1_SRC_CON1,
|
||||
FIFO_SOFT_RST_SFT, 1,
|
||||
NULL, 0),
|
||||
SND_SOC_DAPM_MUX("ADDA_UL_Mux", SND_SOC_NOPM, 0, 0,
|
||||
&adda_ul_mux_control),
|
||||
SND_SOC_DAPM_MUX("ADDA_CH34_UL_Mux", SND_SOC_NOPM, 0, 0,
|
||||
&adda_ch34_ul_mux_control),
|
||||
SND_SOC_DAPM_INPUT("AP_DMIC_INPUT"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = {
|
||||
/* capture */
|
||||
{"ADDA_UL_Mux", "MTKAIF", "ADDA Capture"},
|
||||
{"ADDA_UL_Mux", "AP_DMIC", "AP DMIC Capture"},
|
||||
{"ADDA_UL_Mux", "AP_DMIC_MULTI_CH", "AP DMIC MULTICH Capture"},
|
||||
|
||||
{"ADDA_CH34_UL_Mux", "MTKAIF", "ADDA CH34 Capture"},
|
||||
{"ADDA_CH34_UL_Mux", "AP_DMIC", "AP DMIC CH34 Capture"},
|
||||
{"ADDA_CH34_UL_Mux", "AP_DMIC_MULTI_CH", "AP DMIC MULTICH Capture"},
|
||||
|
||||
{"AP DMIC Capture", NULL, "ADDA Enable"},
|
||||
{"AP DMIC Capture", NULL, "ADDA Capture Enable"},
|
||||
{"AP DMIC Capture", NULL, "ADDA_FIFO"},
|
||||
{"AP DMIC Capture", NULL, "AP_DMIC_EN"},
|
||||
|
||||
{"AP DMIC CH34 Capture", NULL, "ADDA Enable"},
|
||||
{"AP DMIC CH34 Capture", NULL, "ADDA CH34 Capture Enable"},
|
||||
{"AP DMIC CH34 Capture", NULL, "ADDA_CH34_FIFO"},
|
||||
{"AP DMIC CH34 Capture", NULL, "AP_DMIC_CH34_EN"},
|
||||
|
||||
{"AP DMIC MULTICH Capture", NULL, "ADDA Enable"},
|
||||
{"AP DMIC MULTICH Capture", NULL, "ADDA Capture Enable"},
|
||||
{"AP DMIC MULTICH Capture", NULL, "ADDA CH34 Capture Enable"},
|
||||
{"AP DMIC MULTICH Capture", NULL, "ADDA_FIFO"},
|
||||
{"AP DMIC MULTICH Capture", NULL, "ADDA_CH34_FIFO"},
|
||||
{"AP DMIC MULTICH Capture", NULL, "AP_DMIC_EN"},
|
||||
{"AP DMIC MULTICH Capture", NULL, "AP_DMIC_CH34_EN"},
|
||||
|
||||
{"AP DMIC Capture", NULL, "AP_DMIC_INPUT"},
|
||||
{"AP DMIC CH34 Capture", NULL, "AP_DMIC_INPUT"},
|
||||
{"AP DMIC MULTICH Capture", NULL, "AP_DMIC_INPUT"},
|
||||
};
|
||||
|
||||
/* dai ops */
|
||||
static int set_playback_hw_params(struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
|
||||
struct mt8196_afe_private *afe_priv = afe->platform_priv;
|
||||
unsigned int rate = params_rate(params);
|
||||
struct mtk_afe_adda_priv *adda_priv;
|
||||
unsigned int mtkaif_rate = 0;
|
||||
int id = dai->id;
|
||||
|
||||
adda_priv = afe_priv->dai_priv[id];
|
||||
if (!adda_priv)
|
||||
return -EINVAL;
|
||||
|
||||
adda_priv->dl_rate = rate;
|
||||
|
||||
/* get mtkaif dl rate */
|
||||
mtkaif_rate = mtkaif_rate_transform(afe, adda_priv->dl_rate);
|
||||
|
||||
if (id == MT8196_DAI_ADDA) {
|
||||
/* MTKAIF sample rate config */
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_TX_CFG0,
|
||||
MTKAIFV4_TXIF_INPUT_MODE_MASK_SFT,
|
||||
mtkaif_rate << MTKAIFV4_TXIF_INPUT_MODE_SFT);
|
||||
/* AFE_ADDA_MTKAIFV4_TX_CFG0 */
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_TX_CFG0,
|
||||
MTKAIFV4_TXIF_FOUR_CHANNEL_MASK_SFT,
|
||||
0x0 << MTKAIFV4_TXIF_FOUR_CHANNEL_SFT);
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_TX_CFG0,
|
||||
MTKAIFV4_ADDA_OUT_EN_SEL_MASK_SFT,
|
||||
0x1 << MTKAIFV4_ADDA_OUT_EN_SEL_SFT);
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_TX_CFG0,
|
||||
MTKAIFV4_ADDA6_OUT_EN_SEL_MASK_SFT,
|
||||
0x1 << MTKAIFV4_ADDA6_OUT_EN_SEL_SFT);
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_TX_CFG0,
|
||||
MTKAIFV4_TXIF_V4_MASK_SFT,
|
||||
0x1 << MTKAIFV4_TXIF_V4_SFT);
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_TX_CFG0,
|
||||
MTKAIFV4_TXIF_EN_SEL_MASK_SFT,
|
||||
0x0 << MTKAIFV4_TXIF_EN_SEL_SFT);
|
||||
/* clean predistortion */
|
||||
} else {
|
||||
/* MTKAIF sample rate config */
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_TX_CFG0,
|
||||
ADDA6_MTKAIFV4_TXIF_INPUT_MODE_MASK_SFT,
|
||||
mtkaif_rate << ADDA6_MTKAIFV4_TXIF_INPUT_MODE_SFT);
|
||||
/* AFE_ADDA6_MTKAIFV4_TX_CFG0 */
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_TX_CFG0,
|
||||
ADDA6_MTKAIFV4_TXIF_FOUR_CHANNEL_MASK_SFT,
|
||||
0x0 << ADDA6_MTKAIFV4_TXIF_FOUR_CHANNEL_SFT);
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_TX_CFG0,
|
||||
ADDA6_MTKAIFV4_TXIF_EN_SEL_MASK_SFT,
|
||||
0x1 << ADDA6_MTKAIFV4_TXIF_EN_SEL_SFT);
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
static int set_capture_hw_params(struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
|
||||
struct mt8196_afe_private *afe_priv = afe->platform_priv;
|
||||
unsigned int rate = params_rate(params);
|
||||
struct mtk_afe_adda_priv *adda_priv;
|
||||
unsigned int voice_mode = 0;
|
||||
unsigned int ul_src_con0 = 0;
|
||||
unsigned int mtkaif_rate = 0;
|
||||
int id = dai->id;
|
||||
|
||||
adda_priv = afe_priv->dai_priv[id];
|
||||
if (!adda_priv)
|
||||
return -EINVAL;
|
||||
|
||||
adda_priv->ul_rate = rate;
|
||||
|
||||
/* get mtkaif dl rate */
|
||||
mtkaif_rate = mtkaif_rate_transform(afe, adda_priv->ul_rate);
|
||||
|
||||
voice_mode = adda_ul_rate_transform(afe, rate);
|
||||
|
||||
ul_src_con0 |= (voice_mode << 17) & (0x7 << 17);
|
||||
|
||||
/* enable iir */
|
||||
ul_src_con0 |= (1 << UL_IIR_ON_TMP_CTL_SFT) &
|
||||
UL_IIR_ON_TMP_CTL_MASK_SFT;
|
||||
ul_src_con0 |= (UL_IIR_SW << UL_IIRMODE_CTL_SFT) &
|
||||
UL_IIRMODE_CTL_MASK_SFT;
|
||||
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
|
||||
MTKAIFV4_RXIF_INPUT_MODE_MASK_SFT,
|
||||
mtkaif_rate << MTKAIFV4_RXIF_INPUT_MODE_SFT);
|
||||
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_RX_CFG0,
|
||||
ADDA6_MTKAIFV4_RXIF_INPUT_MODE_MASK_SFT,
|
||||
mtkaif_rate << ADDA6_MTKAIFV4_RXIF_INPUT_MODE_SFT);
|
||||
|
||||
switch (id) {
|
||||
case MT8196_DAI_ADDA:
|
||||
case MT8196_DAI_AP_DMIC:
|
||||
case MT8196_DAI_AP_DMIC_MULTICH:
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
|
||||
MTKAIFV4_RXIF_INPUT_MODE_MASK_SFT,
|
||||
mtkaif_rate << MTKAIFV4_RXIF_INPUT_MODE_SFT);
|
||||
/* AFE_ADDA_MTKAIFV4_RX_CFG0 */
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
|
||||
MTKAIFV4_RXIF_FOUR_CHANNEL_MASK_SFT,
|
||||
0x1 << MTKAIFV4_RXIF_FOUR_CHANNEL_SFT);
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
|
||||
MTKAIFV4_RXIF_EN_SEL_MASK_SFT,
|
||||
0x0 << MTKAIFV4_RXIF_EN_SEL_SFT);
|
||||
/* [28] loopback mode
|
||||
* 0: loopback adda tx to adda rx
|
||||
* 1: loopback adda6 tx to adda rx
|
||||
*/
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
|
||||
MTKAIFV4_TXIF_EN_SEL_MASK_SFT,
|
||||
0x0 << MTKAIFV4_TXIF_EN_SEL_SFT);
|
||||
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
|
||||
MTKAIFV4_UL_CH1CH2_IN_EN_SEL_MASK_SFT,
|
||||
0x1 << MTKAIFV4_UL_CH1CH2_IN_EN_SEL_SFT);
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
|
||||
MTKAIFV4_UL_CH3CH4_IN_EN_SEL_MASK_SFT,
|
||||
0x1 << MTKAIFV4_UL_CH3CH4_IN_EN_SEL_SFT);
|
||||
|
||||
/* 35Hz @ 48k */
|
||||
regmap_write(afe->regmap,
|
||||
AFE_ADDA_UL1_IIR_COEF_02_01, 0x00000000);
|
||||
regmap_write(afe->regmap,
|
||||
AFE_ADDA_UL1_IIR_COEF_04_03, 0x00003FB8);
|
||||
regmap_write(afe->regmap,
|
||||
AFE_ADDA_UL1_IIR_COEF_06_05, 0x3FB80000);
|
||||
regmap_write(afe->regmap,
|
||||
AFE_ADDA_UL1_IIR_COEF_08_07, 0x3FB80000);
|
||||
regmap_write(afe->regmap,
|
||||
AFE_ADDA_UL1_IIR_COEF_10_09, 0x0000C048);
|
||||
|
||||
regmap_write(afe->regmap,
|
||||
AFE_ADDA_UL1_SRC_CON0, ul_src_con0);
|
||||
|
||||
/* mtkaif_rxif_data_mode = 0, amic */
|
||||
regmap_update_bits(afe->regmap,
|
||||
AFE_MTKAIF1_RX_CFG0,
|
||||
0x1 << 0,
|
||||
0x0 << 0);
|
||||
|
||||
/* 35Hz @ 48k */
|
||||
regmap_write(afe->regmap,
|
||||
AFE_ADDA_UL0_IIR_COEF_02_01, 0x00000000);
|
||||
regmap_write(afe->regmap,
|
||||
AFE_ADDA_UL0_IIR_COEF_04_03, 0x00003FB8);
|
||||
regmap_write(afe->regmap,
|
||||
AFE_ADDA_UL0_IIR_COEF_06_05, 0x3FB80000);
|
||||
regmap_write(afe->regmap,
|
||||
AFE_ADDA_UL0_IIR_COEF_08_07, 0x3FB80000);
|
||||
regmap_write(afe->regmap,
|
||||
AFE_ADDA_UL0_IIR_COEF_10_09, 0x0000C048);
|
||||
|
||||
regmap_write(afe->regmap,
|
||||
AFE_ADDA_UL0_SRC_CON0, ul_src_con0);
|
||||
|
||||
/* mtkaif_rxif_data_mode = 0, amic */
|
||||
regmap_update_bits(afe->regmap,
|
||||
AFE_MTKAIF0_RX_CFG0,
|
||||
0x1 << 0,
|
||||
0x0 << 0);
|
||||
break;
|
||||
case MT8196_DAI_ADDA_CH34:
|
||||
case MT8196_DAI_AP_DMIC_CH34:
|
||||
/* AFE_ADDA_MTKAIFV4_RX_CFG0 */
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
|
||||
MTKAIFV4_RXIF_FOUR_CHANNEL_MASK_SFT,
|
||||
0x1 << MTKAIFV4_RXIF_FOUR_CHANNEL_SFT);
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
|
||||
MTKAIFV4_RXIF_EN_SEL_MASK_SFT,
|
||||
0x0 << MTKAIFV4_RXIF_EN_SEL_SFT);
|
||||
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
|
||||
MTKAIFV4_UL_CH1CH2_IN_EN_SEL_MASK_SFT,
|
||||
0x1 << MTKAIFV4_UL_CH1CH2_IN_EN_SEL_SFT);
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
|
||||
MTKAIFV4_UL_CH3CH4_IN_EN_SEL_MASK_SFT,
|
||||
0x1 << MTKAIFV4_UL_CH3CH4_IN_EN_SEL_SFT);
|
||||
|
||||
/* 35Hz @ 48k */
|
||||
regmap_write(afe->regmap,
|
||||
AFE_ADDA_UL1_IIR_COEF_02_01, 0x00000000);
|
||||
regmap_write(afe->regmap,
|
||||
AFE_ADDA_UL1_IIR_COEF_04_03, 0x00003FB8);
|
||||
regmap_write(afe->regmap,
|
||||
AFE_ADDA_UL1_IIR_COEF_06_05, 0x3FB80000);
|
||||
regmap_write(afe->regmap,
|
||||
AFE_ADDA_UL1_IIR_COEF_08_07, 0x3FB80000);
|
||||
regmap_write(afe->regmap,
|
||||
AFE_ADDA_UL1_IIR_COEF_10_09, 0x0000C048);
|
||||
|
||||
regmap_write(afe->regmap,
|
||||
AFE_ADDA_UL1_SRC_CON0, ul_src_con0);
|
||||
|
||||
/* mtkaif_rxif_data_mode = 0, amic */
|
||||
regmap_update_bits(afe->regmap,
|
||||
AFE_MTKAIF1_RX_CFG0,
|
||||
0x1 << 0,
|
||||
0x0 << 0);
|
||||
break;
|
||||
case MT8196_DAI_ADDA_CH56:
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_RX_CFG0,
|
||||
ADDA6_MTKAIFV4_RXIF_INPUT_MODE_MASK_SFT,
|
||||
mtkaif_rate << ADDA6_MTKAIFV4_RXIF_INPUT_MODE_SFT);
|
||||
/* AFE_ADDA6_MTKAIFV4_RX_CFG0 */
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_RX_CFG0,
|
||||
ADDA6_MTKAIFV4_RXIF_FOUR_CHANNEL_MASK_SFT,
|
||||
0x1 << ADDA6_MTKAIFV4_RXIF_FOUR_CHANNEL_SFT);
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIFV4_RX_CFG0,
|
||||
MTKAIFV4_UL_CH5CH6_IN_EN_SEL_MASK_SFT,
|
||||
0x1 << MTKAIFV4_UL_CH5CH6_IN_EN_SEL_SFT);
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIFV4_RX_CFG0,
|
||||
ADDA6_MTKAIFV4_RXIF_EN_SEL_MASK_SFT,
|
||||
0x1 << ADDA6_MTKAIFV4_RXIF_EN_SEL_SFT);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* ap dmic */
|
||||
switch (id) {
|
||||
case MT8196_DAI_AP_DMIC:
|
||||
case MT8196_DAI_AP_DMIC_CH34:
|
||||
mtk_adda_ul_src_enable_dmic(afe, id);
|
||||
break;
|
||||
case MT8196_DAI_AP_DMIC_MULTICH:
|
||||
regmap_update_bits(afe->regmap, AFE_ADDA_ULSRC_PHASE_CON1,
|
||||
DMIC_CLK_PHASE_SYNC_SET_MASK_SFT,
|
||||
0x1 << DMIC_CLK_PHASE_SYNC_SET_SFT);
|
||||
mtk_adda_ul_src_set_dmic_phase_sync(afe);
|
||||
mtk_adda_ul_src_enable_dmic(afe, MT8196_DAI_AP_DMIC);
|
||||
mtk_adda_ul_src_enable_dmic(afe, MT8196_DAI_AP_DMIC_CH34);
|
||||
mtk_adda_ul_src_set_dmic_phase_sync_clock(afe);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
|
||||
int id = dai->id;
|
||||
|
||||
if (id >= MT8196_DAI_NUM || id < 0)
|
||||
return -EINVAL;
|
||||
|
||||
dev_dbg(afe->dev, "id %d, stream %d, rate %d\n",
|
||||
id, substream->stream, params_rate(params));
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
return set_playback_hw_params(params, dai);
|
||||
else
|
||||
return set_capture_hw_params(params, dai);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops mtk_dai_adda_ops = {
|
||||
.hw_params = mtk_dai_adda_hw_params,
|
||||
};
|
||||
|
||||
/* dai driver */
|
||||
#define MTK_ADDA_PLAYBACK_RATES (SNDRV_PCM_RATE_8000_48000 |\
|
||||
SNDRV_PCM_RATE_96000 |\
|
||||
SNDRV_PCM_RATE_192000)
|
||||
|
||||
#define MTK_ADDA_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\
|
||||
SNDRV_PCM_RATE_16000 |\
|
||||
SNDRV_PCM_RATE_32000 |\
|
||||
SNDRV_PCM_RATE_48000 |\
|
||||
SNDRV_PCM_RATE_96000 |\
|
||||
SNDRV_PCM_RATE_192000)
|
||||
|
||||
#define MTK_ADDA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
|
||||
SNDRV_PCM_FMTBIT_S24_LE |\
|
||||
SNDRV_PCM_FMTBIT_S32_LE)
|
||||
|
||||
static struct snd_soc_dai_driver mtk_dai_adda_driver[] = {
|
||||
{
|
||||
.name = "ADDA",
|
||||
.id = MT8196_DAI_ADDA,
|
||||
.playback = {
|
||||
.stream_name = "ADDA Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = MTK_ADDA_PLAYBACK_RATES,
|
||||
.formats = MTK_ADDA_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "ADDA Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = MTK_ADDA_CAPTURE_RATES,
|
||||
.formats = MTK_ADDA_FORMATS,
|
||||
},
|
||||
.ops = &mtk_dai_adda_ops,
|
||||
},
|
||||
{
|
||||
.name = "ADDA_CH34",
|
||||
.id = MT8196_DAI_ADDA_CH34,
|
||||
.playback = {
|
||||
.stream_name = "ADDA CH34 Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = MTK_ADDA_PLAYBACK_RATES,
|
||||
.formats = MTK_ADDA_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "ADDA CH34 Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = MTK_ADDA_CAPTURE_RATES,
|
||||
.formats = MTK_ADDA_FORMATS,
|
||||
},
|
||||
.ops = &mtk_dai_adda_ops,
|
||||
},
|
||||
{
|
||||
.name = "ADDA_CH56",
|
||||
.id = MT8196_DAI_ADDA_CH56,
|
||||
.capture = {
|
||||
.stream_name = "ADDA CH56 Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = MTK_ADDA_CAPTURE_RATES,
|
||||
.formats = MTK_ADDA_FORMATS,
|
||||
},
|
||||
.ops = &mtk_dai_adda_ops,
|
||||
},
|
||||
{
|
||||
.name = "AP_DMIC",
|
||||
.id = MT8196_DAI_AP_DMIC,
|
||||
.capture = {
|
||||
.stream_name = "AP DMIC Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = MTK_ADDA_CAPTURE_RATES,
|
||||
.formats = MTK_ADDA_FORMATS,
|
||||
},
|
||||
.ops = &mtk_dai_adda_ops,
|
||||
},
|
||||
{
|
||||
.name = "AP_DMIC_CH34",
|
||||
.id = MT8196_DAI_AP_DMIC_CH34,
|
||||
.capture = {
|
||||
.stream_name = "AP DMIC CH34 Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = MTK_ADDA_CAPTURE_RATES,
|
||||
.formats = MTK_ADDA_FORMATS,
|
||||
},
|
||||
.ops = &mtk_dai_adda_ops,
|
||||
},
|
||||
/*
|
||||
* Multich DMIC combines two DMIC controllers for use together,
|
||||
* so AP_DMIC and Multich DMIC cannot be used at the same time.
|
||||
*/
|
||||
{
|
||||
.name = "AP_DMIC_MULTICH",
|
||||
.id = MT8196_DAI_AP_DMIC_MULTICH,
|
||||
.capture = {
|
||||
.stream_name = "AP DMIC MULTICH Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 4,
|
||||
.rates = MTK_ADDA_CAPTURE_RATES,
|
||||
.formats = MTK_ADDA_FORMATS,
|
||||
},
|
||||
.ops = &mtk_dai_adda_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static int init_adda_priv_data(struct mtk_base_afe *afe)
|
||||
{
|
||||
struct mt8196_afe_private *afe_priv = afe->platform_priv;
|
||||
struct mtk_afe_adda_priv *adda_priv;
|
||||
static const int adda_dai_list[] = {
|
||||
MT8196_DAI_ADDA,
|
||||
MT8196_DAI_ADDA_CH34,
|
||||
MT8196_DAI_ADDA_CH56,
|
||||
MT8196_DAI_AP_DMIC_MULTICH
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(adda_dai_list); i++) {
|
||||
adda_priv = devm_kzalloc(afe->dev,
|
||||
sizeof(struct mtk_afe_adda_priv),
|
||||
GFP_KERNEL);
|
||||
if (!adda_priv)
|
||||
return -ENOMEM;
|
||||
|
||||
afe_priv->dai_priv[adda_dai_list[i]] = adda_priv;
|
||||
}
|
||||
|
||||
/* ap dmic priv share with adda */
|
||||
afe_priv->dai_priv[MT8196_DAI_AP_DMIC] =
|
||||
afe_priv->dai_priv[MT8196_DAI_ADDA];
|
||||
afe_priv->dai_priv[MT8196_DAI_AP_DMIC_CH34] =
|
||||
afe_priv->dai_priv[MT8196_DAI_ADDA_CH34];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mt8196_dai_adda_register(struct mtk_base_afe *afe)
|
||||
{
|
||||
struct mtk_base_afe_dai *dai;
|
||||
int ret;
|
||||
|
||||
dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
|
||||
if (!dai)
|
||||
return -ENOMEM;
|
||||
|
||||
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);
|
||||
|
||||
ret = init_adda_priv_data(afe);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
list_add(&dai->list, &afe->sub_dais);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
2613
sound/soc/mediatek/mt8196/mt8196-dai-i2s.c
Normal file
2613
sound/soc/mediatek/mt8196/mt8196-dai-i2s.c
Normal file
File diff suppressed because it is too large
Load Diff
675
sound/soc/mediatek/mt8196/mt8196-dai-tdm.c
Normal file
675
sound/soc/mediatek/mt8196/mt8196-dai-tdm.c
Normal file
|
|
@ -0,0 +1,675 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* MediaTek ALSA SoC Audio DAI TDM Control
|
||||
*
|
||||
* Copyright (c) 2025 MediaTek Inc.
|
||||
* Author: Darren Ye <darren.ye@mediatek.com>
|
||||
*/
|
||||
|
||||
#include <linux/regmap.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include "mt8196-afe-clk.h"
|
||||
#include "mt8196-afe-common.h"
|
||||
#include "mt8196-interconnection.h"
|
||||
|
||||
struct mtk_afe_tdm_priv {
|
||||
int bck_id;
|
||||
int bck_rate;
|
||||
|
||||
int mclk_id;
|
||||
int mclk_multiple; /* according to sample rate */
|
||||
int mclk_rate;
|
||||
int mclk_apll;
|
||||
};
|
||||
|
||||
enum {
|
||||
TDM_WLEN_8_BIT,
|
||||
TDM_WLEN_16_BIT,
|
||||
TDM_WLEN_24_BIT,
|
||||
TDM_WLEN_32_BIT,
|
||||
};
|
||||
|
||||
enum {
|
||||
TDM_CHANNEL_BCK_16,
|
||||
TDM_CHANNEL_BCK_24,
|
||||
TDM_CHANNEL_BCK_32,
|
||||
};
|
||||
|
||||
enum {
|
||||
TDM_CHANNEL_NUM_2,
|
||||
TDM_CHANNEL_NUM_4,
|
||||
TDM_CHANNEL_NUM_8,
|
||||
};
|
||||
|
||||
enum {
|
||||
TDM_CH_START_O30_O31,
|
||||
TDM_CH_START_O32_O33,
|
||||
TDM_CH_START_O34_O35,
|
||||
TDM_CH_START_O36_O37,
|
||||
TDM_CH_ZERO,
|
||||
};
|
||||
|
||||
enum {
|
||||
DPTX_CHANNEL_2,
|
||||
DPTX_CHANNEL_8,
|
||||
};
|
||||
|
||||
enum {
|
||||
DPTX_WLEN_24_BIT,
|
||||
DPTX_WLEN_16_BIT,
|
||||
};
|
||||
|
||||
#define DPTX_CH_EN_MASK_2CH (0x3)
|
||||
#define DPTX_CH_EN_MASK_4CH (0xf)
|
||||
#define DPTX_CH_EN_MASK_6CH (0x3f)
|
||||
#define DPTX_CH_EN_MASK_8CH (0xff)
|
||||
|
||||
static unsigned int get_tdm_wlen(snd_pcm_format_t format)
|
||||
{
|
||||
return (snd_pcm_format_physical_width(format) / 8) - 1;
|
||||
}
|
||||
|
||||
static unsigned int get_tdm_channel_bck(snd_pcm_format_t format)
|
||||
{
|
||||
return snd_pcm_format_physical_width(format) <= 16 ?
|
||||
TDM_CHANNEL_BCK_16 : TDM_CHANNEL_BCK_32;
|
||||
}
|
||||
|
||||
static unsigned int get_tdm_lrck_width(snd_pcm_format_t format)
|
||||
{
|
||||
return snd_pcm_format_physical_width(format) - 1;
|
||||
}
|
||||
|
||||
static unsigned int get_tdm_ch(unsigned int ch)
|
||||
{
|
||||
switch (ch) {
|
||||
case 1:
|
||||
case 2:
|
||||
return TDM_CHANNEL_NUM_2;
|
||||
case 3:
|
||||
case 4:
|
||||
return TDM_CHANNEL_NUM_4;
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
default:
|
||||
return TDM_CHANNEL_NUM_8;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int get_dptx_ch_enable_mask(struct device *dev, unsigned int ch)
|
||||
{
|
||||
switch (ch) {
|
||||
case 1:
|
||||
case 2:
|
||||
return DPTX_CH_EN_MASK_2CH;
|
||||
case 3:
|
||||
case 4:
|
||||
return DPTX_CH_EN_MASK_4CH;
|
||||
case 5:
|
||||
case 6:
|
||||
return DPTX_CH_EN_MASK_6CH;
|
||||
case 7:
|
||||
case 8:
|
||||
return DPTX_CH_EN_MASK_8CH;
|
||||
default:
|
||||
dev_warn(dev, "invalid channel num, default use 2ch\n");
|
||||
return DPTX_CH_EN_MASK_2CH;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int get_dptx_ch(unsigned int ch)
|
||||
{
|
||||
if (ch == 2)
|
||||
return DPTX_CHANNEL_2;
|
||||
else
|
||||
return DPTX_CHANNEL_8;
|
||||
}
|
||||
|
||||
static unsigned int get_dptx_wlen(snd_pcm_format_t format)
|
||||
{
|
||||
return snd_pcm_format_physical_width(format) <= 16 ?
|
||||
DPTX_WLEN_16_BIT : DPTX_WLEN_24_BIT;
|
||||
}
|
||||
|
||||
/* interconnection */
|
||||
enum {
|
||||
HDMI_CONN_CH0,
|
||||
HDMI_CONN_CH1,
|
||||
HDMI_CONN_CH2,
|
||||
HDMI_CONN_CH3,
|
||||
HDMI_CONN_CH4,
|
||||
HDMI_CONN_CH5,
|
||||
HDMI_CONN_CH6,
|
||||
HDMI_CONN_CH7,
|
||||
};
|
||||
|
||||
static const char *const hdmi_conn_mux_map[] = {
|
||||
"CH0", "CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7",
|
||||
};
|
||||
|
||||
static int hdmi_conn_mux_map_value[] = {
|
||||
HDMI_CONN_CH0, HDMI_CONN_CH1, HDMI_CONN_CH2, HDMI_CONN_CH3,
|
||||
HDMI_CONN_CH4, HDMI_CONN_CH5, HDMI_CONN_CH6, HDMI_CONN_CH7,
|
||||
};
|
||||
|
||||
static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch0_mux_map_enum,
|
||||
AFE_HDMI_CONN0, HDMI_O_0_SFT, HDMI_O_0_MASK,
|
||||
hdmi_conn_mux_map, hdmi_conn_mux_map_value);
|
||||
|
||||
static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch1_mux_map_enum,
|
||||
AFE_HDMI_CONN0,
|
||||
HDMI_O_1_SFT,
|
||||
HDMI_O_1_MASK,
|
||||
hdmi_conn_mux_map,
|
||||
hdmi_conn_mux_map_value);
|
||||
|
||||
static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch2_mux_map_enum,
|
||||
AFE_HDMI_CONN0,
|
||||
HDMI_O_2_SFT,
|
||||
HDMI_O_2_MASK,
|
||||
hdmi_conn_mux_map,
|
||||
hdmi_conn_mux_map_value);
|
||||
|
||||
static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch3_mux_map_enum,
|
||||
AFE_HDMI_CONN0,
|
||||
HDMI_O_3_SFT,
|
||||
HDMI_O_3_MASK,
|
||||
hdmi_conn_mux_map,
|
||||
hdmi_conn_mux_map_value);
|
||||
|
||||
static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch4_mux_map_enum,
|
||||
AFE_HDMI_CONN0,
|
||||
HDMI_O_4_SFT,
|
||||
HDMI_O_4_MASK,
|
||||
hdmi_conn_mux_map,
|
||||
hdmi_conn_mux_map_value);
|
||||
|
||||
static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch5_mux_map_enum,
|
||||
AFE_HDMI_CONN0,
|
||||
HDMI_O_5_SFT,
|
||||
HDMI_O_5_MASK,
|
||||
hdmi_conn_mux_map,
|
||||
hdmi_conn_mux_map_value);
|
||||
|
||||
static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch6_mux_map_enum,
|
||||
AFE_HDMI_CONN0,
|
||||
HDMI_O_6_SFT,
|
||||
HDMI_O_6_MASK,
|
||||
hdmi_conn_mux_map,
|
||||
hdmi_conn_mux_map_value);
|
||||
|
||||
static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch7_mux_map_enum,
|
||||
AFE_HDMI_CONN0,
|
||||
HDMI_O_7_SFT,
|
||||
HDMI_O_7_MASK,
|
||||
hdmi_conn_mux_map,
|
||||
hdmi_conn_mux_map_value);
|
||||
|
||||
static const struct snd_kcontrol_new mtk_dai_tdm_controls[] = {
|
||||
SOC_ENUM("HDMI_CH0_MUX", hdmi_ch0_mux_map_enum),
|
||||
SOC_ENUM("HDMI_CH1_MUX", hdmi_ch1_mux_map_enum),
|
||||
SOC_ENUM("HDMI_CH2_MUX", hdmi_ch2_mux_map_enum),
|
||||
SOC_ENUM("HDMI_CH3_MUX", hdmi_ch3_mux_map_enum),
|
||||
SOC_ENUM("HDMI_CH4_MUX", hdmi_ch4_mux_map_enum),
|
||||
SOC_ENUM("HDMI_CH5_MUX", hdmi_ch5_mux_map_enum),
|
||||
SOC_ENUM("HDMI_CH6_MUX", hdmi_ch6_mux_map_enum),
|
||||
SOC_ENUM("HDMI_CH7_MUX", hdmi_ch7_mux_map_enum),
|
||||
};
|
||||
|
||||
static const char *const tdm_out_demux_texts[] = {
|
||||
"NONE", "TDMOUT", "DPTXOUT",
|
||||
};
|
||||
|
||||
static SOC_ENUM_SINGLE_DECL(tdm_out_demux_enum,
|
||||
SND_SOC_NOPM,
|
||||
0,
|
||||
tdm_out_demux_texts);
|
||||
static const struct snd_kcontrol_new tdm_out_demux_control =
|
||||
SOC_DAPM_ENUM("TDM DEMUX ROUTE", tdm_out_demux_enum);
|
||||
|
||||
enum {
|
||||
SUPPLY_SEQ_APLL,
|
||||
SUPPLY_SEQ_TDM_MCK_EN,
|
||||
SUPPLY_SEQ_TDM_BCK_EN,
|
||||
SUPPLY_SEQ_TDM_DPTX_MCK_EN,
|
||||
SUPPLY_SEQ_TDM_DPTX_BCK_EN,
|
||||
SUPPLY_SEQ_TDM_CG_EN,
|
||||
};
|
||||
|
||||
static int get_tdm_id_by_name(const char *name)
|
||||
{
|
||||
if (strstr(name, "DPTX"))
|
||||
return MT8196_DAI_TDM_DPTX;
|
||||
else
|
||||
return MT8196_DAI_TDM;
|
||||
}
|
||||
|
||||
static int mtk_tdm_bck_en_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol,
|
||||
int event)
|
||||
{
|
||||
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
|
||||
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
|
||||
struct mt8196_afe_private *afe_priv = afe->platform_priv;
|
||||
int dai_id = get_tdm_id_by_name(w->name);
|
||||
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
|
||||
|
||||
dev_dbg(cmpnt->dev, "name %s, event 0x%x, dai_id %d\n",
|
||||
w->name, event, dai_id);
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
mt8196_mck_enable(afe, tdm_priv->bck_id, tdm_priv->bck_rate);
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
mt8196_mck_disable(afe, tdm_priv->bck_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_tdm_mck_en_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol,
|
||||
int event)
|
||||
{
|
||||
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
|
||||
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
|
||||
struct mt8196_afe_private *afe_priv = afe->platform_priv;
|
||||
int dai_id = get_tdm_id_by_name(w->name);
|
||||
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
|
||||
|
||||
dev_dbg(cmpnt->dev, "name %s, event 0x%x, dai_id %d\n",
|
||||
w->name, event, dai_id);
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
mt8196_mck_enable(afe, tdm_priv->mclk_id, tdm_priv->mclk_rate);
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
tdm_priv->mclk_rate = 0;
|
||||
mt8196_mck_disable(afe, tdm_priv->mclk_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_widget mtk_dai_tdm_widgets[] = {
|
||||
SND_SOC_DAPM_DEMUX("TDM_DEMUX", SND_SOC_NOPM, 0, 0,
|
||||
&tdm_out_demux_control),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY_S("TDM_BCK", SUPPLY_SEQ_TDM_BCK_EN,
|
||||
SND_SOC_NOPM, 0, 0,
|
||||
mtk_tdm_bck_en_event,
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY_S("TDM_MCK", SUPPLY_SEQ_TDM_MCK_EN,
|
||||
SND_SOC_NOPM, 0, 0,
|
||||
mtk_tdm_mck_en_event,
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY_S("TDM_DPTX_BCK", SUPPLY_SEQ_TDM_DPTX_BCK_EN,
|
||||
SND_SOC_NOPM, 0, 0,
|
||||
mtk_tdm_bck_en_event,
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY_S("TDM_DPTX_MCK", SUPPLY_SEQ_TDM_DPTX_MCK_EN,
|
||||
SND_SOC_NOPM, 0, 0,
|
||||
mtk_tdm_mck_en_event,
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
|
||||
/* cg */
|
||||
SND_SOC_DAPM_SUPPLY_S("TDM_CG", SUPPLY_SEQ_TDM_CG_EN,
|
||||
AUDIO_TOP_CON2, PDN_TDM_OUT_SFT, 1,
|
||||
NULL, 0),
|
||||
};
|
||||
|
||||
static int mtk_afe_tdm_apll_connect(struct snd_soc_dapm_widget *source,
|
||||
struct snd_soc_dapm_widget *sink)
|
||||
{
|
||||
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(sink->dapm);
|
||||
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
|
||||
struct mt8196_afe_private *afe_priv = afe->platform_priv;
|
||||
int dai_id = get_tdm_id_by_name(sink->name);
|
||||
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
|
||||
int cur_apll;
|
||||
|
||||
/* which apll */
|
||||
cur_apll = mt8196_get_apll_by_name(afe, source->name);
|
||||
|
||||
return (tdm_priv->mclk_apll == cur_apll) ? 1 : 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_route mtk_dai_tdm_routes[] = {
|
||||
{"TDM_DEMUX", NULL, "HDMI"},
|
||||
|
||||
{"TDM", "TDMOUT", "TDM_DEMUX"},
|
||||
{"TDM", NULL, "TDM_BCK"},
|
||||
{"TDM", NULL, "TDM_CG"},
|
||||
|
||||
{"TDM_DPTX", "DPTXOUT", "TDM_DEMUX"},
|
||||
{"TDM_DPTX", NULL, "TDM_DPTX_BCK"},
|
||||
{"TDM_DPTX", NULL, "TDM_CG"},
|
||||
|
||||
{"TDM_BCK", NULL, "TDM_MCK"},
|
||||
{"TDM_DPTX_BCK", NULL, "TDM_DPTX_MCK"},
|
||||
{"TDM_MCK", NULL, APLL1_W_NAME, mtk_afe_tdm_apll_connect},
|
||||
{"TDM_MCK", NULL, APLL2_W_NAME, mtk_afe_tdm_apll_connect},
|
||||
{"TDM_DPTX_MCK", NULL, APLL1_W_NAME, mtk_afe_tdm_apll_connect},
|
||||
{"TDM_DPTX_MCK", NULL, APLL2_W_NAME, mtk_afe_tdm_apll_connect},
|
||||
};
|
||||
|
||||
/* dai ops */
|
||||
static int mtk_dai_tdm_cal_mclk(struct mtk_base_afe *afe,
|
||||
struct mtk_afe_tdm_priv *tdm_priv,
|
||||
int freq)
|
||||
{
|
||||
int apll;
|
||||
int apll_rate;
|
||||
|
||||
apll = mt8196_get_apll_by_rate(afe, freq);
|
||||
apll_rate = mt8196_get_apll_rate(afe, apll);
|
||||
|
||||
if (freq > apll_rate)
|
||||
return -EINVAL;
|
||||
|
||||
if (apll_rate % freq != 0)
|
||||
return -EINVAL;
|
||||
|
||||
tdm_priv->mclk_rate = freq;
|
||||
tdm_priv->mclk_apll = apll;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
|
||||
struct mt8196_afe_private *afe_priv = afe->platform_priv;
|
||||
int tdm_id = dai->id;
|
||||
struct mtk_afe_tdm_priv *tdm_priv;
|
||||
unsigned int rate = params_rate(params);
|
||||
unsigned int channels = params_channels(params);
|
||||
snd_pcm_format_t format = params_format(params);
|
||||
unsigned int tdm_con = 0;
|
||||
|
||||
if (tdm_id >= MT8196_DAI_NUM || tdm_id < 0)
|
||||
return -EINVAL;
|
||||
|
||||
tdm_priv = afe_priv->dai_priv[tdm_id];
|
||||
|
||||
if (!tdm_priv)
|
||||
return -EINVAL;
|
||||
|
||||
/* calculate mclk_rate, if not set explicitly */
|
||||
if (!tdm_priv->mclk_rate) {
|
||||
tdm_priv->mclk_rate = rate * tdm_priv->mclk_multiple;
|
||||
mtk_dai_tdm_cal_mclk(afe,
|
||||
tdm_priv,
|
||||
tdm_priv->mclk_rate);
|
||||
}
|
||||
|
||||
/* calculate bck */
|
||||
tdm_priv->bck_rate = rate *
|
||||
channels *
|
||||
snd_pcm_format_physical_width(format);
|
||||
|
||||
if (tdm_priv->bck_rate > tdm_priv->mclk_rate)
|
||||
return -EINVAL;
|
||||
|
||||
if (tdm_priv->mclk_rate % tdm_priv->bck_rate != 0)
|
||||
return -EINVAL;
|
||||
|
||||
dev_dbg(afe->dev, "id %d, rate %d, ch %d, fmt %d, mclk %d, bck %d\n",
|
||||
tdm_id, rate, channels, format, tdm_priv->mclk_rate, tdm_priv->bck_rate);
|
||||
|
||||
/* set tdm */
|
||||
tdm_con = 0 << BCK_INVERSE_SFT;
|
||||
tdm_con |= 0 << LRCK_INVERSE_SFT;
|
||||
tdm_con |= 0 << DELAY_DATA_SFT;
|
||||
tdm_con |= 1 << LEFT_ALIGN_SFT;
|
||||
tdm_con |= get_tdm_wlen(format) << WLEN_SFT;
|
||||
tdm_con |= get_tdm_ch(channels) << CHANNEL_NUM_SFT;
|
||||
tdm_con |= get_tdm_channel_bck(format) << CHANNEL_BCK_CYCLES_SFT;
|
||||
tdm_con |= get_tdm_lrck_width(format) << LRCK_TDM_WIDTH_SFT;
|
||||
regmap_write(afe->regmap, AFE_TDM_CON1, tdm_con);
|
||||
|
||||
/* set dptx */
|
||||
if (tdm_id == MT8196_DAI_TDM_DPTX) {
|
||||
regmap_update_bits(afe->regmap, AFE_DPTX_CON,
|
||||
DPTX_CHANNEL_ENABLE_MASK_SFT,
|
||||
get_dptx_ch_enable_mask(afe->dev, channels) <<
|
||||
DPTX_CHANNEL_ENABLE_SFT);
|
||||
regmap_update_bits(afe->regmap, AFE_DPTX_CON,
|
||||
DPTX_CHANNEL_NUMBER_MASK_SFT,
|
||||
get_dptx_ch(channels) <<
|
||||
DPTX_CHANNEL_NUMBER_SFT);
|
||||
regmap_update_bits(afe->regmap, AFE_DPTX_CON,
|
||||
DPTX_16BIT_MASK_SFT,
|
||||
get_dptx_wlen(format) << DPTX_16BIT_SFT);
|
||||
}
|
||||
switch (channels) {
|
||||
case 1:
|
||||
case 2:
|
||||
tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
|
||||
tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT1_SFT;
|
||||
tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT;
|
||||
tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
|
||||
tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT;
|
||||
tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT;
|
||||
tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
|
||||
tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT;
|
||||
tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT;
|
||||
tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;
|
||||
break;
|
||||
case 7:
|
||||
case 8:
|
||||
tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
|
||||
tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT;
|
||||
tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT;
|
||||
tdm_con |= TDM_CH_START_O36_O37 << ST_CH_PAIR_SOUT3_SFT;
|
||||
break;
|
||||
default:
|
||||
tdm_con = 0;
|
||||
}
|
||||
|
||||
regmap_write(afe->regmap, AFE_TDM_CON2, tdm_con);
|
||||
regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
|
||||
HDMI_CH_NUM_MASK_SFT,
|
||||
channels << HDMI_CH_NUM_SFT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_dai_tdm_trigger(struct snd_pcm_substream *substream,
|
||||
int cmd,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
|
||||
int tdm_id = dai->id;
|
||||
|
||||
dev_dbg(afe->dev, "cmd %d, tdm_id %d\n", cmd, tdm_id);
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
/* enable Out control */
|
||||
regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
|
||||
HDMI_OUT_ON_MASK_SFT,
|
||||
0x1 << HDMI_OUT_ON_SFT);
|
||||
|
||||
/* enable dptx */
|
||||
if (tdm_id == MT8196_DAI_TDM_DPTX) {
|
||||
regmap_update_bits(afe->regmap, AFE_DPTX_CON,
|
||||
DPTX_ON_MASK_SFT, 0x1 <<
|
||||
DPTX_ON_SFT);
|
||||
}
|
||||
|
||||
/* enable tdm */
|
||||
regmap_update_bits(afe->regmap, AFE_TDM_CON1,
|
||||
TDM_EN_MASK_SFT, 0x1 << TDM_EN_SFT);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
/* disable tdm */
|
||||
regmap_update_bits(afe->regmap, AFE_TDM_CON1,
|
||||
TDM_EN_MASK_SFT, 0);
|
||||
|
||||
/* disable dptx */
|
||||
if (tdm_id == MT8196_DAI_TDM_DPTX) {
|
||||
regmap_update_bits(afe->regmap, AFE_DPTX_CON,
|
||||
DPTX_ON_MASK_SFT, 0);
|
||||
}
|
||||
|
||||
/* disable Out control */
|
||||
regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
|
||||
HDMI_OUT_ON_MASK_SFT, 0);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_dai_tdm_set_sysclk(struct snd_soc_dai *dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
|
||||
struct mt8196_afe_private *afe_priv = afe->platform_priv;
|
||||
struct mtk_afe_tdm_priv *tdm_priv;
|
||||
|
||||
if (dai->id >= MT8196_DAI_NUM || dai->id < 0)
|
||||
return -EINVAL;
|
||||
|
||||
tdm_priv = afe_priv->dai_priv[dai->id];
|
||||
|
||||
if (!tdm_priv)
|
||||
return -EINVAL;
|
||||
|
||||
if (dir != SND_SOC_CLOCK_OUT)
|
||||
return -EINVAL;
|
||||
|
||||
dev_dbg(afe->dev, "freq %d\n", freq);
|
||||
|
||||
return mtk_dai_tdm_cal_mclk(afe, tdm_priv, freq);
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops mtk_dai_tdm_ops = {
|
||||
.hw_params = mtk_dai_tdm_hw_params,
|
||||
.trigger = mtk_dai_tdm_trigger,
|
||||
.set_sysclk = mtk_dai_tdm_set_sysclk,
|
||||
};
|
||||
|
||||
/* dai driver */
|
||||
#define MTK_TDM_RATES (SNDRV_PCM_RATE_8000_48000 |\
|
||||
SNDRV_PCM_RATE_88200 |\
|
||||
SNDRV_PCM_RATE_96000 |\
|
||||
SNDRV_PCM_RATE_176400 |\
|
||||
SNDRV_PCM_RATE_192000)
|
||||
|
||||
#define MTK_TDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
|
||||
SNDRV_PCM_FMTBIT_S24_LE |\
|
||||
SNDRV_PCM_FMTBIT_S32_LE)
|
||||
|
||||
static struct snd_soc_dai_driver mtk_dai_tdm_driver[] = {
|
||||
{
|
||||
.name = "TDM",
|
||||
.id = MT8196_DAI_TDM,
|
||||
.playback = {
|
||||
.stream_name = "TDM",
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = MTK_TDM_RATES,
|
||||
.formats = MTK_TDM_FORMATS,
|
||||
},
|
||||
.ops = &mtk_dai_tdm_ops,
|
||||
},
|
||||
{
|
||||
.name = "TDM_DPTX",
|
||||
.id = MT8196_DAI_TDM_DPTX,
|
||||
.playback = {
|
||||
.stream_name = "TDM_DPTX",
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = MTK_TDM_RATES,
|
||||
.formats = MTK_TDM_FORMATS,
|
||||
},
|
||||
.ops = &mtk_dai_tdm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static struct mtk_afe_tdm_priv *init_tdm_priv_data(struct mtk_base_afe *afe,
|
||||
int id)
|
||||
{
|
||||
struct mtk_afe_tdm_priv *tdm_priv;
|
||||
|
||||
tdm_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_afe_tdm_priv),
|
||||
GFP_KERNEL);
|
||||
if (!tdm_priv)
|
||||
return NULL;
|
||||
|
||||
if (id == MT8196_DAI_TDM_DPTX)
|
||||
tdm_priv->mclk_multiple = 256;
|
||||
else
|
||||
tdm_priv->mclk_multiple = 128;
|
||||
|
||||
tdm_priv->bck_id = MT8196_TDMOUT_BCK;
|
||||
tdm_priv->mclk_id = MT8196_TDMOUT_MCK;
|
||||
|
||||
return tdm_priv;
|
||||
}
|
||||
|
||||
int mt8196_dai_tdm_register(struct mtk_base_afe *afe)
|
||||
{
|
||||
struct mt8196_afe_private *afe_priv = afe->platform_priv;
|
||||
struct mtk_afe_tdm_priv *tdm_priv, *tdm_dptx_priv;
|
||||
struct mtk_base_afe_dai *dai;
|
||||
|
||||
dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
|
||||
if (!dai)
|
||||
return -ENOMEM;
|
||||
|
||||
dai->dai_drivers = mtk_dai_tdm_driver;
|
||||
dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_tdm_driver);
|
||||
dai->controls = mtk_dai_tdm_controls;
|
||||
dai->num_controls = ARRAY_SIZE(mtk_dai_tdm_controls);
|
||||
dai->dapm_widgets = mtk_dai_tdm_widgets;
|
||||
dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_tdm_widgets);
|
||||
dai->dapm_routes = mtk_dai_tdm_routes;
|
||||
dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_tdm_routes);
|
||||
|
||||
tdm_priv = init_tdm_priv_data(afe, MT8196_DAI_TDM);
|
||||
if (!tdm_priv)
|
||||
return -ENOMEM;
|
||||
|
||||
tdm_dptx_priv = init_tdm_priv_data(afe, MT8196_DAI_TDM_DPTX);
|
||||
if (!tdm_dptx_priv)
|
||||
return -ENOMEM;
|
||||
|
||||
list_add(&dai->list, &afe->sub_dais);
|
||||
|
||||
afe_priv->dai_priv[MT8196_DAI_TDM] = tdm_priv;
|
||||
afe_priv->dai_priv[MT8196_DAI_TDM_DPTX] = tdm_dptx_priv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
121
sound/soc/mediatek/mt8196/mt8196-interconnection.h
Normal file
121
sound/soc/mediatek/mt8196/mt8196-interconnection.h
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Mediatek MT8196 audio driver interconnection definition
|
||||
*
|
||||
* Copyright (c) 2025 MediaTek Inc.
|
||||
* Author: Darren Ye <darren.ye@mediatek.com>
|
||||
*/
|
||||
|
||||
#ifndef _MT8196_INTERCONNECTION_H_
|
||||
#define _MT8196_INTERCONNECTION_H_
|
||||
|
||||
/* in port define */
|
||||
|
||||
#define I_CONNSYS_I2S_CH1 0
|
||||
#define I_CONNSYS_I2S_CH2 1
|
||||
#define I_GAIN0_OUT_CH1 6
|
||||
#define I_GAIN0_OUT_CH2 7
|
||||
#define I_GAIN1_OUT_CH1 8
|
||||
#define I_GAIN1_OUT_CH2 9
|
||||
#define I_GAIN2_OUT_CH1 10
|
||||
#define I_GAIN2_OUT_CH2 11
|
||||
#define I_GAIN3_OUT_CH1 12
|
||||
#define I_GAIN3_OUT_CH2 13
|
||||
#define I_STF_CH1 14
|
||||
#define I_ADDA_UL_CH1 16
|
||||
#define I_ADDA_UL_CH2 17
|
||||
#define I_ADDA_UL_CH3 18
|
||||
#define I_ADDA_UL_CH4 19
|
||||
#define I_UL_PROX_CH1 20
|
||||
#define I_UL_PROX_CH2 21
|
||||
#define I_ADDA_UL_CH5 24
|
||||
#define I_ADDA_UL_CH6 25
|
||||
#define I_DMIC0_CH1 28
|
||||
#define I_DMIC0_CH2 29
|
||||
#define I_DMIC1_CH1 30
|
||||
#define I_DMIC1_CH2 31
|
||||
|
||||
/* in port define >= 32 */
|
||||
#define I_32_OFFSET 32
|
||||
#define I_DL0_CH1 (32 - I_32_OFFSET)
|
||||
#define I_DL0_CH2 (33 - I_32_OFFSET)
|
||||
#define I_DL1_CH1 (34 - I_32_OFFSET)
|
||||
#define I_DL1_CH2 (35 - I_32_OFFSET)
|
||||
#define I_DL2_CH1 (36 - I_32_OFFSET)
|
||||
#define I_DL2_CH2 (37 - I_32_OFFSET)
|
||||
#define I_DL3_CH1 (38 - I_32_OFFSET)
|
||||
#define I_DL3_CH2 (39 - I_32_OFFSET)
|
||||
#define I_DL4_CH1 (40 - I_32_OFFSET)
|
||||
#define I_DL4_CH2 (41 - I_32_OFFSET)
|
||||
#define I_DL5_CH1 (42 - I_32_OFFSET)
|
||||
#define I_DL5_CH2 (43 - I_32_OFFSET)
|
||||
#define I_DL6_CH1 (44 - I_32_OFFSET)
|
||||
#define I_DL6_CH2 (45 - I_32_OFFSET)
|
||||
#define I_DL7_CH1 (46 - I_32_OFFSET)
|
||||
#define I_DL7_CH2 (47 - I_32_OFFSET)
|
||||
#define I_DL8_CH1 (48 - I_32_OFFSET)
|
||||
#define I_DL8_CH2 (49 - I_32_OFFSET)
|
||||
#define I_DL_4CH_CH1 (50 - I_32_OFFSET)
|
||||
#define I_DL_4CH_CH2 (51 - I_32_OFFSET)
|
||||
#define I_DL_4CH_CH3 (52 - I_32_OFFSET)
|
||||
#define I_DL_4CH_CH4 (53 - I_32_OFFSET)
|
||||
#define I_DL_24CH_CH1 (54 - I_32_OFFSET)
|
||||
#define I_DL_24CH_CH2 (55 - I_32_OFFSET)
|
||||
#define I_DL_24CH_CH3 (56 - I_32_OFFSET)
|
||||
#define I_DL_24CH_CH4 (57 - I_32_OFFSET)
|
||||
#define I_DL_24CH_CH5 (58 - I_32_OFFSET)
|
||||
#define I_DL_24CH_CH6 (59 - I_32_OFFSET)
|
||||
#define I_DL_24CH_CH7 (60 - I_32_OFFSET)
|
||||
#define I_DL_24CH_CH8 (61 - I_32_OFFSET)
|
||||
|
||||
/* in port define >= 64 */
|
||||
#define I_64_OFFSET 64
|
||||
#define I_DL23_CH1 (78 - I_64_OFFSET)
|
||||
#define I_DL23_CH2 (79 - I_64_OFFSET)
|
||||
#define I_DL24_CH1 (80 - I_64_OFFSET)
|
||||
#define I_DL24_CH2 (81 - I_64_OFFSET)
|
||||
#define I_DL25_CH1 (82 - I_64_OFFSET)
|
||||
#define I_DL25_CH2 (83 - I_64_OFFSET)
|
||||
#define I_DL26_CH1 (84 - I_64_OFFSET)
|
||||
#define I_DL26_CH2 (85 - I_64_OFFSET)
|
||||
|
||||
/* in port define >= 128 */
|
||||
#define I_128_OFFSET 128
|
||||
#define I_PCM_0_CAP_CH1 (130 - I_128_OFFSET)
|
||||
#define I_PCM_0_CAP_CH2 (131 - I_128_OFFSET)
|
||||
#define I_PCM_1_CAP_CH1 (132 - I_128_OFFSET)
|
||||
#define I_PCM_1_CAP_CH2 (133 - I_128_OFFSET)
|
||||
#define I_I2SIN0_CH1 (134 - I_128_OFFSET)
|
||||
#define I_I2SIN0_CH2 (135 - I_128_OFFSET)
|
||||
#define I_I2SIN1_CH1 (136 - I_128_OFFSET)
|
||||
#define I_I2SIN1_CH2 (137 - I_128_OFFSET)
|
||||
#define I_I2SIN2_CH1 (138 - I_128_OFFSET)
|
||||
#define I_I2SIN2_CH2 (139 - I_128_OFFSET)
|
||||
#define I_I2SIN3_CH1 (140 - I_128_OFFSET)
|
||||
#define I_I2SIN3_CH2 (141 - I_128_OFFSET)
|
||||
#define I_I2SIN4_CH1 (142 - I_128_OFFSET)
|
||||
#define I_I2SIN4_CH2 (143 - I_128_OFFSET)
|
||||
#define I_I2SIN4_CH3 (144 - I_128_OFFSET)
|
||||
#define I_I2SIN4_CH4 (145 - I_128_OFFSET)
|
||||
#define I_I2SIN4_CH5 (146 - I_128_OFFSET)
|
||||
#define I_I2SIN4_CH6 (147 - I_128_OFFSET)
|
||||
#define I_I2SIN4_CH7 (148 - I_128_OFFSET)
|
||||
#define I_I2SIN4_CH8 (149 - I_128_OFFSET)
|
||||
|
||||
/* in port define >= 160 */
|
||||
#define I_160_OFFSET 160
|
||||
#define I_I2SIN6_CH1 (166 - I_160_OFFSET)
|
||||
#define I_I2SIN6_CH2 (167 - I_160_OFFSET)
|
||||
|
||||
/* in port define >= 192 */
|
||||
#define I_192_OFFSET 192
|
||||
#define I_SRC_0_OUT_CH1 (198 - I_192_OFFSET)
|
||||
#define I_SRC_0_OUT_CH2 (199 - I_192_OFFSET)
|
||||
#define I_SRC_1_OUT_CH1 (200 - I_192_OFFSET)
|
||||
#define I_SRC_1_OUT_CH2 (201 - I_192_OFFSET)
|
||||
#define I_SRC_2_OUT_CH1 (202 - I_192_OFFSET)
|
||||
#define I_SRC_2_OUT_CH2 (203 - I_192_OFFSET)
|
||||
#define I_SRC_3_OUT_CH1 (204 - I_192_OFFSET)
|
||||
#define I_SRC_3_OUT_CH2 (205 - I_192_OFFSET)
|
||||
|
||||
#endif
|
||||
870
sound/soc/mediatek/mt8196/mt8196-nau8825.c
Normal file
870
sound/soc/mediatek/mt8196/mt8196-nau8825.c
Normal file
|
|
@ -0,0 +1,870 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* mt8196-nau8825.c -- mt8196 nau8825 ALSA SoC machine driver
|
||||
*
|
||||
* Copyright (c) 2025 MediaTek Inc.
|
||||
* Author: Darren Ye <darren.ye@mediatek.com>
|
||||
*/
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <sound/soc.h>
|
||||
#include <sound/jack.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include "mt8196-afe-common.h"
|
||||
|
||||
#include "../../codecs/nau8825.h"
|
||||
#include "../../codecs/rt5682s.h"
|
||||
|
||||
#include "../common/mtk-soc-card.h"
|
||||
#include "../common/mtk-dsp-sof-common.h"
|
||||
#include "../common/mtk-soundcard-driver.h"
|
||||
#include "../common/mtk-afe-platform-driver.h"
|
||||
|
||||
#define NAU8825_HS_PRESENT BIT(0)
|
||||
#define RT5682S_HS_PRESENT BIT(1)
|
||||
#define RT5650_HS_PRESENT BIT(2)
|
||||
|
||||
/*
|
||||
* Nau88l25
|
||||
*/
|
||||
#define NAU8825_CODEC_DAI "nau8825-hifi"
|
||||
|
||||
/*
|
||||
* Rt5682s
|
||||
*/
|
||||
#define RT5682S_CODEC_DAI "rt5682s-aif1"
|
||||
|
||||
/*
|
||||
* Rt5650
|
||||
*/
|
||||
#define RT5650_CODEC_DAI "rt5645-aif1"
|
||||
|
||||
#define SOF_DMA_DL1 "SOF_DMA_DL1"
|
||||
#define SOF_DMA_DL_24CH "SOF_DMA_DL_24CH"
|
||||
#define SOF_DMA_UL0 "SOF_DMA_UL0"
|
||||
#define SOF_DMA_UL1 "SOF_DMA_UL1"
|
||||
#define SOF_DMA_UL2 "SOF_DMA_UL2"
|
||||
|
||||
enum mt8196_jacks {
|
||||
MT8196_JACK_HEADSET,
|
||||
MT8196_JACK_DP,
|
||||
MT8196_JACK_HDMI,
|
||||
MT8196_JACK_MAX,
|
||||
};
|
||||
|
||||
static struct snd_soc_jack_pin mt8196_dp_jack_pins[] = {
|
||||
{
|
||||
.pin = "DP",
|
||||
.mask = SND_JACK_AVOUT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_jack_pin mt8196_hdmi_jack_pins[] = {
|
||||
{
|
||||
.pin = "HDMI",
|
||||
.mask = SND_JACK_AVOUT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_jack_pin nau8825_jack_pins[] = {
|
||||
{
|
||||
.pin = "Headphone Jack",
|
||||
.mask = SND_JACK_HEADPHONE,
|
||||
},
|
||||
{
|
||||
.pin = "Headset Mic",
|
||||
.mask = SND_JACK_MICROPHONE,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new mt8196_dumb_spk_controls[] = {
|
||||
SOC_DAPM_PIN_SWITCH("Ext Spk"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget mt8196_dumb_spk_widgets[] = {
|
||||
SND_SOC_DAPM_SPK("Ext Spk", NULL),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget mt8196_nau8825_widgets[] = {
|
||||
SND_SOC_DAPM_HP("Headphone Jack", NULL),
|
||||
SND_SOC_DAPM_MIC("Headset Mic", NULL),
|
||||
SND_SOC_DAPM_SPK("Ext Spk", NULL),
|
||||
SND_SOC_DAPM_SINK("DP"),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new mt8196_nau8825_controls[] = {
|
||||
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
|
||||
SOC_DAPM_PIN_SWITCH("Headset Mic"),
|
||||
};
|
||||
|
||||
#define EXT_SPK_AMP_W_NAME "Ext_Speaker_Amp"
|
||||
|
||||
static struct snd_soc_card mt8196_nau8825_soc_card;
|
||||
|
||||
static const struct snd_soc_dapm_widget mt8196_nau8825_card_widgets[] = {
|
||||
/* SOF Uplink */
|
||||
SND_SOC_DAPM_MIXER("SOF_DMA_UL0", SND_SOC_NOPM, 0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_MIXER("SOF_DMA_UL1", SND_SOC_NOPM, 0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_MIXER("SOF_DMA_UL2", SND_SOC_NOPM, 0, 0, NULL, 0),
|
||||
|
||||
/*
|
||||
* SOF Downlink
|
||||
* the widgets on the machine driver cannot use the parameter with kcontrol
|
||||
* because the widget domain is its platform driver. so sof downlink route
|
||||
* is written in the i2s dai driver.
|
||||
*/
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route mt8196_nau8825_card_routes[] = {
|
||||
/* SOF Uplink */
|
||||
{"SOF_DMA_UL0", NULL, "UL0_CH1"},
|
||||
{"SOF_DMA_UL0", NULL, "UL0_CH2"},
|
||||
/* SOF Uplink */
|
||||
{"SOF_DMA_UL1", NULL, "UL1_CH1"},
|
||||
{"SOF_DMA_UL1", NULL, "UL1_CH2"},
|
||||
/* SOF Uplink */
|
||||
{"SOF_DMA_UL2", NULL, "UL2_CH1"},
|
||||
{"SOF_DMA_UL2", NULL, "UL2_CH2"},
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new mt8196_nau8825_card_controls[] = {
|
||||
SOC_DAPM_PIN_SWITCH(EXT_SPK_AMP_W_NAME),
|
||||
};
|
||||
|
||||
/*
|
||||
* define mtk_spk_i2s_mck node in dts when need mclk,
|
||||
* BE i2s need assign snd_soc_ops = mt8196_nau8825_i2s_ops
|
||||
*/
|
||||
static int mt8196_nau8825_i2s_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
unsigned int rate = params_rate(params);
|
||||
unsigned int mclk_fs_ratio = 128;
|
||||
unsigned int mclk_fs = rate * mclk_fs_ratio;
|
||||
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
|
||||
|
||||
return snd_soc_dai_set_sysclk(cpu_dai,
|
||||
0, mclk_fs, SND_SOC_CLOCK_OUT);
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops mt8196_nau8825_i2s_ops = {
|
||||
.hw_params = mt8196_nau8825_i2s_hw_params,
|
||||
};
|
||||
|
||||
static int mt8196_dptx_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
unsigned int rate = params_rate(params);
|
||||
unsigned int mclk_fs_ratio = 256;
|
||||
unsigned int mclk_fs = rate * mclk_fs_ratio;
|
||||
struct snd_soc_dai *dai = snd_soc_rtd_to_cpu(rtd, 0);
|
||||
|
||||
return snd_soc_dai_set_sysclk(dai, 0, mclk_fs, SND_SOC_CLOCK_OUT);
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops mt8196_dptx_ops = {
|
||||
.hw_params = mt8196_dptx_hw_params,
|
||||
};
|
||||
|
||||
static int mt8196_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
dev_info(rtd->dev, "fix format to 32bit\n");
|
||||
|
||||
/* fix BE i2s format to 32bit, clean param mask first */
|
||||
snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
|
||||
0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
|
||||
|
||||
params_set_format(params, SNDRV_PCM_FORMAT_S32_LE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt8196_sof_be_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct snd_soc_component *cmpnt_afe = NULL;
|
||||
struct snd_soc_pcm_runtime *runtime;
|
||||
|
||||
/* find afe component */
|
||||
for_each_card_rtds(rtd->card, runtime) {
|
||||
cmpnt_afe = snd_soc_rtdcom_lookup(runtime, AFE_PCM_NAME);
|
||||
if (cmpnt_afe) {
|
||||
dev_info(rtd->dev, "component->name: %s\n", cmpnt_afe->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cmpnt_afe && !pm_runtime_active(cmpnt_afe->dev)) {
|
||||
dev_err(rtd->dev, "afe pm runtime is not active!!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops mt8196_sof_be_ops = {
|
||||
.hw_params = mt8196_sof_be_hw_params,
|
||||
};
|
||||
|
||||
static const struct sof_conn_stream g_sof_conn_streams[] = {
|
||||
{
|
||||
.sof_link = "AFE_SOF_DL1",
|
||||
.sof_dma = SOF_DMA_DL1,
|
||||
.stream_dir = SNDRV_PCM_STREAM_PLAYBACK
|
||||
},
|
||||
{
|
||||
.sof_link = "AFE_SOF_DL_24CH",
|
||||
.sof_dma = SOF_DMA_DL_24CH,
|
||||
.stream_dir = SNDRV_PCM_STREAM_PLAYBACK
|
||||
},
|
||||
{
|
||||
.sof_link = "AFE_SOF_UL0",
|
||||
.sof_dma = SOF_DMA_UL0,
|
||||
.stream_dir = SNDRV_PCM_STREAM_CAPTURE
|
||||
},
|
||||
{
|
||||
.sof_link = "AFE_SOF_UL1",
|
||||
.sof_dma = SOF_DMA_UL1,
|
||||
.stream_dir = SNDRV_PCM_STREAM_CAPTURE
|
||||
},
|
||||
{
|
||||
.sof_link = "AFE_SOF_UL2",
|
||||
.sof_dma = SOF_DMA_UL2,
|
||||
.stream_dir = SNDRV_PCM_STREAM_CAPTURE
|
||||
},
|
||||
};
|
||||
|
||||
/* FE */
|
||||
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(playback_24ch,
|
||||
DAILINK_COMP_ARRAY(COMP_CPU("DL_24CH")),
|
||||
DAILINK_COMP_ARRAY(COMP_DUMMY()),
|
||||
DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
SND_SOC_DAILINK_DEFS(capture0,
|
||||
DAILINK_COMP_ARRAY(COMP_CPU("UL0")),
|
||||
DAILINK_COMP_ARRAY(COMP_DUMMY()),
|
||||
DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
SND_SOC_DAILINK_DEFS(capture1,
|
||||
DAILINK_COMP_ARRAY(COMP_CPU("UL1")),
|
||||
DAILINK_COMP_ARRAY(COMP_DUMMY()),
|
||||
DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
SND_SOC_DAILINK_DEFS(capture2,
|
||||
DAILINK_COMP_ARRAY(COMP_CPU("UL2")),
|
||||
DAILINK_COMP_ARRAY(COMP_DUMMY()),
|
||||
DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
SND_SOC_DAILINK_DEFS(playback_hdmi,
|
||||
DAILINK_COMP_ARRAY(COMP_CPU("HDMI")),
|
||||
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(capture_cm0,
|
||||
DAILINK_COMP_ARRAY(COMP_CPU("UL_CM0")),
|
||||
DAILINK_COMP_ARRAY(COMP_DUMMY()),
|
||||
DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
/* BE */
|
||||
SND_SOC_DAILINK_DEFS(ap_dmic,
|
||||
DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC")),
|
||||
DAILINK_COMP_ARRAY(COMP_DUMMY()),
|
||||
DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
SND_SOC_DAILINK_DEFS(ap_dmic_ch34,
|
||||
DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC_CH34")),
|
||||
DAILINK_COMP_ARRAY(COMP_DUMMY()),
|
||||
DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
SND_SOC_DAILINK_DEFS(ap_dmic_multich,
|
||||
DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC_MULTICH")),
|
||||
DAILINK_COMP_ARRAY(COMP_DUMMY()),
|
||||
DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
SND_SOC_DAILINK_DEFS(i2sin6,
|
||||
DAILINK_COMP_ARRAY(COMP_CPU("I2SIN6")),
|
||||
DAILINK_COMP_ARRAY(COMP_DUMMY()),
|
||||
DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
SND_SOC_DAILINK_DEFS(i2sout3,
|
||||
DAILINK_COMP_ARRAY(COMP_CPU("I2SOUT3")),
|
||||
DAILINK_COMP_ARRAY(COMP_DUMMY()),
|
||||
DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
SND_SOC_DAILINK_DEFS(i2sout4,
|
||||
DAILINK_COMP_ARRAY(COMP_CPU("I2SOUT4")),
|
||||
DAILINK_COMP_ARRAY(COMP_DUMMY()),
|
||||
DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
SND_SOC_DAILINK_DEFS(i2sout6,
|
||||
DAILINK_COMP_ARRAY(COMP_CPU("I2SOUT6")),
|
||||
DAILINK_COMP_ARRAY(COMP_DUMMY()),
|
||||
DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
SND_SOC_DAILINK_DEFS(tdm_dptx,
|
||||
DAILINK_COMP_ARRAY(COMP_CPU("TDM_DPTX")),
|
||||
DAILINK_COMP_ARRAY(COMP_DUMMY()),
|
||||
DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
SND_SOC_DAILINK_DEFS(AFE_SOF_DL_24CH,
|
||||
DAILINK_COMP_ARRAY(COMP_CPU("SOF_DL_24CH")),
|
||||
DAILINK_COMP_ARRAY(COMP_DUMMY()),
|
||||
DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
SND_SOC_DAILINK_DEFS(AFE_SOF_DL1,
|
||||
DAILINK_COMP_ARRAY(COMP_CPU("SOF_DL1")),
|
||||
DAILINK_COMP_ARRAY(COMP_DUMMY()),
|
||||
DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
SND_SOC_DAILINK_DEFS(AFE_SOF_UL0,
|
||||
DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL0")),
|
||||
DAILINK_COMP_ARRAY(COMP_DUMMY()),
|
||||
DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
SND_SOC_DAILINK_DEFS(AFE_SOF_UL1,
|
||||
DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL1")),
|
||||
DAILINK_COMP_ARRAY(COMP_DUMMY()),
|
||||
DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
SND_SOC_DAILINK_DEFS(AFE_SOF_UL2,
|
||||
DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL2")),
|
||||
DAILINK_COMP_ARRAY(COMP_DUMMY()),
|
||||
DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
|
||||
static struct snd_soc_dai_link mt8196_nau8825_dai_links[] = {
|
||||
/*
|
||||
* The SOF topology expects PCM streams 0~4 to be available
|
||||
* for the SOF PCM streams. Put the SOF BE definitions here
|
||||
* so that the PCM device numbers are skipped over.
|
||||
* (BE dailinks do not have PCM devices created.)
|
||||
*/
|
||||
{
|
||||
.name = "AFE_SOF_DL_24CH",
|
||||
.no_pcm = 1,
|
||||
.playback_only = 1,
|
||||
.ops = &mt8196_sof_be_ops,
|
||||
SND_SOC_DAILINK_REG(AFE_SOF_DL_24CH),
|
||||
},
|
||||
{
|
||||
.name = "AFE_SOF_DL1",
|
||||
.no_pcm = 1,
|
||||
.playback_only = 1,
|
||||
.ops = &mt8196_sof_be_ops,
|
||||
SND_SOC_DAILINK_REG(AFE_SOF_DL1),
|
||||
},
|
||||
{
|
||||
.name = "AFE_SOF_UL0",
|
||||
.no_pcm = 1,
|
||||
.capture_only = 1,
|
||||
.ops = &mt8196_sof_be_ops,
|
||||
SND_SOC_DAILINK_REG(AFE_SOF_UL0),
|
||||
},
|
||||
{
|
||||
.name = "AFE_SOF_UL1",
|
||||
.no_pcm = 1,
|
||||
.capture_only = 1,
|
||||
.ops = &mt8196_sof_be_ops,
|
||||
SND_SOC_DAILINK_REG(AFE_SOF_UL1),
|
||||
},
|
||||
{
|
||||
.name = "AFE_SOF_UL2",
|
||||
.no_pcm = 1,
|
||||
.capture_only = 1,
|
||||
.ops = &mt8196_sof_be_ops,
|
||||
SND_SOC_DAILINK_REG(AFE_SOF_UL2),
|
||||
},
|
||||
/* Front End DAI links */
|
||||
{
|
||||
.name = "HDMI_FE",
|
||||
.stream_name = "HDMI Playback",
|
||||
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
|
||||
SND_SOC_DPCM_TRIGGER_PRE},
|
||||
.dynamic = 1,
|
||||
.playback_only = 1,
|
||||
SND_SOC_DAILINK_REG(playback_hdmi),
|
||||
},
|
||||
{
|
||||
.name = "DL2_FE",
|
||||
.stream_name = "DL2 Playback",
|
||||
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
|
||||
SND_SOC_DPCM_TRIGGER_PRE},
|
||||
.dynamic = 1,
|
||||
.playback_only = 1,
|
||||
SND_SOC_DAILINK_REG(playback2),
|
||||
},
|
||||
{
|
||||
.name = "UL_CM0_FE",
|
||||
.stream_name = "UL_CM0 Capture",
|
||||
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
|
||||
SND_SOC_DPCM_TRIGGER_PRE},
|
||||
.dynamic = 1,
|
||||
.capture_only = 1,
|
||||
SND_SOC_DAILINK_REG(capture_cm0),
|
||||
},
|
||||
{
|
||||
.name = "DL_24CH_FE",
|
||||
.stream_name = "DL_24CH Playback",
|
||||
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
|
||||
SND_SOC_DPCM_TRIGGER_PRE},
|
||||
.dynamic = 1,
|
||||
.playback_only = 1,
|
||||
SND_SOC_DAILINK_REG(playback_24ch),
|
||||
},
|
||||
{
|
||||
.name = "DL1_FE",
|
||||
.stream_name = "DL1 Playback",
|
||||
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
|
||||
SND_SOC_DPCM_TRIGGER_PRE},
|
||||
.dynamic = 1,
|
||||
.playback_only = 1,
|
||||
SND_SOC_DAILINK_REG(playback1),
|
||||
},
|
||||
{
|
||||
.name = "UL0_FE",
|
||||
.stream_name = "UL0 Capture",
|
||||
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
|
||||
SND_SOC_DPCM_TRIGGER_PRE},
|
||||
.dynamic = 1,
|
||||
.capture_only = 1,
|
||||
SND_SOC_DAILINK_REG(capture0),
|
||||
},
|
||||
{
|
||||
.name = "UL1_FE",
|
||||
.stream_name = "UL1 Capture",
|
||||
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
|
||||
SND_SOC_DPCM_TRIGGER_PRE},
|
||||
.dynamic = 1,
|
||||
.capture_only = 1,
|
||||
SND_SOC_DAILINK_REG(capture1),
|
||||
},
|
||||
{
|
||||
.name = "UL2_FE",
|
||||
.stream_name = "UL2 Capture",
|
||||
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
|
||||
SND_SOC_DPCM_TRIGGER_PRE},
|
||||
.dynamic = 1,
|
||||
.capture_only = 1,
|
||||
SND_SOC_DAILINK_REG(capture2),
|
||||
},
|
||||
/* Back End DAI links */
|
||||
{
|
||||
.name = "I2SIN6_BE",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC
|
||||
| SND_SOC_DAIFMT_GATED,
|
||||
.ops = &mt8196_nau8825_i2s_ops,
|
||||
.no_pcm = 1,
|
||||
.capture_only = 1,
|
||||
.ignore_suspend = 1,
|
||||
.be_hw_params_fixup = mt8196_hw_params_fixup,
|
||||
SND_SOC_DAILINK_REG(i2sin6),
|
||||
},
|
||||
{
|
||||
.name = "I2SOUT4_BE",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC
|
||||
| SND_SOC_DAIFMT_GATED,
|
||||
.ops = &mt8196_nau8825_i2s_ops,
|
||||
.no_pcm = 1,
|
||||
.playback_only = 1,
|
||||
.ignore_suspend = 1,
|
||||
.ignore_pmdown_time = 1,
|
||||
.be_hw_params_fixup = mt8196_hw_params_fixup,
|
||||
SND_SOC_DAILINK_REG(i2sout4),
|
||||
},
|
||||
{
|
||||
.name = "I2SOUT6_BE",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC
|
||||
| SND_SOC_DAIFMT_GATED,
|
||||
.ops = &mt8196_nau8825_i2s_ops,
|
||||
.no_pcm = 1,
|
||||
.playback_only = 1,
|
||||
.ignore_suspend = 1,
|
||||
.be_hw_params_fixup = mt8196_hw_params_fixup,
|
||||
SND_SOC_DAILINK_REG(i2sout6),
|
||||
},
|
||||
{
|
||||
.name = "AP_DMIC_BE",
|
||||
.no_pcm = 1,
|
||||
.capture_only = 1,
|
||||
.ignore_suspend = 1,
|
||||
SND_SOC_DAILINK_REG(ap_dmic),
|
||||
},
|
||||
{
|
||||
.name = "AP_DMIC_CH34_BE",
|
||||
.no_pcm = 1,
|
||||
.capture_only = 1,
|
||||
.ignore_suspend = 1,
|
||||
SND_SOC_DAILINK_REG(ap_dmic_ch34),
|
||||
},
|
||||
{
|
||||
.name = "AP_DMIC_MULTICH_BE",
|
||||
.no_pcm = 1,
|
||||
.capture_only = 1,
|
||||
.ignore_suspend = 1,
|
||||
SND_SOC_DAILINK_REG(ap_dmic_multich),
|
||||
},
|
||||
{
|
||||
.name = "TDM_DPTX_BE",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC
|
||||
| SND_SOC_DAIFMT_GATED,
|
||||
.ops = &mt8196_dptx_ops,
|
||||
.be_hw_params_fixup = mt8196_hw_params_fixup,
|
||||
.no_pcm = 1,
|
||||
.playback_only = 1,
|
||||
.ignore_suspend = 1,
|
||||
SND_SOC_DAILINK_REG(tdm_dptx),
|
||||
},
|
||||
{
|
||||
.name = "I2SOUT3_BE",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC
|
||||
| SND_SOC_DAIFMT_GATED,
|
||||
.ops = &mt8196_nau8825_i2s_ops,
|
||||
.no_pcm = 1,
|
||||
.playback_only = 1,
|
||||
.ignore_suspend = 1,
|
||||
SND_SOC_DAILINK_REG(i2sout3),
|
||||
},
|
||||
};
|
||||
|
||||
static int mt8196_dumb_amp_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
|
||||
int ret = 0;
|
||||
|
||||
ret = snd_soc_dapm_new_controls(dapm, mt8196_dumb_spk_widgets,
|
||||
ARRAY_SIZE(mt8196_dumb_spk_widgets));
|
||||
if (ret) {
|
||||
dev_err(rtd->dev, "unable to add Dumb Speaker dapm, ret %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_add_card_controls(card, mt8196_dumb_spk_controls,
|
||||
ARRAY_SIZE(mt8196_dumb_spk_controls));
|
||||
if (ret) {
|
||||
dev_err(rtd->dev, "unable to add Dumb card controls, ret %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt8196_dptx_codec_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct snd_soc_jack *jack = &soc_card_data->card_data->jacks[MT8196_JACK_DP];
|
||||
struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
|
||||
int ret = 0;
|
||||
|
||||
ret = snd_soc_card_jack_new_pins(rtd->card, "DP Jack", SND_JACK_AVOUT,
|
||||
jack, mt8196_dp_jack_pins,
|
||||
ARRAY_SIZE(mt8196_dp_jack_pins));
|
||||
if (ret) {
|
||||
dev_err(rtd->dev, "new jack failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_component_set_jack(component, jack, NULL);
|
||||
if (ret) {
|
||||
dev_err(rtd->dev, "set jack failed on %s (ret=%d)\n",
|
||||
component->name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt8196_hdmi_codec_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct snd_soc_jack *jack = &soc_card_data->card_data->jacks[MT8196_JACK_HDMI];
|
||||
struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
|
||||
int ret = 0;
|
||||
|
||||
ret = snd_soc_card_jack_new_pins(rtd->card, "HDMI Jack", SND_JACK_AVOUT,
|
||||
jack, mt8196_hdmi_jack_pins,
|
||||
ARRAY_SIZE(mt8196_hdmi_jack_pins));
|
||||
if (ret) {
|
||||
dev_err(rtd->dev, "new jack failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_component_set_jack(component, jack, NULL);
|
||||
if (ret) {
|
||||
dev_err(rtd->dev, "set jack failed on %s (ret=%d)\n",
|
||||
component->name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt8196_headset_codec_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
|
||||
struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);
|
||||
struct snd_soc_jack *jack = &soc_card_data->card_data->jacks[MT8196_JACK_HEADSET];
|
||||
struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
|
||||
int ret;
|
||||
int type;
|
||||
|
||||
ret = snd_soc_dapm_new_controls(dapm, mt8196_nau8825_widgets,
|
||||
ARRAY_SIZE(mt8196_nau8825_widgets));
|
||||
if (ret) {
|
||||
dev_err(rtd->dev, "unable to add nau8825 card widget, ret %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_add_card_controls(card, mt8196_nau8825_controls,
|
||||
ARRAY_SIZE(mt8196_nau8825_controls));
|
||||
if (ret) {
|
||||
dev_err(rtd->dev, "unable to add nau8825 card controls, ret %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
|
||||
SND_JACK_HEADSET | SND_JACK_BTN_0 |
|
||||
SND_JACK_BTN_1 | SND_JACK_BTN_2 |
|
||||
SND_JACK_BTN_3,
|
||||
jack,
|
||||
nau8825_jack_pins,
|
||||
ARRAY_SIZE(nau8825_jack_pins));
|
||||
if (ret) {
|
||||
dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
|
||||
snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
|
||||
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
|
||||
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
|
||||
|
||||
type = SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3;
|
||||
ret = snd_soc_component_set_jack(component, jack, (void *)&type);
|
||||
|
||||
if (ret) {
|
||||
dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
static void mt8196_headset_codec_exit(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
|
||||
|
||||
snd_soc_component_set_jack(component, NULL, NULL);
|
||||
}
|
||||
|
||||
static int mt8196_nau8825_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
|
||||
unsigned int rate = params_rate(params);
|
||||
unsigned int bit_width = params_width(params);
|
||||
int clk_freq, ret;
|
||||
|
||||
clk_freq = rate * 2 * bit_width;
|
||||
|
||||
/* Configure clock for codec */
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_BLK, 0,
|
||||
SND_SOC_CLOCK_IN);
|
||||
if (ret < 0) {
|
||||
dev_err(codec_dai->dev, "can't set BCLK clock %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Configure pll for codec */
|
||||
ret = snd_soc_dai_set_pll(codec_dai, 0, 0, clk_freq,
|
||||
params_rate(params) * 256);
|
||||
if (ret < 0) {
|
||||
dev_err(codec_dai->dev, "can't set BCLK: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops mt8196_nau8825_ops = {
|
||||
.hw_params = mt8196_nau8825_hw_params,
|
||||
};
|
||||
|
||||
static int mt8196_rt5682s_i2s_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
|
||||
struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
|
||||
unsigned int rate = params_rate(params);
|
||||
int bitwidth;
|
||||
int ret;
|
||||
|
||||
bitwidth = snd_pcm_format_width(params_format(params));
|
||||
if (bitwidth < 0) {
|
||||
dev_err(card->dev, "invalid bit width: %d\n", bitwidth);
|
||||
return bitwidth;
|
||||
}
|
||||
|
||||
ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x00, 0x0, 0x2, bitwidth);
|
||||
if (ret) {
|
||||
dev_err(card->dev, "failed to set tdm slot\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_dai_set_pll(codec_dai, RT5682S_PLL1, RT5682S_PLL_S_BCLK1,
|
||||
rate * 32, rate * 512);
|
||||
if (ret) {
|
||||
dev_err(card->dev, "failed to set pll\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_info(card->dev, "%s set mclk rate: %d\n", __func__, rate * 512);
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, RT5682S_SCLK_S_MCLK,
|
||||
rate * 512, SND_SOC_CLOCK_IN);
|
||||
if (ret) {
|
||||
dev_err(card->dev, "failed to set sysclk\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return snd_soc_dai_set_sysclk(cpu_dai, 0, rate * 512,
|
||||
SND_SOC_CLOCK_OUT);
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops mt8196_rt5682s_i2s_ops = {
|
||||
.hw_params = mt8196_rt5682s_i2s_hw_params,
|
||||
};
|
||||
|
||||
static int mt8196_nau8825_soc_card_probe(struct mtk_soc_card_data *soc_card_data, bool legacy)
|
||||
{
|
||||
struct snd_soc_card *card = soc_card_data->card_data->card;
|
||||
struct snd_soc_dai_link *dai_link;
|
||||
bool init_nau8825 = false;
|
||||
bool init_rt5682s = false;
|
||||
bool init_rt5650 = false;
|
||||
bool init_dumb = false;
|
||||
int i;
|
||||
|
||||
dev_info(card->dev, "legacy: %d\n", legacy);
|
||||
|
||||
for_each_card_prelinks(card, i, dai_link) {
|
||||
if (strcmp(dai_link->name, "TDM_DPTX_BE") == 0) {
|
||||
if (dai_link->num_codecs &&
|
||||
strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai"))
|
||||
dai_link->init = mt8196_dptx_codec_init;
|
||||
} else if (strcmp(dai_link->name, "I2SOUT3_BE") == 0) {
|
||||
if (dai_link->num_codecs &&
|
||||
strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai"))
|
||||
dai_link->init = mt8196_hdmi_codec_init;
|
||||
} else if (strcmp(dai_link->name, "I2SOUT6_BE") == 0 ||
|
||||
strcmp(dai_link->name, "I2SIN6_BE") == 0) {
|
||||
if (!strcmp(dai_link->codecs->dai_name, NAU8825_CODEC_DAI)) {
|
||||
dai_link->ops = &mt8196_nau8825_ops;
|
||||
if (!init_nau8825) {
|
||||
dai_link->init = mt8196_headset_codec_init;
|
||||
dai_link->exit = mt8196_headset_codec_exit;
|
||||
init_nau8825 = true;
|
||||
}
|
||||
} else if (!strcmp(dai_link->codecs->dai_name, RT5682S_CODEC_DAI)) {
|
||||
dai_link->ops = &mt8196_rt5682s_i2s_ops;
|
||||
if (!init_rt5682s) {
|
||||
dai_link->init = mt8196_headset_codec_init;
|
||||
dai_link->exit = mt8196_headset_codec_exit;
|
||||
init_rt5682s = true;
|
||||
}
|
||||
} else if (!strcmp(dai_link->codecs->dai_name, RT5650_CODEC_DAI)) {
|
||||
dai_link->ops = &mt8196_rt5682s_i2s_ops;
|
||||
if (!init_rt5650) {
|
||||
dai_link->init = mt8196_headset_codec_init;
|
||||
dai_link->exit = mt8196_headset_codec_exit;
|
||||
init_rt5650 = true;
|
||||
}
|
||||
} else {
|
||||
if (strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai")) {
|
||||
if (!init_dumb) {
|
||||
dai_link->init = mt8196_dumb_amp_init;
|
||||
init_dumb = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct mtk_sof_priv mt8196_sof_priv = {
|
||||
.conn_streams = g_sof_conn_streams,
|
||||
.num_streams = ARRAY_SIZE(g_sof_conn_streams),
|
||||
};
|
||||
|
||||
static struct snd_soc_card mt8196_nau8825_soc_card = {
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = mt8196_nau8825_dai_links,
|
||||
.num_links = ARRAY_SIZE(mt8196_nau8825_dai_links),
|
||||
.dapm_widgets = mt8196_nau8825_card_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(mt8196_nau8825_card_widgets),
|
||||
.dapm_routes = mt8196_nau8825_card_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(mt8196_nau8825_card_routes),
|
||||
.controls = mt8196_nau8825_card_controls,
|
||||
.num_controls = ARRAY_SIZE(mt8196_nau8825_card_controls),
|
||||
};
|
||||
|
||||
static const struct mtk_soundcard_pdata mt8196_nau8825_card = {
|
||||
.card_name = "mt8196_nau8825",
|
||||
.card_data = &(struct mtk_platform_card_data) {
|
||||
.card = &mt8196_nau8825_soc_card,
|
||||
.num_jacks = MT8196_JACK_MAX,
|
||||
.flags = NAU8825_HS_PRESENT
|
||||
},
|
||||
.sof_priv = &mt8196_sof_priv,
|
||||
.soc_probe = mt8196_nau8825_soc_card_probe,
|
||||
};
|
||||
|
||||
static const struct mtk_soundcard_pdata mt8196_rt5682s_card = {
|
||||
.card_name = "mt8196_rt5682s",
|
||||
.card_data = &(struct mtk_platform_card_data) {
|
||||
.card = &mt8196_nau8825_soc_card,
|
||||
.num_jacks = MT8196_JACK_MAX,
|
||||
.flags = RT5682S_HS_PRESENT
|
||||
},
|
||||
.sof_priv = &mt8196_sof_priv,
|
||||
.soc_probe = mt8196_nau8825_soc_card_probe,
|
||||
};
|
||||
|
||||
static const struct mtk_soundcard_pdata mt8196_rt5650_card = {
|
||||
.card_name = "mt8196_rt5650",
|
||||
.card_data = &(struct mtk_platform_card_data) {
|
||||
.card = &mt8196_nau8825_soc_card,
|
||||
.num_jacks = MT8196_JACK_MAX,
|
||||
.flags = RT5650_HS_PRESENT
|
||||
},
|
||||
.sof_priv = &mt8196_sof_priv,
|
||||
.soc_probe = mt8196_nau8825_soc_card_probe,
|
||||
};
|
||||
|
||||
static const struct of_device_id mt8196_nau8825_dt_match[] = {
|
||||
{.compatible = "mediatek,mt8196-nau8825-sound", .data = &mt8196_nau8825_card,},
|
||||
{.compatible = "mediatek,mt8196-rt5682s-sound", .data = &mt8196_rt5682s_card,},
|
||||
{.compatible = "mediatek,mt8196-rt5650-sound", .data = &mt8196_rt5650_card,},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mt8196_nau8825_dt_match);
|
||||
|
||||
static struct platform_driver mt8196_nau8825_driver = {
|
||||
.driver = {
|
||||
.name = "mt8196-nau8825",
|
||||
.of_match_table = mt8196_nau8825_dt_match,
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = mtk_soundcard_common_probe,
|
||||
};
|
||||
module_platform_driver(mt8196_nau8825_driver);
|
||||
|
||||
/* Module information */
|
||||
MODULE_DESCRIPTION("MT8196 nau8825 ALSA SoC machine driver");
|
||||
MODULE_AUTHOR("Darren Ye <darren.ye@mediatek.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("mt8196 nau8825 soc card");
|
||||
|
||||
12068
sound/soc/mediatek/mt8196/mt8196-reg.h
Normal file
12068
sound/soc/mediatek/mt8196/mt8196-reg.h
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user