From patchwork Sun Mar 13 15:10:07 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?SmlheGluIFl1ICjkv57lrrbpkasp?= X-Patchwork-Id: 550996 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2BAE1C433EF for ; Sun, 13 Mar 2022 15:10:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234739AbiCMPLr (ORCPT ); Sun, 13 Mar 2022 11:11:47 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38936 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234735AbiCMPLr (ORCPT ); Sun, 13 Mar 2022 11:11:47 -0400 Received: from mailgw01.mediatek.com (unknown [60.244.123.138]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B377C85944; Sun, 13 Mar 2022 08:10:37 -0700 (PDT) X-UUID: 03739023df0046fe94754a751c4f215f-20220313 X-UUID: 03739023df0046fe94754a751c4f215f-20220313 Received: from mtkexhb01.mediatek.inc [(172.21.101.102)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 539636030; Sun, 13 Mar 2022 23:10:30 +0800 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkmbs10n2.mediatek.inc (172.21.101.183) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.2.792.3; Sun, 13 Mar 2022 23:10:28 +0800 Received: from localhost.localdomain (10.17.3.154) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sun, 13 Mar 2022 23:10:27 +0800 From: Jiaxin Yu To: , , CC: , , , , , , , , , , , Jiaxin Yu Subject: [v3 03/19] ASoC: mediatek: mt8186: support audsys clock control Date: Sun, 13 Mar 2022 23:10:07 +0800 Message-ID: <20220313151023.21229-4-jiaxin.yu@mediatek.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220313151023.21229-1-jiaxin.yu@mediatek.com> References: <20220313151023.21229-1-jiaxin.yu@mediatek.com> MIME-Version: 1.0 X-MTK: N Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Add mt8186 audio cg control. Audio clock gates are registered to CCF for reference count and clock parent management. Signed-off-by: Jiaxin Yu --- sound/soc/mediatek/mt8186/mt8186-audsys-clk.c | 150 ++++++++++++++++++ sound/soc/mediatek/mt8186/mt8186-audsys-clk.h | 15 ++ .../soc/mediatek/mt8186/mt8186-audsys-clkid.h | 45 ++++++ 3 files changed, 210 insertions(+) create mode 100644 sound/soc/mediatek/mt8186/mt8186-audsys-clk.c create mode 100644 sound/soc/mediatek/mt8186/mt8186-audsys-clk.h create mode 100644 sound/soc/mediatek/mt8186/mt8186-audsys-clkid.h diff --git a/sound/soc/mediatek/mt8186/mt8186-audsys-clk.c b/sound/soc/mediatek/mt8186/mt8186-audsys-clk.c new file mode 100644 index 000000000000..578969ca91c8 --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-audsys-clk.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// mt8186-audsys-clk.h -- Mediatek 8186 audsys clock control +// +// Copyright (c) 2022 MediaTek Inc. +// Author: Jiaxin Yu + +#include +#include +#include +#include "mt8186-afe-common.h" +#include "mt8186-audsys-clk.h" +#include "mt8186-audsys-clkid.h" +#include "mt8186-reg.h" + +struct afe_gate { + int id; + const char *name; + const char *parent_name; + int reg; + u8 bit; + const struct clk_ops *ops; + unsigned long flags; + u8 cg_flags; +}; + +#define GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit, _flags, _cgflags) {\ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .reg = _reg, \ + .bit = _bit, \ + .flags = _flags, \ + .cg_flags = _cgflags, \ + } + +#define GATE_AFE(_id, _name, _parent, _reg, _bit) \ + GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit, \ + CLK_SET_RATE_PARENT, CLK_GATE_SET_TO_DISABLE) + +#define GATE_AUD0(_id, _name, _parent, _bit) \ + GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON0, _bit) + +#define GATE_AUD1(_id, _name, _parent, _bit) \ + GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON1, _bit) + +#define GATE_AUD2(_id, _name, _parent, _bit) \ + GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON2, _bit) + +static const struct afe_gate aud_clks[CLK_AUD_NR_CLK] = { + /* AUD0 */ + GATE_AUD0(CLK_AUD_AFE, "aud_afe_clk", "top_audio", 2), + GATE_AUD0(CLK_AUD_22M, "aud_apll22m_clk", "top_aud_engen1", 8), + GATE_AUD0(CLK_AUD_24M, "aud_apll24m_clk", "top_aud_engen2", 9), + GATE_AUD0(CLK_AUD_APLL2_TUNER, "aud_apll2_tuner_clk", "top_aud_engen2", 18), + GATE_AUD0(CLK_AUD_APLL_TUNER, "aud_apll_tuner_clk", "top_aud_engen1", 19), + GATE_AUD0(CLK_AUD_TDM, "aud_tdm_clk", "top_aud_1", 20), + GATE_AUD0(CLK_AUD_ADC, "aud_adc_clk", "top_audio", 24), + GATE_AUD0(CLK_AUD_DAC, "aud_dac_clk", "top_audio", 25), + GATE_AUD0(CLK_AUD_DAC_PREDIS, "aud_dac_predis_clk", "top_audio", 26), + GATE_AUD0(CLK_AUD_TML, "aud_tml_clk", "top_audio", 27), + GATE_AUD0(CLK_AUD_NLE, "aud_nle_clk", "top_audio", 28), + + /* AUD1 */ + GATE_AUD1(CLK_AUD_I2S1_BCLK, "aud_i2s1_bclk", "top_audio", 4), + GATE_AUD1(CLK_AUD_I2S2_BCLK, "aud_i2s2_bclk", "top_audio", 5), + GATE_AUD1(CLK_AUD_I2S3_BCLK, "aud_i2s3_bclk", "top_audio", 6), + GATE_AUD1(CLK_AUD_I2S4_BCLK, "aud_i2s4_bclk", "top_audio", 7), + GATE_AUD1(CLK_AUD_CONNSYS_I2S_ASRC, "aud_connsys_i2s_asrc", "top_audio", 12), + GATE_AUD1(CLK_AUD_GENERAL1_ASRC, "aud_general1_asrc", "top_audio", 13), + GATE_AUD1(CLK_AUD_GENERAL2_ASRC, "aud_general2_asrc", "top_audio", 14), + GATE_AUD1(CLK_AUD_DAC_HIRES, "aud_dac_hires_clk", "top_audio_h", 15), + GATE_AUD1(CLK_AUD_ADC_HIRES, "aud_adc_hires_clk", "top_audio_h", 16), + GATE_AUD1(CLK_AUD_ADC_HIRES_TML, "aud_adc_hires_tml", "top_audio_h", 17), + GATE_AUD1(CLK_AUD_ADDA6_ADC, "aud_adda6_adc", "top_audio", 20), + GATE_AUD1(CLK_AUD_ADDA6_ADC_HIRES, "aud_adda6_adc_hires", "top_audio_h", 21), + GATE_AUD1(CLK_AUD_3RD_DAC, "aud_3rd_dac", "top_audio", 28), + GATE_AUD1(CLK_AUD_3RD_DAC_PREDIS, "aud_3rd_dac_predis", "top_audio", 29), + GATE_AUD1(CLK_AUD_3RD_DAC_TML, "aud_3rd_dac_tml", "top_audio", 30), + GATE_AUD1(CLK_AUD_3RD_DAC_HIRES, "aud_3rd_dac_hires", "top_audio_h", 31), + + /* AUD2 */ + GATE_AUD2(CLK_AUD_ETDM_IN1_BCLK, "aud_etdm_in1_bclk", "top_audio", 23), + GATE_AUD2(CLK_AUD_ETDM_OUT1_BCLK, "aud_etdm_out1_bclk", "top_audio", 24), +}; + +int mt8186_audsys_clk_register(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + struct clk *clk; + struct clk_lookup *cl; + int i; + + afe_priv->lookup = devm_kcalloc(afe->dev, CLK_AUD_NR_CLK, + sizeof(*afe_priv->lookup), + GFP_KERNEL); + + if (!afe_priv->lookup) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(aud_clks); i++) { + const struct afe_gate *gate = &aud_clks[i]; + + clk = clk_register_gate(afe->dev, gate->name, gate->parent_name, + gate->flags, afe->base_addr + gate->reg, + gate->bit, gate->cg_flags, NULL); + + if (IS_ERR(clk)) { + dev_err(afe->dev, "Failed to register clk %s: %ld\n", + gate->name, PTR_ERR(clk)); + continue; + } + + /* add clk_lookup for devm_clk_get(SND_SOC_DAPM_CLOCK_SUPPLY) */ + cl = kzalloc(sizeof(*cl), GFP_KERNEL); + if (!cl) + return -ENOMEM; + + cl->clk = clk; + cl->con_id = gate->name; + cl->dev_id = dev_name(afe->dev); + clkdev_add(cl); + + afe_priv->lookup[i] = cl; + } + + return 0; +} + +void mt8186_audsys_clk_unregister(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + struct clk *clk; + struct clk_lookup *cl; + int i; + + if (!afe_priv) + return; + + for (i = 0; i < CLK_AUD_NR_CLK; i++) { + cl = afe_priv->lookup[i]; + if (!cl) + continue; + + clk = cl->clk; + clk_unregister_gate(clk); + + clkdev_drop(cl); + } +} diff --git a/sound/soc/mediatek/mt8186/mt8186-audsys-clk.h b/sound/soc/mediatek/mt8186/mt8186-audsys-clk.h new file mode 100644 index 000000000000..b8d6a06e11e8 --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-audsys-clk.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * mt8186-audsys-clk.h -- Mediatek 8186 audsys clock definition + * + * Copyright (c) 2022 MediaTek Inc. + * Author: Trevor Wu + */ + +#ifndef _MT8186_AUDSYS_CLK_H_ +#define _MT8186_AUDSYS_CLK_H_ + +int mt8186_audsys_clk_register(struct mtk_base_afe *afe); +void mt8186_audsys_clk_unregister(struct mtk_base_afe *afe); + +#endif diff --git a/sound/soc/mediatek/mt8186/mt8186-audsys-clkid.h b/sound/soc/mediatek/mt8186/mt8186-audsys-clkid.h new file mode 100644 index 000000000000..3ce5937c1823 --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-audsys-clkid.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * mt8186-audsys-clkid.h -- Mediatek 8186 audsys clock id definition + * + * Copyright (c) 2022 MediaTek Inc. + * Author: Jiaxin Yu + */ + +#ifndef _MT8186_AUDSYS_CLKID_H_ +#define _MT8186_AUDSYS_CLKID_H_ + +enum{ + CLK_AUD_AFE, + CLK_AUD_22M, + CLK_AUD_24M, + CLK_AUD_APLL2_TUNER, + CLK_AUD_APLL_TUNER, + CLK_AUD_TDM, + CLK_AUD_ADC, + CLK_AUD_DAC, + CLK_AUD_DAC_PREDIS, + CLK_AUD_TML, + CLK_AUD_NLE, + CLK_AUD_I2S1_BCLK, + CLK_AUD_I2S2_BCLK, + CLK_AUD_I2S3_BCLK, + CLK_AUD_I2S4_BCLK, + CLK_AUD_CONNSYS_I2S_ASRC, + CLK_AUD_GENERAL1_ASRC, + CLK_AUD_GENERAL2_ASRC, + CLK_AUD_DAC_HIRES, + CLK_AUD_ADC_HIRES, + CLK_AUD_ADC_HIRES_TML, + CLK_AUD_ADDA6_ADC, + CLK_AUD_ADDA6_ADC_HIRES, + CLK_AUD_3RD_DAC, + CLK_AUD_3RD_DAC_PREDIS, + CLK_AUD_3RD_DAC_TML, + CLK_AUD_3RD_DAC_HIRES, + CLK_AUD_ETDM_IN1_BCLK, + CLK_AUD_ETDM_OUT1_BCLK, + CLK_AUD_NR_CLK, +}; + +#endif From patchwork Sun Mar 13 15:10:08 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?SmlheGluIFl1ICjkv57lrrbpkasp?= X-Patchwork-Id: 550995 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E1EDBC433EF for ; Sun, 13 Mar 2022 15:10:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234753AbiCMPLv (ORCPT ); Sun, 13 Mar 2022 11:11:51 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39066 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234743AbiCMPLs (ORCPT ); Sun, 13 Mar 2022 11:11:48 -0400 Received: from mailgw01.mediatek.com (unknown [60.244.123.138]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BD0E88567E; Sun, 13 Mar 2022 08:10:39 -0700 (PDT) X-UUID: fa25f7cd7b0c40d68ec17f85c2465ade-20220313 X-UUID: fa25f7cd7b0c40d68ec17f85c2465ade-20220313 Received: from mtkcas11.mediatek.inc [(172.21.101.40)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 1974082692; Sun, 13 Mar 2022 23:10:31 +0800 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkmbs07n1.mediatek.inc (172.21.101.16) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sun, 13 Mar 2022 23:10:29 +0800 Received: from localhost.localdomain (10.17.3.154) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sun, 13 Mar 2022 23:10:28 +0800 From: Jiaxin Yu To: , , CC: , , , , , , , , , , , Jiaxin Yu Subject: [v3 04/19] ASoC: mediatek: mt8186: support adda in platform driver Date: Sun, 13 Mar 2022 23:10:08 +0800 Message-ID: <20220313151023.21229-5-jiaxin.yu@mediatek.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220313151023.21229-1-jiaxin.yu@mediatek.com> References: <20220313151023.21229-1-jiaxin.yu@mediatek.com> MIME-Version: 1.0 X-MTK: N Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Add mt8186 adda dai driver. Signed-off-by: Jiaxin Yu --- sound/soc/mediatek/mt8186/mt8186-dai-adda.c | 878 ++++++++++++++++++++ 1 file changed, 878 insertions(+) create mode 100644 sound/soc/mediatek/mt8186/mt8186-dai-adda.c diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-adda.c b/sound/soc/mediatek/mt8186/mt8186-dai-adda.c new file mode 100644 index 000000000000..1af4109495bb --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-dai-adda.c @@ -0,0 +1,878 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MediaTek ALSA SoC Audio DAI ADDA Control +// +// Copyright (c) 2022 MediaTek Inc. +// Author: Jiaxin Yu + +#include +#include +#include "mt8186-afe-clk.h" +#include "mt8186-afe-common.h" +#include "mt8186-afe-gpio.h" +#include "mt8186-interconnection.h" + +enum { + UL_IIR_SW = 0, + UL_IIR_5HZ, + UL_IIR_10HZ, + UL_IIR_25HZ, + UL_IIR_50HZ, + UL_IIR_75HZ, +}; + +enum { + AUDIO_SDM_LEVEL_MUTE = 0, + AUDIO_SDM_LEVEL_NORMAL = 0x1d, + /* if you change level normal */ + /* you need to change formula of hp impedance and dc trim too */ +}; + +enum { + AUDIO_SDM_2ND = 0, + AUDIO_SDM_3RD, +}; + +enum { + DELAY_DATA_MISO1 = 0, + DELAY_DATA_MISO2, +}; + +enum { + MTK_AFE_ADDA_DL_RATE_8K = 0, + MTK_AFE_ADDA_DL_RATE_11K = 1, + MTK_AFE_ADDA_DL_RATE_12K = 2, + MTK_AFE_ADDA_DL_RATE_16K = 3, + MTK_AFE_ADDA_DL_RATE_22K = 4, + MTK_AFE_ADDA_DL_RATE_24K = 5, + MTK_AFE_ADDA_DL_RATE_32K = 6, + MTK_AFE_ADDA_DL_RATE_44K = 7, + MTK_AFE_ADDA_DL_RATE_48K = 8, + MTK_AFE_ADDA_DL_RATE_96K = 9, + MTK_AFE_ADDA_DL_RATE_192K = 10, +}; + +enum { + MTK_AFE_ADDA_UL_RATE_8K = 0, + MTK_AFE_ADDA_UL_RATE_16K = 1, + MTK_AFE_ADDA_UL_RATE_32K = 2, + MTK_AFE_ADDA_UL_RATE_48K = 3, + MTK_AFE_ADDA_UL_RATE_96K = 4, + MTK_AFE_ADDA_UL_RATE_192K = 5, + MTK_AFE_ADDA_UL_RATE_48K_HD = 6, +}; + +#define SDM_AUTO_RESET_THRESHOLD 0x190000 + +struct mtk_afe_adda_priv { + int dl_rate; + int ul_rate; +}; + +static struct mtk_afe_adda_priv *get_adda_priv_by_name(struct mtk_base_afe *afe, + const char *name) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int dai_id; + + if (strncmp(name, "aud_dac_hires_clk", 7) == 0 || + strncmp(name, "aud_adc_hires_clk", 7) == 0) + dai_id = MT8186_DAI_ADDA; + else + return NULL; + + return afe_priv->dai_priv[dai_id]; +} + +static unsigned int adda_dl_rate_transform(struct mtk_base_afe *afe, + unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_ADDA_DL_RATE_8K; + case 11025: + return MTK_AFE_ADDA_DL_RATE_11K; + case 12000: + return MTK_AFE_ADDA_DL_RATE_12K; + case 16000: + return MTK_AFE_ADDA_DL_RATE_16K; + case 22050: + return MTK_AFE_ADDA_DL_RATE_22K; + case 24000: + return MTK_AFE_ADDA_DL_RATE_24K; + case 32000: + return MTK_AFE_ADDA_DL_RATE_32K; + case 44100: + return MTK_AFE_ADDA_DL_RATE_44K; + case 48000: + return MTK_AFE_ADDA_DL_RATE_48K; + case 96000: + return MTK_AFE_ADDA_DL_RATE_96K; + case 192000: + return MTK_AFE_ADDA_DL_RATE_192K; + default: + dev_info(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n", + __func__, rate); + } + + return MTK_AFE_ADDA_DL_RATE_48K; +} + +static unsigned int adda_ul_rate_transform(struct mtk_base_afe *afe, + unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_ADDA_UL_RATE_8K; + case 16000: + return MTK_AFE_ADDA_UL_RATE_16K; + case 32000: + return MTK_AFE_ADDA_UL_RATE_32K; + case 48000: + return MTK_AFE_ADDA_UL_RATE_48K; + case 96000: + return MTK_AFE_ADDA_UL_RATE_96K; + case 192000: + return MTK_AFE_ADDA_UL_RATE_192K; + default: + dev_info(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n", + __func__, rate); + } + + return MTK_AFE_ADDA_UL_RATE_48K; +} + +/* dai component */ +static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN3, I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1 Switch", AFE_CONN3, I_DL12_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN3, I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN3, I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN3_1, I_DL4_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN3_1, I_DL5_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1 Switch", AFE_CONN3_1, I_DL6_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1 Switch", AFE_CONN3_1, I_DL8_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN3, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN3, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1 Switch", AFE_CONN3, + I_GAIN1_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1 Switch", AFE_CONN3, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1 Switch", AFE_CONN3, + I_PCM_2_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH1 Switch", AFE_CONN3_1, + I_SRC_1_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("SRC_2_OUT_CH1 Switch", AFE_CONN3_1, + I_SRC_2_OUT_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_adda_dl_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN4, I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN4, I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN4, I_DL12_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN4, I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN4, I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN4, I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN4, I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN4_1, I_DL4_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN4_1, I_DL5_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2 Switch", AFE_CONN4_1, I_DL6_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2 Switch", AFE_CONN4_1, I_DL8_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN4, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN4, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2 Switch", AFE_CONN4, + I_GAIN1_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1 Switch", AFE_CONN4, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2 Switch", AFE_CONN4, + I_PCM_1_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH2 Switch", AFE_CONN4_1, + I_SRC_1_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("SRC_2_OUT_CH2 Switch", AFE_CONN4_1, + I_SRC_2_OUT_CH2, 1, 0), +}; + +enum { + SUPPLY_SEQ_ADDA_AFE_ON, + SUPPLY_SEQ_ADDA_DL_ON, + SUPPLY_SEQ_ADDA_AUD_PAD_TOP, + SUPPLY_SEQ_ADDA_MTKAIF_CFG, + SUPPLY_SEQ_ADDA_FIFO, + SUPPLY_SEQ_ADDA_AP_DMIC, + SUPPLY_SEQ_ADDA_UL_ON, +}; + +static int mtk_adda_ul_src_dmic(struct mtk_base_afe *afe, int id) +{ + unsigned int reg; + + switch (id) { + case MT8186_DAI_ADDA: + case MT8186_DAI_AP_DMIC: + reg = AFE_ADDA_UL_SRC_CON0; + break; + default: + return -EINVAL; + } + + /* dmic mode, 3.25M*/ + regmap_update_bits(afe->regmap, reg, + DIGMIC_3P25M_1P625M_SEL_MASK_SFT, 0); + regmap_update_bits(afe->regmap, reg, + DMIC_LOW_POWER_CTL_MASK_SFT, 0); + + /* turn on dmic, ch1, ch2 */ + regmap_update_bits(afe->regmap, reg, + UL_SDM_3_LEVEL_MASK_SFT, + BIT(UL_SDM_3_LEVEL_SFT)); + regmap_update_bits(afe->regmap, reg, + UL_MODE_3P25M_CH1_CTL_MASK_SFT, + BIT(UL_MODE_3P25M_CH1_CTL_SFT)); + regmap_update_bits(afe->regmap, reg, + UL_MODE_3P25M_CH2_CTL_MASK_SFT, + BIT(UL_MODE_3P25M_CH2_CTL_SFT)); + + return 0; +} + +static int mtk_adda_ul_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int mtkaif_dmic = afe_priv->mtkaif_dmic; + + dev_dbg(afe->dev, "%s(), name %s, event 0x%x, mtkaif_dmic %d\n", + __func__, w->name, event, mtkaif_dmic); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8186_afe_gpio_request(afe->dev, true, MT8186_DAI_ADDA, 1); + + /* update setting to dmic */ + if (mtkaif_dmic) { + /* mtkaif_rxif_data_mode = 1, dmic */ + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_RX_CFG0, + 0x1, 0x1); + + /* dmic mode, 3.25M*/ + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_RX_CFG0, + MTKAIF_RXIF_VOICE_MODE_MASK_SFT, + 0x0); + mtk_adda_ul_src_dmic(afe, MT8186_DAI_ADDA); + } + break; + case SND_SOC_DAPM_POST_PMD: + /* should delayed 1/fs(smallest is 8k) = 125us before afe off */ + usleep_range(125, 135); + mt8186_afe_gpio_request(afe->dev, false, MT8186_DAI_ADDA, 1); + + /* reset dmic */ + afe_priv->mtkaif_dmic = 0; + break; + default: + break; + } + + return 0; +} + +static int mtk_adda_pad_top_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2) + regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x38); + else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2) + regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x30); + else + regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x30); + break; + default: + break; + } + + return 0; +} + +static int mtk_adda_mtkaif_cfg_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int delay_data; + int delay_cycle; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2) { + /* set protocol 2 */ + regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0, 0x10000); + /* mtkaif_rxif_clkinv_adc inverse */ + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_CFG0, + MTKAIF_RXIF_CLKINV_ADC_MASK_SFT, + BIT(MTKAIF_RXIF_CLKINV_ADC_SFT)); + + if (strcmp(w->name, "ADDA_MTKAIF_CFG") == 0) { + if (afe_priv->mtkaif_chosen_phase[0] < 0 && + afe_priv->mtkaif_chosen_phase[1] < 0) { + dev_err(afe->dev, + "%s(), calib fail mtkaif_chosen_phase[0/1]:%d/%d\n", + __func__, + afe_priv->mtkaif_chosen_phase[0], + afe_priv->mtkaif_chosen_phase[1]); + break; + } + + if (afe_priv->mtkaif_chosen_phase[0] < 0 || + afe_priv->mtkaif_chosen_phase[1] < 0) { + dev_err(afe->dev, + "%s(), skip dealy setting mtkaif_chosen_phase[0/1]:%d/%d\n", + __func__, + afe_priv->mtkaif_chosen_phase[0], + afe_priv->mtkaif_chosen_phase[1]); + break; + } + } + + /* set delay for ch12 */ + if (afe_priv->mtkaif_phase_cycle[0] >= + afe_priv->mtkaif_phase_cycle[1]) { + delay_data = DELAY_DATA_MISO1; + delay_cycle = afe_priv->mtkaif_phase_cycle[0] - + afe_priv->mtkaif_phase_cycle[1]; + } else { + delay_data = DELAY_DATA_MISO2; + delay_cycle = afe_priv->mtkaif_phase_cycle[1] - + afe_priv->mtkaif_phase_cycle[0]; + } + + regmap_update_bits(afe->regmap, + AFE_ADDA_MTKAIF_RX_CFG2, + MTKAIF_RXIF_DELAY_DATA_MASK_SFT, + delay_data << + MTKAIF_RXIF_DELAY_DATA_SFT); + + regmap_update_bits(afe->regmap, + AFE_ADDA_MTKAIF_RX_CFG2, + MTKAIF_RXIF_DELAY_CYCLE_MASK_SFT, + delay_cycle << + MTKAIF_RXIF_DELAY_CYCLE_SFT); + + } else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2) { + regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0, 0x10000); + } else { + regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0, 0); + } + + break; + default: + break; + } + + return 0; +} + +static int mtk_adda_dl_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8186_afe_gpio_request(afe->dev, true, MT8186_DAI_ADDA, 0); + break; + case SND_SOC_DAPM_POST_PMD: + /* should delayed 1/fs(smallest is 8k) = 125us before afe off */ + usleep_range(125, 135); + mt8186_afe_gpio_request(afe->dev, false, MT8186_DAI_ADDA, 0); + break; + default: + break; + } + + return 0; +} + +static int mt8186_adda_dmic_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + + ucontrol->value.integer.value[0] = afe_priv->mtkaif_dmic; + + return 0; +} + +static int mt8186_adda_dmic_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int dmic_on; + + if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + + dmic_on = ucontrol->value.integer.value[0]; + + dev_dbg(afe->dev, "%s(), kcontrol name %s, dmic_on %d\n", + __func__, kcontrol->id.name, dmic_on); + + if (afe_priv->mtkaif_dmic == dmic_on) + return 0; + + afe_priv->mtkaif_dmic = dmic_on; + + return 1; +} + +static const struct snd_kcontrol_new mtk_adda_controls[] = { + SOC_SINGLE("ADDA_DL_GAIN", AFE_ADDA_DL_SRC2_CON1, + DL_2_GAIN_CTL_PRE_SFT, DL_2_GAIN_CTL_PRE_MASK, 0), + SOC_SINGLE_BOOL_EXT("MTKAIF_DMIC Switch", 0, + mt8186_adda_dmic_get, mt8186_adda_dmic_set), +}; + +/* ADDA UL MUX */ +enum { + ADDA_UL_MUX_MTKAIF = 0, + ADDA_UL_MUX_AP_DMIC, + ADDA_UL_MUX_MASK = 0x1, +}; + +static const char * const adda_ul_mux_map[] = { + "MTKAIF", "AP_DMIC" +}; + +static int adda_ul_map_value[] = { + ADDA_UL_MUX_MTKAIF, + ADDA_UL_MUX_AP_DMIC, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(adda_ul_mux_map_enum, + SND_SOC_NOPM, + 0, + ADDA_UL_MUX_MASK, + adda_ul_mux_map, + adda_ul_map_value); + +static const struct snd_kcontrol_new adda_ul_mux_control = + SOC_DAPM_ENUM("ADDA_UL_MUX Select", adda_ul_mux_map_enum); + +static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = { + /* inter-connections */ + SND_SOC_DAPM_MIXER("ADDA_DL_CH1", SND_SOC_NOPM, 0, 0, + mtk_adda_dl_ch1_mix, + ARRAY_SIZE(mtk_adda_dl_ch1_mix)), + SND_SOC_DAPM_MIXER("ADDA_DL_CH2", SND_SOC_NOPM, 0, 0, + mtk_adda_dl_ch2_mix, + ARRAY_SIZE(mtk_adda_dl_ch2_mix)), + + SND_SOC_DAPM_SUPPLY_S("ADDA Enable", SUPPLY_SEQ_ADDA_AFE_ON, + AFE_ADDA_UL_DL_CON0, ADDA_AFE_ON_SFT, 0, + NULL, 0), + + SND_SOC_DAPM_SUPPLY_S("ADDA Playback Enable", SUPPLY_SEQ_ADDA_DL_ON, + AFE_ADDA_DL_SRC2_CON0, + DL_2_SRC_ON_CTL_PRE_SFT, 0, + mtk_adda_dl_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("ADDA Capture Enable", SUPPLY_SEQ_ADDA_UL_ON, + AFE_ADDA_UL_SRC_CON0, + UL_SRC_ON_CTL_SFT, 0, + mtk_adda_ul_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("AUD_PAD_TOP", SUPPLY_SEQ_ADDA_AUD_PAD_TOP, + AFE_AUD_PAD_TOP, + RG_RX_FIFO_ON_SFT, 0, + mtk_adda_pad_top_event, + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY_S("ADDA_MTKAIF_CFG", SUPPLY_SEQ_ADDA_MTKAIF_CFG, + SND_SOC_NOPM, 0, 0, + mtk_adda_mtkaif_cfg_event, + SND_SOC_DAPM_PRE_PMU), + + SND_SOC_DAPM_SUPPLY_S("AP_DMIC_EN", SUPPLY_SEQ_ADDA_AP_DMIC, + AFE_ADDA_UL_SRC_CON0, + UL_AP_DMIC_ON_SFT, 0, + NULL, 0), + + SND_SOC_DAPM_SUPPLY_S("ADDA_FIFO", SUPPLY_SEQ_ADDA_FIFO, + AFE_ADDA_UL_DL_CON0, + AFE_ADDA_FIFO_AUTO_RST_SFT, 1, + NULL, 0), + + SND_SOC_DAPM_MUX("ADDA_UL_Mux", SND_SOC_NOPM, 0, 0, + &adda_ul_mux_control), + + SND_SOC_DAPM_INPUT("AP_DMIC_INPUT"), + + /* clock */ + SND_SOC_DAPM_CLOCK_SUPPLY("top_mux_audio_h"), + + SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_clk"), + SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_hires_clk"), + SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_predis_clk"), + + SND_SOC_DAPM_CLOCK_SUPPLY("aud_adc_clk"), + SND_SOC_DAPM_CLOCK_SUPPLY("aud_adc_hires_clk"), +}; + +#define HIRES_THRESHOLD 48000 +static int mtk_afe_dac_hires_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = source; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_adda_priv *adda_priv; + + adda_priv = get_adda_priv_by_name(afe, w->name); + + if (!adda_priv) { + dev_err(afe->dev, "%s(), adda_priv == NULL", __func__); + return 0; + } + + return (adda_priv->dl_rate > HIRES_THRESHOLD) ? 1 : 0; +} + +static int mtk_afe_adc_hires_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = source; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_adda_priv *adda_priv; + + adda_priv = get_adda_priv_by_name(afe, w->name); + + if (!adda_priv) { + dev_err(afe->dev, "%s(), adda_priv == NULL", __func__); + return 0; + } + + return (adda_priv->ul_rate > HIRES_THRESHOLD) ? 1 : 0; +} + +static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = { + /* playback */ + {"ADDA_DL_CH1", "DL1_CH1 Switch", "DL1"}, + {"ADDA_DL_CH2", "DL1_CH1 Switch", "DL1"}, + {"ADDA_DL_CH2", "DL1_CH2 Switch", "DL1"}, + + {"ADDA_DL_CH1", "DL12_CH1 Switch", "DL12"}, + {"ADDA_DL_CH2", "DL12_CH2 Switch", "DL12"}, + + {"ADDA_DL_CH1", "DL6_CH1 Switch", "DL6"}, + {"ADDA_DL_CH2", "DL6_CH2 Switch", "DL6"}, + + {"ADDA_DL_CH1", "DL8_CH1 Switch", "DL8"}, + {"ADDA_DL_CH2", "DL8_CH2 Switch", "DL8"}, + + {"ADDA_DL_CH1", "DL2_CH1 Switch", "DL2"}, + {"ADDA_DL_CH2", "DL2_CH1 Switch", "DL2"}, + {"ADDA_DL_CH2", "DL2_CH2 Switch", "DL2"}, + + {"ADDA_DL_CH1", "DL3_CH1 Switch", "DL3"}, + {"ADDA_DL_CH2", "DL3_CH1 Switch", "DL3"}, + {"ADDA_DL_CH2", "DL3_CH2 Switch", "DL3"}, + + {"ADDA_DL_CH1", "DL4_CH1 Switch", "DL4"}, + {"ADDA_DL_CH2", "DL4_CH2 Switch", "DL4"}, + + {"ADDA_DL_CH1", "DL5_CH1 Switch", "DL5"}, + {"ADDA_DL_CH2", "DL5_CH2 Switch", "DL5"}, + + {"ADDA Playback", NULL, "ADDA_DL_CH1"}, + {"ADDA Playback", NULL, "ADDA_DL_CH2"}, + + {"ADDA Playback", NULL, "ADDA Enable"}, + {"ADDA Playback", NULL, "ADDA Playback Enable"}, + + /* capture */ + {"ADDA_UL_Mux", "MTKAIF", "ADDA Capture"}, + {"ADDA_UL_Mux", "AP_DMIC", "AP DMIC Capture"}, + + {"ADDA Capture", NULL, "ADDA Enable"}, + {"ADDA Capture", NULL, "ADDA Capture Enable"}, + {"ADDA Capture", NULL, "AUD_PAD_TOP"}, + {"ADDA Capture", NULL, "ADDA_MTKAIF_CFG"}, + + {"AP DMIC Capture", NULL, "ADDA Enable"}, + {"AP DMIC Capture", NULL, "ADDA Capture Enable"}, + {"AP DMIC Capture", NULL, "ADDA_FIFO"}, + {"AP DMIC Capture", NULL, "AP_DMIC_EN"}, + + {"AP DMIC Capture", NULL, "AP_DMIC_INPUT"}, + + /* clk */ + {"ADDA Playback", NULL, "aud_dac_clk"}, + {"ADDA Playback", NULL, "aud_dac_predis_clk"}, + {"ADDA Playback", NULL, "aud_dac_hires_clk", mtk_afe_dac_hires_connect}, + + {"ADDA Capture Enable", NULL, "aud_adc_clk"}, + {"ADDA Capture Enable", NULL, "aud_adc_hires_clk", + mtk_afe_adc_hires_connect}, + + /* hires source from apll1 */ + {"top_mux_audio_h", NULL, APLL2_W_NAME}, + + {"aud_dac_hires_clk", NULL, "top_mux_audio_h"}, + {"aud_adc_hires_clk", NULL, "top_mux_audio_h"}, +}; + +/* dai ops */ +static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + unsigned int rate = params_rate(params); + int id = dai->id; + struct mtk_afe_adda_priv *adda_priv = afe_priv->dai_priv[id]; + + dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n", + __func__, id, substream->stream, rate); + + if (!adda_priv) { + dev_err(afe->dev, "%s(), adda_priv == NULL", __func__); + return -EINVAL; + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + unsigned int dl_src2_con0; + unsigned int dl_src2_con1; + + adda_priv->dl_rate = rate; + + /* set sampling rate */ + dl_src2_con0 = adda_dl_rate_transform(afe, rate) << + DL_2_INPUT_MODE_CTL_SFT; + + /* set output mode, UP_SAMPLING_RATE_X8 */ + dl_src2_con0 |= (0x3 << DL_2_OUTPUT_SEL_CTL_SFT); + + /* turn off mute function */ + dl_src2_con0 |= BIT(DL_2_MUTE_CH2_OFF_CTL_PRE_SFT); + dl_src2_con0 |= BIT(DL_2_MUTE_CH1_OFF_CTL_PRE_SFT); + + /* set voice input data if input sample rate is 8k or 16k */ + if (rate == 8000 || rate == 16000) + dl_src2_con0 |= BIT(DL_2_VOICE_MODE_CTL_PRE_SFT); + + /* SA suggest apply -0.3db to audio/speech path */ + dl_src2_con1 = MTK_AFE_ADDA_DL_GAIN_NORMAL << + DL_2_GAIN_CTL_PRE_SFT; + + /* turn on down-link gain */ + dl_src2_con0 |= BIT(DL_2_GAIN_ON_CTL_PRE_SFT); + + if (id == MT8186_DAI_ADDA) { + /* clean predistortion */ + regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON0, 0); + regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON1, 0); + + regmap_write(afe->regmap, + AFE_ADDA_DL_SRC2_CON0, dl_src2_con0); + regmap_write(afe->regmap, + AFE_ADDA_DL_SRC2_CON1, dl_src2_con1); + + /* set sdm gain */ + regmap_update_bits(afe->regmap, + AFE_ADDA_DL_SDM_DCCOMP_CON, + ATTGAIN_CTL_MASK_SFT, + AUDIO_SDM_LEVEL_NORMAL << + ATTGAIN_CTL_SFT); + + /* Use new 2nd sdm */ + regmap_update_bits(afe->regmap, + AFE_ADDA_DL_SDM_DITHER_CON, + AFE_DL_SDM_DITHER_64TAP_EN_MASK_SFT, + BIT(AFE_DL_SDM_DITHER_64TAP_EN_SFT)); + regmap_update_bits(afe->regmap, + AFE_ADDA_DL_SDM_AUTO_RESET_CON, + AFE_DL_USE_NEW_2ND_SDM_MASK_SFT, + BIT(AFE_DL_USE_NEW_2ND_SDM_SFT)); + regmap_update_bits(afe->regmap, + AFE_ADDA_DL_SDM_DCCOMP_CON, + USE_3RD_SDM_MASK_SFT, + AUDIO_SDM_2ND << USE_3RD_SDM_SFT); + + /* sdm auto reset */ + regmap_write(afe->regmap, + AFE_ADDA_DL_SDM_AUTO_RESET_CON, + SDM_AUTO_RESET_THRESHOLD); + regmap_update_bits(afe->regmap, + AFE_ADDA_DL_SDM_AUTO_RESET_CON, + SDM_AUTO_RESET_TEST_ON_MASK_SFT, + BIT(SDM_AUTO_RESET_TEST_ON_SFT)); + } + } else { + unsigned int ul_src_con0 = 0; + unsigned int voice_mode = adda_ul_rate_transform(afe, rate); + + adda_priv->ul_rate = rate; + ul_src_con0 |= (voice_mode << 17) & (0x7 << 17); + + /* enable iir */ + ul_src_con0 |= (1 << UL_IIR_ON_TMP_CTL_SFT) & + UL_IIR_ON_TMP_CTL_MASK_SFT; + ul_src_con0 |= (UL_IIR_SW << UL_IIRMODE_CTL_SFT) & + UL_IIRMODE_CTL_MASK_SFT; + switch (id) { + case MT8186_DAI_ADDA: + case MT8186_DAI_AP_DMIC: + /* 35Hz @ 48k */ + regmap_write(afe->regmap, + AFE_ADDA_IIR_COEF_02_01, 0); + regmap_write(afe->regmap, + AFE_ADDA_IIR_COEF_04_03, 0x3fb8); + regmap_write(afe->regmap, + AFE_ADDA_IIR_COEF_06_05, 0x3fb80000); + regmap_write(afe->regmap, + AFE_ADDA_IIR_COEF_08_07, 0x3fb80000); + regmap_write(afe->regmap, + AFE_ADDA_IIR_COEF_10_09, 0xc048); + + regmap_write(afe->regmap, + AFE_ADDA_UL_SRC_CON0, ul_src_con0); + + /* Using Internal ADC */ + regmap_update_bits(afe->regmap, AFE_ADDA_TOP_CON0, BIT(0), 0); + + /* mtkaif_rxif_data_mode = 0, amic */ + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_RX_CFG0, BIT(0), 0); + break; + default: + break; + } + + /* ap dmic */ + switch (id) { + case MT8186_DAI_AP_DMIC: + mtk_adda_ul_src_dmic(afe, id); + break; + default: + break; + } + } + + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_adda_ops = { + .hw_params = mtk_dai_adda_hw_params, +}; + +/* dai driver */ +#define MTK_ADDA_PLAYBACK_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_ADDA_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\ + SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 |\ + SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_ADDA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_adda_driver[] = { + { + .name = "ADDA", + .id = MT8186_DAI_ADDA, + .playback = { + .stream_name = "ADDA Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ADDA_PLAYBACK_RATES, + .formats = MTK_ADDA_FORMATS, + }, + .capture = { + .stream_name = "ADDA Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ADDA_CAPTURE_RATES, + .formats = MTK_ADDA_FORMATS, + }, + .ops = &mtk_dai_adda_ops, + }, + { + .name = "AP_DMIC", + .id = MT8186_DAI_AP_DMIC, + .capture = { + .stream_name = "AP DMIC Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ADDA_CAPTURE_RATES, + .formats = MTK_ADDA_FORMATS, + }, + .ops = &mtk_dai_adda_ops, + }, +}; + +int mt8186_dai_adda_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int ret; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_adda_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver); + + dai->controls = mtk_adda_controls; + dai->num_controls = ARRAY_SIZE(mtk_adda_controls); + dai->dapm_widgets = mtk_dai_adda_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets); + dai->dapm_routes = mtk_dai_adda_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes); + + /* set dai priv */ + ret = mt8186_dai_set_priv(afe, MT8186_DAI_ADDA, + sizeof(struct mtk_afe_adda_priv), NULL); + if (ret) + return ret; + + /* ap dmic priv share with adda */ + afe_priv->dai_priv[MT8186_DAI_AP_DMIC] = + afe_priv->dai_priv[MT8186_DAI_ADDA]; + + return 0; +} From patchwork Sun Mar 13 15:10:10 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?SmlheGluIFl1ICjkv57lrrbpkasp?= X-Patchwork-Id: 550994 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AA5EAC43217 for ; Sun, 13 Mar 2022 15:10:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234766AbiCMPLx (ORCPT ); Sun, 13 Mar 2022 11:11:53 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39202 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234755AbiCMPLv (ORCPT ); Sun, 13 Mar 2022 11:11:51 -0400 Received: from mailgw02.mediatek.com (unknown [210.61.82.184]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 82E9E85BCA; Sun, 13 Mar 2022 08:10:41 -0700 (PDT) X-UUID: 733a571747e644478275ea7025d69603-20220313 X-UUID: 733a571747e644478275ea7025d69603-20220313 Received: from mtkexhb02.mediatek.inc [(172.21.101.103)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 748771953; Sun, 13 Mar 2022 23:10:33 +0800 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkmbs10n2.mediatek.inc (172.21.101.183) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.2.792.3; Sun, 13 Mar 2022 23:10:31 +0800 Received: from localhost.localdomain (10.17.3.154) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sun, 13 Mar 2022 23:10:30 +0800 From: Jiaxin Yu To: , , CC: , , , , , , , , , , , Jiaxin Yu Subject: [v3 06/19] ASoC: mediatek: mt8186: support hw gain in platform driver Date: Sun, 13 Mar 2022 23:10:10 +0800 Message-ID: <20220313151023.21229-7-jiaxin.yu@mediatek.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220313151023.21229-1-jiaxin.yu@mediatek.com> References: <20220313151023.21229-1-jiaxin.yu@mediatek.com> MIME-Version: 1.0 X-MTK: N Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Add mt8186 hw gain dai driver. Signed-off-by: Jiaxin Yu --- .../soc/mediatek/mt8186/mt8186-dai-hw-gain.c | 236 ++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 sound/soc/mediatek/mt8186/mt8186-dai-hw-gain.c diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-hw-gain.c b/sound/soc/mediatek/mt8186/mt8186-dai-hw-gain.c new file mode 100644 index 000000000000..33edd6cbde12 --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-dai-hw-gain.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MediaTek ALSA SoC Audio DAI HW Gain Control +// +// Copyright (c) 2022 MediaTek Inc. +// Author: Jiaxin Yu + +#include +#include "mt8186-afe-common.h" +#include "mt8186-interconnection.h" + +#define HW_GAIN_1_EN_W_NAME "HW GAIN 1 Enable" +#define HW_GAIN_2_EN_W_NAME "HW GAIN 2 Enable" + +/* dai component */ +static const struct snd_kcontrol_new mtk_hw_gain1_in_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH1 Switch", AFE_CONN13_1, + I_CONNSYS_I2S_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_hw_gain1_in_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH2 Switch", AFE_CONN14_1, + I_CONNSYS_I2S_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_hw_gain2_in_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN15, + I_ADDA_UL_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_hw_gain2_in_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN16, + I_ADDA_UL_CH2, 1, 0), +}; + +static int mtk_hw_gain_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + unsigned int gain_cur; + unsigned int gain_con1; + + dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (strcmp(w->name, HW_GAIN_1_EN_W_NAME) == 0) { + gain_cur = AFE_GAIN1_CUR; + gain_con1 = AFE_GAIN1_CON1; + } else { + gain_cur = AFE_GAIN2_CUR; + gain_con1 = AFE_GAIN2_CON1; + } + + /* let hw gain ramp up, set cur gain to 0 */ + regmap_update_bits(afe->regmap, gain_cur, AFE_GAIN1_CUR_MASK_SFT, 0); + + /* set target gain to 0 */ + regmap_update_bits(afe->regmap, gain_con1, GAIN1_TARGET_MASK_SFT, 0); + break; + default: + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget mtk_dai_hw_gain_widgets[] = { + /* inter-connections */ + SND_SOC_DAPM_MIXER("HW_GAIN1_IN_CH1", SND_SOC_NOPM, 0, 0, + mtk_hw_gain1_in_ch1_mix, + ARRAY_SIZE(mtk_hw_gain1_in_ch1_mix)), + SND_SOC_DAPM_MIXER("HW_GAIN1_IN_CH2", SND_SOC_NOPM, 0, 0, + mtk_hw_gain1_in_ch2_mix, + ARRAY_SIZE(mtk_hw_gain1_in_ch2_mix)), + SND_SOC_DAPM_MIXER("HW_GAIN2_IN_CH1", SND_SOC_NOPM, 0, 0, + mtk_hw_gain2_in_ch1_mix, + ARRAY_SIZE(mtk_hw_gain2_in_ch1_mix)), + SND_SOC_DAPM_MIXER("HW_GAIN2_IN_CH2", SND_SOC_NOPM, 0, 0, + mtk_hw_gain2_in_ch2_mix, + ARRAY_SIZE(mtk_hw_gain2_in_ch2_mix)), + + SND_SOC_DAPM_SUPPLY(HW_GAIN_1_EN_W_NAME, + AFE_GAIN1_CON0, GAIN1_ON_SFT, 0, + mtk_hw_gain_event, + SND_SOC_DAPM_PRE_PMU), + + SND_SOC_DAPM_SUPPLY(HW_GAIN_2_EN_W_NAME, + AFE_GAIN2_CON0, GAIN2_ON_SFT, 0, + mtk_hw_gain_event, + SND_SOC_DAPM_PRE_PMU), + + SND_SOC_DAPM_INPUT("HW Gain 1 Out Endpoint"), + SND_SOC_DAPM_INPUT("HW Gain 2 Out Endpoint"), + SND_SOC_DAPM_OUTPUT("HW Gain 1 In Endpoint"), +}; + +static const struct snd_soc_dapm_route mtk_dai_hw_gain_routes[] = { + {"HW Gain 1 In", NULL, "HW_GAIN1_IN_CH1"}, + {"HW Gain 1 In", NULL, "HW_GAIN1_IN_CH2"}, + {"HW Gain 2 In", NULL, "HW_GAIN2_IN_CH1"}, + {"HW Gain 2 In", NULL, "HW_GAIN2_IN_CH2"}, + + {"HW Gain 1 In", NULL, HW_GAIN_1_EN_W_NAME}, + {"HW Gain 1 Out", NULL, HW_GAIN_1_EN_W_NAME}, + {"HW Gain 2 In", NULL, HW_GAIN_2_EN_W_NAME}, + {"HW Gain 2 Out", NULL, HW_GAIN_2_EN_W_NAME}, + + {"HW Gain 1 In Endpoint", NULL, "HW Gain 1 In"}, + {"HW Gain 1 Out", NULL, "HW Gain 1 Out Endpoint"}, + {"HW Gain 2 Out", NULL, "HW Gain 2 Out Endpoint"}, +}; + +static const struct snd_kcontrol_new mtk_hw_gain_controls[] = { + SOC_SINGLE("HW Gain 1 Volume", AFE_GAIN1_CON1, + GAIN1_TARGET_SFT, GAIN1_TARGET_MASK, 0), + SOC_SINGLE("HW Gain 2 Volume", AFE_GAIN2_CON1, + GAIN2_TARGET_SFT, GAIN2_TARGET_MASK, 0), +}; + +/* dai ops */ +static int mtk_dai_gain_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + unsigned int rate = params_rate(params); + unsigned int rate_reg = mt8186_rate_transform(afe->dev, rate, dai->id); + + dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n", + __func__, dai->id, substream->stream, rate); + + /* rate */ + regmap_update_bits(afe->regmap, + dai->id == MT8186_DAI_HW_GAIN_1 ? + AFE_GAIN1_CON0 : AFE_GAIN2_CON0, + GAIN1_MODE_MASK_SFT, + rate_reg << GAIN1_MODE_SFT); + + /* sample per step */ + regmap_update_bits(afe->regmap, + dai->id == MT8186_DAI_HW_GAIN_1 ? + AFE_GAIN1_CON0 : AFE_GAIN2_CON0, + GAIN1_SAMPLE_PER_STEP_MASK_SFT, + (dai->id == MT8186_DAI_HW_GAIN_1 ? 0x40 : 0x0) << + GAIN1_SAMPLE_PER_STEP_SFT); + + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_gain_ops = { + .hw_params = mtk_dai_gain_hw_params, +}; + +/* dai driver */ +#define MTK_HW_GAIN_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_HW_GAIN_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_gain_driver[] = { + { + .name = "HW Gain 1", + .id = MT8186_DAI_HW_GAIN_1, + .playback = { + .stream_name = "HW Gain 1 In", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HW_GAIN_RATES, + .formats = MTK_HW_GAIN_FORMATS, + }, + .capture = { + .stream_name = "HW Gain 1 Out", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HW_GAIN_RATES, + .formats = MTK_HW_GAIN_FORMATS, + }, + .ops = &mtk_dai_gain_ops, + .symmetric_rate = 1, + .symmetric_channels = 1, + .symmetric_sample_bits = 1, + }, + { + .name = "HW Gain 2", + .id = MT8186_DAI_HW_GAIN_2, + .playback = { + .stream_name = "HW Gain 2 In", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HW_GAIN_RATES, + .formats = MTK_HW_GAIN_FORMATS, + }, + .capture = { + .stream_name = "HW Gain 2 Out", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HW_GAIN_RATES, + .formats = MTK_HW_GAIN_FORMATS, + }, + .ops = &mtk_dai_gain_ops, + .symmetric_rate = 1, + .symmetric_channels = 1, + .symmetric_sample_bits = 1, + }, +}; + +int mt8186_dai_hw_gain_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_gain_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_gain_driver); + + dai->controls = mtk_hw_gain_controls; + dai->num_controls = ARRAY_SIZE(mtk_hw_gain_controls); + dai->dapm_widgets = mtk_dai_hw_gain_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_hw_gain_widgets); + dai->dapm_routes = mtk_dai_hw_gain_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_hw_gain_routes); + return 0; +} From patchwork Sun Mar 13 15:10:11 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?SmlheGluIFl1ICjkv57lrrbpkasp?= X-Patchwork-Id: 550993 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 80503C433EF for ; Sun, 13 Mar 2022 15:10:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234756AbiCMPL5 (ORCPT ); Sun, 13 Mar 2022 11:11:57 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39218 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234746AbiCMPLv (ORCPT ); Sun, 13 Mar 2022 11:11:51 -0400 Received: from mailgw01.mediatek.com (unknown [60.244.123.138]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BC90C85BDE; Sun, 13 Mar 2022 08:10:41 -0700 (PDT) X-UUID: 242bf9bf7a1841f1ba4b8ab9ddc16f09-20220313 X-UUID: 242bf9bf7a1841f1ba4b8ab9ddc16f09-20220313 Received: from mtkexhb01.mediatek.inc [(172.21.101.102)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 916423103; Sun, 13 Mar 2022 23:10:34 +0800 Received: from mtkexhb01.mediatek.inc (172.21.101.102) by mtkmbs10n1.mediatek.inc (172.21.101.34) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.2.792.15; Sun, 13 Mar 2022 23:10:33 +0800 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkexhb01.mediatek.inc (172.21.101.102) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sun, 13 Mar 2022 23:10:32 +0800 Received: from localhost.localdomain (10.17.3.154) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sun, 13 Mar 2022 23:10:31 +0800 From: Jiaxin Yu To: , , CC: , , , , , , , , , , , Jiaxin Yu Subject: [v3 07/19] ASoC: mediatek: mt8186: support i2s in platform driver Date: Sun, 13 Mar 2022 23:10:11 +0800 Message-ID: <20220313151023.21229-8-jiaxin.yu@mediatek.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220313151023.21229-1-jiaxin.yu@mediatek.com> References: <20220313151023.21229-1-jiaxin.yu@mediatek.com> MIME-Version: 1.0 X-MTK: N Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Add mt8186 i2s dai driver. Signed-off-by: Jiaxin Yu --- sound/soc/mediatek/mt8186/mt8186-dai-i2s.c | 1355 ++++++++++++++++++++ 1 file changed, 1355 insertions(+) create mode 100644 sound/soc/mediatek/mt8186/mt8186-dai-i2s.c diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c b/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c new file mode 100644 index 000000000000..85150271434e --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c @@ -0,0 +1,1355 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MediaTek ALSA SoC Audio DAI I2S Control +// +// Copyright (c) 2022 MediaTek Inc. +// Author: Jiaxin Yu + +#include +#include +#include +#include "mt8186-afe-clk.h" +#include "mt8186-afe-common.h" +#include "mt8186-afe-gpio.h" +#include "mt8186-interconnection.h" + +enum { + I2S_FMT_EIAJ = 0, + I2S_FMT_I2S = 1, +}; + +enum { + I2S_WLEN_16_BIT = 0, + I2S_WLEN_32_BIT = 1, +}; + +enum { + I2S_HD_NORMAL = 0, + I2S_HD_LOW_JITTER = 1, +}; + +enum { + I2S1_SEL_O28_O29 = 0, + I2S1_SEL_O03_O04 = 1, +}; + +enum { + I2S_IN_PAD_CONNSYS = 0, + I2S_IN_PAD_IO_MUX = 1, +}; + +struct mtk_afe_i2s_priv { + int id; + int rate; /* for determine which apll to use */ + int low_jitter_en; + int master; /* only i2s0 has slave mode*/ + + const char *share_property_name; + int share_i2s_id; + + int mclk_id; + int mclk_rate; + int mclk_apll; +}; + +static unsigned int get_i2s_wlen(snd_pcm_format_t format) +{ + return snd_pcm_format_physical_width(format) <= 16 ? + I2S_WLEN_16_BIT : I2S_WLEN_32_BIT; +} + +#define MTK_AFE_I2S0_KCONTROL_NAME "I2S0_HD_Mux" +#define MTK_AFE_I2S1_KCONTROL_NAME "I2S1_HD_Mux" +#define MTK_AFE_I2S2_KCONTROL_NAME "I2S2_HD_Mux" +#define MTK_AFE_I2S3_KCONTROL_NAME "I2S3_HD_Mux" +#define MTK_AFE_I2S0_SRC_KCONTROL_NAME "I2S0_SRC_Mux" + +#define I2S0_HD_EN_W_NAME "I2S0_HD_EN" +#define I2S1_HD_EN_W_NAME "I2S1_HD_EN" +#define I2S2_HD_EN_W_NAME "I2S2_HD_EN" +#define I2S3_HD_EN_W_NAME "I2S3_HD_EN" + +#define I2S0_MCLK_EN_W_NAME "I2S0_MCLK_EN" +#define I2S1_MCLK_EN_W_NAME "I2S1_MCLK_EN" +#define I2S2_MCLK_EN_W_NAME "I2S2_MCLK_EN" +#define I2S3_MCLK_EN_W_NAME "I2S3_MCLK_EN" + +static int get_i2s_id_by_name(struct mtk_base_afe *afe, + const char *name) +{ + if (strncmp(name, "I2S0", 4) == 0) + return MT8186_DAI_I2S_0; + else if (strncmp(name, "I2S1", 4) == 0) + return MT8186_DAI_I2S_1; + else if (strncmp(name, "I2S2", 4) == 0) + return MT8186_DAI_I2S_2; + else if (strncmp(name, "I2S3", 4) == 0) + return MT8186_DAI_I2S_3; + + return -EINVAL; +} + +static struct mtk_afe_i2s_priv *get_i2s_priv_by_name(struct mtk_base_afe *afe, + const char *name) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int dai_id = get_i2s_id_by_name(afe, name); + + if (dai_id < 0) + return NULL; + + return afe_priv->dai_priv[dai_id]; +} + +/* low jitter control */ +static const char * const mt8186_i2s_hd_str[] = { + "Normal", "Low_Jitter" +}; + +static const struct soc_enum mt8186_i2s_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8186_i2s_hd_str), + mt8186_i2s_hd_str), +}; + +/* clock source control */ +static const char * const mt8186_i2s_src_str[] = { + "Master", "Slave" +}; + +static const struct soc_enum mt8186_i2s_src_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8186_i2s_src_str), + mt8186_i2s_src_str), +}; + +static int mt8186_i2s_hd_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + i2s_priv = get_i2s_priv_by_name(afe, kcontrol->id.name); + + if (!i2s_priv) { + dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); + return -EINVAL; + } + + ucontrol->value.integer.value[0] = i2s_priv->low_jitter_en; + + return 0; +} + +static int mt8186_i2s_hd_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int hd_en; + + if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + + hd_en = ucontrol->value.integer.value[0]; + + dev_dbg(afe->dev, "%s(), kcontrol name %s, hd_en %d\n", + __func__, kcontrol->id.name, hd_en); + + i2s_priv = get_i2s_priv_by_name(afe, kcontrol->id.name); + + if (!i2s_priv) { + dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); + return -EINVAL; + } + + i2s_priv->low_jitter_en = hd_en; + + return 0; +} + +static int mt8186_i2s_src_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + i2s_priv = get_i2s_priv_by_name(afe, kcontrol->id.name); + + if (!i2s_priv) { + dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); + return -EINVAL; + } + + ucontrol->value.integer.value[0] = i2s_priv->master; + + return 0; +} + +static int mt8186_i2s_src_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int clk_src; + int dai_id; + + if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + + clk_src = ucontrol->value.integer.value[0]; + + dev_dbg(afe->dev, "%s(), kcontrol name %s, hd_en %d\n", + __func__, kcontrol->id.name, clk_src); + + i2s_priv = get_i2s_priv_by_name(afe, kcontrol->id.name); + dai_id = get_i2s_id_by_name(afe, kcontrol->id.name); + + if (!i2s_priv) { + dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); + return -EINVAL; + } + + switch (dai_id) { + case MT8186_DAI_I2S_0: + regmap_update_bits(afe->regmap, AFE_I2S_CON, + I2S_SRC_MASK_SFT, + clk_src << I2S_SRC_SFT); + break; + default: + break; + } + + i2s_priv->master = clk_src; + + return 0; +} + +static const struct snd_kcontrol_new mtk_dai_i2s_controls[] = { + SOC_ENUM_EXT(MTK_AFE_I2S0_KCONTROL_NAME, mt8186_i2s_enum[0], + mt8186_i2s_hd_get, mt8186_i2s_hd_set), + SOC_ENUM_EXT(MTK_AFE_I2S1_KCONTROL_NAME, mt8186_i2s_enum[0], + mt8186_i2s_hd_get, mt8186_i2s_hd_set), + SOC_ENUM_EXT(MTK_AFE_I2S2_KCONTROL_NAME, mt8186_i2s_enum[0], + mt8186_i2s_hd_get, mt8186_i2s_hd_set), + SOC_ENUM_EXT(MTK_AFE_I2S3_KCONTROL_NAME, mt8186_i2s_enum[0], + mt8186_i2s_hd_get, mt8186_i2s_hd_set), + SOC_ENUM_EXT(MTK_AFE_I2S0_SRC_KCONTROL_NAME, mt8186_i2s_src_enum[0], + mt8186_i2s_src_get, mt8186_i2s_src_set), +}; + +/* dai component */ +/* i2s virtual mux to output widget */ +static const char * const i2s_mux_map[] = { + "Normal", "Dummy_Widget", +}; + +static int i2s_mux_map_value[] = { + 0, 1, +}; + +static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(i2s_mux_map_enum, + SND_SOC_NOPM, + 0, + 1, + i2s_mux_map, + i2s_mux_map_value); + +static const struct snd_kcontrol_new i2s0_in_mux_control = + SOC_DAPM_ENUM("I2S0 In Select", i2s_mux_map_enum); + +static const struct snd_kcontrol_new i2s1_out_mux_control = + SOC_DAPM_ENUM("I2S1 Out Select", i2s_mux_map_enum); + +static const struct snd_kcontrol_new i2s2_in_mux_control = + SOC_DAPM_ENUM("I2S2 In Select", i2s_mux_map_enum); + +static const struct snd_kcontrol_new i2s3_out_mux_control = + SOC_DAPM_ENUM("I2S3 Out Select", i2s_mux_map_enum); + +/* i2s in lpbk */ +static const char * const i2s_lpbk_mux_map[] = { + "Normal", "Lpbk", +}; + +static int i2s_lpbk_mux_map_value[] = { + 0, 1, +}; + +static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(i2s0_lpbk_mux_map_enum, + AFE_I2S_CON, + I2S_LOOPBACK_SFT, + 1, + i2s_lpbk_mux_map, + i2s_lpbk_mux_map_value); + +static const struct snd_kcontrol_new i2s0_lpbk_mux_control = + SOC_DAPM_ENUM("I2S Lpbk Select", i2s0_lpbk_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(i2s2_lpbk_mux_map_enum, + AFE_I2S_CON2, + I2S3_LOOPBACK_SFT, + 1, + i2s_lpbk_mux_map, + i2s_lpbk_mux_map_value); + +static const struct snd_kcontrol_new i2s2_lpbk_mux_control = + SOC_DAPM_ENUM("I2S Lpbk Select", i2s2_lpbk_mux_map_enum); + +/* interconnection */ +static const struct snd_kcontrol_new mtk_i2s3_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN0, + I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN0, + I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN0, + I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1 Switch", AFE_CONN0, + I_DL12_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH3 Switch", AFE_CONN0, + I_DL12_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1 Switch", AFE_CONN0_1, + I_DL6_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN0_1, + I_DL4_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN0_1, + I_DL5_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1 Switch", AFE_CONN0_1, + I_DL8_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1 Switch", AFE_CONN0, + I_GAIN1_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN0, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN0, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3 Switch", AFE_CONN0, + I_ADDA_UL_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1 Switch", AFE_CONN0, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH1 Switch", AFE_CONN0_1, + I_SRC_1_OUT_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_i2s3_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN1, + I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN1, + I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN1, + I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN1, + I_DL12_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH4 Switch", AFE_CONN1, + I_DL12_CH4, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2 Switch", AFE_CONN1_1, + I_DL6_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN1_1, + I_DL4_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN1_1, + I_DL5_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2 Switch", AFE_CONN1_1, + I_DL8_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2 Switch", AFE_CONN1, + I_GAIN1_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN1, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN1, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3 Switch", AFE_CONN1, + I_ADDA_UL_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1 Switch", AFE_CONN1, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2 Switch", AFE_CONN1, + I_PCM_1_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH2 Switch", AFE_CONN1_1, + I_SRC_1_OUT_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_i2s1_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN28, + I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN28, + I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN28, + I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1 Switch", AFE_CONN28, + I_DL12_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH3 Switch", AFE_CONN28, + I_DL12_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1 Switch", AFE_CONN28_1, + I_DL6_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN28_1, + I_DL4_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN28_1, + I_DL5_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1 Switch", AFE_CONN28_1, + I_DL8_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1 Switch", AFE_CONN28, + I_GAIN1_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN28, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1 Switch", AFE_CONN28, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH1 Switch", AFE_CONN28_1, + I_SRC_1_OUT_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_i2s1_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN29, + I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN29, + I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN29, + I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN29, + I_DL12_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH4 Switch", AFE_CONN29, + I_DL12_CH4, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2 Switch", AFE_CONN29_1, + I_DL6_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN29_1, + I_DL4_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN29_1, + I_DL5_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2 Switch", AFE_CONN29_1, + I_DL8_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2 Switch", AFE_CONN29, + I_GAIN1_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN29, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1 Switch", AFE_CONN29, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2 Switch", AFE_CONN29, + I_PCM_1_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH2 Switch", AFE_CONN29_1, + I_SRC_1_OUT_CH2, 1, 0), +}; + +enum { + SUPPLY_SEQ_APLL, + SUPPLY_SEQ_I2S_MCLK_EN, + SUPPLY_SEQ_I2S_HD_EN, + SUPPLY_SEQ_I2S_EN, +}; + +static int mtk_i2s_en_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + i2s_priv = get_i2s_priv_by_name(afe, w->name); + + if (!i2s_priv) { + dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); + return -EINVAL; + } + + dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8186_afe_gpio_request(afe->dev, true, i2s_priv->id, 0); + break; + case SND_SOC_DAPM_POST_PMD: + mt8186_afe_gpio_request(afe->dev, false, i2s_priv->id, 0); + break; + default: + break; + } + + return 0; +} + +static int mtk_apll_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (strcmp(w->name, APLL1_W_NAME) == 0) + mt8186_apll1_enable(afe); + else + mt8186_apll2_enable(afe); + break; + case SND_SOC_DAPM_POST_PMD: + if (strcmp(w->name, APLL1_W_NAME) == 0) + mt8186_apll1_disable(afe); + else + mt8186_apll2_disable(afe); + break; + default: + break; + } + + return 0; +} + +static int mtk_mclk_en_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + i2s_priv = get_i2s_priv_by_name(afe, w->name); + + if (!i2s_priv) { + dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8186_mck_enable(afe, i2s_priv->mclk_id, i2s_priv->mclk_rate); + break; + case SND_SOC_DAPM_POST_PMD: + i2s_priv->mclk_rate = 0; + mt8186_mck_disable(afe, i2s_priv->mclk_id); + break; + default: + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget mtk_dai_i2s_widgets[] = { + SND_SOC_DAPM_INPUT("CONNSYS"), + + SND_SOC_DAPM_MIXER("I2S1_CH1", SND_SOC_NOPM, 0, 0, + mtk_i2s1_ch1_mix, + ARRAY_SIZE(mtk_i2s1_ch1_mix)), + SND_SOC_DAPM_MIXER("I2S1_CH2", SND_SOC_NOPM, 0, 0, + mtk_i2s1_ch2_mix, + ARRAY_SIZE(mtk_i2s1_ch2_mix)), + + SND_SOC_DAPM_MIXER("I2S3_CH1", SND_SOC_NOPM, 0, 0, + mtk_i2s3_ch1_mix, + ARRAY_SIZE(mtk_i2s3_ch1_mix)), + SND_SOC_DAPM_MIXER("I2S3_CH2", SND_SOC_NOPM, 0, 0, + mtk_i2s3_ch2_mix, + ARRAY_SIZE(mtk_i2s3_ch2_mix)), + + /* i2s en*/ + SND_SOC_DAPM_SUPPLY_S("I2S0_EN", SUPPLY_SEQ_I2S_EN, + AFE_I2S_CON, I2S_EN_SFT, 0, + mtk_i2s_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("I2S1_EN", SUPPLY_SEQ_I2S_EN, + AFE_I2S_CON1, I2S_EN_SFT, 0, + mtk_i2s_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("I2S2_EN", SUPPLY_SEQ_I2S_EN, + AFE_I2S_CON2, I2S_EN_SFT, 0, + mtk_i2s_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("I2S3_EN", SUPPLY_SEQ_I2S_EN, + AFE_I2S_CON3, I2S_EN_SFT, 0, + mtk_i2s_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + /* i2s hd en */ + SND_SOC_DAPM_SUPPLY_S(I2S0_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN, + AFE_I2S_CON, I2S1_HD_EN_SFT, 0, NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S1_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN, + AFE_I2S_CON1, I2S2_HD_EN_SFT, 0, NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S2_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN, + AFE_I2S_CON2, I2S3_HD_EN_SFT, 0, NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S3_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN, + AFE_I2S_CON3, I2S4_HD_EN_SFT, 0, NULL, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* i2s mclk en */ + SND_SOC_DAPM_SUPPLY_S(I2S0_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN, + SND_SOC_NOPM, 0, 0, + mtk_mclk_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S1_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN, + SND_SOC_NOPM, 0, 0, + mtk_mclk_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S2_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN, + SND_SOC_NOPM, 0, 0, + mtk_mclk_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S3_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN, + SND_SOC_NOPM, 0, 0, + mtk_mclk_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* apll */ + SND_SOC_DAPM_SUPPLY_S(APLL1_W_NAME, SUPPLY_SEQ_APLL, + SND_SOC_NOPM, 0, 0, + mtk_apll_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(APLL2_W_NAME, SUPPLY_SEQ_APLL, + SND_SOC_NOPM, 0, 0, + mtk_apll_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* allow i2s on without codec on */ + SND_SOC_DAPM_OUTPUT("I2S_DUMMY_OUT"), + SND_SOC_DAPM_MUX("I2S1_Out_Mux", + SND_SOC_NOPM, 0, 0, &i2s1_out_mux_control), + SND_SOC_DAPM_MUX("I2S3_Out_Mux", + SND_SOC_NOPM, 0, 0, &i2s3_out_mux_control), + SND_SOC_DAPM_INPUT("I2S_DUMMY_IN"), + SND_SOC_DAPM_MUX("I2S0_In_Mux", + SND_SOC_NOPM, 0, 0, &i2s0_in_mux_control), + SND_SOC_DAPM_MUX("I2S2_In_Mux", + SND_SOC_NOPM, 0, 0, &i2s2_in_mux_control), + + /* i2s in lpbk */ + SND_SOC_DAPM_MUX("I2S0_Lpbk_Mux", + SND_SOC_NOPM, 0, 0, &i2s0_lpbk_mux_control), + SND_SOC_DAPM_MUX("I2S2_Lpbk_Mux", + SND_SOC_NOPM, 0, 0, &i2s2_lpbk_mux_control), +}; + +static int mtk_afe_i2s_share_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + i2s_priv = get_i2s_priv_by_name(afe, sink->name); + + if (!i2s_priv) { + dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); + return 0; + } + + if (i2s_priv->share_i2s_id < 0) + return 0; + + return i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name); +} + +static int mtk_afe_i2s_hd_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + i2s_priv = get_i2s_priv_by_name(afe, sink->name); + + if (!i2s_priv) { + dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); + return 0; + } + + if (get_i2s_id_by_name(afe, sink->name) == + get_i2s_id_by_name(afe, source->name)) + return i2s_priv->low_jitter_en; + + /* check if share i2s need hd en */ + if (i2s_priv->share_i2s_id < 0) + return 0; + + if (i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name)) + return i2s_priv->low_jitter_en; + + return 0; +} + +static int mtk_afe_i2s_apll_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + int cur_apll; + int i2s_need_apll; + + i2s_priv = get_i2s_priv_by_name(afe, w->name); + + if (!i2s_priv) { + dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); + return 0; + } + + /* which apll */ + cur_apll = mt8186_get_apll_by_name(afe, source->name); + + /* choose APLL from i2s rate */ + i2s_need_apll = mt8186_get_apll_by_rate(afe, i2s_priv->rate); + + return (i2s_need_apll == cur_apll) ? 1 : 0; +} + +static int mtk_afe_i2s_mclk_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + i2s_priv = get_i2s_priv_by_name(afe, sink->name); + + if (!i2s_priv) { + dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); + return 0; + } + + if (get_i2s_id_by_name(afe, sink->name) == + get_i2s_id_by_name(afe, source->name)) + return (i2s_priv->mclk_rate > 0) ? 1 : 0; + + /* check if share i2s need mclk */ + if (i2s_priv->share_i2s_id < 0) + return 0; + + if (i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name)) + return (i2s_priv->mclk_rate > 0) ? 1 : 0; + + return 0; +} + +static int mtk_afe_mclk_apll_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + int cur_apll; + + i2s_priv = get_i2s_priv_by_name(afe, w->name); + + if (!i2s_priv) { + dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); + return 0; + } + + /* which apll */ + cur_apll = mt8186_get_apll_by_name(afe, source->name); + + return (i2s_priv->mclk_apll == cur_apll) ? 1 : 0; +} + +static const struct snd_soc_dapm_route mtk_dai_i2s_routes[] = { + {"Connsys I2S", NULL, "CONNSYS"}, + + /* i2s0 */ + {"I2S0", NULL, "I2S0_EN"}, + {"I2S0", NULL, "I2S1_EN", mtk_afe_i2s_share_connect}, + {"I2S0", NULL, "I2S2_EN", mtk_afe_i2s_share_connect}, + {"I2S0", NULL, "I2S3_EN", mtk_afe_i2s_share_connect}, + + {"I2S0", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S0", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S0", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S0", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {I2S0_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect}, + {I2S0_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect}, + + {"I2S0", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S0", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S0", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S0", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {I2S0_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {I2S0_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + /* i2s1 */ + {"I2S1_CH1", "DL1_CH1 Switch", "DL1"}, + {"I2S1_CH2", "DL1_CH2 Switch", "DL1"}, + + {"I2S1_CH1", "DL2_CH1 Switch", "DL2"}, + {"I2S1_CH2", "DL2_CH2 Switch", "DL2"}, + + {"I2S1_CH1", "DL3_CH1 Switch", "DL3"}, + {"I2S1_CH2", "DL3_CH2 Switch", "DL3"}, + + {"I2S1_CH1", "DL12_CH1 Switch", "DL12"}, + {"I2S1_CH2", "DL12_CH2 Switch", "DL12"}, + + {"I2S1_CH1", "DL12_CH3 Switch", "DL12"}, + {"I2S1_CH2", "DL12_CH4 Switch", "DL12"}, + + {"I2S1_CH1", "DL6_CH1 Switch", "DL6"}, + {"I2S1_CH2", "DL6_CH2 Switch", "DL6"}, + + {"I2S1_CH1", "DL4_CH1 Switch", "DL4"}, + {"I2S1_CH2", "DL4_CH2 Switch", "DL4"}, + + {"I2S1_CH1", "DL5_CH1 Switch", "DL5"}, + {"I2S1_CH2", "DL5_CH2 Switch", "DL5"}, + + {"I2S1_CH1", "DL8_CH1 Switch", "DL8"}, + {"I2S1_CH2", "DL8_CH2 Switch", "DL8"}, + + {"I2S1", NULL, "I2S1_CH1"}, + {"I2S1", NULL, "I2S1_CH2"}, + + {"I2S1", NULL, "I2S0_EN", mtk_afe_i2s_share_connect}, + {"I2S1", NULL, "I2S1_EN"}, + {"I2S1", NULL, "I2S2_EN", mtk_afe_i2s_share_connect}, + {"I2S1", NULL, "I2S3_EN", mtk_afe_i2s_share_connect}, + + {"I2S1", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S1", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S1", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S1", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {I2S1_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect}, + {I2S1_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect}, + + {"I2S1", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S1", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S1", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S1", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {I2S1_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {I2S1_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + /* i2s2 */ + {"I2S2", NULL, "I2S0_EN", mtk_afe_i2s_share_connect}, + {"I2S2", NULL, "I2S1_EN", mtk_afe_i2s_share_connect}, + {"I2S2", NULL, "I2S2_EN"}, + {"I2S2", NULL, "I2S3_EN", mtk_afe_i2s_share_connect}, + + {"I2S2", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S2", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S2", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S2", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {I2S2_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect}, + {I2S2_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect}, + + {"I2S2", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S2", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S2", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S2", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {I2S2_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {I2S2_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + /* i2s3 */ + {"I2S3_CH1", "DL1_CH1 Switch", "DL1"}, + {"I2S3_CH2", "DL1_CH2 Switch", "DL1"}, + + {"I2S3_CH1", "DL2_CH1 Switch", "DL2"}, + {"I2S3_CH2", "DL2_CH2 Switch", "DL2"}, + + {"I2S3_CH1", "DL3_CH1 Switch", "DL3"}, + {"I2S3_CH2", "DL3_CH2 Switch", "DL3"}, + + {"I2S3_CH1", "DL12_CH1 Switch", "DL12"}, + {"I2S3_CH2", "DL12_CH2 Switch", "DL12"}, + + {"I2S3_CH1", "DL12_CH3 Switch", "DL12"}, + {"I2S3_CH2", "DL12_CH4 Switch", "DL12"}, + + {"I2S3_CH1", "DL6_CH1 Switch", "DL6"}, + {"I2S3_CH2", "DL6_CH2 Switch", "DL6"}, + + {"I2S3_CH1", "DL4_CH1 Switch", "DL4"}, + {"I2S3_CH2", "DL4_CH2 Switch", "DL4"}, + + {"I2S3_CH1", "DL5_CH1 Switch", "DL5"}, + {"I2S3_CH2", "DL5_CH2 Switch", "DL5"}, + + {"I2S3_CH1", "DL8_CH1 Switch", "DL8"}, + {"I2S3_CH2", "DL8_CH2 Switch", "DL8"}, + + {"I2S3", NULL, "I2S3_CH1"}, + {"I2S3", NULL, "I2S3_CH2"}, + + {"I2S3", NULL, "I2S0_EN", mtk_afe_i2s_share_connect}, + {"I2S3", NULL, "I2S1_EN", mtk_afe_i2s_share_connect}, + {"I2S3", NULL, "I2S2_EN", mtk_afe_i2s_share_connect}, + {"I2S3", NULL, "I2S3_EN"}, + + {"I2S3", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S3", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S3", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S3", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {I2S3_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect}, + {I2S3_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect}, + + {"I2S3", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S3", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S3", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S3", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {I2S3_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {I2S3_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + /* allow i2s on without codec on */ + {"I2S0", NULL, "I2S0_In_Mux"}, + {"I2S0_In_Mux", "Dummy_Widget", "I2S_DUMMY_IN"}, + + {"I2S1_Out_Mux", "Dummy_Widget", "I2S1"}, + {"I2S_DUMMY_OUT", NULL, "I2S1_Out_Mux"}, + + {"I2S2", NULL, "I2S2_In_Mux"}, + {"I2S2_In_Mux", "Dummy_Widget", "I2S_DUMMY_IN"}, + + {"I2S3_Out_Mux", "Dummy_Widget", "I2S3"}, + {"I2S_DUMMY_OUT", NULL, "I2S3_Out_Mux"}, + + /* i2s in lpbk */ + {"I2S0_Lpbk_Mux", "Lpbk", "I2S3"}, + {"I2S2_Lpbk_Mux", "Lpbk", "I2S1"}, + {"I2S0", NULL, "I2S0_Lpbk_Mux"}, + {"I2S2", NULL, "I2S2_Lpbk_Mux"}, +}; + +/* dai ops */ +static int mtk_dai_connsys_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + unsigned int rate = params_rate(params); + unsigned int rate_reg = mt8186_rate_transform(afe->dev, + rate, dai->id); + unsigned int i2s_con = 0; + + dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n", + __func__, dai->id, substream->stream, rate); + + /* non-inverse, i2s mode, slave, 16bits, from connsys */ + i2s_con |= 0 << INV_PAD_CTRL_SFT; + i2s_con |= I2S_FMT_I2S << I2S_FMT_SFT; + i2s_con |= 1 << I2S_SRC_SFT; + i2s_con |= get_i2s_wlen(SNDRV_PCM_FORMAT_S16_LE) << I2S_WLEN_SFT; + i2s_con |= 0 << I2SIN_PAD_SEL_SFT; + regmap_write(afe->regmap, AFE_CONNSYS_I2S_CON, i2s_con); + + /* use asrc */ + regmap_update_bits(afe->regmap, AFE_CONNSYS_I2S_CON, + I2S_BYPSRC_MASK_SFT, 0); + + /* slave mode, set i2s for asrc */ + regmap_update_bits(afe->regmap, AFE_CONNSYS_I2S_CON, + I2S_MODE_MASK_SFT, rate_reg << I2S_MODE_SFT); + + if (rate == 44100) + regmap_write(afe->regmap, AFE_ASRC_2CH_CON3, 0x1b9000); + else if (rate == 32000) + regmap_write(afe->regmap, AFE_ASRC_2CH_CON3, 0x140000); + else + regmap_write(afe->regmap, AFE_ASRC_2CH_CON3, 0x1e0000); + + /* Calibration setting */ + regmap_write(afe->regmap, AFE_ASRC_2CH_CON4, 0x140000); + regmap_write(afe->regmap, AFE_ASRC_2CH_CON9, 0x36000); + regmap_write(afe->regmap, AFE_ASRC_2CH_CON10, 0x2fc00); + regmap_write(afe->regmap, AFE_ASRC_2CH_CON6, 0x7ef4); + regmap_write(afe->regmap, AFE_ASRC_2CH_CON5, 0xff5986); + + /* 0:Stereo 1:Mono */ + regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON2, + CHSET_IS_MONO_MASK_SFT, 0); + + return 0; +} + +static int mtk_dai_connsys_i2s_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + + dev_dbg(afe->dev, "%s(), cmd %d, stream %d\n", + __func__, cmd, substream->stream); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + /* i2s enable */ + regmap_update_bits(afe->regmap, + AFE_CONNSYS_I2S_CON, + I2S_EN_MASK_SFT, + BIT(I2S_EN_SFT)); + + /* calibrator enable */ + regmap_update_bits(afe->regmap, + AFE_ASRC_2CH_CON5, + CALI_EN_MASK_SFT, + BIT(CALI_EN_SFT)); + + /* asrc enable */ + regmap_update_bits(afe->regmap, + AFE_ASRC_2CH_CON0, + CON0_CHSET_STR_CLR_MASK_SFT, + BIT(CON0_CHSET_STR_CLR_SFT)); + regmap_update_bits(afe->regmap, + AFE_ASRC_2CH_CON0, + CON0_ASM_ON_MASK_SFT, + BIT(CON0_ASM_ON_SFT)); + + afe_priv->dai_on[dai->id] = true; + return 0; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON0, + CON0_ASM_ON_MASK_SFT, 0); + regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON5, + CALI_EN_MASK_SFT, 0); + + /* i2s disable */ + regmap_update_bits(afe->regmap, AFE_CONNSYS_I2S_CON, + I2S_EN_MASK_SFT, 0); + + /* bypass asrc */ + regmap_update_bits(afe->regmap, AFE_CONNSYS_I2S_CON, + I2S_BYPSRC_MASK_SFT, BIT(I2S_BYPSRC_SFT)); + + afe_priv->dai_on[dai->id] = false; + return 0; + default: + return -EINVAL; + } + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_connsys_i2s_ops = { + .hw_params = mtk_dai_connsys_i2s_hw_params, + .trigger = mtk_dai_connsys_i2s_trigger, +}; + +/* i2s */ +static int mtk_dai_i2s_config(struct mtk_base_afe *afe, + struct snd_pcm_hw_params *params, + int i2s_id) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_i2s_priv *i2s_priv = afe_priv->dai_priv[i2s_id]; + + unsigned int rate = params_rate(params); + unsigned int rate_reg = mt8186_rate_transform(afe->dev, + rate, i2s_id); + snd_pcm_format_t format = params_format(params); + unsigned int i2s_con = 0; + int ret; + + dev_dbg(afe->dev, "%s(), id %d, rate %d, format %d\n", + __func__, i2s_id, rate, format); + + if (!i2s_priv) { + dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); + return -EINVAL; + } + + i2s_priv->rate = rate; + + switch (i2s_id) { + case MT8186_DAI_I2S_0: + i2s_con = I2S_IN_PAD_IO_MUX << I2SIN_PAD_SEL_SFT; + i2s_con |= rate_reg << I2S_OUT_MODE_SFT; + i2s_con |= I2S_FMT_I2S << I2S_FMT_SFT; + i2s_con |= get_i2s_wlen(format) << I2S_WLEN_SFT; + regmap_update_bits(afe->regmap, AFE_I2S_CON, + 0xffffeffa, i2s_con); + break; + case MT8186_DAI_I2S_1: + i2s_con = I2S1_SEL_O28_O29 << I2S2_SEL_O03_O04_SFT; + i2s_con |= rate_reg << I2S2_OUT_MODE_SFT; + i2s_con |= I2S_FMT_I2S << I2S2_FMT_SFT; + i2s_con |= get_i2s_wlen(format) << I2S2_WLEN_SFT; + regmap_update_bits(afe->regmap, AFE_I2S_CON1, + 0xffffeffa, i2s_con); + break; + case MT8186_DAI_I2S_2: + i2s_con = 8 << I2S3_UPDATE_WORD_SFT; + i2s_con |= rate_reg << I2S3_OUT_MODE_SFT; + i2s_con |= I2S_FMT_I2S << I2S3_FMT_SFT; + i2s_con |= get_i2s_wlen(format) << I2S3_WLEN_SFT; + regmap_update_bits(afe->regmap, AFE_I2S_CON2, + 0xffffeffa, i2s_con); + break; + case MT8186_DAI_I2S_3: + i2s_con = rate_reg << I2S4_OUT_MODE_SFT; + i2s_con |= I2S_FMT_I2S << I2S4_FMT_SFT; + i2s_con |= get_i2s_wlen(format) << I2S4_WLEN_SFT; + regmap_update_bits(afe->regmap, AFE_I2S_CON3, + 0xffffeffa, i2s_con); + break; + default: + dev_err(afe->dev, "%s(), id %d not support\n", + __func__, i2s_id); + return -EINVAL; + } + + /* set share i2s */ + if (i2s_priv && i2s_priv->share_i2s_id >= 0) { + ret = mtk_dai_i2s_config(afe, params, i2s_priv->share_i2s_id); + if (ret) + return ret; + } + + return 0; +} + +static int mtk_dai_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + + return mtk_dai_i2s_config(afe, params, dai->id); +} + +static int mtk_dai_i2s_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dai->dev); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_i2s_priv *i2s_priv = afe_priv->dai_priv[dai->id]; + int apll; + int apll_rate; + + if (!i2s_priv) { + dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__); + return -EINVAL; + } + + if (dir != SND_SOC_CLOCK_OUT) { + dev_err(afe->dev, "%s(), dir != SND_SOC_CLOCK_OUT", __func__); + return -EINVAL; + } + + dev_dbg(afe->dev, "%s(), freq %d\n", __func__, freq); + + apll = mt8186_get_apll_by_rate(afe, freq); + apll_rate = mt8186_get_apll_rate(afe, apll); + + if (freq > apll_rate) { + dev_err(afe->dev, "%s(), freq > apll rate", __func__); + return -EINVAL; + } + + if (apll_rate % freq != 0) { + dev_err(afe->dev, "%s(), APLL cannot generate freq Hz", __func__); + return -EINVAL; + } + + i2s_priv->mclk_rate = freq; + i2s_priv->mclk_apll = apll; + + if (i2s_priv->share_i2s_id > 0) { + struct mtk_afe_i2s_priv *share_i2s_priv; + + share_i2s_priv = afe_priv->dai_priv[i2s_priv->share_i2s_id]; + if (!share_i2s_priv) { + dev_err(afe->dev, "%s(), share_i2s_priv == NULL", __func__); + return -EINVAL; + } + + share_i2s_priv->mclk_rate = i2s_priv->mclk_rate; + share_i2s_priv->mclk_apll = i2s_priv->mclk_apll; + } + + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_i2s_ops = { + .hw_params = mtk_dai_i2s_hw_params, + .set_sysclk = mtk_dai_i2s_set_sysclk, +}; + +/* dai driver */ +#define MTK_CONNSYS_I2S_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) + +#define MTK_I2S_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_i2s_driver[] = { + { + .name = "CONNSYS_I2S", + .id = MT8186_DAI_CONNSYS_I2S, + .capture = { + .stream_name = "Connsys I2S", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_CONNSYS_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_connsys_i2s_ops, + }, + { + .name = "I2S0", + .id = MT8186_DAI_I2S_0, + .capture = { + .stream_name = "I2S0", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_i2s_ops, + }, + { + .name = "I2S1", + .id = MT8186_DAI_I2S_1, + .playback = { + .stream_name = "I2S1", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_i2s_ops, + }, + { + .name = "I2S2", + .id = MT8186_DAI_I2S_2, + .capture = { + .stream_name = "I2S2", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_i2s_ops, + }, + { + .name = "I2S3", + .id = MT8186_DAI_I2S_3, + .playback = { + .stream_name = "I2S3", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_i2s_ops, + } +}; + +/* this enum is merely for mtk_afe_i2s_priv declare */ +enum { + DAI_I2S0 = 0, + DAI_I2S1, + DAI_I2S2, + DAI_I2S3, + DAI_I2S_NUM, +}; + +static const struct mtk_afe_i2s_priv mt8186_i2s_priv[DAI_I2S_NUM] = { + [DAI_I2S0] = { + .id = MT8186_DAI_I2S_0, + .mclk_id = MT8186_I2S0_MCK, + .share_property_name = "i2s0-share", + .share_i2s_id = -1, + }, + [DAI_I2S1] = { + .id = MT8186_DAI_I2S_1, + .mclk_id = MT8186_I2S1_MCK, + .share_property_name = "i2s1-share", + .share_i2s_id = -1, + }, + [DAI_I2S2] = { + .id = MT8186_DAI_I2S_2, + .mclk_id = MT8186_I2S2_MCK, + .share_property_name = "i2s2-share", + .share_i2s_id = -1, + }, + [DAI_I2S3] = { + .id = MT8186_DAI_I2S_3, + /* clock gate naming is hf_faud_i2s4_m_ck*/ + .mclk_id = MT8186_I2S4_MCK, + .share_property_name = "i2s3-share", + .share_i2s_id = -1, + } +}; + +static int mt8186_dai_i2s_get_share(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + const struct device_node *of_node = afe->dev->of_node; + const char *of_str; + const char *property_name; + struct mtk_afe_i2s_priv *i2s_priv; + int i; + + for (i = 0; i < DAI_I2S_NUM; i++) { + i2s_priv = afe_priv->dai_priv[mt8186_i2s_priv[i].id]; + property_name = mt8186_i2s_priv[i].share_property_name; + if (of_property_read_string(of_node, property_name, &of_str)) + continue; + i2s_priv->share_i2s_id = get_i2s_id_by_name(afe, of_str); + } + + return 0; +} + +static int mt8186_dai_i2s_set_priv(struct mtk_base_afe *afe) +{ + int i; + int ret; + + for (i = 0; i < DAI_I2S_NUM; i++) { + ret = mt8186_dai_set_priv(afe, mt8186_i2s_priv[i].id, + sizeof(struct mtk_afe_i2s_priv), + &mt8186_i2s_priv[i]); + if (ret) + return ret; + } + + return 0; +} + +int mt8186_dai_i2s_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + int ret; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_i2s_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_i2s_driver); + + dai->controls = mtk_dai_i2s_controls; + dai->num_controls = ARRAY_SIZE(mtk_dai_i2s_controls); + dai->dapm_widgets = mtk_dai_i2s_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_i2s_widgets); + dai->dapm_routes = mtk_dai_i2s_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_i2s_routes); + + /* set all dai i2s private data */ + ret = mt8186_dai_i2s_set_priv(afe); + if (ret) + return ret; + + /* parse share i2s */ + ret = mt8186_dai_i2s_get_share(afe); + if (ret) + return ret; + + return 0; +} From patchwork Sun Mar 13 15:10:15 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?SmlheGluIFl1ICjkv57lrrbpkasp?= X-Patchwork-Id: 550991 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A0219C43219 for ; Sun, 13 Mar 2022 15:10:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234752AbiCMPMC (ORCPT ); Sun, 13 Mar 2022 11:12:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39416 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234761AbiCMPLw (ORCPT ); Sun, 13 Mar 2022 11:11:52 -0400 Received: from mailgw02.mediatek.com (unknown [210.61.82.184]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3C5DF86E12; Sun, 13 Mar 2022 08:10:43 -0700 (PDT) X-UUID: 54e1fcc4478141899f95a4b34f6ba2b0-20220313 X-UUID: 54e1fcc4478141899f95a4b34f6ba2b0-20220313 Received: from mtkmbs10n1.mediatek.inc [(172.21.101.34)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1411294203; Sun, 13 Mar 2022 23:10:37 +0800 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkmbs10n2.mediatek.inc (172.21.101.183) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.2.792.3; Sun, 13 Mar 2022 23:10:36 +0800 Received: from localhost.localdomain (10.17.3.154) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sun, 13 Mar 2022 23:10:35 +0800 From: Jiaxin Yu To: , , CC: , , , , , , , , , , , Jiaxin Yu Subject: [v3 11/19] ASoC: mediatek: mt8186: support audio clock control in platform driver Date: Sun, 13 Mar 2022 23:10:15 +0800 Message-ID: <20220313151023.21229-12-jiaxin.yu@mediatek.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220313151023.21229-1-jiaxin.yu@mediatek.com> References: <20220313151023.21229-1-jiaxin.yu@mediatek.com> MIME-Version: 1.0 X-MTK: N Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Add audio clock control with CCF interface. Signed-off-by: Jiaxin Yu --- sound/soc/mediatek/mt8186/mt8186-afe-clk.c | 651 +++++++++++++++++++++ sound/soc/mediatek/mt8186/mt8186-afe-clk.h | 106 ++++ 2 files changed, 757 insertions(+) create mode 100644 sound/soc/mediatek/mt8186/mt8186-afe-clk.c create mode 100644 sound/soc/mediatek/mt8186/mt8186-afe-clk.h diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-clk.c b/sound/soc/mediatek/mt8186/mt8186-afe-clk.c new file mode 100644 index 000000000000..0275f66ddc18 --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-afe-clk.c @@ -0,0 +1,651 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// mt8186-afe-clk.c -- Mediatek 8186 afe clock ctrl +// +// Copyright (c) 2022 MediaTek Inc. +// Author: Jiaxin Yu + +#include +#include +#include + +#include "mt8186-afe-common.h" +#include "mt8186-afe-clk.h" +#include "mt8186-audsys-clk.h" + +static DEFINE_MUTEX(mutex_request_dram); + +static const char *aud_clks[CLK_NUM] = { + [CLK_AFE] = "aud_afe_clk", + [CLK_DAC] = "aud_dac_clk", + [CLK_DAC_PREDIS] = "aud_dac_predis_clk", + [CLK_ADC] = "aud_adc_clk", + [CLK_TML] = "aud_tml_clk", + [CLK_APLL22M] = "aud_apll22m_clk", + [CLK_APLL24M] = "aud_apll24m_clk", + [CLK_APLL1_TUNER] = "aud_apll_tuner_clk", + [CLK_APLL2_TUNER] = "aud_apll2_tuner_clk", + [CLK_TDM] = "aud_tdm_clk", + [CLK_NLE] = "aud_nle_clk", + [CLK_DAC_HIRES] = "aud_dac_hires_clk", + [CLK_ADC_HIRES] = "aud_adc_hires_clk", + [CLK_I2S1_BCLK] = "aud_i2s1_bclk", + [CLK_I2S2_BCLK] = "aud_i2s2_bclk", + [CLK_I2S3_BCLK] = "aud_i2s3_bclk", + [CLK_I2S4_BCLK] = "aud_i2s4_bclk", + [CLK_CONNSYS_I2S_ASRC] = "aud_connsys_i2s_asrc", + [CLK_GENERAL1_ASRC] = "aud_general1_asrc", + [CLK_GENERAL2_ASRC] = "aud_general2_asrc", + [CLK_ADC_HIRES_TML] = "aud_adc_hires_tml", + [CLK_ADDA6_ADC] = "aud_adda6_adc", + [CLK_ADDA6_ADC_HIRES] = "aud_adda6_adc_hires", + [CLK_3RD_DAC] = "aud_3rd_dac", + [CLK_3RD_DAC_PREDIS] = "aud_3rd_dac_predis", + [CLK_3RD_DAC_TML] = "aud_3rd_dac_tml", + [CLK_3RD_DAC_HIRES] = "aud_3rd_dac_hires", + [CLK_ETDM_IN1_BCLK] = "aud_etdm_in1_bclk", + [CLK_ETDM_OUT1_BCLK] = "aud_etdm_out1_bclk", + [CLK_INFRA_SYS_AUDIO] = "aud_infra_clk", + [CLK_INFRA_AUDIO_26M] = "mtkaif_26m_clk", + [CLK_MUX_AUDIO] = "top_mux_audio", + [CLK_MUX_AUDIOINTBUS] = "top_mux_audio_int", + [CLK_TOP_MAINPLL_D2_D4] = "top_mainpll_d2_d4", + [CLK_TOP_MUX_AUD_1] = "top_mux_aud_1", + [CLK_TOP_APLL1_CK] = "top_apll1_ck", + [CLK_TOP_MUX_AUD_2] = "top_mux_aud_2", + [CLK_TOP_APLL2_CK] = "top_apll2_ck", + [CLK_TOP_MUX_AUD_ENG1] = "top_mux_aud_eng1", + [CLK_TOP_APLL1_D8] = "top_apll1_d8", + [CLK_TOP_MUX_AUD_ENG2] = "top_mux_aud_eng2", + [CLK_TOP_APLL2_D8] = "top_apll2_d8", + [CLK_TOP_MUX_AUDIO_H] = "top_mux_audio_h", + [CLK_TOP_I2S0_M_SEL] = "top_i2s0_m_sel", + [CLK_TOP_I2S1_M_SEL] = "top_i2s1_m_sel", + [CLK_TOP_I2S2_M_SEL] = "top_i2s2_m_sel", + [CLK_TOP_I2S4_M_SEL] = "top_i2s4_m_sel", + [CLK_TOP_TDM_M_SEL] = "top_tdm_m_sel", + [CLK_TOP_APLL12_DIV0] = "top_apll12_div0", + [CLK_TOP_APLL12_DIV1] = "top_apll12_div1", + [CLK_TOP_APLL12_DIV2] = "top_apll12_div2", + [CLK_TOP_APLL12_DIV4] = "top_apll12_div4", + [CLK_TOP_APLL12_DIV_TDM] = "top_apll12_div_tdm", + [CLK_CLK26M] = "top_clk26m_clk", +}; + +int mt8186_set_audio_int_bus_parent(struct mtk_base_afe *afe, + int clk_id) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int ret; + + ret = clk_set_parent(afe_priv->clk[CLK_MUX_AUDIOINTBUS], + afe_priv->clk[clk_id]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_MUX_AUDIOINTBUS], + aud_clks[clk_id], ret); + return ret; + } + + return 0; +} + +static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int ret; + + if (enable) { + ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_1]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_1], ret); + return ret; + } + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_1], + afe_priv->clk[CLK_TOP_APLL1_CK]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_1], + aud_clks[CLK_TOP_APLL1_CK], ret); + return ret; + } + + /* 180.6336 / 8 = 22.5792MHz */ + ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1], ret); + return ret; + } + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1], + afe_priv->clk[CLK_TOP_APLL1_D8]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1], + aud_clks[CLK_TOP_APLL1_D8], ret); + return ret; + } + } else { + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1], + aud_clks[CLK_CLK26M], ret); + return ret; + } + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1]); + + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_1], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_1], + aud_clks[CLK_CLK26M], ret); + return ret; + } + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_1]); + } + + return 0; +} + +static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int ret; + + if (enable) { + ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_2]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_2], ret); + return ret; + } + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_2], + afe_priv->clk[CLK_TOP_APLL2_CK]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_2], + aud_clks[CLK_TOP_APLL2_CK], ret); + return ret; + } + + /* 196.608 / 8 = 24.576MHz */ + ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2], ret); + return ret; + } + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2], + afe_priv->clk[CLK_TOP_APLL2_D8]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2], + aud_clks[CLK_TOP_APLL2_D8], ret); + return ret; + } + } else { + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2], + aud_clks[CLK_CLK26M], ret); + return ret; + } + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2]); + + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_2], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_2], + aud_clks[CLK_CLK26M], ret); + return ret; + } + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_2]); + } + + return 0; +} + +int mt8186_afe_enable_cgs(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int ret = 0; + int i; + + for (i = CLK_I2S1_BCLK; i <= CLK_ETDM_OUT1_BCLK; i++) { + ret = clk_prepare_enable(afe_priv->clk[i]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[i], ret); + return ret; + } + } + + return 0; +} + +void mt8186_afe_disable_cgs(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int i; + + for (i = CLK_I2S1_BCLK; i <= CLK_ETDM_OUT1_BCLK; i++) + clk_disable_unprepare(afe_priv->clk[i]); +} + +int mt8186_afe_enable_clock(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int ret = 0; + + ret = clk_prepare_enable(afe_priv->clk[CLK_INFRA_SYS_AUDIO]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_INFRA_SYS_AUDIO], ret); + goto clk_infra_sys_audio_err; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_INFRA_AUDIO_26M]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_INFRA_AUDIO_26M], ret); + goto clk_infra_audio_26m_err; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIO]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_MUX_AUDIO], ret); + goto clk_mux_audio_err; + } + ret = clk_set_parent(afe_priv->clk[CLK_MUX_AUDIO], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_MUX_AUDIO], + aud_clks[CLK_CLK26M], ret); + goto clk_mux_audio_err; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_MUX_AUDIOINTBUS], ret); + goto clk_mux_audio_intbus_err; + } + ret = mt8186_set_audio_int_bus_parent(afe, + CLK_TOP_MAINPLL_D2_D4); + if (ret) + goto clk_mux_audio_intbus_parent_err; + + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUDIO_H], + afe_priv->clk[CLK_TOP_APLL2_CK]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUDIO_H], + aud_clks[CLK_TOP_APLL2_CK], ret); + goto clk_mux_audio_h_parent_err; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_AFE]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_AFE], ret); + goto clk_afe_err; + } + + return 0; + +clk_afe_err: + clk_disable_unprepare(afe_priv->clk[CLK_AFE]); +clk_mux_audio_h_parent_err: +clk_mux_audio_intbus_parent_err: + mt8186_set_audio_int_bus_parent(afe, CLK_CLK26M); +clk_mux_audio_intbus_err: + clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); +clk_mux_audio_err: + clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIO]); +clk_infra_sys_audio_err: + clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUDIO]); +clk_infra_audio_26m_err: + clk_disable_unprepare(afe_priv->clk[CLK_INFRA_AUDIO_26M]); + + return ret; +} + +void mt8186_afe_disable_clock(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + + clk_disable_unprepare(afe_priv->clk[CLK_AFE]); + mt8186_set_audio_int_bus_parent(afe, CLK_CLK26M); + clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); + clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIO]); + clk_disable_unprepare(afe_priv->clk[CLK_INFRA_AUDIO_26M]); + clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUDIO]); +} + +int mt8186_afe_suspend_clock(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int ret; + + /* set audio int bus to 26M */ + ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); + if (ret) { + dev_info(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_MUX_AUDIOINTBUS], ret); + goto clk_mux_audio_intbus_err; + } + ret = mt8186_set_audio_int_bus_parent(afe, CLK_CLK26M); + if (ret) + goto clk_mux_audio_intbus_parent_err; + + clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); + + return 0; + +clk_mux_audio_intbus_parent_err: + mt8186_set_audio_int_bus_parent(afe, CLK_TOP_MAINPLL_D2_D4); +clk_mux_audio_intbus_err: + clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); + return ret; +} + +int mt8186_afe_resume_clock(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int ret; + + /* set audio int bus to normal working clock */ + ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); + if (ret) { + dev_info(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_MUX_AUDIOINTBUS], ret); + goto clk_mux_audio_intbus_err; + } + ret = mt8186_set_audio_int_bus_parent(afe, + CLK_TOP_MAINPLL_D2_D4); + if (ret) + goto clk_mux_audio_intbus_parent_err; + + clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); + + return 0; + +clk_mux_audio_intbus_parent_err: + mt8186_set_audio_int_bus_parent(afe, CLK_CLK26M); +clk_mux_audio_intbus_err: + clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); + return ret; +} + +int mt8186_apll1_enable(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int ret; + + /* setting for APLL */ + apll1_mux_setting(afe, true); + + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL22M]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_APLL22M], ret); + goto err_clk_apll22m; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL1_TUNER]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_APLL1_TUNER], ret); + goto err_clk_apll1_tuner; + } + + regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0xfff7, 0x832); + regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0x1, 0x1); + + regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE, + AFE_22M_ON_MASK_SFT, BIT(AFE_22M_ON_SFT)); + + return 0; + +err_clk_apll1_tuner: + clk_disable_unprepare(afe_priv->clk[CLK_APLL1_TUNER]); +err_clk_apll22m: + clk_disable_unprepare(afe_priv->clk[CLK_APLL22M]); + + return ret; +} + +void mt8186_apll1_disable(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + + regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE, + AFE_22M_ON_MASK_SFT, 0); + + regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0x1, 0); + + clk_disable_unprepare(afe_priv->clk[CLK_APLL1_TUNER]); + clk_disable_unprepare(afe_priv->clk[CLK_APLL22M]); + + apll1_mux_setting(afe, false); +} + +int mt8186_apll2_enable(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int ret; + + /* setting for APLL */ + apll2_mux_setting(afe, true); + + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL24M]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_APLL24M], ret); + goto err_clk_apll24m; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL2_TUNER]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_APLL2_TUNER], ret); + goto err_clk_apll2_tuner; + } + + regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0xfff7, 0x634); + regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0x1, 0x1); + + regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE, + AFE_24M_ON_MASK_SFT, BIT(AFE_24M_ON_SFT)); + + return 0; + +err_clk_apll2_tuner: + clk_disable_unprepare(afe_priv->clk[CLK_APLL2_TUNER]); +err_clk_apll24m: + clk_disable_unprepare(afe_priv->clk[CLK_APLL24M]); + + return ret; +} + +void mt8186_apll2_disable(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + + regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE, + AFE_24M_ON_MASK_SFT, 0); + + regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0x1, 0); + + clk_disable_unprepare(afe_priv->clk[CLK_APLL2_TUNER]); + clk_disable_unprepare(afe_priv->clk[CLK_APLL24M]); + + apll2_mux_setting(afe, false); +} + +int mt8186_get_apll_rate(struct mtk_base_afe *afe, int apll) +{ + return (apll == MT8186_APLL1) ? 180633600 : 196608000; +} + +int mt8186_get_apll_by_rate(struct mtk_base_afe *afe, int rate) +{ + return ((rate % 8000) == 0) ? MT8186_APLL2 : MT8186_APLL1; +} + +int mt8186_get_apll_by_name(struct mtk_base_afe *afe, const char *name) +{ + if (strcmp(name, APLL1_W_NAME) == 0) + return MT8186_APLL1; + + return MT8186_APLL2; +} + +/* mck */ +struct mt8186_mck_div { + u32 m_sel_id; + u32 div_clk_id; +}; + +static const struct mt8186_mck_div mck_div[MT8186_MCK_NUM] = { + [MT8186_I2S0_MCK] = { + .m_sel_id = CLK_TOP_I2S0_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV0, + }, + [MT8186_I2S1_MCK] = { + .m_sel_id = CLK_TOP_I2S1_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV1, + }, + [MT8186_I2S2_MCK] = { + .m_sel_id = CLK_TOP_I2S2_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV2, + }, + [MT8186_I2S4_MCK] = { + .m_sel_id = CLK_TOP_I2S4_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV4, + }, + [MT8186_TDM_MCK] = { + .m_sel_id = CLK_TOP_TDM_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV_TDM, + }, +}; + +int mt8186_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int apll = mt8186_get_apll_by_rate(afe, rate); + int apll_clk_id = apll == MT8186_APLL1 ? + CLK_TOP_MUX_AUD_1 : CLK_TOP_MUX_AUD_2; + int m_sel_id = mck_div[mck_id].m_sel_id; + int div_clk_id = mck_div[mck_id].div_clk_id; + int ret; + + /* select apll */ + if (m_sel_id >= 0) { + ret = clk_prepare_enable(afe_priv->clk[m_sel_id]); + if (ret) { + dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n", + __func__, aud_clks[m_sel_id], ret); + return ret; + } + ret = clk_set_parent(afe_priv->clk[m_sel_id], + afe_priv->clk[apll_clk_id]); + if (ret) { + dev_err(afe->dev, "%s(), clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[m_sel_id], + aud_clks[apll_clk_id], ret); + return ret; + } + } + + /* enable div, set rate */ + ret = clk_prepare_enable(afe_priv->clk[div_clk_id]); + if (ret) { + dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n", + __func__, aud_clks[div_clk_id], ret); + return ret; + } + ret = clk_set_rate(afe_priv->clk[div_clk_id], rate); + if (ret) { + dev_err(afe->dev, "%s(), clk_set_rate %s, rate %d, fail %d\n", + __func__, aud_clks[div_clk_id], rate, ret); + return ret; + } + + return 0; +} + +void mt8186_mck_disable(struct mtk_base_afe *afe, int mck_id) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + int m_sel_id = mck_div[mck_id].m_sel_id; + int div_clk_id = mck_div[mck_id].div_clk_id; + + clk_disable_unprepare(afe_priv->clk[div_clk_id]); + if (m_sel_id >= 0) + clk_disable_unprepare(afe_priv->clk[m_sel_id]); +} + +int mt8186_init_clock(struct mtk_base_afe *afe) +{ + struct mt8186_afe_private *afe_priv = afe->platform_priv; + struct device_node *of_node = afe->dev->of_node; + int i = 0; + + mt8186_audsys_clk_register(afe); + + afe_priv->clk = devm_kcalloc(afe->dev, CLK_NUM, sizeof(*afe_priv->clk), + GFP_KERNEL); + if (!afe_priv->clk) + return -ENOMEM; + + for (i = 0; i < CLK_NUM; i++) { + afe_priv->clk[i] = devm_clk_get(afe->dev, aud_clks[i]); + if (IS_ERR(afe_priv->clk[i])) { + dev_err(afe->dev, "%s devm_clk_get %s fail, ret %ld\n", + __func__, + aud_clks[i], PTR_ERR(afe_priv->clk[i])); + afe_priv->clk[i] = NULL; + } + } + + afe_priv->apmixedsys = syscon_regmap_lookup_by_phandle(of_node, + "mediatek,apmixedsys"); + if (IS_ERR(afe_priv->apmixedsys)) { + dev_err(afe->dev, "%s() Cannot find apmixedsys controller: %ld\n", + __func__, PTR_ERR(afe_priv->apmixedsys)); + return PTR_ERR(afe_priv->apmixedsys); + } + + afe_priv->topckgen = syscon_regmap_lookup_by_phandle(of_node, + "mediatek,topckgen"); + if (IS_ERR(afe_priv->topckgen)) { + dev_err(afe->dev, "%s() Cannot find topckgen controller: %ld\n", + __func__, PTR_ERR(afe_priv->topckgen)); + return PTR_ERR(afe_priv->topckgen); + } + + afe_priv->infracfg = syscon_regmap_lookup_by_phandle(of_node, + "mediatek,infracfg"); + if (IS_ERR(afe_priv->infracfg)) { + dev_err(afe->dev, "%s() Cannot find infracfg: %ld\n", + __func__, PTR_ERR(afe_priv->infracfg)); + return PTR_ERR(afe_priv->infracfg); + } + + return 0; +} + +void mt8186_deinit_clock(struct mtk_base_afe *afe) +{ + mt8186_audsys_clk_unregister(afe); +} diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-clk.h b/sound/soc/mediatek/mt8186/mt8186-afe-clk.h new file mode 100644 index 000000000000..c539557d7c78 --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-afe-clk.h @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * mt8186-afe-clk.h -- Mediatek 8186 afe clock ctrl definition + * + * Copyright (c) 2022 MediaTek Inc. + * Author: Jiaxin Yu + */ + +#ifndef _MT8186_AFE_CLOCK_CTRL_H_ +#define _MT8186_AFE_CLOCK_CTRL_H_ + +#define PERI_BUS_DCM_CTRL 0x74 + +/* APLL */ +#define APLL1_W_NAME "APLL1" +#define APLL2_W_NAME "APLL2" +enum { + MT8186_APLL1 = 0, + MT8186_APLL2, +}; + +enum { + CLK_AFE = 0, + CLK_DAC, + CLK_DAC_PREDIS, + CLK_ADC, + CLK_TML, + CLK_APLL22M, + CLK_APLL24M, + CLK_APLL1_TUNER, + CLK_APLL2_TUNER, + CLK_TDM, + CLK_NLE, + CLK_DAC_HIRES, + CLK_ADC_HIRES, + CLK_I2S1_BCLK, + CLK_I2S2_BCLK, + CLK_I2S3_BCLK, + CLK_I2S4_BCLK, + CLK_CONNSYS_I2S_ASRC, + CLK_GENERAL1_ASRC, + CLK_GENERAL2_ASRC, + CLK_ADC_HIRES_TML, + CLK_ADDA6_ADC, + CLK_ADDA6_ADC_HIRES, + CLK_3RD_DAC, + CLK_3RD_DAC_PREDIS, + CLK_3RD_DAC_TML, + CLK_3RD_DAC_HIRES, + CLK_ETDM_IN1_BCLK, + CLK_ETDM_OUT1_BCLK, + CLK_INFRA_SYS_AUDIO, + CLK_INFRA_AUDIO_26M, + CLK_MUX_AUDIO, + CLK_MUX_AUDIOINTBUS, + CLK_TOP_MAINPLL_D2_D4, + /* apll related mux */ + CLK_TOP_MUX_AUD_1, + CLK_TOP_APLL1_CK, + CLK_TOP_MUX_AUD_2, + CLK_TOP_APLL2_CK, + CLK_TOP_MUX_AUD_ENG1, + CLK_TOP_APLL1_D8, + CLK_TOP_MUX_AUD_ENG2, + CLK_TOP_APLL2_D8, + CLK_TOP_MUX_AUDIO_H, + CLK_TOP_I2S0_M_SEL, + CLK_TOP_I2S1_M_SEL, + CLK_TOP_I2S2_M_SEL, + CLK_TOP_I2S4_M_SEL, + CLK_TOP_TDM_M_SEL, + CLK_TOP_APLL12_DIV0, + CLK_TOP_APLL12_DIV1, + CLK_TOP_APLL12_DIV2, + CLK_TOP_APLL12_DIV4, + CLK_TOP_APLL12_DIV_TDM, + CLK_CLK26M, + CLK_NUM +}; + +struct mtk_base_afe; +int mt8186_set_audio_int_bus_parent(struct mtk_base_afe *afe, int clk_id); +int mt8186_init_clock(struct mtk_base_afe *afe); +void mt8186_deinit_clock(struct mtk_base_afe *afe); +int mt8186_afe_enable_cgs(struct mtk_base_afe *afe); +void mt8186_afe_disable_cgs(struct mtk_base_afe *afe); +int mt8186_afe_enable_clock(struct mtk_base_afe *afe); +void mt8186_afe_disable_clock(struct mtk_base_afe *afe); +int mt8186_afe_suspend_clock(struct mtk_base_afe *afe); +int mt8186_afe_resume_clock(struct mtk_base_afe *afe); + +int mt8186_apll1_enable(struct mtk_base_afe *afe); +void mt8186_apll1_disable(struct mtk_base_afe *afe); + +int mt8186_apll2_enable(struct mtk_base_afe *afe); +void mt8186_apll2_disable(struct mtk_base_afe *afe); + +int mt8186_get_apll_rate(struct mtk_base_afe *afe, int apll); +int mt8186_get_apll_by_rate(struct mtk_base_afe *afe, int rate); +int mt8186_get_apll_by_name(struct mtk_base_afe *afe, const char *name); + +/* these will be replaced by using CCF */ +int mt8186_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate); +void mt8186_mck_disable(struct mtk_base_afe *afe, int mck_id); + +#endif From patchwork Sun Mar 13 15:10:16 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?SmlheGluIFl1ICjkv57lrrbpkasp?= X-Patchwork-Id: 550992 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4C4E0C433F5 for ; Sun, 13 Mar 2022 15:10:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234771AbiCMPMB (ORCPT ); Sun, 13 Mar 2022 11:12:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39808 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234772AbiCMPL4 (ORCPT ); Sun, 13 Mar 2022 11:11:56 -0400 Received: from mailgw02.mediatek.com (unknown [210.61.82.184]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1605F85BCA; Sun, 13 Mar 2022 08:10:44 -0700 (PDT) X-UUID: 03de554f72ab4e9e9d6a81aa3b220bd4-20220313 X-UUID: 03de554f72ab4e9e9d6a81aa3b220bd4-20220313 Received: from mtkmbs10n1.mediatek.inc [(172.21.101.34)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 974439378; Sun, 13 Mar 2022 23:10:39 +0800 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkmbs07n1.mediatek.inc (172.21.101.16) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sun, 13 Mar 2022 23:10:37 +0800 Received: from localhost.localdomain (10.17.3.154) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sun, 13 Mar 2022 23:10:36 +0800 From: Jiaxin Yu To: , , CC: , , , , , , , , , , , Jiaxin Yu Subject: [v3 12/19] ASoC: mediatek: mt8186: support gpio control in platform driver Date: Sun, 13 Mar 2022 23:10:16 +0800 Message-ID: <20220313151023.21229-13-jiaxin.yu@mediatek.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220313151023.21229-1-jiaxin.yu@mediatek.com> References: <20220313151023.21229-1-jiaxin.yu@mediatek.com> MIME-Version: 1.0 X-MTK: N Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Add gpio control for all audio interface separately. Signed-off-by: Jiaxin Yu --- sound/soc/mediatek/mt8186/mt8186-afe-gpio.c | 244 ++++++++++++++++++++ sound/soc/mediatek/mt8186/mt8186-afe-gpio.h | 19 ++ 2 files changed, 263 insertions(+) create mode 100644 sound/soc/mediatek/mt8186/mt8186-afe-gpio.c create mode 100644 sound/soc/mediatek/mt8186/mt8186-afe-gpio.h diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-gpio.c b/sound/soc/mediatek/mt8186/mt8186-afe-gpio.c new file mode 100644 index 000000000000..5ba28095b7da --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-afe-gpio.c @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// mt8186-afe-gpio.c -- Mediatek 8186 afe gpio ctrl +// +// Copyright (c) 2022 MediaTek Inc. +// Author: Jiaxin Yu + +#include +#include + +#include "mt8186-afe-common.h" +#include "mt8186-afe-gpio.h" + +struct pinctrl *aud_pinctrl; + +enum mt8186_afe_gpio { + MT8186_AFE_GPIO_CLK_MOSI_OFF, + MT8186_AFE_GPIO_CLK_MOSI_ON, + MT8186_AFE_GPIO_CLK_MISO_OFF, + MT8186_AFE_GPIO_CLK_MISO_ON, + MT8186_AFE_GPIO_DAT_MISO_OFF, + MT8186_AFE_GPIO_DAT_MISO_ON, + MT8186_AFE_GPIO_DAT_MOSI_OFF, + MT8186_AFE_GPIO_DAT_MOSI_ON, + MT8186_AFE_GPIO_I2S0_OFF, + MT8186_AFE_GPIO_I2S0_ON, + MT8186_AFE_GPIO_I2S1_OFF, + MT8186_AFE_GPIO_I2S1_ON, + MT8186_AFE_GPIO_I2S2_OFF, + MT8186_AFE_GPIO_I2S2_ON, + MT8186_AFE_GPIO_I2S3_OFF, + MT8186_AFE_GPIO_I2S3_ON, + MT8186_AFE_GPIO_TDM_OFF, + MT8186_AFE_GPIO_TDM_ON, + MT8186_AFE_GPIO_PCM_OFF, + MT8186_AFE_GPIO_PCM_ON, + MT8186_AFE_GPIO_GPIO_NUM +}; + +struct audio_gpio_attr { + const char *name; + bool gpio_prepare; + struct pinctrl_state *gpioctrl; +}; + +static struct audio_gpio_attr aud_gpios[MT8186_AFE_GPIO_GPIO_NUM] = { + [MT8186_AFE_GPIO_CLK_MOSI_OFF] = {"aud_clk_mosi_off", false, NULL}, + [MT8186_AFE_GPIO_CLK_MOSI_ON] = {"aud_clk_mosi_on", false, NULL}, + [MT8186_AFE_GPIO_CLK_MISO_OFF] = {"aud_clk_miso_off", false, NULL}, + [MT8186_AFE_GPIO_CLK_MISO_ON] = {"aud_clk_miso_on", false, NULL}, + [MT8186_AFE_GPIO_DAT_MISO_OFF] = {"aud_dat_miso_off", false, NULL}, + [MT8186_AFE_GPIO_DAT_MISO_ON] = {"aud_dat_miso_on", false, NULL}, + [MT8186_AFE_GPIO_DAT_MOSI_OFF] = {"aud_dat_mosi_off", false, NULL}, + [MT8186_AFE_GPIO_DAT_MOSI_ON] = {"aud_dat_mosi_on", false, NULL}, + [MT8186_AFE_GPIO_I2S0_OFF] = {"aud_gpio_i2s0_off", false, NULL}, + [MT8186_AFE_GPIO_I2S0_ON] = {"aud_gpio_i2s0_on", false, NULL}, + [MT8186_AFE_GPIO_I2S1_OFF] = {"aud_gpio_i2s1_off", false, NULL}, + [MT8186_AFE_GPIO_I2S1_ON] = {"aud_gpio_i2s1_on", false, NULL}, + [MT8186_AFE_GPIO_I2S2_OFF] = {"aud_gpio_i2s2_off", false, NULL}, + [MT8186_AFE_GPIO_I2S2_ON] = {"aud_gpio_i2s2_on", false, NULL}, + [MT8186_AFE_GPIO_I2S3_OFF] = {"aud_gpio_i2s3_off", false, NULL}, + [MT8186_AFE_GPIO_I2S3_ON] = {"aud_gpio_i2s3_on", false, NULL}, + [MT8186_AFE_GPIO_TDM_OFF] = {"aud_gpio_tdm_off", false, NULL}, + [MT8186_AFE_GPIO_TDM_ON] = {"aud_gpio_tdm_on", false, NULL}, + [MT8186_AFE_GPIO_PCM_OFF] = {"aud_gpio_pcm_off", false, NULL}, + [MT8186_AFE_GPIO_PCM_ON] = {"aud_gpio_pcm_on", false, NULL}, +}; + +static DEFINE_MUTEX(gpio_request_mutex); + +int mt8186_afe_gpio_init(struct device *dev) +{ + int i, j, ret; + + aud_pinctrl = devm_pinctrl_get(dev); + if (IS_ERR(aud_pinctrl)) { + ret = PTR_ERR(aud_pinctrl); + dev_err(dev, "%s(), ret %d, cannot get aud_pinctrl!\n", + __func__, ret); + return ret; + } + + for (i = 0; i < ARRAY_SIZE(aud_gpios); i++) { + aud_gpios[i].gpioctrl = pinctrl_lookup_state(aud_pinctrl, + aud_gpios[i].name); + if (IS_ERR(aud_gpios[i].gpioctrl)) { + ret = PTR_ERR(aud_gpios[i].gpioctrl); + dev_info(dev, "%s(), pinctrl_lookup_state %s fail, ret %d\n", + __func__, aud_gpios[i].name, ret); + } else { + aud_gpios[i].gpio_prepare = true; + } + } + + /* gpio status init */ + for (i = MT8186_DAI_ADDA; i <= MT8186_DAI_TDM_IN; i++) { + for (j = 0; j <= 1; j++) + mt8186_afe_gpio_request(dev, false, i, j); + } + + return 0; +} +EXPORT_SYMBOL_GPL(mt8186_afe_gpio_init); + +static int mt8186_afe_gpio_select(struct device *dev, + enum mt8186_afe_gpio type) +{ + int ret = 0; + + if (type < 0 || type >= MT8186_AFE_GPIO_GPIO_NUM) { + dev_err(dev, "%s(), error, invalid gpio type %d\n", + __func__, type); + return -EINVAL; + } + + if (!aud_gpios[type].gpio_prepare) { + dev_err(dev, "%s(), error, gpio type %d not prepared\n", + __func__, type); + return -EIO; + } + + ret = pinctrl_select_state(aud_pinctrl, + aud_gpios[type].gpioctrl); + if (ret) { + dev_err(dev, "%s(), error, can not set gpio type %d\n", + __func__, type); + return ret; + } + + return 0; +} + +static int mt8186_afe_gpio_adda_dl(struct device *dev, bool enable) +{ + int ret; + + if (enable) { + ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MOSI_ON); + if (ret) { + dev_err(dev, "%s(), MOSI CLK ON slect fail!\n", __func__); + return ret; + } + + ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MOSI_ON); + if (ret) { + dev_err(dev, "%s(), MOSI DAT ON slect fail!\n", __func__); + return ret; + } + } else { + ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MOSI_OFF); + if (ret) { + dev_err(dev, "%s(), MOSI DAT OFF slect fail!\n", __func__); + return ret; + } + + ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MOSI_OFF); + if (ret) { + dev_err(dev, "%s(), MOSI CLK ON slect fail!\n", __func__); + return ret; + } + } + + return 0; +} + +static int mt8186_afe_gpio_adda_ul(struct device *dev, bool enable) +{ + int ret; + + if (enable) { + ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MISO_ON); + if (ret) { + dev_err(dev, "%s(), MISO CLK ON slect fail!\n", __func__); + return ret; + } + + ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MISO_ON); + if (ret) { + dev_err(dev, "%s(), MISO DAT ON slect fail!\n", __func__); + return ret; + } + } else { + ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MISO_OFF); + if (ret) { + dev_err(dev, "%s(), MISO DAT OFF slect fail!\n", __func__); + return ret; + } + + ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MISO_OFF); + if (ret) { + dev_err(dev, "%s(), MISO CLK OFF slect fail!\n", __func__); + return ret; + } + } + + return 0; +} + +int mt8186_afe_gpio_request(struct device *dev, bool enable, + int dai, int uplink) +{ + enum mt8186_afe_gpio sel; + int ret = -EINVAL; + + mutex_lock(&gpio_request_mutex); + + switch (dai) { + case MT8186_DAI_ADDA: + if (uplink) + ret = mt8186_afe_gpio_adda_ul(dev, enable); + else + ret = mt8186_afe_gpio_adda_dl(dev, enable); + goto unlock; + case MT8186_DAI_I2S_0: + sel = enable ? MT8186_AFE_GPIO_I2S0_ON : MT8186_AFE_GPIO_I2S0_OFF; + break; + case MT8186_DAI_I2S_1: + sel = enable ? MT8186_AFE_GPIO_I2S1_ON : MT8186_AFE_GPIO_I2S1_OFF; + break; + case MT8186_DAI_I2S_2: + sel = enable ? MT8186_AFE_GPIO_I2S2_ON : MT8186_AFE_GPIO_I2S2_OFF; + break; + case MT8186_DAI_I2S_3: + sel = enable ? MT8186_AFE_GPIO_I2S3_ON : MT8186_AFE_GPIO_I2S3_OFF; + break; + case MT8186_DAI_TDM_IN: + sel = enable ? MT8186_AFE_GPIO_TDM_ON : MT8186_AFE_GPIO_TDM_OFF; + break; + case MT8186_DAI_PCM: + sel = enable ? MT8186_AFE_GPIO_PCM_ON : MT8186_AFE_GPIO_PCM_OFF; + break; + default: + mutex_unlock(&gpio_request_mutex); + dev_err(dev, "%s(), invalid dai %d\n", __func__, dai); + goto unlock; + } + + ret = mt8186_afe_gpio_select(dev, sel); + +unlock: + mutex_unlock(&gpio_request_mutex); + + return ret; +} diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-gpio.h b/sound/soc/mediatek/mt8186/mt8186-afe-gpio.h new file mode 100644 index 000000000000..1ddc27838eb1 --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-afe-gpio.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * mt6833-afe-gpio.h -- Mediatek 6833 afe gpio ctrl definition + * + * Copyright (c) 2022 MediaTek Inc. + * Author: Jiaxin Yu + */ + +#ifndef _MT8186_AFE_GPIO_H_ +#define _MT8186_AFE_GPIO_H_ + +struct mtk_base_afe; + +int mt8186_afe_gpio_init(struct device *dev); + +int mt8186_afe_gpio_request(struct device *dev, bool enable, + int dai, int uplink); + +#endif From patchwork Sun Mar 13 15:10:21 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?SmlheGluIFl1ICjkv57lrrbpkasp?= X-Patchwork-Id: 550989 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 32542C4332F for ; Sun, 13 Mar 2022 15:11:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234819AbiCMPMM (ORCPT ); Sun, 13 Mar 2022 11:12:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39434 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234818AbiCMPMH (ORCPT ); Sun, 13 Mar 2022 11:12:07 -0400 Received: from mailgw01.mediatek.com (unknown [60.244.123.138]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CB3A186E15; Sun, 13 Mar 2022 08:10:51 -0700 (PDT) X-UUID: 512427454d354fd7b3f1fc70b50fca91-20220313 X-UUID: 512427454d354fd7b3f1fc70b50fca91-20220313 Received: from mtkcas10.mediatek.inc [(172.21.101.39)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 1449827572; Sun, 13 Mar 2022 23:10:43 +0800 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkmbs07n2.mediatek.inc (172.21.101.141) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sun, 13 Mar 2022 23:10:42 +0800 Received: from localhost.localdomain (10.17.3.154) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sun, 13 Mar 2022 23:10:41 +0800 From: Jiaxin Yu To: , , CC: , , , , , , , , , , , Jiaxin Yu Subject: [v3 17/19] ASoC: mediatek: mt8186: add machine driver with mt6366, rt1019 and rt5682s Date: Sun, 13 Mar 2022 23:10:21 +0800 Message-ID: <20220313151023.21229-18-jiaxin.yu@mediatek.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220313151023.21229-1-jiaxin.yu@mediatek.com> References: <20220313151023.21229-1-jiaxin.yu@mediatek.com> MIME-Version: 1.0 X-MTK: N Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Add support for mt8186 board with mt6366, rt1019 and rt5682s. Signed-off-by: Jiaxin Yu --- .../mt8186/mt8186-mt6366-rt1019-rt5682s.c | 900 ++++++++++++++++++ 1 file changed, 900 insertions(+) create mode 100644 sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c new file mode 100644 index 000000000000..294d9ce7c11d --- /dev/null +++ b/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c @@ -0,0 +1,900 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// mt8186-mt6366-rt1019-rt5682s.c +// -- MT8186-MT6366-RT1019-RT5682S ALSA SoC machine driver +// +// Copyright (c) 2022 MediaTek Inc. +// Author: Jiaxin Yu +// + +#include +#include +#include +#include +#include +#include +#include + +#include "../../codecs/mt6358.h" +#include "../../codecs/rt5682.h" +#include "../common/mtk-afe-platform-driver.h" +#include "mt8186-afe-common.h" +#include "mt8186-afe-clk.h" +#include "mt8186-afe-gpio.h" + +#define RT1019_CODEC_DAI "HiFi" +#define RT1019_DEV0_NAME "rt1019p" + +#define RT5682S_CODEC_DAI "rt5682s-aif1" +#define RT5682S_DEV0_NAME "rt5682s.5-001a" + +struct mt8186_mt6366_rt1019_rt5682s_priv { + struct snd_soc_jack headset_jack, hdmi_jack; +}; + +static struct snd_soc_codec_conf mt6366_codec_conf[] = { + { + .dlc = COMP_CODEC_CONF("mt6358-sound"), + .name_prefix = "Mt6366", + }, + { + .dlc = COMP_CODEC_CONF("bt-sco"), + .name_prefix = "Mt8186 bt", + }, + { + .dlc = COMP_CODEC_CONF("hdmi-audio-codec"), + .name_prefix = "Mt8186 hdmi", + }, +}; + +static int mt8186_rt5682s_init(struct snd_soc_pcm_runtime *rtd) +{ + struct mt8186_mt6366_rt1019_rt5682s_priv *priv = + snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_jack *jack = &priv->headset_jack; + struct snd_soc_component *cmpnt_codec = + asoc_rtd_to_codec(rtd, 0)->component; + int ret; + + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + jack, NULL, 0); + 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); + + return snd_soc_component_set_jack(cmpnt_codec, jack, NULL); +} + +static int mt8186_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 = asoc_rtd_to_cpu(rtd, 0); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + unsigned int rate = params_rate(params); + unsigned int mclk_fs_ratio = 128; + unsigned int mclk_fs = rate * mclk_fs_ratio; + 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, RT5682_PLL1, + RT5682_PLL1_S_BCLK1, + params_rate(params) * 64, + params_rate(params) * 512); + if (ret) { + dev_err(card->dev, "failed to set pll\n"); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, + RT5682_SCLK_S_PLL1, + params_rate(params) * 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, mclk_fs, SND_SOC_CLOCK_OUT); +} + +static const struct snd_soc_ops mt8186_rt5682s_i2s_ops = { + .hw_params = mt8186_rt5682s_i2s_hw_params, +}; + +static int mt8186_mt6366_hdmi_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *cmpnt_codec = + asoc_rtd_to_codec(rtd, 0)->component; + struct mt8186_mt6366_rt1019_rt5682s_priv *priv = + snd_soc_card_get_drvdata(rtd->card); + int ret; + + ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT, + &priv->hdmi_jack, NULL, 0); + if (ret) { + dev_err(rtd->dev, "HDMI Jack creation failed: %d\n", ret); + return ret; + } + + return snd_soc_component_set_jack(cmpnt_codec, &priv->hdmi_jack, NULL); +} + +static int mt8186_mt6366_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *cmpnt_afe = + snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); + struct snd_soc_component *cmpnt_codec = + asoc_rtd_to_codec(rtd, 0)->component; + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt_afe); + struct mt8186_afe_private *afe_priv = afe->platform_priv; + struct snd_soc_dapm_context *dapm = &rtd->card->dapm; + int ret; + + /* set mtkaif protocol */ + mt6358_set_mtkaif_protocol(cmpnt_codec, + MT6358_MTKAIF_PROTOCOL_1); + afe_priv->mtkaif_protocol = MT6358_MTKAIF_PROTOCOL_1; + + ret = snd_soc_dapm_sync(dapm); + if (ret) { + dev_info(rtd->dev, "failed to snd_soc_dapm_sync\n"); + return ret; + } + + return 0; +} + +static int mt8186_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params, + snd_pcm_format_t fmt) +{ + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + dev_dbg(rtd->dev, "%s(), fix format to %d\n", __func__, fmt); + + /* fix BE i2s channel to 2 channel */ + channels->min = 2; + channels->max = 2; + + /* 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, fmt); + + return 0; +} + +static int mt8186_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + return mt8186_hw_params_fixup(rtd, params, SNDRV_PCM_FORMAT_S24_LE); +} + +static int mt8186_hdmi_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + return mt8186_hw_params_fixup(rtd, params, SNDRV_PCM_FORMAT_S32_LE); +} + +/* 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(playback12, + DAILINK_COMP_ARRAY(COMP_CPU("DL12")), + 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(playback3, + DAILINK_COMP_ARRAY(COMP_CPU("DL3")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback4, + DAILINK_COMP_ARRAY(COMP_CPU("DL4")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback5, + DAILINK_COMP_ARRAY(COMP_CPU("DL5")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback6, + DAILINK_COMP_ARRAY(COMP_CPU("DL6")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback7, + DAILINK_COMP_ARRAY(COMP_CPU("DL7")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback8, + DAILINK_COMP_ARRAY(COMP_CPU("DL8")), + 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(capture3, + DAILINK_COMP_ARRAY(COMP_CPU("UL3")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture4, + DAILINK_COMP_ARRAY(COMP_CPU("UL4")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture5, + DAILINK_COMP_ARRAY(COMP_CPU("UL5")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture6, + DAILINK_COMP_ARRAY(COMP_CPU("UL6")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture7, + DAILINK_COMP_ARRAY(COMP_CPU("UL7")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +/* hostless */ +SND_SOC_DAILINK_DEFS(hostless_lpbk, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless LPBK DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hostless_fm, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless FM DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hostless_src1, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless_SRC_1_DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hostless_src_bargein, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless_SRC_Bargein_DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +/* BE */ +SND_SOC_DAILINK_DEFS(adda, + DAILINK_COMP_ARRAY(COMP_CPU("ADDA")), + DAILINK_COMP_ARRAY(COMP_CODEC("mt6358-sound", + "mt6358-snd-codec-aif1"), + COMP_CODEC("dmic-codec", + "dmic-hifi")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(i2s0, + DAILINK_COMP_ARRAY(COMP_CPU("I2S0")), + DAILINK_COMP_ARRAY(COMP_CODEC(RT5682S_DEV0_NAME, + RT5682S_CODEC_DAI)), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(i2s1, + DAILINK_COMP_ARRAY(COMP_CPU("I2S1")), + DAILINK_COMP_ARRAY(COMP_CODEC(RT5682S_DEV0_NAME, + RT5682S_CODEC_DAI)), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(i2s2, + DAILINK_COMP_ARRAY(COMP_CPU("I2S2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(i2s3, + DAILINK_COMP_ARRAY(COMP_CPU("I2S3")), + DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "i2s-hifi"), + COMP_CODEC(RT1019_DEV0_NAME, + RT1019_CODEC_DAI)), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hw_gain1, + DAILINK_COMP_ARRAY(COMP_CPU("HW Gain 1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hw_gain2, + DAILINK_COMP_ARRAY(COMP_CPU("HW Gain 2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hw_src1, + DAILINK_COMP_ARRAY(COMP_CPU("HW_SRC_1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hw_src2, + DAILINK_COMP_ARRAY(COMP_CPU("HW_SRC_2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(connsys_i2s, + DAILINK_COMP_ARRAY(COMP_CPU("CONNSYS_I2S")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(pcm1, + DAILINK_COMP_ARRAY(COMP_CPU("PCM 1")), + DAILINK_COMP_ARRAY(COMP_CODEC("bt-sco", "bt-sco-pcm-wb")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(tdm_in, + DAILINK_COMP_ARRAY(COMP_CPU("TDM IN")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +/* hostless */ +SND_SOC_DAILINK_DEFS(hostless_ul1, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL1 DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hostless_ul2, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL2 DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hostless_ul3, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL3 DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hostless_ul5, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL5 DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hostless_ul6, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL6 DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hostless_hw_gain_aaudio, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless HW Gain AAudio DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(hostless_src_aaudio, + DAILINK_COMP_ARRAY(COMP_CPU("Hostless SRC AAudio DAI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +#if IS_ENABLED(CONFIG_SND_SOC_MTK_BTCVSD) +SND_SOC_DAILINK_DEFS(btcvsd, + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_PLATFORM("18050000.mtk-btcvsd-snd"))); +#endif +static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { + /* Front End DAI links */ + { + .name = "Playback_1", + .stream_name = "Playback_1", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_merged_format = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + SND_SOC_DAILINK_REG(playback1), + }, + { + .name = "Playback_12", + .stream_name = "Playback_12", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback12), + }, + { + .name = "Playback_2", + .stream_name = "Playback_2", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_merged_format = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + SND_SOC_DAILINK_REG(playback2), + }, + { + .name = "Playback_3", + .stream_name = "Playback_3", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_merged_format = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + SND_SOC_DAILINK_REG(playback3), + }, + { + .name = "Playback_4", + .stream_name = "Playback_4", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback4), + }, + { + .name = "Playback_5", + .stream_name = "Playback_5", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback5), + }, + { + .name = "Playback_6", + .stream_name = "Playback_6", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback6), + }, + { + .name = "Playback_7", + .stream_name = "Playback_7", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback7), + }, + { + .name = "Playback_8", + .stream_name = "Playback_8", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback8), + }, + { + .name = "Capture_1", + .stream_name = "Capture_1", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(capture1), + }, + { + .name = "Capture_2", + .stream_name = "Capture_2", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_merged_format = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + SND_SOC_DAILINK_REG(capture2), + }, + { + .name = "Capture_3", + .stream_name = "Capture_3", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(capture3), + }, + { + .name = "Capture_4", + .stream_name = "Capture_4", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_merged_format = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + SND_SOC_DAILINK_REG(capture4), + }, + { + .name = "Capture_5", + .stream_name = "Capture_5", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(capture5), + }, + { + .name = "Capture_6", + .stream_name = "Capture_6", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_merged_format = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + SND_SOC_DAILINK_REG(capture6), + }, + { + .name = "Capture_7", + .stream_name = "Capture_7", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(capture7), + }, + { + .name = "Hostless_LPBK", + .stream_name = "Hostless_LPBK", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_lpbk), + }, + { + .name = "Hostless_FM", + .stream_name = "Hostless_FM", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_fm), + }, + { + .name = "Hostless_SRC_1", + .stream_name = "Hostless_SRC_1", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_src1), + }, + { + .name = "Hostless_SRC_Bargein", + .stream_name = "Hostless_SRC_Bargein", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_src_bargein), + }, + { + .name = "Hostless_HW_Gain_AAudio", + .stream_name = "Hostless_HW_Gain_AAudio", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_hw_gain_aaudio), + }, + { + .name = "Hostless_SRC_AAudio", + .stream_name = "Hostless_SRC_AAudio", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_src_aaudio), + }, + /* BTCVSD */ +#if IS_ENABLED(CONFIG_SND_SOC_MTK_BTCVSD) + { + .name = "BTCVSD", + .stream_name = "BTCVSD", + SND_SOC_DAILINK_REG(btcvsd), + }, +#endif + /* Back End DAI links */ + { + .name = "Primary Codec", + .no_pcm = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + .init = mt8186_mt6366_init, + SND_SOC_DAILINK_REG(adda), + }, + { + .name = "I2S3", + .no_pcm = 1, + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_IB_IF | + SND_SOC_DAIFMT_CBM_CFM, + .dpcm_playback = 1, + .ignore_suspend = 1, + .init = mt8186_mt6366_hdmi_init, + .be_hw_params_fixup = mt8186_hdmi_i2s_hw_params_fixup, + SND_SOC_DAILINK_REG(i2s3), + }, + { + .name = "I2S0", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + .be_hw_params_fixup = mt8186_i2s_hw_params_fixup, + .ops = &mt8186_rt5682s_i2s_ops, + SND_SOC_DAILINK_REG(i2s0), + }, + { + .name = "I2S1", + .no_pcm = 1, + .dpcm_playback = 1, + .ignore_suspend = 1, + .be_hw_params_fixup = mt8186_i2s_hw_params_fixup, + .init = mt8186_rt5682s_init, + .ops = &mt8186_rt5682s_i2s_ops, + SND_SOC_DAILINK_REG(i2s1), + }, + { + .name = "I2S2", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + .be_hw_params_fixup = mt8186_i2s_hw_params_fixup, + SND_SOC_DAILINK_REG(i2s2), + }, + { + .name = "HW Gain 1", + .no_pcm = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hw_gain1), + }, + { + .name = "HW Gain 2", + .no_pcm = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hw_gain2), + }, + { + .name = "HW_SRC_1", + .no_pcm = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hw_src1), + }, + { + .name = "HW_SRC_2", + .no_pcm = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hw_src2), + }, + { + .name = "CONNSYS_I2S", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(connsys_i2s), + }, + { + .name = "PCM 1", + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_IF, + .no_pcm = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(pcm1), + }, + { + .name = "TDM IN", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(tdm_in), + }, + /* dummy BE for ul memif to record from dl memif */ + { + .name = "Hostless_UL1", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_ul1), + }, + { + .name = "Hostless_UL2", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_ul2), + }, + { + .name = "Hostless_UL3", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_ul3), + }, + { + .name = "Hostless_UL5", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_ul5), + }, + { + .name = "Hostless_UL6", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(hostless_ul6), + }, +}; + +static const struct snd_soc_dapm_widget +mt8186_mt6366_rt1019_rt5682s_widgets[] = { + SND_SOC_DAPM_SPK("SPK Out", NULL), + SND_SOC_DAPM_OUTPUT("HDMI Out"), +}; + +static const struct snd_soc_dapm_route +mt8186_mt6366_rt1019_rt5682s_routes[] = { + /* SPK */ + { "SPK Out", NULL, "Speaker" }, + /* HDMI */ + { "HDMI Out", NULL, "TX" }, +}; + +static const struct snd_kcontrol_new +mt8186_mt6366_rt1019_rt5682s_controls[] = { + SOC_DAPM_PIN_SWITCH("SPK Out"), + SOC_DAPM_PIN_SWITCH("HDMI Out"), +}; + +static struct snd_soc_card mt8186_mt6366_rt1019_rt5682s_soc_card = { + .name = "mt8186_mt6366_rt1019_rt5682s", + .owner = THIS_MODULE, + .dai_link = mt8186_mt6366_rt1019_rt5682s_dai_links, + .num_links = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_dai_links), + .controls = mt8186_mt6366_rt1019_rt5682s_controls, + .num_controls = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_controls), + .dapm_widgets = mt8186_mt6366_rt1019_rt5682s_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_widgets), + .dapm_routes = mt8186_mt6366_rt1019_rt5682s_routes, + .num_dapm_routes = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_routes), + .codec_conf = mt6366_codec_conf, + .num_configs = ARRAY_SIZE(mt6366_codec_conf), +}; + +static int mt8186_mt6366_rt1019_rt5682s_dev_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &mt8186_mt6366_rt1019_rt5682s_soc_card; + struct snd_soc_dai_link *dai_link; + struct mt8186_mt6366_rt1019_rt5682s_priv *priv; + struct device_node *platform_node, *hdmi_codec; + int ret, i; + + dev_info(&pdev->dev, "%s(), ++\n", __func__); + + card->dev = &pdev->dev; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + platform_node = of_parse_phandle(pdev->dev.of_node, "mediatek,platform", 0); + if (!platform_node) { + ret = -EINVAL; + dev_err_probe(&pdev->dev, ret, "Property 'platform' missing or invalid\n"); + goto err_platform_node; + } + + hdmi_codec = of_parse_phandle(pdev->dev.of_node, "mediatek,hdmi-codec", 0); + if (!hdmi_codec) { + ret = -EINVAL; + dev_err_probe(&pdev->dev, ret, "Property 'hdmi' missing or invalid\n"); + goto err_hdmi_node; + } + + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->platforms->name) + continue; + + if (hdmi_codec && strcmp(dai_link->name, "I2S3") == 0) { + dai_link->codecs->of_node = hdmi_codec; + dai_link->ignore = 0; + } + + dai_link->platforms->of_node = platform_node; + } + + snd_soc_card_set_drvdata(card, priv); + + /* init gpio */ + ret = mt8186_afe_gpio_init(&pdev->dev); + if (ret) { + dev_err_probe(&pdev->dev, ret, "%s init gpio error\n", __func__); + goto err_init_gpio; + } + + dev_info(&pdev->dev, "%s(), devm_snd_soc_register_card\n", __func__); + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) + dev_err_probe(&pdev->dev, ret, + "%s snd_soc_register_card fail\n", __func__); + +err_init_gpio: + of_node_put(hdmi_codec); +err_hdmi_node: + of_node_put(platform_node); +err_platform_node: + + return ret; +} + +#if IS_ENABLED(CONFIG_OF) +static const struct of_device_id mt8186_mt6366_rt1019_rt5682s_dt_match[] = { + {.compatible = "mediatek,mt8186_mt6366_rt1019_rt5682s_sound",}, + {} +}; +#endif + +static struct platform_driver mt8186_mt6366_rt1019_rt5682s_driver = { + .driver = { + .name = "mt8186_mt6366_rt1019_rt5682s", +#if IS_ENABLED(CONFIG_OF) + .of_match_table = mt8186_mt6366_rt1019_rt5682s_dt_match, +#endif + .pm = &snd_soc_pm_ops, + }, + .probe = mt8186_mt6366_rt1019_rt5682s_dev_probe, +}; + +module_platform_driver(mt8186_mt6366_rt1019_rt5682s_driver); + +/* Module information */ +MODULE_DESCRIPTION("MT8186-MT6366-RT1019-RT5682S ALSA SoC machine driver"); +MODULE_AUTHOR("Jiaxin Yu "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("mt8186_mt6366_rt1019_rt5682s soc card"); From patchwork Sun Mar 13 15:10:22 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?SmlheGluIFl1ICjkv57lrrbpkasp?= X-Patchwork-Id: 550990 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A9506C433F5 for ; Sun, 13 Mar 2022 15:11:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234783AbiCMPML (ORCPT ); Sun, 13 Mar 2022 11:12:11 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39202 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234780AbiCMPL7 (ORCPT ); Sun, 13 Mar 2022 11:11:59 -0400 Received: from mailgw02.mediatek.com (unknown [210.61.82.184]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F178988B14; Sun, 13 Mar 2022 08:10:48 -0700 (PDT) X-UUID: 1003244b05be4069ab712c2e3286fb51-20220313 X-UUID: 1003244b05be4069ab712c2e3286fb51-20220313 Received: from mtkexhb01.mediatek.inc [(172.21.101.102)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 1927310907; Sun, 13 Mar 2022 23:10:45 +0800 Received: from mtkexhb01.mediatek.inc (172.21.101.102) by mtkmbs07n1.mediatek.inc (172.21.101.16) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sun, 13 Mar 2022 23:10:44 +0800 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkexhb01.mediatek.inc (172.21.101.102) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sun, 13 Mar 2022 23:10:43 +0800 Received: from localhost.localdomain (10.17.3.154) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sun, 13 Mar 2022 23:10:42 +0800 From: Jiaxin Yu To: , , CC: , , , , , , , , , , , Jiaxin Yu Subject: [v3 18/19] dt-bindings: mediatek: mt8186: add mt8186-mt6366-rt1019-rt5682s document Date: Sun, 13 Mar 2022 23:10:22 +0800 Message-ID: <20220313151023.21229-19-jiaxin.yu@mediatek.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220313151023.21229-1-jiaxin.yu@mediatek.com> References: <20220313151023.21229-1-jiaxin.yu@mediatek.com> MIME-Version: 1.0 X-MTK: N Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Add document for mt8186 board with mt6366, rt1019 and rt5682s. Signed-off-by: Jiaxin Yu --- .../sound/mt8186-mt6366-rt1019-rt5682s.yaml | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/mt8186-mt6366-rt1019-rt5682s.yaml diff --git a/Documentation/devicetree/bindings/sound/mt8186-mt6366-rt1019-rt5682s.yaml b/Documentation/devicetree/bindings/sound/mt8186-mt6366-rt1019-rt5682s.yaml new file mode 100644 index 000000000000..9280a26038f3 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mt8186-mt6366-rt1019-rt5682s.yaml @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/mt8186-mt6366-rt1019-rt5682s.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mediatek MT8186 with MT6366, RT1019 and RT5682S ASoC sound card driver + +maintainers: + - Jiaxin Yu + +description: + This binding describes the MT8186 sound card. + +properties: + compatible: + enum: + - mediatek,mt8186_mt6366_rt1019_rt5682s_sound + + mediatek,platform: + $ref: "/schemas/types.yaml#/definitions/phandle" + description: The phandle of MT8186 ASoC platform. + + mediatek,hdmi-codec: + $ref: "/schemas/types.yaml#/definitions/phandle" + description: The phandle of HDMI codec. + +additionalProperties: false + +required: + - compatible + - mediatek,platform + +examples: + - | + + sound: mt8186-sound { + compatible = "mediatek,mt8186_mt6366_rt1019_rt5682s_sound"; + mediatek,platform = <&afe>; + mediatek,hdmi-codec = <&it6505dptx>; + pinctrl-names = "aud_clk_mosi_off", + "aud_clk_mosi_on"; + pinctrl-0 = <&aud_clk_mosi_off>; + pinctrl-1 = <&aud_clk_mosi_on>; + }; + +... From patchwork Sun Mar 13 15:10:23 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?SmlheGluIFl1ICjkv57lrrbpkasp?= X-Patchwork-Id: 550988 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 591FAC433EF for ; Sun, 13 Mar 2022 15:11:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234834AbiCMPMU (ORCPT ); Sun, 13 Mar 2022 11:12:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40648 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234828AbiCMPMI (ORCPT ); Sun, 13 Mar 2022 11:12:08 -0400 Received: from mailgw02.mediatek.com (unknown [210.61.82.184]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0F8DD888D6; Sun, 13 Mar 2022 08:10:53 -0700 (PDT) X-UUID: c6224603de6f45a1b82afd12952ba3ab-20220313 X-UUID: c6224603de6f45a1b82afd12952ba3ab-20220313 Received: from mtkcas11.mediatek.inc [(172.21.101.40)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 118659618; Sun, 13 Mar 2022 23:10:46 +0800 Received: from mtkexhb02.mediatek.inc (172.21.101.103) by mtkmbs07n2.mediatek.inc (172.21.101.141) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sun, 13 Mar 2022 23:10:44 +0800 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkexhb02.mediatek.inc (172.21.101.103) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sun, 13 Mar 2022 23:10:44 +0800 Received: from localhost.localdomain (10.17.3.154) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sun, 13 Mar 2022 23:10:43 +0800 From: Jiaxin Yu To: , , CC: , , , , , , , , , , , Jiaxin Yu Subject: [v3 19/19] ASoC: mediatek: mt6358: add missing EXPORT_SYMBOLs Date: Sun, 13 Mar 2022 23:10:23 +0800 Message-ID: <20220313151023.21229-20-jiaxin.yu@mediatek.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220313151023.21229-1-jiaxin.yu@mediatek.com> References: <20220313151023.21229-1-jiaxin.yu@mediatek.com> MIME-Version: 1.0 X-MTK: N Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org This fixes the following build errors when mt6358 is configured as module: >> ERROR: modpost: "mt6358_set_mtkaif_protocol" >> [sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.ko] undefined! >> ERROR: modpost: "mt6358_set_mtkaif_protocol" >> [sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.ko] undefined! Signed-off-by: Jiaxin Yu --- sound/soc/codecs/mt6358.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/codecs/mt6358.c b/sound/soc/codecs/mt6358.c index 1fdd2f8cf877..61f2a7632fd4 100644 --- a/sound/soc/codecs/mt6358.c +++ b/sound/soc/codecs/mt6358.c @@ -107,6 +107,7 @@ int mt6358_set_mtkaif_protocol(struct snd_soc_component *cmpnt, priv->mtkaif_protocol = mtkaif_protocol; return 0; } +EXPORT_SYMBOL_GPL(mt6358_set_mtkaif_protocol); static void playback_gpio_set(struct mt6358_priv *priv) { @@ -273,6 +274,7 @@ int mt6358_mtkaif_calibration_enable(struct snd_soc_component *cmpnt) 1 << RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_SFT); return 0; } +EXPORT_SYMBOL_GPL(mt6358_mtkaif_calibration_enable); int mt6358_mtkaif_calibration_disable(struct snd_soc_component *cmpnt) { @@ -296,6 +298,7 @@ int mt6358_mtkaif_calibration_disable(struct snd_soc_component *cmpnt) capture_gpio_reset(priv); return 0; } +EXPORT_SYMBOL_GPL(mt6358_mtkaif_calibration_disable); int mt6358_set_mtkaif_calibration_phase(struct snd_soc_component *cmpnt, int phase_1, int phase_2) @@ -310,6 +313,7 @@ int mt6358_set_mtkaif_calibration_phase(struct snd_soc_component *cmpnt, phase_2 << RG_AUD_PAD_TOP_PHASE_MODE2_SFT); return 0; } +EXPORT_SYMBOL_GPL(mt6358_set_mtkaif_calibration_phase); /* dl pga gain */ enum {