Path: blob/master/sound/soc/mediatek/mt8365/mt8365-dai-dmic.c
26488 views
// SPDX-License-Identifier: GPL-2.01/*2* MediaTek 8365 ALSA SoC Audio DAI DMIC Control3*4* Copyright (c) 2024 MediaTek Inc.5* Authors: Jia Zeng <[email protected]>6* Alexandre Mergnat <[email protected]>7*/89#include <linux/bitops.h>10#include <linux/regmap.h>11#include <sound/pcm_params.h>12#include "mt8365-afe-clk.h"13#include "mt8365-afe-common.h"1415struct mt8365_dmic_data {16bool two_wire_mode;17unsigned int clk_phase_sel_ch1;18unsigned int clk_phase_sel_ch2;19bool iir_on;20unsigned int irr_mode;21unsigned int dmic_mode;22unsigned int dmic_channel;23};2425static int get_chan_reg(unsigned int channel)26{27switch (channel) {28case 8:29fallthrough;30case 7:31return AFE_DMIC3_UL_SRC_CON0;32case 6:33fallthrough;34case 5:35return AFE_DMIC2_UL_SRC_CON0;36case 4:37fallthrough;38case 3:39return AFE_DMIC1_UL_SRC_CON0;40case 2:41fallthrough;42case 1:43return AFE_DMIC0_UL_SRC_CON0;44default:45return -EINVAL;46}47}4849/* DAI Drivers */5051static void audio_dmic_adda_enable(struct mtk_base_afe *afe)52{53mt8365_dai_enable_adda_on(afe);54regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0,55AFE_ADDA_UL_DL_DMIC_CLKDIV_ON,56AFE_ADDA_UL_DL_DMIC_CLKDIV_ON);57}5859static void audio_dmic_adda_disable(struct mtk_base_afe *afe)60{61regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0,62AFE_ADDA_UL_DL_DMIC_CLKDIV_ON,63~AFE_ADDA_UL_DL_DMIC_CLKDIV_ON);64mt8365_dai_disable_adda_on(afe);65}6667static void mt8365_dai_enable_dmic(struct mtk_base_afe *afe,68struct snd_pcm_substream *substream,69struct snd_soc_dai *dai)70{71struct mt8365_afe_private *afe_priv = afe->platform_priv;72struct mt8365_dmic_data *dmic_data = afe_priv->dai_priv[MT8365_AFE_IO_DMIC];73unsigned int val_mask;74int reg = get_chan_reg(dmic_data->dmic_channel);7576if (reg < 0)77return;7879/* val and mask will be always same to enable */80val_mask = DMIC_TOP_CON_CH1_ON |81DMIC_TOP_CON_CH2_ON |82DMIC_TOP_CON_SRC_ON;8384regmap_update_bits(afe->regmap, reg, val_mask, val_mask);85}8687static void mt8365_dai_disable_dmic(struct mtk_base_afe *afe,88struct snd_pcm_substream *substream,89struct snd_soc_dai *dai)90{91struct mt8365_afe_private *afe_priv = afe->platform_priv;92struct mt8365_dmic_data *dmic_data = afe_priv->dai_priv[MT8365_AFE_IO_DMIC];93unsigned int mask;94int reg = get_chan_reg(dmic_data->dmic_channel);9596if (reg < 0)97return;9899dev_dbg(afe->dev, "%s dmic_channel %d\n", __func__, dmic_data->dmic_channel);100101mask = DMIC_TOP_CON_CH1_ON |102DMIC_TOP_CON_CH2_ON |103DMIC_TOP_CON_SRC_ON |104DMIC_TOP_CON_SDM3_LEVEL_MODE;105106/* Set all masked values to 0 */107regmap_update_bits(afe->regmap, reg, mask, 0);108}109110static int mt8365_dai_configure_dmic(struct mtk_base_afe *afe,111struct snd_pcm_substream *substream,112struct snd_soc_dai *dai)113{114struct mt8365_afe_private *afe_priv = afe->platform_priv;115struct mt8365_dmic_data *dmic_data = afe_priv->dai_priv[MT8365_AFE_IO_DMIC];116bool two_wire_mode = dmic_data->two_wire_mode;117unsigned int clk_phase_sel_ch1 = dmic_data->clk_phase_sel_ch1;118unsigned int clk_phase_sel_ch2 = dmic_data->clk_phase_sel_ch2;119unsigned int val = 0;120unsigned int rate = dai->symmetric_rate;121int reg = get_chan_reg(dai->symmetric_channels);122123if (reg < 0)124return -EINVAL;125126dmic_data->dmic_channel = dai->symmetric_channels;127128val |= DMIC_TOP_CON_SDM3_LEVEL_MODE;129130if (two_wire_mode) {131val |= DMIC_TOP_CON_TWO_WIRE_MODE;132} else {133val |= FIELD_PREP(DMIC_TOP_CON_CK_PHASE_SEL_CH1,134clk_phase_sel_ch1);135val |= FIELD_PREP(DMIC_TOP_CON_CK_PHASE_SEL_CH2,136clk_phase_sel_ch2);137}138139switch (rate) {140case 48000:141val |= DMIC_TOP_CON_VOICE_MODE_48K;142break;143case 32000:144val |= DMIC_TOP_CON_VOICE_MODE_32K;145break;146case 16000:147val |= DMIC_TOP_CON_VOICE_MODE_16K;148break;149case 8000:150val |= DMIC_TOP_CON_VOICE_MODE_8K;151break;152default:153return -EINVAL;154}155156regmap_update_bits(afe->regmap, reg, DMIC_TOP_CON_CONFIG_MASK, val);157158return 0;159}160161static int mt8365_dai_dmic_startup(struct snd_pcm_substream *substream,162struct snd_soc_dai *dai)163{164struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);165166mt8365_afe_enable_main_clk(afe);167168mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DMIC0_ADC);169mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DMIC1_ADC);170mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DMIC2_ADC);171mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DMIC3_ADC);172173audio_dmic_adda_enable(afe);174175return 0;176}177178static void mt8365_dai_dmic_shutdown(struct snd_pcm_substream *substream,179struct snd_soc_dai *dai)180{181struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);182183mt8365_dai_disable_dmic(afe, substream, dai);184audio_dmic_adda_disable(afe);185/* HW Request delay 125us before CG off */186usleep_range(125, 300);187mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DMIC3_ADC);188mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DMIC2_ADC);189mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DMIC1_ADC);190mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DMIC0_ADC);191192mt8365_afe_disable_main_clk(afe);193}194195static int mt8365_dai_dmic_prepare(struct snd_pcm_substream *substream,196struct snd_soc_dai *dai)197{198struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);199200mt8365_dai_configure_dmic(afe, substream, dai);201mt8365_dai_enable_dmic(afe, substream, dai);202203return 0;204}205206static const struct snd_soc_dai_ops mt8365_afe_dmic_ops = {207.startup = mt8365_dai_dmic_startup,208.shutdown = mt8365_dai_dmic_shutdown,209.prepare = mt8365_dai_dmic_prepare,210};211212static struct snd_soc_dai_driver mtk_dai_dmic_driver[] = {213{214.name = "DMIC",215.id = MT8365_AFE_IO_DMIC,216.capture = {217.stream_name = "DMIC Capture",218.channels_min = 1,219.channels_max = 8,220.rates = SNDRV_PCM_RATE_16000 |221SNDRV_PCM_RATE_32000 |222SNDRV_PCM_RATE_48000,223.formats = SNDRV_PCM_FMTBIT_S16_LE |224SNDRV_PCM_FMTBIT_S32_LE,225},226.ops = &mt8365_afe_dmic_ops,227}228};229230/* DAI Controls */231232/* Values for 48kHz mode */233static const char * const iir_mode_src[] = {234"SW custom", "5Hz", "10Hz", "25Hz", "50Hz", "65Hz"235};236237static SOC_ENUM_SINGLE_DECL(iir_mode, AFE_DMIC0_UL_SRC_CON0, 7, iir_mode_src);238239static const struct snd_kcontrol_new mtk_dai_dmic_controls[] = {240SOC_SINGLE("DMIC IIR Switch", AFE_DMIC0_UL_SRC_CON0, DMIC_TOP_CON_IIR_ON, 1, 0),241SOC_ENUM("DMIC IIR Mode", iir_mode),242};243244/* DAI widget */245246static const struct snd_soc_dapm_widget mtk_dai_dmic_widgets[] = {247SND_SOC_DAPM_INPUT("DMIC In"),248};249250/* DAI route */251252static const struct snd_soc_dapm_route mtk_dai_dmic_routes[] = {253{"I14", NULL, "DMIC Capture"},254{"I15", NULL, "DMIC Capture"},255{"I16", NULL, "DMIC Capture"},256{"I17", NULL, "DMIC Capture"},257{"I18", NULL, "DMIC Capture"},258{"I19", NULL, "DMIC Capture"},259{"I20", NULL, "DMIC Capture"},260{"I21", NULL, "DMIC Capture"},261{"DMIC Capture", NULL, "DMIC In"},262};263264static int init_dmic_priv_data(struct mtk_base_afe *afe)265{266struct mt8365_afe_private *afe_priv = afe->platform_priv;267struct mt8365_dmic_data *dmic_priv;268struct device_node *np = afe->dev->of_node;269unsigned int temps[4];270int ret;271272dmic_priv = devm_kzalloc(afe->dev, sizeof(*dmic_priv), GFP_KERNEL);273if (!dmic_priv)274return -ENOMEM;275276ret = of_property_read_u32_array(np, "mediatek,dmic-mode",277&temps[0],2781);279if (ret == 0)280dmic_priv->two_wire_mode = !!temps[0];281282if (!dmic_priv->two_wire_mode) {283dmic_priv->clk_phase_sel_ch1 = 0;284dmic_priv->clk_phase_sel_ch2 = 4;285}286287afe_priv->dai_priv[MT8365_AFE_IO_DMIC] = dmic_priv;288return 0;289}290291int mt8365_dai_dmic_register(struct mtk_base_afe *afe)292{293struct mtk_base_afe_dai *dai;294295dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);296if (!dai)297return -ENOMEM;298299list_add(&dai->list, &afe->sub_dais);300dai->dai_drivers = mtk_dai_dmic_driver;301dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_dmic_driver);302dai->controls = mtk_dai_dmic_controls;303dai->num_controls = ARRAY_SIZE(mtk_dai_dmic_controls);304dai->dapm_widgets = mtk_dai_dmic_widgets;305dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_dmic_widgets);306dai->dapm_routes = mtk_dai_dmic_routes;307dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_dmic_routes);308return init_dmic_priv_data(afe);309}310311312