1ae92dcbeSJiaxin Yu // SPDX-License-Identifier: GPL-2.0
2ae92dcbeSJiaxin Yu //
3ae92dcbeSJiaxin Yu // MediaTek ALSA SoC Audio DAI TDM Control
4ae92dcbeSJiaxin Yu //
5ae92dcbeSJiaxin Yu // Copyright (c) 2022 MediaTek Inc.
6ae92dcbeSJiaxin Yu // Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
7ae92dcbeSJiaxin Yu 
8ae92dcbeSJiaxin Yu #include <linux/regmap.h>
9ae92dcbeSJiaxin Yu #include <sound/pcm_params.h>
10ae92dcbeSJiaxin Yu 
11ae92dcbeSJiaxin Yu #include "mt8186-afe-clk.h"
12ae92dcbeSJiaxin Yu #include "mt8186-afe-common.h"
13ae92dcbeSJiaxin Yu #include "mt8186-afe-gpio.h"
14ae92dcbeSJiaxin Yu #include "mt8186-interconnection.h"
15ae92dcbeSJiaxin Yu 
16ae92dcbeSJiaxin Yu #define TDM_HD_EN_W_NAME "TDM_HD_EN"
17ae92dcbeSJiaxin Yu #define TDM_MCLK_EN_W_NAME "TDM_MCLK_EN"
18ae92dcbeSJiaxin Yu #define MTK_AFE_TDM_KCONTROL_NAME "TDM_HD_Mux"
19ae92dcbeSJiaxin Yu 
20ae92dcbeSJiaxin Yu struct mtk_afe_tdm_priv {
21ae92dcbeSJiaxin Yu 	unsigned int id;
22ae92dcbeSJiaxin Yu 	unsigned int rate; /* for determine which apll to use */
23ae92dcbeSJiaxin Yu 	unsigned int bck_invert;
24ae92dcbeSJiaxin Yu 	unsigned int lck_invert;
25ae92dcbeSJiaxin Yu 	unsigned int lrck_width;
26ae92dcbeSJiaxin Yu 	unsigned int mclk_id;
27ae92dcbeSJiaxin Yu 	unsigned int mclk_multiple; /* according to sample rate */
28ae92dcbeSJiaxin Yu 	unsigned int mclk_rate;
29ae92dcbeSJiaxin Yu 	unsigned int mclk_apll;
30ae92dcbeSJiaxin Yu 	unsigned int tdm_mode;
31ae92dcbeSJiaxin Yu 	unsigned int data_mode;
32ae92dcbeSJiaxin Yu 	unsigned int slave_mode;
33ae92dcbeSJiaxin Yu 	unsigned int low_jitter_en;
34ae92dcbeSJiaxin Yu };
35ae92dcbeSJiaxin Yu 
36ae92dcbeSJiaxin Yu enum {
37ae92dcbeSJiaxin Yu 	TDM_IN_I2S = 0,
38ae92dcbeSJiaxin Yu 	TDM_IN_LJ = 1,
39ae92dcbeSJiaxin Yu 	TDM_IN_RJ = 2,
40ae92dcbeSJiaxin Yu 	TDM_IN_DSP_A = 4,
41ae92dcbeSJiaxin Yu 	TDM_IN_DSP_B = 5,
42ae92dcbeSJiaxin Yu };
43ae92dcbeSJiaxin Yu 
44ae92dcbeSJiaxin Yu enum {
45ae92dcbeSJiaxin Yu 	TDM_DATA_ONE_PIN = 0,
46ae92dcbeSJiaxin Yu 	TDM_DATA_MULTI_PIN,
47ae92dcbeSJiaxin Yu };
48ae92dcbeSJiaxin Yu 
49ae92dcbeSJiaxin Yu enum {
50ae92dcbeSJiaxin Yu 	TDM_BCK_NON_INV = 0,
51ae92dcbeSJiaxin Yu 	TDM_BCK_INV = 1,
52ae92dcbeSJiaxin Yu };
53ae92dcbeSJiaxin Yu 
54ae92dcbeSJiaxin Yu enum {
55ae92dcbeSJiaxin Yu 	TDM_LCK_NON_INV = 0,
56ae92dcbeSJiaxin Yu 	TDM_LCK_INV = 1,
57ae92dcbeSJiaxin Yu };
58ae92dcbeSJiaxin Yu 
get_tdm_lrck_width(snd_pcm_format_t format,unsigned int mode)59ae92dcbeSJiaxin Yu static unsigned int get_tdm_lrck_width(snd_pcm_format_t format,
60ae92dcbeSJiaxin Yu 				       unsigned int mode)
61ae92dcbeSJiaxin Yu {
62ae92dcbeSJiaxin Yu 	if (mode == TDM_IN_DSP_A || mode == TDM_IN_DSP_B)
63ae92dcbeSJiaxin Yu 		return 0;
64ae92dcbeSJiaxin Yu 
65ae92dcbeSJiaxin Yu 	return snd_pcm_format_physical_width(format) - 1;
66ae92dcbeSJiaxin Yu }
67ae92dcbeSJiaxin Yu 
get_tdm_ch_fixup(unsigned int channels)68ae92dcbeSJiaxin Yu static unsigned int get_tdm_ch_fixup(unsigned int channels)
69ae92dcbeSJiaxin Yu {
70ae92dcbeSJiaxin Yu 	if (channels > 4)
71ae92dcbeSJiaxin Yu 		return 8;
72ae92dcbeSJiaxin Yu 	else if (channels > 2)
73ae92dcbeSJiaxin Yu 		return 4;
74ae92dcbeSJiaxin Yu 
75ae92dcbeSJiaxin Yu 	return 2;
76ae92dcbeSJiaxin Yu }
77ae92dcbeSJiaxin Yu 
get_tdm_ch_per_sdata(unsigned int mode,unsigned int channels)78ae92dcbeSJiaxin Yu static unsigned int get_tdm_ch_per_sdata(unsigned int mode,
79ae92dcbeSJiaxin Yu 					 unsigned int channels)
80ae92dcbeSJiaxin Yu {
81ae92dcbeSJiaxin Yu 	if (mode == TDM_IN_DSP_A || mode == TDM_IN_DSP_B)
82ae92dcbeSJiaxin Yu 		return get_tdm_ch_fixup(channels);
83ae92dcbeSJiaxin Yu 
84ae92dcbeSJiaxin Yu 	return 2;
85ae92dcbeSJiaxin Yu }
86ae92dcbeSJiaxin Yu 
87ae92dcbeSJiaxin Yu enum {
88ae92dcbeSJiaxin Yu 	SUPPLY_SEQ_APLL,
89ae92dcbeSJiaxin Yu 	SUPPLY_SEQ_TDM_MCK_EN,
90ae92dcbeSJiaxin Yu 	SUPPLY_SEQ_TDM_HD_EN,
91ae92dcbeSJiaxin Yu 	SUPPLY_SEQ_TDM_EN,
92ae92dcbeSJiaxin Yu };
93ae92dcbeSJiaxin Yu 
get_tdm_id_by_name(const char * name)94ae92dcbeSJiaxin Yu static int get_tdm_id_by_name(const char *name)
95ae92dcbeSJiaxin Yu {
96ae92dcbeSJiaxin Yu 	return MT8186_DAI_TDM_IN;
97ae92dcbeSJiaxin Yu }
98ae92dcbeSJiaxin Yu 
mtk_tdm_en_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)99ae92dcbeSJiaxin Yu static int mtk_tdm_en_event(struct snd_soc_dapm_widget *w,
100ae92dcbeSJiaxin Yu 			    struct snd_kcontrol *kcontrol,
101ae92dcbeSJiaxin Yu 			    int event)
102ae92dcbeSJiaxin Yu {
103ae92dcbeSJiaxin Yu 	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
104ae92dcbeSJiaxin Yu 	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
105ae92dcbeSJiaxin Yu 	struct mt8186_afe_private *afe_priv = afe->platform_priv;
106ae92dcbeSJiaxin Yu 	int dai_id = get_tdm_id_by_name(w->name);
107ae92dcbeSJiaxin Yu 	struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
108ae92dcbeSJiaxin Yu 
109ae92dcbeSJiaxin Yu 	dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n",
110ae92dcbeSJiaxin Yu 		__func__, w->name, event);
111ae92dcbeSJiaxin Yu 
112ae92dcbeSJiaxin Yu 	switch (event) {
113ae92dcbeSJiaxin Yu 	case SND_SOC_DAPM_PRE_PMU:
114ae92dcbeSJiaxin Yu 		mt8186_afe_gpio_request(afe->dev, true, tdm_priv->id, 0);
115ae92dcbeSJiaxin Yu 		break;
116ae92dcbeSJiaxin Yu 	case SND_SOC_DAPM_POST_PMD:
117ae92dcbeSJiaxin Yu 		mt8186_afe_gpio_request(afe->dev, false, tdm_priv->id, 0);
118ae92dcbeSJiaxin Yu 		break;
119ae92dcbeSJiaxin Yu 	default:
120ae92dcbeSJiaxin Yu 		break;
121ae92dcbeSJiaxin Yu 	}
122ae92dcbeSJiaxin Yu 
123ae92dcbeSJiaxin Yu 	return 0;
124ae92dcbeSJiaxin Yu }
125ae92dcbeSJiaxin Yu 
mtk_tdm_mck_en_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)126ae92dcbeSJiaxin Yu static int mtk_tdm_mck_en_event(struct snd_soc_dapm_widget *w,
127ae92dcbeSJiaxin Yu 				struct snd_kcontrol *kcontrol,
128ae92dcbeSJiaxin Yu 				int event)
129ae92dcbeSJiaxin Yu {
130ae92dcbeSJiaxin Yu 	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
131ae92dcbeSJiaxin Yu 	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
132ae92dcbeSJiaxin Yu 	struct mt8186_afe_private *afe_priv = afe->platform_priv;
133ae92dcbeSJiaxin Yu 	int dai_id = get_tdm_id_by_name(w->name);
134ae92dcbeSJiaxin Yu 	struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
135ae92dcbeSJiaxin Yu 
136ae92dcbeSJiaxin Yu 	dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x, dai_id %d\n",
137ae92dcbeSJiaxin Yu 		__func__, w->name, event, dai_id);
138ae92dcbeSJiaxin Yu 
139ae92dcbeSJiaxin Yu 	switch (event) {
140ae92dcbeSJiaxin Yu 	case SND_SOC_DAPM_PRE_PMU:
141ae92dcbeSJiaxin Yu 		mt8186_mck_enable(afe, tdm_priv->mclk_id, tdm_priv->mclk_rate);
142ae92dcbeSJiaxin Yu 		break;
143ae92dcbeSJiaxin Yu 	case SND_SOC_DAPM_POST_PMD:
144ae92dcbeSJiaxin Yu 		tdm_priv->mclk_rate = 0;
145ae92dcbeSJiaxin Yu 		mt8186_mck_disable(afe, tdm_priv->mclk_id);
146ae92dcbeSJiaxin Yu 		break;
147ae92dcbeSJiaxin Yu 	default:
148ae92dcbeSJiaxin Yu 		break;
149ae92dcbeSJiaxin Yu 	}
150ae92dcbeSJiaxin Yu 
151ae92dcbeSJiaxin Yu 	return 0;
152ae92dcbeSJiaxin Yu }
153ae92dcbeSJiaxin Yu 
154ae92dcbeSJiaxin Yu /* dai component */
155ae92dcbeSJiaxin Yu /* tdm virtual mux to output widget */
156ae92dcbeSJiaxin Yu static const char * const tdm_mux_map[] = {
157ae92dcbeSJiaxin Yu 	"Normal", "Dummy_Widget",
158ae92dcbeSJiaxin Yu };
159ae92dcbeSJiaxin Yu 
160ae92dcbeSJiaxin Yu static int tdm_mux_map_value[] = {
161ae92dcbeSJiaxin Yu 	0, 1,
162ae92dcbeSJiaxin Yu };
163ae92dcbeSJiaxin Yu 
164ae92dcbeSJiaxin Yu static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(tdm_mux_map_enum,
165ae92dcbeSJiaxin Yu 					      SND_SOC_NOPM,
166ae92dcbeSJiaxin Yu 					      0,
167ae92dcbeSJiaxin Yu 					      1,
168ae92dcbeSJiaxin Yu 					      tdm_mux_map,
169ae92dcbeSJiaxin Yu 					      tdm_mux_map_value);
170ae92dcbeSJiaxin Yu 
171ae92dcbeSJiaxin Yu static const struct snd_kcontrol_new tdm_in_mux_control =
172ae92dcbeSJiaxin Yu 	SOC_DAPM_ENUM("TDM In Select", tdm_mux_map_enum);
173ae92dcbeSJiaxin Yu 
174ae92dcbeSJiaxin Yu static const struct snd_soc_dapm_widget mtk_dai_tdm_widgets[] = {
175ae92dcbeSJiaxin Yu 	SND_SOC_DAPM_CLOCK_SUPPLY("aud_tdm_clk"),
176ae92dcbeSJiaxin Yu 
177ae92dcbeSJiaxin Yu 	SND_SOC_DAPM_SUPPLY_S("TDM_EN", SUPPLY_SEQ_TDM_EN,
178ae92dcbeSJiaxin Yu 			      ETDM_IN1_CON0, ETDM_IN1_CON0_REG_ETDM_IN_EN_SFT,
179ae92dcbeSJiaxin Yu 			      0, mtk_tdm_en_event,
180ae92dcbeSJiaxin Yu 			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
181ae92dcbeSJiaxin Yu 	/* tdm hd en */
182ae92dcbeSJiaxin Yu 	SND_SOC_DAPM_SUPPLY_S(TDM_HD_EN_W_NAME, SUPPLY_SEQ_TDM_HD_EN,
183ae92dcbeSJiaxin Yu 			      ETDM_IN1_CON2, ETDM_IN1_CON2_REG_CLOCK_SOURCE_SEL_SFT,
184ae92dcbeSJiaxin Yu 			      0, NULL,
185ae92dcbeSJiaxin Yu 			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
186ae92dcbeSJiaxin Yu 
187ae92dcbeSJiaxin Yu 	SND_SOC_DAPM_SUPPLY_S(TDM_MCLK_EN_W_NAME, SUPPLY_SEQ_TDM_MCK_EN,
188ae92dcbeSJiaxin Yu 			      SND_SOC_NOPM, 0, 0,
189ae92dcbeSJiaxin Yu 			      mtk_tdm_mck_en_event,
190ae92dcbeSJiaxin Yu 			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
191ae92dcbeSJiaxin Yu 
192ae92dcbeSJiaxin Yu 	SND_SOC_DAPM_INPUT("TDM_DUMMY_IN"),
193ae92dcbeSJiaxin Yu 
194ae92dcbeSJiaxin Yu 	SND_SOC_DAPM_MUX("TDM_In_Mux",
195ae92dcbeSJiaxin Yu 			 SND_SOC_NOPM, 0, 0, &tdm_in_mux_control),
196ae92dcbeSJiaxin Yu };
197ae92dcbeSJiaxin Yu 
mtk_afe_tdm_mclk_connect(struct snd_soc_dapm_widget * source,struct snd_soc_dapm_widget * sink)198ae92dcbeSJiaxin Yu static int mtk_afe_tdm_mclk_connect(struct snd_soc_dapm_widget *source,
199ae92dcbeSJiaxin Yu 				    struct snd_soc_dapm_widget *sink)
200ae92dcbeSJiaxin Yu {
201ae92dcbeSJiaxin Yu 	struct snd_soc_dapm_widget *w = sink;
202ae92dcbeSJiaxin Yu 	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
203ae92dcbeSJiaxin Yu 	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
204ae92dcbeSJiaxin Yu 	struct mt8186_afe_private *afe_priv = afe->platform_priv;
205ae92dcbeSJiaxin Yu 	int dai_id = get_tdm_id_by_name(w->name);
206ae92dcbeSJiaxin Yu 	struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
207ae92dcbeSJiaxin Yu 
208ae92dcbeSJiaxin Yu 	return (tdm_priv->mclk_rate > 0) ? 1 : 0;
209ae92dcbeSJiaxin Yu }
210ae92dcbeSJiaxin Yu 
mtk_afe_tdm_mclk_apll_connect(struct snd_soc_dapm_widget * source,struct snd_soc_dapm_widget * sink)211ae92dcbeSJiaxin Yu static int mtk_afe_tdm_mclk_apll_connect(struct snd_soc_dapm_widget *source,
212ae92dcbeSJiaxin Yu 					 struct snd_soc_dapm_widget *sink)
213ae92dcbeSJiaxin Yu {
214ae92dcbeSJiaxin Yu 	struct snd_soc_dapm_widget *w = sink;
215ae92dcbeSJiaxin Yu 	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
216ae92dcbeSJiaxin Yu 	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
217ae92dcbeSJiaxin Yu 	struct mt8186_afe_private *afe_priv = afe->platform_priv;
218ae92dcbeSJiaxin Yu 	int dai_id = get_tdm_id_by_name(w->name);
219ae92dcbeSJiaxin Yu 	struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
220ae92dcbeSJiaxin Yu 	int cur_apll;
221ae92dcbeSJiaxin Yu 
222ae92dcbeSJiaxin Yu 	/* which apll */
223ae92dcbeSJiaxin Yu 	cur_apll = mt8186_get_apll_by_name(afe, source->name);
224ae92dcbeSJiaxin Yu 
225ae92dcbeSJiaxin Yu 	return (tdm_priv->mclk_apll == cur_apll) ? 1 : 0;
226ae92dcbeSJiaxin Yu }
227ae92dcbeSJiaxin Yu 
mtk_afe_tdm_hd_connect(struct snd_soc_dapm_widget * source,struct snd_soc_dapm_widget * sink)228ae92dcbeSJiaxin Yu static int mtk_afe_tdm_hd_connect(struct snd_soc_dapm_widget *source,
229ae92dcbeSJiaxin Yu 				  struct snd_soc_dapm_widget *sink)
230ae92dcbeSJiaxin Yu {
231ae92dcbeSJiaxin Yu 	struct snd_soc_dapm_widget *w = sink;
232ae92dcbeSJiaxin Yu 	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
233ae92dcbeSJiaxin Yu 	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
234ae92dcbeSJiaxin Yu 	struct mt8186_afe_private *afe_priv = afe->platform_priv;
235ae92dcbeSJiaxin Yu 	int dai_id = get_tdm_id_by_name(w->name);
236ae92dcbeSJiaxin Yu 	struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
237ae92dcbeSJiaxin Yu 
238ae92dcbeSJiaxin Yu 	return tdm_priv->low_jitter_en;
239ae92dcbeSJiaxin Yu }
240ae92dcbeSJiaxin Yu 
mtk_afe_tdm_apll_connect(struct snd_soc_dapm_widget * source,struct snd_soc_dapm_widget * sink)241ae92dcbeSJiaxin Yu static int mtk_afe_tdm_apll_connect(struct snd_soc_dapm_widget *source,
242ae92dcbeSJiaxin Yu 				    struct snd_soc_dapm_widget *sink)
243ae92dcbeSJiaxin Yu {
244ae92dcbeSJiaxin Yu 	struct snd_soc_dapm_widget *w = sink;
245ae92dcbeSJiaxin Yu 	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
246ae92dcbeSJiaxin Yu 	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
247ae92dcbeSJiaxin Yu 	struct mt8186_afe_private *afe_priv = afe->platform_priv;
248ae92dcbeSJiaxin Yu 	int dai_id = get_tdm_id_by_name(w->name);
249ae92dcbeSJiaxin Yu 	struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
250ae92dcbeSJiaxin Yu 	int cur_apll;
251ae92dcbeSJiaxin Yu 	int tdm_need_apll;
252ae92dcbeSJiaxin Yu 
253ae92dcbeSJiaxin Yu 	/* which apll */
254ae92dcbeSJiaxin Yu 	cur_apll = mt8186_get_apll_by_name(afe, source->name);
255ae92dcbeSJiaxin Yu 
256ae92dcbeSJiaxin Yu 	/* choose APLL from tdm rate */
257ae92dcbeSJiaxin Yu 	tdm_need_apll = mt8186_get_apll_by_rate(afe, tdm_priv->rate);
258ae92dcbeSJiaxin Yu 
259ae92dcbeSJiaxin Yu 	return (tdm_need_apll == cur_apll) ? 1 : 0;
260ae92dcbeSJiaxin Yu }
261ae92dcbeSJiaxin Yu 
262ae92dcbeSJiaxin Yu /* low jitter control */
263ae92dcbeSJiaxin Yu static const char * const mt8186_tdm_hd_str[] = {
264ae92dcbeSJiaxin Yu 	"Normal", "Low_Jitter"
265ae92dcbeSJiaxin Yu };
266ae92dcbeSJiaxin Yu 
267ae92dcbeSJiaxin Yu static const struct soc_enum mt8186_tdm_enum[] = {
268ae92dcbeSJiaxin Yu 	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8186_tdm_hd_str),
269ae92dcbeSJiaxin Yu 			    mt8186_tdm_hd_str),
270ae92dcbeSJiaxin Yu };
271ae92dcbeSJiaxin Yu 
mt8186_tdm_hd_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)272ae92dcbeSJiaxin Yu static int mt8186_tdm_hd_get(struct snd_kcontrol *kcontrol,
273ae92dcbeSJiaxin Yu 			     struct snd_ctl_elem_value *ucontrol)
274ae92dcbeSJiaxin Yu {
275ae92dcbeSJiaxin Yu 	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
276ae92dcbeSJiaxin Yu 	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
277ae92dcbeSJiaxin Yu 	struct mt8186_afe_private *afe_priv = afe->platform_priv;
278ae92dcbeSJiaxin Yu 	int dai_id = get_tdm_id_by_name(kcontrol->id.name);
279ae92dcbeSJiaxin Yu 	struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
280ae92dcbeSJiaxin Yu 
281ae92dcbeSJiaxin Yu 	ucontrol->value.integer.value[0] = tdm_priv->low_jitter_en;
282ae92dcbeSJiaxin Yu 
283ae92dcbeSJiaxin Yu 	return 0;
284ae92dcbeSJiaxin Yu }
285ae92dcbeSJiaxin Yu 
mt8186_tdm_hd_set(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)286ae92dcbeSJiaxin Yu static int mt8186_tdm_hd_set(struct snd_kcontrol *kcontrol,
287ae92dcbeSJiaxin Yu 			     struct snd_ctl_elem_value *ucontrol)
288ae92dcbeSJiaxin Yu {
289ae92dcbeSJiaxin Yu 	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
290ae92dcbeSJiaxin Yu 	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
291ae92dcbeSJiaxin Yu 	struct mt8186_afe_private *afe_priv = afe->platform_priv;
292ae92dcbeSJiaxin Yu 	int dai_id = get_tdm_id_by_name(kcontrol->id.name);
293ae92dcbeSJiaxin Yu 	struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
294ae92dcbeSJiaxin Yu 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
295ae92dcbeSJiaxin Yu 	int hd_en;
296ae92dcbeSJiaxin Yu 
297ae92dcbeSJiaxin Yu 	if (ucontrol->value.enumerated.item[0] >= e->items)
298ae92dcbeSJiaxin Yu 		return -EINVAL;
299ae92dcbeSJiaxin Yu 
300ae92dcbeSJiaxin Yu 	hd_en = ucontrol->value.integer.value[0];
301ae92dcbeSJiaxin Yu 
302ae92dcbeSJiaxin Yu 	dev_dbg(afe->dev, "%s(), kcontrol name %s, hd_en %d\n",
303ae92dcbeSJiaxin Yu 		__func__, kcontrol->id.name, hd_en);
304ae92dcbeSJiaxin Yu 
305ae92dcbeSJiaxin Yu 	if (tdm_priv->low_jitter_en == hd_en)
306ae92dcbeSJiaxin Yu 		return 0;
307ae92dcbeSJiaxin Yu 
308ae92dcbeSJiaxin Yu 	tdm_priv->low_jitter_en = hd_en;
309ae92dcbeSJiaxin Yu 
310ae92dcbeSJiaxin Yu 	return 1;
311ae92dcbeSJiaxin Yu }
312ae92dcbeSJiaxin Yu 
313ae92dcbeSJiaxin Yu static const struct snd_kcontrol_new mtk_dai_tdm_controls[] = {
314ae92dcbeSJiaxin Yu 	SOC_ENUM_EXT(MTK_AFE_TDM_KCONTROL_NAME, mt8186_tdm_enum[0],
315ae92dcbeSJiaxin Yu 		     mt8186_tdm_hd_get, mt8186_tdm_hd_set),
316ae92dcbeSJiaxin Yu };
317ae92dcbeSJiaxin Yu 
318ae92dcbeSJiaxin Yu static const struct snd_soc_dapm_route mtk_dai_tdm_routes[] = {
319ae92dcbeSJiaxin Yu 	{"TDM IN", NULL, "aud_tdm_clk"},
320ae92dcbeSJiaxin Yu 	{"TDM IN", NULL, "TDM_EN"},
321ae92dcbeSJiaxin Yu 	{"TDM IN", NULL, TDM_HD_EN_W_NAME, mtk_afe_tdm_hd_connect},
322ae92dcbeSJiaxin Yu 	{TDM_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_tdm_apll_connect},
323ae92dcbeSJiaxin Yu 	{TDM_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_tdm_apll_connect},
324ae92dcbeSJiaxin Yu 
325ae92dcbeSJiaxin Yu 	{"TDM IN", NULL, TDM_MCLK_EN_W_NAME, mtk_afe_tdm_mclk_connect},
326ae92dcbeSJiaxin Yu 	{TDM_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_tdm_mclk_apll_connect},
327ae92dcbeSJiaxin Yu 	{TDM_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_tdm_mclk_apll_connect},
328ae92dcbeSJiaxin Yu 
329ae92dcbeSJiaxin Yu 	/* allow tdm on without codec on */
330ae92dcbeSJiaxin Yu 	{"TDM IN", NULL, "TDM_In_Mux"},
331ae92dcbeSJiaxin Yu 	{"TDM_In_Mux", "Dummy_Widget", "TDM_DUMMY_IN"},
332ae92dcbeSJiaxin Yu };
333ae92dcbeSJiaxin Yu 
334ae92dcbeSJiaxin Yu /* dai ops */
mtk_dai_tdm_cal_mclk(struct mtk_base_afe * afe,struct mtk_afe_tdm_priv * tdm_priv,int freq)335ae92dcbeSJiaxin Yu static int mtk_dai_tdm_cal_mclk(struct mtk_base_afe *afe,
336ae92dcbeSJiaxin Yu 				struct mtk_afe_tdm_priv *tdm_priv,
337ae92dcbeSJiaxin Yu 				int freq)
338ae92dcbeSJiaxin Yu {
339ae92dcbeSJiaxin Yu 	int apll;
340ae92dcbeSJiaxin Yu 	int apll_rate;
341ae92dcbeSJiaxin Yu 
342ae92dcbeSJiaxin Yu 	apll = mt8186_get_apll_by_rate(afe, freq);
343ae92dcbeSJiaxin Yu 	apll_rate = mt8186_get_apll_rate(afe, apll);
344ae92dcbeSJiaxin Yu 
345ae92dcbeSJiaxin Yu 	if (!freq || freq > apll_rate) {
346ae92dcbeSJiaxin Yu 		dev_err(afe->dev,
347ae92dcbeSJiaxin Yu 			"%s(), freq(%d Hz) invalid\n", __func__, freq);
348ae92dcbeSJiaxin Yu 		return -EINVAL;
349ae92dcbeSJiaxin Yu 	}
350ae92dcbeSJiaxin Yu 
351ae92dcbeSJiaxin Yu 	if (apll_rate % freq != 0) {
352ae92dcbeSJiaxin Yu 		dev_err(afe->dev,
353ae92dcbeSJiaxin Yu 			"%s(), APLL cannot generate %d Hz", __func__, freq);
354ae92dcbeSJiaxin Yu 		return -EINVAL;
355ae92dcbeSJiaxin Yu 	}
356ae92dcbeSJiaxin Yu 
357ae92dcbeSJiaxin Yu 	tdm_priv->mclk_rate = freq;
358ae92dcbeSJiaxin Yu 	tdm_priv->mclk_apll = apll;
359ae92dcbeSJiaxin Yu 
360ae92dcbeSJiaxin Yu 	return 0;
361ae92dcbeSJiaxin Yu }
362ae92dcbeSJiaxin Yu 
mtk_dai_tdm_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)363ae92dcbeSJiaxin Yu static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream,
364ae92dcbeSJiaxin Yu 				 struct snd_pcm_hw_params *params,
365ae92dcbeSJiaxin Yu 				 struct snd_soc_dai *dai)
366ae92dcbeSJiaxin Yu {
367ae92dcbeSJiaxin Yu 	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
368ae92dcbeSJiaxin Yu 	struct mt8186_afe_private *afe_priv = afe->platform_priv;
369ae92dcbeSJiaxin Yu 	int tdm_id = dai->id;
370ae92dcbeSJiaxin Yu 	struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[tdm_id];
371ae92dcbeSJiaxin Yu 	unsigned int tdm_mode = tdm_priv->tdm_mode;
372ae92dcbeSJiaxin Yu 	unsigned int data_mode = tdm_priv->data_mode;
373ae92dcbeSJiaxin Yu 	unsigned int rate = params_rate(params);
374ae92dcbeSJiaxin Yu 	unsigned int channels = params_channels(params);
375ae92dcbeSJiaxin Yu 	snd_pcm_format_t format = params_format(params);
376ae92dcbeSJiaxin Yu 	unsigned int bit_width =
377ae92dcbeSJiaxin Yu 		snd_pcm_format_physical_width(format);
378ae92dcbeSJiaxin Yu 	unsigned int tdm_channels = (data_mode == TDM_DATA_ONE_PIN) ?
379ae92dcbeSJiaxin Yu 		get_tdm_ch_per_sdata(tdm_mode, channels) : 2;
380ae92dcbeSJiaxin Yu 	unsigned int lrck_width =
381ae92dcbeSJiaxin Yu 		get_tdm_lrck_width(format, tdm_mode);
382ae92dcbeSJiaxin Yu 	unsigned int tdm_con = 0;
383ae92dcbeSJiaxin Yu 	bool slave_mode = tdm_priv->slave_mode;
384ae92dcbeSJiaxin Yu 	bool lrck_inv = tdm_priv->lck_invert;
385ae92dcbeSJiaxin Yu 	bool bck_inv = tdm_priv->bck_invert;
386ae92dcbeSJiaxin Yu 	unsigned int tran_rate;
387ae92dcbeSJiaxin Yu 	unsigned int tran_relatch_rate;
388ae92dcbeSJiaxin Yu 
389ae92dcbeSJiaxin Yu 	tdm_priv->rate = rate;
390ae92dcbeSJiaxin Yu 	tran_rate = mt8186_rate_transform(afe->dev, rate, dai->id);
391ae92dcbeSJiaxin Yu 	tran_relatch_rate = mt8186_tdm_relatch_rate_transform(afe->dev, rate);
392ae92dcbeSJiaxin Yu 
393ae92dcbeSJiaxin Yu 	/* calculate mclk_rate, if not set explicitly */
394ae92dcbeSJiaxin Yu 	if (!tdm_priv->mclk_rate) {
395ae92dcbeSJiaxin Yu 		tdm_priv->mclk_rate = rate * tdm_priv->mclk_multiple;
396*d7bffbe9SJiaxin Yu 		mtk_dai_tdm_cal_mclk(afe, tdm_priv, tdm_priv->mclk_rate);
397ae92dcbeSJiaxin Yu 	}
398ae92dcbeSJiaxin Yu 
399ae92dcbeSJiaxin Yu 	/* ETDM_IN1_CON0 */
400ae92dcbeSJiaxin Yu 	tdm_con |= slave_mode << ETDM_IN1_CON0_REG_SLAVE_MODE_SFT;
401ae92dcbeSJiaxin Yu 	tdm_con |= tdm_mode << ETDM_IN1_CON0_REG_FMT_SFT;
402ae92dcbeSJiaxin Yu 	tdm_con |= (bit_width - 1) << ETDM_IN1_CON0_REG_BIT_LENGTH_SFT;
403ae92dcbeSJiaxin Yu 	tdm_con |= (bit_width - 1) << ETDM_IN1_CON0_REG_WORD_LENGTH_SFT;
404ae92dcbeSJiaxin Yu 	tdm_con |= (tdm_channels - 1) << ETDM_IN1_CON0_REG_CH_NUM_SFT;
405ae92dcbeSJiaxin Yu 	/* need to disable sync mode otherwise this may cause latch data error */
406ae92dcbeSJiaxin Yu 	tdm_con |= 0 << ETDM_IN1_CON0_REG_SYNC_MODE_SFT;
407ae92dcbeSJiaxin Yu 	/* relatch 1x en clock fix to h26m */
408ae92dcbeSJiaxin Yu 	tdm_con |= 0 << ETDM_IN1_CON0_REG_RELATCH_1X_EN_SEL_DOMAIN_SFT;
409ae92dcbeSJiaxin Yu 	regmap_update_bits(afe->regmap, ETDM_IN1_CON0, ETDM_IN_CON0_CTRL_MASK, tdm_con);
410ae92dcbeSJiaxin Yu 
411ae92dcbeSJiaxin Yu 	/* ETDM_IN1_CON1 */
412ae92dcbeSJiaxin Yu 	tdm_con = 0;
413ae92dcbeSJiaxin Yu 	tdm_con |= 0 << ETDM_IN1_CON1_REG_LRCK_AUTO_MODE_SFT;
414ae92dcbeSJiaxin Yu 	tdm_con |= 1 << ETDM_IN1_CON1_PINMUX_MCLK_CTRL_OE_SFT;
415ae92dcbeSJiaxin Yu 	tdm_con |= (lrck_width - 1) << ETDM_IN1_CON1_REG_LRCK_WIDTH_SFT;
416ae92dcbeSJiaxin Yu 	regmap_update_bits(afe->regmap, ETDM_IN1_CON1, ETDM_IN_CON1_CTRL_MASK, tdm_con);
417ae92dcbeSJiaxin Yu 
418ae92dcbeSJiaxin Yu 	/* ETDM_IN1_CON3 */
419ae92dcbeSJiaxin Yu 	tdm_con = 0;
420ae92dcbeSJiaxin Yu 	tdm_con = ETDM_IN_CON3_FS(tran_rate);
421ae92dcbeSJiaxin Yu 	regmap_update_bits(afe->regmap, ETDM_IN1_CON3, ETDM_IN_CON3_CTRL_MASK, tdm_con);
422ae92dcbeSJiaxin Yu 
423ae92dcbeSJiaxin Yu 	/* ETDM_IN1_CON4 */
424ae92dcbeSJiaxin Yu 	tdm_con = 0;
425ae92dcbeSJiaxin Yu 	tdm_con = ETDM_IN_CON4_FS(tran_relatch_rate);
426ae92dcbeSJiaxin Yu 	if (slave_mode) {
427ae92dcbeSJiaxin Yu 		if (lrck_inv)
428ae92dcbeSJiaxin Yu 			tdm_con |= ETDM_IN_CON4_CON0_SLAVE_LRCK_INV;
429ae92dcbeSJiaxin Yu 		if (bck_inv)
430ae92dcbeSJiaxin Yu 			tdm_con |= ETDM_IN_CON4_CON0_SLAVE_BCK_INV;
431ae92dcbeSJiaxin Yu 	} else {
432ae92dcbeSJiaxin Yu 		if (lrck_inv)
433ae92dcbeSJiaxin Yu 			tdm_con |= ETDM_IN_CON4_CON0_MASTER_LRCK_INV;
434ae92dcbeSJiaxin Yu 		if (bck_inv)
435ae92dcbeSJiaxin Yu 			tdm_con |= ETDM_IN_CON4_CON0_MASTER_BCK_INV;
436ae92dcbeSJiaxin Yu 	}
437ae92dcbeSJiaxin Yu 	regmap_update_bits(afe->regmap, ETDM_IN1_CON4, ETDM_IN_CON4_CTRL_MASK, tdm_con);
438ae92dcbeSJiaxin Yu 
439ae92dcbeSJiaxin Yu 	/* ETDM_IN1_CON2 */
440ae92dcbeSJiaxin Yu 	tdm_con = 0;
441ae92dcbeSJiaxin Yu 	if (data_mode == TDM_DATA_MULTI_PIN) {
442ae92dcbeSJiaxin Yu 		tdm_con |= ETDM_IN_CON2_MULTI_IP_2CH_MODE;
443ae92dcbeSJiaxin Yu 		tdm_con |= ETDM_IN_CON2_MULTI_IP_CH(channels);
444ae92dcbeSJiaxin Yu 	}
445ae92dcbeSJiaxin Yu 	regmap_update_bits(afe->regmap, ETDM_IN1_CON2, ETDM_IN_CON2_CTRL_MASK, tdm_con);
446ae92dcbeSJiaxin Yu 
447ae92dcbeSJiaxin Yu 	/* ETDM_IN1_CON8 */
448ae92dcbeSJiaxin Yu 	tdm_con = 0;
449ae92dcbeSJiaxin Yu 	if (slave_mode) {
450ae92dcbeSJiaxin Yu 		tdm_con |= 1 << ETDM_IN1_CON8_REG_ETDM_USE_AFIFO_SFT;
451ae92dcbeSJiaxin Yu 		tdm_con |= 0 << ETDM_IN1_CON8_REG_AFIFO_CLOCK_DOMAIN_SEL_SFT;
452ae92dcbeSJiaxin Yu 		tdm_con |= ETDM_IN_CON8_FS(tran_relatch_rate);
453ae92dcbeSJiaxin Yu 	} else {
454ae92dcbeSJiaxin Yu 		tdm_con |= 0 << ETDM_IN1_CON8_REG_ETDM_USE_AFIFO_SFT;
455ae92dcbeSJiaxin Yu 	}
456ae92dcbeSJiaxin Yu 	regmap_update_bits(afe->regmap, ETDM_IN1_CON8, ETDM_IN_CON8_CTRL_MASK, tdm_con);
457ae92dcbeSJiaxin Yu 
458ae92dcbeSJiaxin Yu 	return 0;
459ae92dcbeSJiaxin Yu }
460ae92dcbeSJiaxin Yu 
mtk_dai_tdm_set_sysclk(struct snd_soc_dai * dai,int clk_id,unsigned int freq,int dir)461ae92dcbeSJiaxin Yu static int mtk_dai_tdm_set_sysclk(struct snd_soc_dai *dai,
462ae92dcbeSJiaxin Yu 				  int clk_id, unsigned int freq, int dir)
463ae92dcbeSJiaxin Yu {
464ae92dcbeSJiaxin Yu 	struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
465ae92dcbeSJiaxin Yu 	struct mt8186_afe_private *afe_priv = afe->platform_priv;
466ae92dcbeSJiaxin Yu 	struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id];
467ae92dcbeSJiaxin Yu 
468ae92dcbeSJiaxin Yu 	if (dir != SND_SOC_CLOCK_IN) {
469ae92dcbeSJiaxin Yu 		dev_err(afe->dev, "%s(), dir != SND_SOC_CLOCK_OUT", __func__);
470ae92dcbeSJiaxin Yu 		return -EINVAL;
471ae92dcbeSJiaxin Yu 	}
472ae92dcbeSJiaxin Yu 
473ae92dcbeSJiaxin Yu 	dev_dbg(afe->dev, "%s(), freq %d\n", __func__, freq);
474ae92dcbeSJiaxin Yu 
475ae92dcbeSJiaxin Yu 	return mtk_dai_tdm_cal_mclk(afe, tdm_priv, freq);
476ae92dcbeSJiaxin Yu }
477ae92dcbeSJiaxin Yu 
mtk_dai_tdm_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)478ae92dcbeSJiaxin Yu static int mtk_dai_tdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
479ae92dcbeSJiaxin Yu {
480ae92dcbeSJiaxin Yu 	struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
481ae92dcbeSJiaxin Yu 	struct mt8186_afe_private *afe_priv = afe->platform_priv;
482ae92dcbeSJiaxin Yu 	struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id];
483ae92dcbeSJiaxin Yu 
484ae92dcbeSJiaxin Yu 	/* DAI mode*/
485ae92dcbeSJiaxin Yu 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
486ae92dcbeSJiaxin Yu 	case SND_SOC_DAIFMT_I2S:
487ae92dcbeSJiaxin Yu 		tdm_priv->tdm_mode = TDM_IN_I2S;
488ae92dcbeSJiaxin Yu 		tdm_priv->data_mode = TDM_DATA_MULTI_PIN;
489ae92dcbeSJiaxin Yu 		break;
490ae92dcbeSJiaxin Yu 	case SND_SOC_DAIFMT_LEFT_J:
491ae92dcbeSJiaxin Yu 		tdm_priv->tdm_mode = TDM_IN_LJ;
492ae92dcbeSJiaxin Yu 		tdm_priv->data_mode = TDM_DATA_MULTI_PIN;
493ae92dcbeSJiaxin Yu 		break;
494ae92dcbeSJiaxin Yu 	case SND_SOC_DAIFMT_RIGHT_J:
495ae92dcbeSJiaxin Yu 		tdm_priv->tdm_mode = TDM_IN_RJ;
496ae92dcbeSJiaxin Yu 		tdm_priv->data_mode = TDM_DATA_MULTI_PIN;
497ae92dcbeSJiaxin Yu 		break;
498ae92dcbeSJiaxin Yu 	case SND_SOC_DAIFMT_DSP_A:
499ae92dcbeSJiaxin Yu 		tdm_priv->tdm_mode = TDM_IN_DSP_A;
500ae92dcbeSJiaxin Yu 		tdm_priv->data_mode = TDM_DATA_ONE_PIN;
501ae92dcbeSJiaxin Yu 		break;
502ae92dcbeSJiaxin Yu 	case SND_SOC_DAIFMT_DSP_B:
503ae92dcbeSJiaxin Yu 		tdm_priv->tdm_mode = TDM_IN_DSP_B;
504ae92dcbeSJiaxin Yu 		tdm_priv->data_mode = TDM_DATA_ONE_PIN;
505ae92dcbeSJiaxin Yu 		break;
506ae92dcbeSJiaxin Yu 	default:
507ae92dcbeSJiaxin Yu 		dev_err(afe->dev, "%s(), invalid DAIFMT_FORMAT_MASK", __func__);
508ae92dcbeSJiaxin Yu 		return -EINVAL;
509ae92dcbeSJiaxin Yu 	}
510ae92dcbeSJiaxin Yu 
511ae92dcbeSJiaxin Yu 	/* DAI clock inversion*/
512ae92dcbeSJiaxin Yu 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
513ae92dcbeSJiaxin Yu 	case SND_SOC_DAIFMT_NB_NF:
514ae92dcbeSJiaxin Yu 		tdm_priv->bck_invert = TDM_BCK_NON_INV;
515ae92dcbeSJiaxin Yu 		tdm_priv->lck_invert = TDM_LCK_NON_INV;
516ae92dcbeSJiaxin Yu 		break;
517ae92dcbeSJiaxin Yu 	case SND_SOC_DAIFMT_NB_IF:
518ae92dcbeSJiaxin Yu 		tdm_priv->bck_invert = TDM_BCK_NON_INV;
519ae92dcbeSJiaxin Yu 		tdm_priv->lck_invert = TDM_LCK_INV;
520ae92dcbeSJiaxin Yu 		break;
521ae92dcbeSJiaxin Yu 	case SND_SOC_DAIFMT_IB_NF:
522ae92dcbeSJiaxin Yu 		tdm_priv->bck_invert = TDM_BCK_INV;
523ae92dcbeSJiaxin Yu 		tdm_priv->lck_invert = TDM_LCK_NON_INV;
524ae92dcbeSJiaxin Yu 		break;
525ae92dcbeSJiaxin Yu 	case SND_SOC_DAIFMT_IB_IF:
526ae92dcbeSJiaxin Yu 		tdm_priv->bck_invert = TDM_BCK_INV;
527ae92dcbeSJiaxin Yu 		tdm_priv->lck_invert = TDM_LCK_INV;
528ae92dcbeSJiaxin Yu 		break;
529ae92dcbeSJiaxin Yu 	default:
530ae92dcbeSJiaxin Yu 		dev_err(afe->dev, "%s(), invalid DAIFMT_INV_MASK", __func__);
531ae92dcbeSJiaxin Yu 		return -EINVAL;
532ae92dcbeSJiaxin Yu 	}
533ae92dcbeSJiaxin Yu 
534ae92dcbeSJiaxin Yu 	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
535845a2155SCharles Keepax 	case SND_SOC_DAIFMT_BP_FP:
536ae92dcbeSJiaxin Yu 		tdm_priv->slave_mode = false;
537ae92dcbeSJiaxin Yu 		break;
538845a2155SCharles Keepax 	case SND_SOC_DAIFMT_BC_FC:
539ae92dcbeSJiaxin Yu 		tdm_priv->slave_mode = true;
540ae92dcbeSJiaxin Yu 		break;
541ae92dcbeSJiaxin Yu 	default:
542ae92dcbeSJiaxin Yu 		dev_err(afe->dev, "%s(), invalid DAIFMT_CLOCK_PROVIDER_MASK",
543ae92dcbeSJiaxin Yu 			__func__);
544ae92dcbeSJiaxin Yu 		return -EINVAL;
545ae92dcbeSJiaxin Yu 	}
546ae92dcbeSJiaxin Yu 
547ae92dcbeSJiaxin Yu 	return 0;
548ae92dcbeSJiaxin Yu }
549ae92dcbeSJiaxin Yu 
mtk_dai_tdm_set_tdm_slot(struct snd_soc_dai * dai,unsigned int tx_mask,unsigned int rx_mask,int slots,int slot_width)550ae92dcbeSJiaxin Yu static int mtk_dai_tdm_set_tdm_slot(struct snd_soc_dai *dai,
551ae92dcbeSJiaxin Yu 				    unsigned int tx_mask,
552ae92dcbeSJiaxin Yu 				    unsigned int rx_mask,
553ae92dcbeSJiaxin Yu 				    int slots,
554ae92dcbeSJiaxin Yu 				    int slot_width)
555ae92dcbeSJiaxin Yu {
556ae92dcbeSJiaxin Yu 	struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
557ae92dcbeSJiaxin Yu 	struct mt8186_afe_private *afe_priv = afe->platform_priv;
558ae92dcbeSJiaxin Yu 	struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id];
559ae92dcbeSJiaxin Yu 
560ae92dcbeSJiaxin Yu 	dev_dbg(dai->dev, "%s %d slot_width %d\n", __func__, dai->id, slot_width);
561ae92dcbeSJiaxin Yu 
562ae92dcbeSJiaxin Yu 	tdm_priv->lrck_width = slot_width;
563ae92dcbeSJiaxin Yu 
564ae92dcbeSJiaxin Yu 	return 0;
565ae92dcbeSJiaxin Yu }
566ae92dcbeSJiaxin Yu 
567ae92dcbeSJiaxin Yu static const struct snd_soc_dai_ops mtk_dai_tdm_ops = {
568ae92dcbeSJiaxin Yu 	.hw_params = mtk_dai_tdm_hw_params,
569ae92dcbeSJiaxin Yu 	.set_sysclk = mtk_dai_tdm_set_sysclk,
570ae92dcbeSJiaxin Yu 	.set_fmt = mtk_dai_tdm_set_fmt,
571ae92dcbeSJiaxin Yu 	.set_tdm_slot = mtk_dai_tdm_set_tdm_slot,
572ae92dcbeSJiaxin Yu };
573ae92dcbeSJiaxin Yu 
574ae92dcbeSJiaxin Yu /* dai driver */
575ae92dcbeSJiaxin Yu #define MTK_TDM_RATES (SNDRV_PCM_RATE_8000_48000 |\
576ae92dcbeSJiaxin Yu 		       SNDRV_PCM_RATE_88200 |\
577ae92dcbeSJiaxin Yu 		       SNDRV_PCM_RATE_96000 |\
578ae92dcbeSJiaxin Yu 		       SNDRV_PCM_RATE_176400 |\
579ae92dcbeSJiaxin Yu 		       SNDRV_PCM_RATE_192000)
580ae92dcbeSJiaxin Yu 
581ae92dcbeSJiaxin Yu #define MTK_TDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
582ae92dcbeSJiaxin Yu 			 SNDRV_PCM_FMTBIT_S24_LE |\
583ae92dcbeSJiaxin Yu 			 SNDRV_PCM_FMTBIT_S32_LE)
584ae92dcbeSJiaxin Yu 
585ae92dcbeSJiaxin Yu static struct snd_soc_dai_driver mtk_dai_tdm_driver[] = {
586ae92dcbeSJiaxin Yu 	{
587ae92dcbeSJiaxin Yu 		.name = "TDM IN",
588ae92dcbeSJiaxin Yu 		.id = MT8186_DAI_TDM_IN,
589ae92dcbeSJiaxin Yu 		.capture = {
590ae92dcbeSJiaxin Yu 			.stream_name = "TDM IN",
591ae92dcbeSJiaxin Yu 			.channels_min = 2,
592ae92dcbeSJiaxin Yu 			.channels_max = 8,
593ae92dcbeSJiaxin Yu 			.rates = MTK_TDM_RATES,
594ae92dcbeSJiaxin Yu 			.formats = MTK_TDM_FORMATS,
595ae92dcbeSJiaxin Yu 		},
596ae92dcbeSJiaxin Yu 		.ops = &mtk_dai_tdm_ops,
597ae92dcbeSJiaxin Yu 	},
598ae92dcbeSJiaxin Yu };
599ae92dcbeSJiaxin Yu 
init_tdm_priv_data(struct mtk_base_afe * afe)600ae92dcbeSJiaxin Yu static struct mtk_afe_tdm_priv *init_tdm_priv_data(struct mtk_base_afe *afe)
601ae92dcbeSJiaxin Yu {
602ae92dcbeSJiaxin Yu 	struct mtk_afe_tdm_priv *tdm_priv;
603ae92dcbeSJiaxin Yu 
604ae92dcbeSJiaxin Yu 	tdm_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_afe_tdm_priv),
605ae92dcbeSJiaxin Yu 				GFP_KERNEL);
606ae92dcbeSJiaxin Yu 	if (!tdm_priv)
607ae92dcbeSJiaxin Yu 		return NULL;
608ae92dcbeSJiaxin Yu 
609ae92dcbeSJiaxin Yu 	tdm_priv->mclk_multiple = 512;
610ae92dcbeSJiaxin Yu 	tdm_priv->mclk_id = MT8186_TDM_MCK;
611ae92dcbeSJiaxin Yu 	tdm_priv->id = MT8186_DAI_TDM_IN;
612ae92dcbeSJiaxin Yu 
613ae92dcbeSJiaxin Yu 	return tdm_priv;
614ae92dcbeSJiaxin Yu }
615ae92dcbeSJiaxin Yu 
mt8186_dai_tdm_register(struct mtk_base_afe * afe)616ae92dcbeSJiaxin Yu int mt8186_dai_tdm_register(struct mtk_base_afe *afe)
617ae92dcbeSJiaxin Yu {
618ae92dcbeSJiaxin Yu 	struct mt8186_afe_private *afe_priv = afe->platform_priv;
619ae92dcbeSJiaxin Yu 	struct mtk_afe_tdm_priv *tdm_priv;
620ae92dcbeSJiaxin Yu 	struct mtk_base_afe_dai *dai;
621ae92dcbeSJiaxin Yu 
622ae92dcbeSJiaxin Yu 	dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
623ae92dcbeSJiaxin Yu 	if (!dai)
624ae92dcbeSJiaxin Yu 		return -ENOMEM;
625ae92dcbeSJiaxin Yu 
626ae92dcbeSJiaxin Yu 	list_add(&dai->list, &afe->sub_dais);
627ae92dcbeSJiaxin Yu 
628ae92dcbeSJiaxin Yu 	dai->dai_drivers = mtk_dai_tdm_driver;
629ae92dcbeSJiaxin Yu 	dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_tdm_driver);
630ae92dcbeSJiaxin Yu 
631ae92dcbeSJiaxin Yu 	dai->controls = mtk_dai_tdm_controls;
632ae92dcbeSJiaxin Yu 	dai->num_controls = ARRAY_SIZE(mtk_dai_tdm_controls);
633ae92dcbeSJiaxin Yu 	dai->dapm_widgets = mtk_dai_tdm_widgets;
634ae92dcbeSJiaxin Yu 	dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_tdm_widgets);
635ae92dcbeSJiaxin Yu 	dai->dapm_routes = mtk_dai_tdm_routes;
636ae92dcbeSJiaxin Yu 	dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_tdm_routes);
637ae92dcbeSJiaxin Yu 
638ae92dcbeSJiaxin Yu 	tdm_priv = init_tdm_priv_data(afe);
639ae92dcbeSJiaxin Yu 	if (!tdm_priv)
640ae92dcbeSJiaxin Yu 		return -ENOMEM;
641ae92dcbeSJiaxin Yu 
642ae92dcbeSJiaxin Yu 	afe_priv->dai_priv[MT8186_DAI_TDM_IN] = tdm_priv;
643ae92dcbeSJiaxin Yu 
644ae92dcbeSJiaxin Yu 	return 0;
645ae92dcbeSJiaxin Yu }
646