1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * MediaTek 8365 ALSA SoC Audio DAI DMIC Control 4 * 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 16 struct 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 26 static 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 52 static 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 60 static 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 68 static 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 88 static 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 111 static 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 162 static 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 179 static 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 196 static 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 207 static 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 213 static 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 */ 234 static const char * const iir_mode_src[] = { 235 "SW custom", "5Hz", "10Hz", "25Hz", "50Hz", "65Hz" 236 }; 237 238 static SOC_ENUM_SINGLE_DECL(iir_mode, AFE_DMIC0_UL_SRC_CON0, 7, iir_mode_src); 239 240 static 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 247 static const struct snd_soc_dapm_widget mtk_dai_dmic_widgets[] = { 248 SND_SOC_DAPM_INPUT("DMIC In"), 249 }; 250 251 /* DAI route */ 252 253 static 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 265 static 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 292 int 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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.