311 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * MediaTek 8365 ALSA SoC Audio DAI DMIC Control4 *5 * Copyright (c) 2024 MediaTek Inc.6 * Authors: Jia Zeng <jia.zeng@mediatek.com>7 * Alexandre Mergnat <amergnat@baylibre.com>8 */9 10#include <linux/bitops.h>11#include <linux/regmap.h>12#include <sound/pcm_params.h>13#include "mt8365-afe-clk.h"14#include "mt8365-afe-common.h"15 16struct mt8365_dmic_data {17 bool two_wire_mode;18 unsigned int clk_phase_sel_ch1;19 unsigned int clk_phase_sel_ch2;20 bool iir_on;21 unsigned int irr_mode;22 unsigned int dmic_mode;23 unsigned int dmic_channel;24};25 26static int get_chan_reg(unsigned int channel)27{28 switch (channel) {29 case 8:30 fallthrough;31 case 7:32 return AFE_DMIC3_UL_SRC_CON0;33 case 6:34 fallthrough;35 case 5:36 return AFE_DMIC2_UL_SRC_CON0;37 case 4:38 fallthrough;39 case 3:40 return AFE_DMIC1_UL_SRC_CON0;41 case 2:42 fallthrough;43 case 1:44 return AFE_DMIC0_UL_SRC_CON0;45 default:46 return -EINVAL;47 }48}49 50/* DAI Drivers */51 52static void audio_dmic_adda_enable(struct mtk_base_afe *afe)53{54 mt8365_dai_enable_adda_on(afe);55 regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0,56 AFE_ADDA_UL_DL_DMIC_CLKDIV_ON,57 AFE_ADDA_UL_DL_DMIC_CLKDIV_ON);58}59 60static void audio_dmic_adda_disable(struct mtk_base_afe *afe)61{62 regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0,63 AFE_ADDA_UL_DL_DMIC_CLKDIV_ON,64 ~AFE_ADDA_UL_DL_DMIC_CLKDIV_ON);65 mt8365_dai_disable_adda_on(afe);66}67 68static void mt8365_dai_enable_dmic(struct mtk_base_afe *afe,69 struct snd_pcm_substream *substream,70 struct snd_soc_dai *dai)71{72 struct mt8365_afe_private *afe_priv = afe->platform_priv;73 struct mt8365_dmic_data *dmic_data = afe_priv->dai_priv[MT8365_AFE_IO_DMIC];74 unsigned int val_mask;75 int reg = get_chan_reg(dmic_data->dmic_channel);76 77 if (reg < 0)78 return;79 80 /* val and mask will be always same to enable */81 val_mask = DMIC_TOP_CON_CH1_ON |82 DMIC_TOP_CON_CH2_ON |83 DMIC_TOP_CON_SRC_ON;84 85 regmap_update_bits(afe->regmap, reg, val_mask, val_mask);86}87 88static void mt8365_dai_disable_dmic(struct mtk_base_afe *afe,89 struct snd_pcm_substream *substream,90 struct snd_soc_dai *dai)91{92 struct mt8365_afe_private *afe_priv = afe->platform_priv;93 struct mt8365_dmic_data *dmic_data = afe_priv->dai_priv[MT8365_AFE_IO_DMIC];94 unsigned int mask;95 int reg = get_chan_reg(dmic_data->dmic_channel);96 97 if (reg < 0)98 return;99 100 dev_dbg(afe->dev, "%s dmic_channel %d\n", __func__, dmic_data->dmic_channel);101 102 mask = DMIC_TOP_CON_CH1_ON |103 DMIC_TOP_CON_CH2_ON |104 DMIC_TOP_CON_SRC_ON |105 DMIC_TOP_CON_SDM3_LEVEL_MODE;106 107 /* Set all masked values to 0 */108 regmap_update_bits(afe->regmap, reg, mask, 0);109}110 111static int mt8365_dai_configure_dmic(struct mtk_base_afe *afe,112 struct snd_pcm_substream *substream,113 struct snd_soc_dai *dai)114{115 struct mt8365_afe_private *afe_priv = afe->platform_priv;116 struct mt8365_dmic_data *dmic_data = afe_priv->dai_priv[MT8365_AFE_IO_DMIC];117 bool two_wire_mode = dmic_data->two_wire_mode;118 unsigned int clk_phase_sel_ch1 = dmic_data->clk_phase_sel_ch1;119 unsigned int clk_phase_sel_ch2 = dmic_data->clk_phase_sel_ch2;120 unsigned int val = 0;121 unsigned int rate = dai->rate;122 int reg = get_chan_reg(dai->channels);123 124 if (reg < 0)125 return -EINVAL;126 127 dmic_data->dmic_channel = dai->channels;128 129 val |= DMIC_TOP_CON_SDM3_LEVEL_MODE;130 131 if (two_wire_mode) {132 val |= DMIC_TOP_CON_TWO_WIRE_MODE;133 } else {134 val |= FIELD_PREP(DMIC_TOP_CON_CK_PHASE_SEL_CH1,135 clk_phase_sel_ch1);136 val |= FIELD_PREP(DMIC_TOP_CON_CK_PHASE_SEL_CH2,137 clk_phase_sel_ch2);138 }139 140 switch (rate) {141 case 48000:142 val |= DMIC_TOP_CON_VOICE_MODE_48K;143 break;144 case 32000:145 val |= DMIC_TOP_CON_VOICE_MODE_32K;146 break;147 case 16000:148 val |= DMIC_TOP_CON_VOICE_MODE_16K;149 break;150 case 8000:151 val |= DMIC_TOP_CON_VOICE_MODE_8K;152 break;153 default:154 return -EINVAL;155 }156 157 regmap_update_bits(afe->regmap, reg, DMIC_TOP_CON_CONFIG_MASK, val);158 159 return 0;160}161 162static int mt8365_dai_dmic_startup(struct snd_pcm_substream *substream,163 struct snd_soc_dai *dai)164{165 struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);166 167 mt8365_afe_enable_main_clk(afe);168 169 mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DMIC0_ADC);170 mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DMIC1_ADC);171 mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DMIC2_ADC);172 mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DMIC3_ADC);173 174 audio_dmic_adda_enable(afe);175 176 return 0;177}178 179static void mt8365_dai_dmic_shutdown(struct snd_pcm_substream *substream,180 struct snd_soc_dai *dai)181{182 struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);183 184 mt8365_dai_disable_dmic(afe, substream, dai);185 audio_dmic_adda_disable(afe);186 /* HW Request delay 125us before CG off */187 usleep_range(125, 300);188 mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DMIC3_ADC);189 mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DMIC2_ADC);190 mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DMIC1_ADC);191 mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DMIC0_ADC);192 193 mt8365_afe_disable_main_clk(afe);194}195 196static int mt8365_dai_dmic_prepare(struct snd_pcm_substream *substream,197 struct snd_soc_dai *dai)198{199 struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);200 201 mt8365_dai_configure_dmic(afe, substream, dai);202 mt8365_dai_enable_dmic(afe, substream, dai);203 204 return 0;205}206 207static const struct snd_soc_dai_ops mt8365_afe_dmic_ops = {208 .startup = mt8365_dai_dmic_startup,209 .shutdown = mt8365_dai_dmic_shutdown,210 .prepare = mt8365_dai_dmic_prepare,211};212 213static struct snd_soc_dai_driver mtk_dai_dmic_driver[] = {214 {215 .name = "DMIC",216 .id = MT8365_AFE_IO_DMIC,217 .capture = {218 .stream_name = "DMIC Capture",219 .channels_min = 1,220 .channels_max = 8,221 .rates = SNDRV_PCM_RATE_16000 |222 SNDRV_PCM_RATE_32000 |223 SNDRV_PCM_RATE_48000,224 .formats = SNDRV_PCM_FMTBIT_S16_LE |225 SNDRV_PCM_FMTBIT_S32_LE,226 },227 .ops = &mt8365_afe_dmic_ops,228 }229};230 231/* DAI Controls */232 233/* Values for 48kHz mode */234static const char * const iir_mode_src[] = {235 "SW custom", "5Hz", "10Hz", "25Hz", "50Hz", "65Hz"236};237 238static SOC_ENUM_SINGLE_DECL(iir_mode, AFE_DMIC0_UL_SRC_CON0, 7, iir_mode_src);239 240static const struct snd_kcontrol_new mtk_dai_dmic_controls[] = {241 SOC_SINGLE("DMIC IIR Switch", AFE_DMIC0_UL_SRC_CON0, DMIC_TOP_CON_IIR_ON, 1, 0),242 SOC_ENUM("DMIC IIR Mode", iir_mode),243};244 245/* DAI widget */246 247static const struct snd_soc_dapm_widget mtk_dai_dmic_widgets[] = {248 SND_SOC_DAPM_INPUT("DMIC In"),249};250 251/* DAI route */252 253static const struct snd_soc_dapm_route mtk_dai_dmic_routes[] = {254 {"I14", NULL, "DMIC Capture"},255 {"I15", NULL, "DMIC Capture"},256 {"I16", NULL, "DMIC Capture"},257 {"I17", NULL, "DMIC Capture"},258 {"I18", NULL, "DMIC Capture"},259 {"I19", NULL, "DMIC Capture"},260 {"I20", NULL, "DMIC Capture"},261 {"I21", NULL, "DMIC Capture"},262 {"DMIC Capture", NULL, "DMIC In"},263};264 265static int init_dmic_priv_data(struct mtk_base_afe *afe)266{267 struct mt8365_afe_private *afe_priv = afe->platform_priv;268 struct mt8365_dmic_data *dmic_priv;269 struct device_node *np = afe->dev->of_node;270 unsigned int temps[4];271 int ret;272 273 dmic_priv = devm_kzalloc(afe->dev, sizeof(*dmic_priv), GFP_KERNEL);274 if (!dmic_priv)275 return -ENOMEM;276 277 ret = of_property_read_u32_array(np, "mediatek,dmic-mode",278 &temps[0],279 1);280 if (ret == 0)281 dmic_priv->two_wire_mode = !!temps[0];282 283 if (!dmic_priv->two_wire_mode) {284 dmic_priv->clk_phase_sel_ch1 = 0;285 dmic_priv->clk_phase_sel_ch2 = 4;286 }287 288 afe_priv->dai_priv[MT8365_AFE_IO_DMIC] = dmic_priv;289 return 0;290}291 292int mt8365_dai_dmic_register(struct mtk_base_afe *afe)293{294 struct mtk_base_afe_dai *dai;295 296 dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);297 if (!dai)298 return -ENOMEM;299 300 list_add(&dai->list, &afe->sub_dais);301 dai->dai_drivers = mtk_dai_dmic_driver;302 dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_dmic_driver);303 dai->controls = mtk_dai_dmic_controls;304 dai->num_controls = ARRAY_SIZE(mtk_dai_dmic_controls);305 dai->dapm_widgets = mtk_dai_dmic_widgets;306 dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_dmic_widgets);307 dai->dapm_routes = mtk_dai_dmic_routes;308 dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_dmic_routes);309 return init_dmic_priv_data(afe);310}311