File Index
Files and directories
Sign in
FILE

mt8365-dai-dmic.c

File preview with syntax highlighting.

linux-6.19.14/sound/soc/mediatek/mt8365/mt8365-dai-dmic.c C
  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
 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->symmetric_rate;
122	int reg = get_chan_reg(dai->symmetric_channels);
123
124	if (reg < 0)
125		return -EINVAL;
126
127	dmic_data->dmic_channel = dai->symmetric_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}
~/ Read-only file preview.