~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/mediatek/mt8365/mt8365-dai-dmic.c

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php