1 /*
2  * Copyright (c) 2022 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <errno.h>
8 #include <zephyr/sys/util_macro.h>
9 #include <stdbool.h>
10 #include <stdint.h>
11 #include <zephyr/spinlock.h>
12 #include <zephyr/devicetree.h>
13 #include <zephyr/pm/device.h>
14 #include <zephyr/pm/device_runtime.h>
15 #define LOG_DOMAIN dai_intel_ssp
16 #include <zephyr/logging/log.h>
17 LOG_MODULE_REGISTER(LOG_DOMAIN);
18 
19 #include "ssp.h"
20 
21 #define DT_DRV_COMPAT intel_ssp_dai
22 
23 #define dai_set_drvdata(dai, data) (dai->priv_data = data)
24 #define dai_get_drvdata(dai) dai->priv_data
25 #define dai_get_mn(dai) dai->plat_data.mn_inst
26 #define dai_get_ftable(dai) dai->plat_data.ftable
27 #define dai_get_fsources(dai) dai->plat_data.fsources
28 #define dai_mn_base(dai) dai->plat_data.mn_inst->base
29 #define dai_base(dai) dai->plat_data.base
30 #define dai_ip_base(dai) dai->plat_data.ip_base
31 #define dai_shim_base(dai) dai->plat_data.shim_base
32 #define dai_hdamlssp_base(dai) dai->plat_data.hdamlssp_base
33 #define dai_i2svss_base(dai) dai->plat_data.i2svss_base
34 
35 #define DAI_DIR_PLAYBACK 0
36 #define DAI_DIR_CAPTURE 1
37 #define SSP_ARRAY_INDEX(dir) dir == DAI_DIR_RX ? DAI_DIR_CAPTURE : DAI_DIR_PLAYBACK
38 
dai_ssp_update_bits(struct dai_intel_ssp * dp,uint32_t reg,uint32_t mask,uint32_t val)39 static void dai_ssp_update_bits(struct dai_intel_ssp *dp, uint32_t reg, uint32_t mask, uint32_t val)
40 {
41 	uint32_t dest = dai_base(dp) + reg;
42 
43 	LOG_INF("%s base %x, reg %x, mask %x, value %x", __func__,
44 		dai_base(dp), reg, mask, val);
45 
46 	sys_write32((sys_read32(dest) & (~mask)) | (val & mask), dest);
47 }
48 
49 #if CONFIG_INTEL_MN
dai_ssp_gcd(int a,int b)50 static int dai_ssp_gcd(int a, int b)
51 {
52 	int aux;
53 	int k;
54 
55 	if (a == 0) {
56 		return b;
57 	}
58 
59 	if (b == 0) {
60 		return a;
61 	}
62 
63 	/* If the numbers are negative, convert them to positive numbers
64 	 * gcd(a, b) = gcd(-a, -b) = gcd(-a, b) = gcd(a, -b)
65 	 */
66 	if (a < 0) {
67 		a = -a;
68 	}
69 
70 	if (b < 0) {
71 		b = -b;
72 	}
73 
74 	/* Find the greatest power of 2 that devides both a and b */
75 	for (k = 0; ((a | b) & 1) == 0; k++) {
76 		a >>= 1;
77 		b >>= 1;
78 	}
79 
80 	/* divide by 2 until a becomes odd */
81 	while ((a & 1) == 0) {
82 		a >>= 1;
83 	}
84 
85 	do {
86 		/*if b is even, remove all factors of 2*/
87 		while ((b & 1) == 0) {
88 			b >>= 1;
89 		}
90 
91 		/* both a and b are odd now. Swap so a <= b
92 		 * then set b = b - a, which is also even
93 		 */
94 		if (a > b) {
95 			aux = a;
96 			a = b;
97 			b = aux;
98 		}
99 
100 		b = b - a;
101 
102 	} while (b != 0);
103 
104 	/* restore common factors of 2 */
105 	return a << k;
106 }
107 #endif
108 
109 /**
110  * \brief Checks if given clock is used as source for any MCLK.
111  *
112  * \return true if any port use given clock source, false otherwise.
113  */
dai_ssp_is_mclk_source_in_use(struct dai_intel_ssp * dp)114 static bool dai_ssp_is_mclk_source_in_use(struct dai_intel_ssp *dp)
115 {
116 	struct dai_intel_ssp_mn *mp = dai_get_mn(dp);
117 	bool ret = false;
118 	int i;
119 
120 	for (i = 0; i < ARRAY_SIZE(mp->mclk_sources_ref); i++) {
121 		if (mp->mclk_sources_ref[i] > 0) {
122 			ret = true;
123 			break;
124 		}
125 	}
126 
127 	return ret;
128 }
129 
130 /**
131  * \brief Configures source clock for MCLK.
132  *	  All MCLKs share the same source, so it should be changed
133  *	  only if there are no other ports using it already.
134  * \param[in] mclk_rate main clock frequency.
135  * \return 0 on success, error code otherwise.
136  */
dai_ssp_setup_initial_mclk_source(struct dai_intel_ssp * dp,uint32_t mclk_id,uint32_t mclk_rate)137 static int dai_ssp_setup_initial_mclk_source(struct dai_intel_ssp *dp, uint32_t mclk_id,
138 					     uint32_t mclk_rate)
139 {
140 	struct dai_intel_ssp_freq_table *ft = dai_get_ftable(dp);
141 	uint32_t *fs = dai_get_fsources(dp);
142 	struct dai_intel_ssp_mn *mp = dai_get_mn(dp);
143 	int clk_index = -1;
144 	uint32_t mdivc;
145 	int ret = 0;
146 	int i;
147 
148 	if (mclk_id >= DAI_INTEL_SSP_NUM_MCLK) {
149 		LOG_ERR("%s can't configure MCLK %d, only %d mclk[s] existed!",
150 			__func__, mclk_id, DAI_INTEL_SSP_NUM_MCLK);
151 		ret = -EINVAL;
152 		goto out;
153 	}
154 
155 	/* searching the smallest possible mclk source */
156 	for (i = 0; i <= DAI_INTEL_SSP_MAX_FREQ_INDEX; i++) {
157 		if (ft[i].freq % mclk_rate == 0) {
158 			clk_index = i;
159 			break;
160 		}
161 	}
162 
163 	if (clk_index < 0) {
164 		LOG_ERR("%s MCLK %d, no valid source", __func__, mclk_rate);
165 		ret = -EINVAL;
166 		goto out;
167 	}
168 
169 	mp->mclk_source_clock = clk_index;
170 
171 	mdivc = sys_read32(dai_mn_base(dp) + MN_MDIVCTRL);
172 
173 	/* enable MCLK divider */
174 	mdivc |= MN_MDIVCTRL_M_DIV_ENABLE(mclk_id);
175 
176 	/* clear source mclk clock - bits 17-16 */
177 	mdivc &= ~MCDSS(MN_SOURCE_CLKS_MASK);
178 
179 	/* select source clock */
180 	mdivc |= MCDSS(fs[clk_index]);
181 
182 	sys_write32(mdivc, dai_mn_base(dp) + MN_MDIVCTRL);
183 
184 	mp->mclk_sources_ref[mclk_id]++;
185 out:
186 
187 	return ret;
188 }
189 
190 /**
191  * \brief Checks if requested MCLK can be achieved with current source.
192  * \param[in] mclk_rate main clock frequency.
193  * \return 0 on success, error code otherwise.
194  */
dai_ssp_check_current_mclk_source(struct dai_intel_ssp * dp,uint16_t mclk_id,uint32_t mclk_rate)195 static int dai_ssp_check_current_mclk_source(struct dai_intel_ssp *dp, uint16_t mclk_id,
196 					     uint32_t mclk_rate)
197 {
198 	struct dai_intel_ssp_freq_table *ft = dai_get_ftable(dp);
199 	struct dai_intel_ssp_mn *mp = dai_get_mn(dp);
200 	uint32_t mdivc;
201 	int ret = 0;
202 
203 	LOG_INF("%s MCLK %d, source = %d", __func__, mclk_rate, mp->mclk_source_clock);
204 
205 	if (ft[mp->mclk_source_clock].freq % mclk_rate != 0) {
206 		LOG_ERR("%s MCLK %d, no valid configuration for already selected source = %d",
207 			__func__, mclk_rate, mp->mclk_source_clock);
208 		ret = -EINVAL;
209 	}
210 
211 	/* if the mclk is already used, can't change its divider, just increase ref count */
212 	if (mp->mclk_sources_ref[mclk_id] > 0) {
213 		if (mp->mclk_rate[mclk_id] != mclk_rate) {
214 			LOG_ERR("%s Can't set MCLK %d to %d, it is already configured to %d",
215 				__func__, mclk_id, mclk_rate, mp->mclk_rate[mclk_id]);
216 			return -EINVAL;
217 		}
218 
219 		mp->mclk_sources_ref[mclk_id]++;
220 	} else {
221 		mdivc = sys_read32(dai_mn_base(dp) + MN_MDIVCTRL);
222 
223 		/* enable MCLK divider */
224 		mdivc |= MN_MDIVCTRL_M_DIV_ENABLE(mclk_id);
225 		sys_write32(mdivc, dai_mn_base(dp) + MN_MDIVCTRL);
226 
227 		mp->mclk_sources_ref[mclk_id]++;
228 	}
229 
230 	return ret;
231 }
232 
233 /**
234  * \brief Sets MCLK divider to given value.
235  * \param[in] mclk_id ID of MCLK.
236  * \param[in] mdivr_val divider value.
237  * \return 0 on success, error code otherwise.
238  */
dai_ssp_set_mclk_divider(struct dai_intel_ssp * dp,uint16_t mclk_id,uint32_t mdivr_val)239 static int dai_ssp_set_mclk_divider(struct dai_intel_ssp *dp, uint16_t mclk_id, uint32_t mdivr_val)
240 {
241 	uint32_t mdivr;
242 
243 	LOG_INF("%s mclk_id %d mdivr_val %d", __func__, mclk_id, mdivr_val);
244 	switch (mdivr_val) {
245 	case 1:
246 		mdivr = 0x00000fff; /* bypass divider for MCLK */
247 		break;
248 	case 2 ... 8:
249 		mdivr = mdivr_val - 2; /* 1/n */
250 		break;
251 	default:
252 		LOG_ERR("%s invalid mdivr_val %d", __func__, mdivr_val);
253 		return -EINVAL;
254 	}
255 
256 	sys_write32(mdivr, dai_mn_base(dp) + MN_MDIVR(mclk_id));
257 
258 	return 0;
259 }
260 
dai_ssp_mn_set_mclk(struct dai_intel_ssp * dp,uint16_t mclk_id,uint32_t mclk_rate)261 static int dai_ssp_mn_set_mclk(struct dai_intel_ssp *dp, uint16_t mclk_id, uint32_t mclk_rate)
262 {
263 	struct dai_intel_ssp_freq_table *ft = dai_get_ftable(dp);
264 	struct dai_intel_ssp_mn *mp = dai_get_mn(dp);
265 	k_spinlock_key_t key;
266 	int ret = 0;
267 
268 	if (mclk_id >= DAI_INTEL_SSP_NUM_MCLK) {
269 		LOG_ERR("%s mclk ID (%d) >= %d", __func__, mclk_id, DAI_INTEL_SSP_NUM_MCLK);
270 		return -EINVAL;
271 	}
272 
273 	key = k_spin_lock(&mp->lock);
274 
275 	if (dai_ssp_is_mclk_source_in_use(dp)) {
276 		ret = dai_ssp_check_current_mclk_source(dp, mclk_id, mclk_rate);
277 	} else {
278 		ret = dai_ssp_setup_initial_mclk_source(dp, mclk_id, mclk_rate);
279 	}
280 
281 	if (ret < 0) {
282 		goto out;
283 	}
284 
285 	LOG_INF("%s mclk_rate %d, mclk_source_clock %d", __func__,
286 		mclk_rate, mp->mclk_source_clock);
287 
288 	ret = dai_ssp_set_mclk_divider(dp, mclk_id, ft[mp->mclk_source_clock].freq / mclk_rate);
289 	if (!ret) {
290 		mp->mclk_rate[mclk_id] = mclk_rate;
291 	}
292 
293 out:
294 	k_spin_unlock(&mp->lock, key);
295 
296 	return ret;
297 }
298 
dai_ssp_mn_set_mclk_blob(struct dai_intel_ssp * dp,uint32_t mdivc,uint32_t mdivr)299 static int dai_ssp_mn_set_mclk_blob(struct dai_intel_ssp *dp, uint32_t mdivc, uint32_t mdivr)
300 {
301 	sys_write32(mdivc, dai_mn_base(dp) + MN_MDIVCTRL);
302 	sys_write32(mdivr, dai_mn_base(dp) + MN_MDIVR(0));
303 
304 	return 0;
305 }
306 
dai_ssp_mn_release_mclk(struct dai_intel_ssp * dp,uint32_t mclk_id)307 static void dai_ssp_mn_release_mclk(struct dai_intel_ssp *dp, uint32_t mclk_id)
308 {
309 	struct dai_intel_ssp_mn *mp = dai_get_mn(dp);
310 	k_spinlock_key_t key;
311 	uint32_t mdivc;
312 
313 	key = k_spin_lock(&mp->lock);
314 
315 	mp->mclk_sources_ref[mclk_id]--;
316 
317 	/* disable MCLK divider if nobody use it */
318 	if (!mp->mclk_sources_ref[mclk_id]) {
319 		mdivc = sys_read32(dai_mn_base(dp) + MN_MDIVCTRL);
320 
321 		mdivc &= ~MN_MDIVCTRL_M_DIV_ENABLE(mclk_id);
322 		sys_write32(mdivc, dai_mn_base(dp) + MN_MDIVCTRL);
323 	}
324 
325 	/* release the clock source if all mclks are released */
326 	if (!dai_ssp_is_mclk_source_in_use(dp)) {
327 		mdivc = sys_read32(dai_mn_base(dp) + MN_MDIVCTRL);
328 
329 		/* clear source mclk clock - bits 17-16 */
330 		mdivc &= ~MCDSS(MN_SOURCE_CLKS_MASK);
331 
332 		sys_write32(mdivc, dai_mn_base(dp) + MN_MDIVCTRL);
333 
334 		mp->mclk_source_clock = 0;
335 	}
336 	k_spin_unlock(&mp->lock, key);
337 }
338 
339 #if CONFIG_INTEL_MN
340 /**
341  * \brief Finds valid M/(N * SCR) values for given frequencies.
342  * \param[in] freq SSP clock frequency.
343  * \param[in] bclk Bit clock frequency.
344  * \param[out] out_scr_div SCR divisor.
345  * \param[out] out_m M value of M/N divider.
346  * \param[out] out_n N value of M/N divider.
347  * \return true if found suitable values, false otherwise.
348  */
dai_ssp_find_mn(uint32_t freq,uint32_t bclk,uint32_t * out_scr_div,uint32_t * out_m,uint32_t * out_n)349 static bool dai_ssp_find_mn(uint32_t freq, uint32_t bclk, uint32_t *out_scr_div, uint32_t *out_m,
350 			    uint32_t *out_n)
351 {
352 	uint32_t m, n, mn_div;
353 	uint32_t scr_div = freq / bclk;
354 
355 	LOG_INF("%s for freq %d bclk %d", __func__, freq, bclk);
356 	/* check if just SCR is enough */
357 	if (freq % bclk == 0 && scr_div < (SSCR0_SCR_MASK >> 8) + 1) {
358 		*out_scr_div = scr_div;
359 		*out_m = 1;
360 		*out_n = 1;
361 
362 		return true;
363 	}
364 
365 	/* M/(N * scr_div) has to be less than 1/2 */
366 	if ((bclk * 2) >= freq) {
367 		return false;
368 	}
369 
370 	/* odd SCR gives lower duty cycle */
371 	if (scr_div > 1 && scr_div % 2 != 0) {
372 		--scr_div;
373 	}
374 
375 	/* clamp to valid SCR range */
376 	scr_div = MIN(scr_div, (SSCR0_SCR_MASK >> 8) + 1);
377 
378 	/* find highest even divisor */
379 	while (scr_div > 1 && freq % scr_div != 0) {
380 		scr_div -= 2;
381 	}
382 
383 	/* compute M/N with smallest dividend and divisor */
384 	mn_div = dai_ssp_gcd(bclk, freq / scr_div);
385 
386 	m = bclk / mn_div;
387 	n = freq / scr_div / mn_div;
388 
389 	/* M/N values can be up to 24 bits */
390 	if (n & (~0xffffff)) {
391 		return false;
392 	}
393 
394 	*out_scr_div = scr_div;
395 	*out_m = m;
396 	*out_n = n;
397 
398 	LOG_INF("%s m %d n %d", __func__, m, n);
399 	return true;
400 }
401 
402 /**
403  * \brief Finds index of clock valid for given BCLK rate.
404  *	  Clock that can use just SCR is preferred.
405  *	  M/N other than 1/1 is used only if there are no other possibilities.
406  * \param[in] bclk Bit clock frequency.
407  * \param[out] scr_div SCR divisor.
408  * \param[out] m M value of M/N divider.
409  * \param[out] n N value of M/N divider.
410  * \return index of suitable clock if could find it, -EINVAL otherwise.
411  */
dai_ssp_find_bclk_source(struct dai_intel_ssp * dp,uint32_t bclk,uint32_t * scr_div,uint32_t * m,uint32_t * n)412 static int dai_ssp_find_bclk_source(struct dai_intel_ssp *dp, uint32_t bclk, uint32_t *scr_div,
413 				    uint32_t *m, uint32_t *n)
414 {
415 	struct dai_intel_ssp_freq_table *ft = dai_get_ftable(dp);
416 	struct dai_intel_ssp_mn *mp = dai_get_mn(dp);
417 	int i;
418 
419 	/* check if we can use MCLK source clock */
420 	if (dai_ssp_is_mclk_source_in_use(dp)) {
421 		if (dai_ssp_find_mn(ft[mp->mclk_source_clock].freq, bclk, scr_div, m, n)) {
422 			return mp->mclk_source_clock;
423 		}
424 
425 		LOG_WRN("%s BCLK %d warning: cannot use MCLK source %d",
426 			__func__, bclk, ft[mp->mclk_source_clock].freq);
427 	}
428 
429 	/* searching the smallest possible bclk source */
430 	for (i = 0; i <= DAI_INTEL_SSP_MAX_FREQ_INDEX; i++)
431 		if (ft[i].freq % bclk == 0) {
432 			*scr_div = ft[i].freq / bclk;
433 			return i;
434 		}
435 
436 	/* check if we can get target BCLK with M/N */
437 	for (i = 0; i <= DAI_INTEL_SSP_MAX_FREQ_INDEX; i++) {
438 		if (dai_ssp_find_mn(ft[i].freq, bclk, scr_div, m, n)) {
439 			return i;
440 		}
441 	}
442 
443 	return -EINVAL;
444 }
445 
446 /**
447  * \brief Finds index of SSP clock with the given clock source encoded index.
448  * \return the index in ssp_freq if could find it, -EINVAL otherwise.
449  */
dai_ssp_find_clk_ssp_index(struct dai_intel_ssp * dp,uint32_t src_enc)450 static int dai_ssp_find_clk_ssp_index(struct dai_intel_ssp *dp, uint32_t src_enc)
451 {
452 	uint32_t *fs = dai_get_fsources(dp);
453 	int i;
454 
455 	/* searching for the encode value matched bclk source */
456 	for (i = 0; i <= DAI_INTEL_SSP_MAX_FREQ_INDEX; i++) {
457 		if (fs[i] == src_enc) {
458 			return i;
459 		}
460 	}
461 
462 	return -EINVAL;
463 }
464 
465 /**
466  * \brief Checks if given clock is used as source for any BCLK.
467  * \param[in] clk_src Bit clock source.
468  * \return true if any port use given clock source, false otherwise.
469  */
dai_ssp_is_bclk_source_in_use(struct dai_intel_ssp * dp,enum bclk_source clk_src)470 static bool dai_ssp_is_bclk_source_in_use(struct dai_intel_ssp *dp, enum bclk_source clk_src)
471 {
472 	struct dai_intel_ssp_mn *mp = dai_get_mn(dp);
473 	bool ret = false;
474 	int i;
475 
476 	for (i = 0; i < ARRAY_SIZE(mp->bclk_sources); i++) {
477 		if (mp->bclk_sources[i] == clk_src) {
478 			ret = true;
479 			break;
480 		}
481 	}
482 
483 	return ret;
484 }
485 
486 /**
487  * \brief Configures M/N source clock for BCLK.
488  *	  All ports that use M/N share the same source, so it should be changed
489  *	  only if there are no other ports using M/N already.
490  * \param[in] bclk Bit clock frequency.
491  * \param[out] scr_div SCR divisor.
492  * \param[out] m M value of M/N divider.
493  * \param[out] n N value of M/N divider.
494  * \return 0 on success, error code otherwise.
495  */
dai_ssp_setup_initial_bclk_mn_source(struct dai_intel_ssp * dp,uint32_t bclk,uint32_t * scr_div,uint32_t * m,uint32_t * n)496 static int dai_ssp_setup_initial_bclk_mn_source(struct dai_intel_ssp *dp, uint32_t bclk,
497 						uint32_t *scr_div, uint32_t *m, uint32_t *n)
498 {
499 	uint32_t *fs = dai_get_fsources(dp);
500 	struct dai_intel_ssp_mn *mp = dai_get_mn(dp);
501 	uint32_t mdivc;
502 	int clk_index = dai_ssp_find_bclk_source(dp, bclk, scr_div, m, n);
503 
504 	if (clk_index < 0) {
505 		LOG_ERR("%s BCLK %d, no valid source", __func__, bclk);
506 		return -EINVAL;
507 	}
508 
509 	mp->bclk_source_mn_clock = clk_index;
510 
511 	mdivc = sys_read32(dai_mn_base(dp) + MN_MDIVCTRL);
512 
513 	/* clear source bclk clock - 21-20 bits */
514 	mdivc &= ~MNDSS(MN_SOURCE_CLKS_MASK);
515 
516 	/* select source clock */
517 	mdivc |= MNDSS(fs[clk_index]);
518 
519 	sys_write32(mdivc, dai_mn_base(dp) + MN_MDIVCTRL);
520 
521 	return 0;
522 }
523 
524 /**
525  * \brief Reset M/N source clock for BCLK.
526  *	  If no port is using bclk, reset to use SSP_CLOCK_XTAL_OSCILLATOR
527  *	  as the default clock source.
528  */
dai_ssp_reset_bclk_mn_source(struct dai_intel_ssp * dp)529 static void dai_ssp_reset_bclk_mn_source(struct dai_intel_ssp *dp)
530 {
531 	struct dai_intel_ssp_mn *mp = dai_get_mn(dp);
532 	uint32_t mdivc;
533 	int clk_index = dai_ssp_find_clk_ssp_index(dp, DAI_INTEL_SSP_CLOCK_XTAL_OSCILLATOR);
534 
535 	if (clk_index < 0) {
536 		LOG_ERR("%s BCLK reset failed, no SSP_CLOCK_XTAL_OSCILLATOR source!",
537 			__func__);
538 		return;
539 	}
540 
541 	mdivc = sys_read32(dai_mn_base(dp) + MN_MDIVCTRL);
542 
543 	/* reset to use XTAL Oscillator */
544 	mdivc &= ~MNDSS(MN_SOURCE_CLKS_MASK);
545 	mdivc |= MNDSS(DAI_INTEL_SSP_CLOCK_XTAL_OSCILLATOR);
546 
547 	sys_write32(mdivc, dai_mn_base(dp) + MN_MDIVCTRL);
548 
549 	mp->bclk_source_mn_clock = clk_index;
550 }
551 
552 /**
553  * \brief Finds valid M/(N * SCR) values for source clock that is already locked
554  *	  because other ports use it.
555  * \param[in] bclk Bit clock frequency.
556  * \param[out] scr_div SCR divisor.
557  * \param[out] m M value of M/N divider.
558  * \param[out] n N value of M/N divider.
559  * \return 0 on success, error code otherwise.
560  */
dai_ssp_setup_current_bclk_mn_source(struct dai_intel_ssp * dp,uint32_t bclk,uint32_t * scr_div,uint32_t * m,uint32_t * n)561 static int dai_ssp_setup_current_bclk_mn_source(struct dai_intel_ssp *dp, uint32_t bclk,
562 						uint32_t *scr_div, uint32_t *m, uint32_t *n)
563 {
564 	struct dai_intel_ssp_freq_table *ft = dai_get_ftable(dp);
565 	struct dai_intel_ssp_mn *mp = dai_get_mn(dp);
566 	int ret = 0;
567 
568 	/* source for M/N is already set, no need to do it */
569 	if (dai_ssp_find_mn(ft[mp->bclk_source_mn_clock].freq, bclk, scr_div, m, n)) {
570 		goto out;
571 	}
572 
573 	LOG_ERR("%s BCLK %d, no valid configuration for already selected source = %d",
574 		__func__, bclk, mp->bclk_source_mn_clock);
575 	ret = -EINVAL;
576 
577 out:
578 
579 	return ret;
580 }
581 
dai_ssp_check_bclk_xtal_source(uint32_t bclk,bool mn_in_use,uint32_t * scr_div)582 static bool dai_ssp_check_bclk_xtal_source(uint32_t bclk, bool mn_in_use,
583 					   uint32_t *scr_div)
584 {
585 	/* since cAVS 2.0 bypassing XTAL (ECS=0) is not supported */
586 	return false;
587 }
588 
dai_ssp_mn_set_bclk(struct dai_intel_ssp * dp,uint32_t dai_index,uint32_t bclk_rate,uint32_t * out_scr_div,bool * out_need_ecs)589 static int dai_ssp_mn_set_bclk(struct dai_intel_ssp *dp, uint32_t dai_index, uint32_t bclk_rate,
590 			       uint32_t *out_scr_div, bool *out_need_ecs)
591 {
592 	struct dai_intel_ssp_mn *mp = dai_get_mn(dp);
593 	k_spinlock_key_t key;
594 	uint32_t m = 1;
595 	uint32_t n = 1;
596 	int ret = 0;
597 	bool mn_in_use;
598 
599 	key = k_spin_lock(&mp->lock);
600 
601 	mp->bclk_sources[dai_index] = MN_BCLK_SOURCE_NONE;
602 
603 	mn_in_use = dai_ssp_is_bclk_source_in_use(dp, MN_BCLK_SOURCE_MN);
604 
605 	if (dai_ssp_check_bclk_xtal_source(bclk_rate, mn_in_use, out_scr_div)) {
606 		mp->bclk_sources[dai_index] = MN_BCLK_SOURCE_XTAL;
607 		*out_need_ecs = false;
608 		goto out;
609 	}
610 
611 	*out_need_ecs = true;
612 
613 	if (mn_in_use) {
614 		ret = dai_ssp_setup_current_bclk_mn_source(dp, bclk_rate, out_scr_div, &m, &n);
615 	} else {
616 		ret = dai_ssp_setup_initial_bclk_mn_source(dp, bclk_rate, out_scr_div, &m, &n);
617 	}
618 
619 	if (ret >= 0) {
620 		mp->bclk_sources[dai_index] = MN_BCLK_SOURCE_MN;
621 
622 		LOG_INF("%s bclk_rate %d, *out_scr_div %d, m %d, n %d",
623 			__func__, bclk_rate, *out_scr_div, m, n);
624 
625 		sys_write32(m, dai_mn_base(dp) + MN_MDIV_M_VAL(dai_index));
626 		sys_write32(n, dai_mn_base(dp) + MN_MDIV_N_VAL(dai_index));
627 	}
628 
629 out:
630 
631 	k_spin_unlock(&mp->lock, key);
632 
633 	return ret;
634 }
635 
dai_ssp_mn_release_bclk(struct dai_intel_ssp * dp,uint32_t dai_index)636 static void dai_ssp_mn_release_bclk(struct dai_intel_ssp *dp, uint32_t dai_index)
637 {
638 	struct dai_intel_ssp_mn *mp = dai_get_mn(dp);
639 	k_spinlock_key_t key;
640 	bool mn_in_use;
641 
642 	key = k_spin_lock(&mp->lock);
643 	mp->bclk_sources[dai_index] = MN_BCLK_SOURCE_NONE;
644 
645 	mn_in_use = dai_ssp_is_bclk_source_in_use(dp, MN_BCLK_SOURCE_MN);
646 	/* release the M/N clock source if not used */
647 	if (!mn_in_use) {
648 		dai_ssp_reset_bclk_mn_source(dp);
649 	}
650 
651 	k_spin_unlock(&mp->lock, key);
652 }
653 
dai_ssp_mn_reset_bclk_divider(struct dai_intel_ssp * dp,uint32_t dai_index)654 static void dai_ssp_mn_reset_bclk_divider(struct dai_intel_ssp *dp, uint32_t dai_index)
655 {
656 	struct dai_intel_ssp_mn *mp = dai_get_mn(dp);
657 	k_spinlock_key_t key;
658 
659 	key = k_spin_lock(&mp->lock);
660 
661 	sys_write32(1, dai_mn_base(dp) + MN_MDIV_M_VAL(dai_index));
662 	sys_write32(1, dai_mn_base(dp) + MN_MDIV_N_VAL(dai_index));
663 
664 	k_spin_unlock(&mp->lock, key);
665 }
666 #endif
667 
dai_ssp_poll_for_register_delay(uint32_t reg,uint32_t mask,uint32_t val,uint64_t us)668 static int dai_ssp_poll_for_register_delay(uint32_t reg, uint32_t mask,
669 					   uint32_t val, uint64_t us)
670 {
671 	if (!WAIT_FOR((sys_read32(reg) & mask) == val, us, k_busy_wait(1))) {
672 		LOG_ERR("%s poll timeout reg %u mask %u val %u us %u",
673 			__func__, reg, mask, val, (uint32_t)us);
674 		return -EIO;
675 	}
676 
677 	return 0;
678 }
679 
dai_ssp_pm_runtime_dis_ssp_clk_gating(struct dai_intel_ssp * dp,uint32_t index)680 static inline void dai_ssp_pm_runtime_dis_ssp_clk_gating(struct dai_intel_ssp *dp, uint32_t index)
681 {
682 #if CONFIG_DAI_SSP_CLK_FORCE_DYNAMIC_CLOCK_GATING
683 	uint32_t shim_reg;
684 
685 	shim_reg = sys_read32(dai_shim_base(dp) + SHIM_CLKCTL) |
686 		(index < CONFIG_DAI_INTEL_SSP_NUM_BASE ?
687 			SHIM_CLKCTL_I2SFDCGB(index) :
688 			SHIM_CLKCTL_I2SEFDCGB(index -
689 					      CONFIG_DAI_INTEL_SSP_NUM_BASE));
690 
691 	sys_write32(shim_reg, dai_shim_base(dp) + SHIM_CLKCTL);
692 
693 	LOG_INF("%s index %d CLKCTL %08x", __func__, index, shim_reg);
694 #endif
695 }
696 
dai_ssp_pm_runtime_en_ssp_clk_gating(struct dai_intel_ssp * dp,uint32_t index)697 static inline void dai_ssp_pm_runtime_en_ssp_clk_gating(struct dai_intel_ssp *dp, uint32_t index)
698 {
699 #if CONFIG_DAI_SSP_CLK_FORCE_DYNAMIC_CLOCK_GATING
700 	uint32_t shim_reg;
701 
702 	shim_reg = sys_read32(dai_shim_base(dp) + SHIM_CLKCTL) &
703 		~(index < CONFIG_DAI_INTEL_SSP_NUM_BASE ?
704 			SHIM_CLKCTL_I2SFDCGB(index) :
705 			SHIM_CLKCTL_I2SEFDCGB(index -
706 					      CONFIG_DAI_INTEL_SSP_NUM_BASE));
707 
708 	sys_write32(shim_reg, dai_shim_base(dp) + SHIM_CLKCTL);
709 
710 	LOG_INF("%s index %d CLKCTL %08x", __func__, index, shim_reg);
711 #endif
712 }
713 
dai_ssp_pm_runtime_en_ssp_power(struct dai_intel_ssp * dp,uint32_t index)714 static void dai_ssp_pm_runtime_en_ssp_power(struct dai_intel_ssp *dp, uint32_t index)
715 {
716 #if CONFIG_DAI_SSP_HAS_POWER_CONTROL
717 	int ret;
718 
719 	LOG_INF("%s en_ssp_power index %d", __func__, index);
720 #if CONFIG_SOC_INTEL_ACE15_MTPM || CONFIG_SOC_SERIES_INTEL_ADSP_CAVS
721 	sys_write32(sys_read32(dai_ip_base(dp) + I2SLCTL_OFFSET) | I2SLCTL_SPA(index),
722 		    dai_ip_base(dp) + I2SLCTL_OFFSET);
723 
724 	/* Check if powered on. */
725 	ret = dai_ssp_poll_for_register_delay(dai_ip_base(dp) + I2SLCTL_OFFSET,
726 					      I2SLCTL_CPA(index), 0,
727 					      DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE);
728 #elif CONFIG_SOC_INTEL_ACE20_LNL
729 	sys_write32(sys_read32(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET) |
730 			       I2SLCTL_SPA(index),
731 			       dai_hdamlssp_base(dp) + I2SLCTL_OFFSET);
732 	/* Check if powered on. */
733 	ret = dai_ssp_poll_for_register_delay(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET,
734 					      I2SLCTL_CPA(index), 0,
735 					      DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE);
736 #else
737 #error need to define SOC
738 #endif
739 	if (ret) {
740 		LOG_WRN("%s warning: timeout", __func__);
741 	}
742 
743 	LOG_INF("%s I2SLCTL", __func__);
744 #else
745 	ARG_UNUSED(dp);
746 	ARG_UNUSED(index);
747 #endif /* CONFIG_DAI_SSP_HAS_POWER_CONTROL */
748 }
749 
dai_ssp_pm_runtime_dis_ssp_power(struct dai_intel_ssp * dp,uint32_t index)750 static void dai_ssp_pm_runtime_dis_ssp_power(struct dai_intel_ssp *dp, uint32_t index)
751 {
752 #if CONFIG_DAI_SSP_HAS_POWER_CONTROL
753 	int ret;
754 
755 	LOG_INF("%s index %d", __func__, index);
756 #if CONFIG_SOC_INTEL_ACE15_MTPM || CONFIG_SOC_SERIES_INTEL_ADSP_CAVS
757 	sys_write32(sys_read32(dai_ip_base(dp) + I2SLCTL_OFFSET) & (~I2SLCTL_SPA(index)),
758 		    dai_ip_base(dp) + I2SLCTL_OFFSET);
759 
760 	/* Check if powered off. */
761 	ret = dai_ssp_poll_for_register_delay(dai_ip_base(dp) + I2SLCTL_OFFSET,
762 					      I2SLCTL_CPA(index), I2SLCTL_CPA(index),
763 					      DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE);
764 #elif CONFIG_SOC_INTEL_ACE20_LNL
765 	sys_write32(sys_read32(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET) & (~I2SLCTL_SPA(index)),
766 			dai_hdamlssp_base(dp) + I2SLCTL_OFFSET);
767 
768 	/* Check if powered off. */
769 	ret = dai_ssp_poll_for_register_delay(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET,
770 					      I2SLCTL_CPA(index), I2SLCTL_CPA(index),
771 					      DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE);
772 #else
773 #error need to define SOC
774 #endif
775 	if (ret) {
776 		LOG_WRN("%s warning: timeout", __func__);
777 	}
778 
779 	LOG_INF("%s I2SLCTL", __func__);
780 #else
781 	ARG_UNUSED(dp);
782 	ARG_UNUSED(index);
783 #endif /* CONFIG_DAI_SSP_HAS_POWER_CONTROL */
784 }
785 
dai_ssp_program_channel_map(struct dai_intel_ssp * dp,const struct dai_config * cfg,uint32_t index)786 static void dai_ssp_program_channel_map(struct dai_intel_ssp *dp,
787 		const struct dai_config *cfg, uint32_t index)
788 {
789 #ifdef CONFIG_SOC_INTEL_ACE20_LNL
790 	uint16_t pcmsycm = cfg->link_config;
791 	struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
792 
793 	/* Set upper slot number from configuration */
794 	pcmsycm = pcmsycm | (ssp->params.tdm_slots - 1) << 4;
795 
796 	if (DAI_INTEL_SSP_IS_BIT_SET(pcmsycm, 15)) {
797 		uint32_t reg_add = dai_ip_base(dp) + 0x1000 * index + PCMS0CM_OFFSET;
798 		/* Program HDA output stream parameters */
799 		sys_write16((pcmsycm & 0xffff), reg_add);
800 	} else {
801 		uint32_t reg_add = dai_ip_base(dp) + 0x1000 * index + PCMS1CM_OFFSET;
802 		/* Program HDA input stream parameters */
803 		sys_write16((pcmsycm & 0xffff), reg_add);
804 	}
805 #else
806 	ARG_UNUSED(dp);
807 	ARG_UNUSED(cfg);
808 	ARG_UNUSED(index);
809 #endif /* CONFIG_SOC_INTEL_ACE20_LNL */
810 }
811 
812 /* empty SSP transmit FIFO */
dai_ssp_empty_tx_fifo(struct dai_intel_ssp * dp)813 static void dai_ssp_empty_tx_fifo(struct dai_intel_ssp *dp)
814 {
815 	int ret;
816 	uint32_t sssr;
817 
818 	/*
819 	 * SSSR_TNF is cleared when TX FIFO is empty or full,
820 	 * so wait for set TNF then for TFL zero - order matter.
821 	 */
822 	ret = dai_ssp_poll_for_register_delay(dai_base(dp) + SSSR, SSSR_TNF, SSSR_TNF,
823 					      DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE);
824 	ret |= dai_ssp_poll_for_register_delay(dai_base(dp) + SSCR3, SSCR3_TFL_MASK, 0,
825 					       DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE *
826 					       (DAI_INTEL_SSP_FIFO_DEPTH - 1) / 2);
827 
828 	if (ret) {
829 		LOG_WRN("%s warning: timeout", __func__);
830 	}
831 
832 	sssr = sys_read32(dai_base(dp) + SSSR);
833 
834 	/* clear interrupt */
835 	if (sssr & SSSR_TUR) {
836 		sys_write32(sssr, dai_base(dp) + SSSR);
837 	}
838 }
839 
840 /* empty SSP receive FIFO */
dai_ssp_empty_rx_fifo(struct dai_intel_ssp * dp)841 static void dai_ssp_empty_rx_fifo(struct dai_intel_ssp *dp)
842 {
843 	struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
844 	uint32_t retry = DAI_INTEL_SSP_RX_FLUSH_RETRY_MAX;
845 	uint32_t entries;
846 	uint32_t i;
847 
848 	/*
849 	 * To make sure all the RX FIFO entries are read out for the flushing,
850 	 * we need to wait a minimal SSP port delay after entries are all read,
851 	 * and then re-check to see if there is any subsequent entries written
852 	 * to the FIFO. This will help to make sure there is no sample mismatched
853 	 * issue for the next run with the SSP RX.
854 	 */
855 	while ((sys_read32(dai_base(dp) + SSSR) & SSSR_RNE) && retry--) {
856 		entries = SSCR3_RFL_VAL(sys_read32(dai_base(dp) + SSCR3));
857 		LOG_DBG("%s before flushing, entries %d", __func__, entries);
858 		for (i = 0; i < entries + 1; i++) {
859 			/* read to try empty fifo */
860 			sys_read32(dai_base(dp) + SSDR);
861 		}
862 
863 		/* wait to get valid fifo status and re-check */
864 		k_busy_wait(ssp->params.fsync_rate ? 1000000 / ssp->params.fsync_rate : 0);
865 		entries = SSCR3_RFL_VAL(sys_read32(dai_base(dp) + SSCR3));
866 		LOG_DBG("%s after flushing, entries %d", __func__, entries);
867 	}
868 
869 	/* clear interrupt */
870 	dai_ssp_update_bits(dp, SSSR, SSSR_ROR, SSSR_ROR);
871 }
872 
dai_ssp_mclk_prepare_enable(struct dai_intel_ssp * dp)873 static int dai_ssp_mclk_prepare_enable(struct dai_intel_ssp *dp)
874 {
875 	struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
876 	int ret;
877 
878 	if (ssp->clk_active & SSP_CLK_MCLK_ACTIVE) {
879 		return 0;
880 	}
881 
882 	/* MCLK config */
883 	ret = dai_ssp_mn_set_mclk(dp, ssp->params.mclk_id, ssp->params.mclk_rate);
884 	if (ret < 0) {
885 		LOG_ERR("%s invalid mclk_rate = %d for mclk_id = %d", __func__,
886 			ssp->params.mclk_rate, ssp->params.mclk_id);
887 	} else {
888 		ssp->clk_active |= SSP_CLK_MCLK_ACTIVE;
889 	}
890 
891 	return ret;
892 }
893 
dai_ssp_mclk_disable_unprepare(struct dai_intel_ssp * dp)894 static void dai_ssp_mclk_disable_unprepare(struct dai_intel_ssp *dp)
895 {
896 	struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
897 
898 	if (!(ssp->clk_active & SSP_CLK_MCLK_ACTIVE)) {
899 		return;
900 	}
901 
902 	dai_ssp_mn_release_mclk(dp, ssp->params.mclk_id);
903 
904 	ssp->clk_active &= ~SSP_CLK_MCLK_ACTIVE;
905 }
906 
dai_ssp_bclk_prepare_enable(struct dai_intel_ssp * dp)907 static int dai_ssp_bclk_prepare_enable(struct dai_intel_ssp *dp)
908 {
909 #if !(CONFIG_INTEL_MN)
910 	struct dai_intel_ssp_freq_table *ft = dai_get_ftable(dp);
911 #endif
912 	struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
913 	struct dai_config *config = &ssp->config;
914 	uint32_t sscr0;
915 	uint32_t mdiv;
916 	bool need_ecs = false;
917 	int ret = 0;
918 
919 	if (ssp->clk_active & SSP_CLK_BCLK_ACTIVE) {
920 		return 0;
921 	}
922 
923 	sscr0 = sys_read32(dai_base(dp) + SSCR0);
924 
925 #if CONFIG_INTEL_MN
926 	/* BCLK config */
927 	ret = dai_ssp_mn_set_bclk(dp, config->dai_index, ssp->params.bclk_rate,
928 				  &mdiv, &need_ecs);
929 	if (ret < 0) {
930 		LOG_ERR("%s invalid bclk_rate = %d for dai_index = %d", __func__,
931 			ssp->params.bclk_rate, config->dai_index);
932 		goto out;
933 	}
934 #else
935 	if (ft[DAI_INTEL_SSP_DEFAULT_IDX].freq % ssp->params.bclk_rate != 0) {
936 		LOG_ERR("%s invalid bclk_rate = %d for dai_index = %d", __func__,
937 			ssp->params.bclk_rate, config->dai_index);
938 		ret = -EINVAL;
939 		goto out;
940 	}
941 
942 	mdiv = ft[DAI_INTEL_SSP_DEFAULT_IDX].freq / ssp->params.bclk_rate;
943 #endif
944 
945 	if (need_ecs) {
946 		sscr0 |= SSCR0_ECS;
947 	}
948 
949 	/* clock divisor is SCR + 1 */
950 	mdiv -= 1;
951 
952 	/* divisor must be within SCR range */
953 	if (mdiv > (SSCR0_SCR_MASK >> 8)) {
954 		LOG_ERR("%s divisor %d is not within SCR range", __func__, mdiv);
955 		ret = -EINVAL;
956 		goto out;
957 	}
958 
959 	/* set the SCR divisor */
960 	sscr0 &= ~SSCR0_SCR_MASK;
961 	sscr0 |= SSCR0_SCR(mdiv);
962 
963 	sys_write32(sscr0, dai_base(dp) + SSCR0);
964 
965 	LOG_INF("%s sscr0 = 0x%08x", __func__, sscr0);
966 out:
967 	if (!ret) {
968 		ssp->clk_active |= SSP_CLK_BCLK_ACTIVE;
969 	}
970 
971 	return ret;
972 }
973 
dai_ssp_bclk_disable_unprepare(struct dai_intel_ssp * dp)974 static void dai_ssp_bclk_disable_unprepare(struct dai_intel_ssp *dp)
975 {
976 	struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
977 
978 	if (!(ssp->clk_active & SSP_CLK_BCLK_ACTIVE)) {
979 		return;
980 	}
981 #if CONFIG_INTEL_MN
982 	dai_ssp_mn_release_bclk(dp, dp->index);
983 #endif
984 	ssp->clk_active &= ~SSP_CLK_BCLK_ACTIVE;
985 }
986 
dai_ssp_log_ssp_data(struct dai_intel_ssp * dp)987 static void dai_ssp_log_ssp_data(struct dai_intel_ssp *dp)
988 {
989 	LOG_INF("%s dai index: %u", __func__, dp->index);
990 	LOG_INF("%s plat_data base: %u", __func__, dp->plat_data.base);
991 	LOG_INF("%s plat_data irq: %u", __func__, dp->plat_data.irq);
992 	LOG_INF("%s plat_data fifo playback offset: %u", __func__,
993 		dp->plat_data.fifo[DAI_DIR_PLAYBACK].offset);
994 	LOG_INF("%s plat_data fifo playback handshake: %u", __func__,
995 		dp->plat_data.fifo[DAI_DIR_PLAYBACK].handshake);
996 	LOG_INF("%s plat_data fifo capture offset: %u", __func__,
997 		dp->plat_data.fifo[DAI_DIR_CAPTURE].offset);
998 	LOG_INF("%s plat_data fifo capture handshake: %u", __func__,
999 		dp->plat_data.fifo[DAI_DIR_CAPTURE].handshake);
1000 }
1001 
1002 /* Digital Audio interface formatting */
dai_ssp_set_config_tplg(struct dai_intel_ssp * dp,const struct dai_config * config,const void * bespoke_cfg)1003 static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_config *config,
1004 				   const void *bespoke_cfg)
1005 {
1006 	struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
1007 	struct dai_intel_ssp_freq_table *ft = dai_get_ftable(dp);
1008 	uint32_t sscr0;
1009 	uint32_t sscr1;
1010 	uint32_t sscr2;
1011 	uint32_t sscr3;
1012 	uint32_t sspsp;
1013 	uint32_t sspsp2;
1014 	uint32_t sstsa;
1015 	uint32_t ssrsa;
1016 	uint32_t ssto;
1017 	uint32_t ssioc;
1018 	uint32_t bdiv;
1019 	uint32_t data_size;
1020 	uint32_t frame_end_padding;
1021 	uint32_t slot_end_padding;
1022 	uint32_t frame_len = 0;
1023 	uint32_t bdiv_min;
1024 	uint32_t tft;
1025 	uint32_t rft;
1026 	uint32_t active_tx_slots = 2;
1027 	uint32_t active_rx_slots = 2;
1028 	uint32_t sample_width = 2;
1029 
1030 	bool inverted_bclk = false;
1031 	bool inverted_frame = false;
1032 	bool cfs = false;
1033 	bool start_delay = false;
1034 	k_spinlock_key_t key;
1035 	int ret = 0;
1036 
1037 	dai_ssp_log_ssp_data(dp);
1038 
1039 	key = k_spin_lock(&dp->lock);
1040 
1041 	/* ignore config if SSP is already configured */
1042 	if (ssp->state[DAI_DIR_PLAYBACK] > DAI_STATE_READY ||
1043 	    ssp->state[DAI_DIR_CAPTURE] > DAI_STATE_READY) {
1044 		if (!memcmp(&ssp->params, bespoke_cfg, sizeof(struct dai_intel_ipc3_ssp_params))) {
1045 			LOG_INF("%s Already configured. Ignore config", __func__);
1046 			goto clk;
1047 		}
1048 
1049 		if (ssp->clk_active & (SSP_CLK_MCLK_ACTIVE | SSP_CLK_BCLK_ACTIVE)) {
1050 			LOG_WRN("%s SSP active, cannot change config", __func__);
1051 			goto clk;
1052 		}
1053 
1054 		/* safe to proceed and change HW config */
1055 	}
1056 
1057 	LOG_INF("%s", __func__);
1058 
1059 	/* reset SSP settings */
1060 	/* sscr0 dynamic settings are DSS, EDSS, SCR, FRDC, ECS */
1061 	/*
1062 	 * FIXME: MOD, ACS, NCS are not set,
1063 	 * no support for network mode for now
1064 	 */
1065 	sscr0 = SSCR0_PSP | SSCR0_RIM | SSCR0_TIM;
1066 
1067 	/* sscr1 dynamic settings are SFRMDIR, SCLKDIR, SCFR, RSRE, TSRE */
1068 	sscr1 = SSCR1_TTE | SSCR1_TTELP | SSCR1_TRAIL;
1069 
1070 	/* sscr2 dynamic setting is LJDFD */
1071 	sscr2 = SSCR2_SDFD | SSCR2_TURM1;
1072 
1073 	/* sscr3 dynamic settings are TFT, RFT */
1074 	sscr3 = 0;
1075 
1076 	/* sspsp dynamic settings are SCMODE, SFRMP, DMYSTRT, SFRMWDTH */
1077 	sspsp = 0;
1078 
1079 	ssp->config = *config;
1080 	memcpy(&ssp->params, bespoke_cfg, sizeof(struct dai_intel_ipc3_ssp_params));
1081 
1082 	/* sspsp2 no dynamic setting */
1083 	sspsp2 = 0x0;
1084 
1085 	/* ssioc dynamic setting is SFCR */
1086 	ssioc = SSIOC_SCOE;
1087 
1088 	/* ssto no dynamic setting */
1089 	ssto = 0x0;
1090 
1091 	/* sstsa dynamic setting is TTSA, default 2 slots */
1092 	sstsa = SSTSA_SSTSA(ssp->params.tx_slots);
1093 
1094 	/* ssrsa dynamic setting is RTSA, default 2 slots */
1095 	ssrsa = SSRSA_SSRSA(ssp->params.rx_slots);
1096 
1097 	switch (config->format & DAI_INTEL_IPC3_SSP_FMT_CLOCK_PROVIDER_MASK) {
1098 	case DAI_INTEL_IPC3_SSP_FMT_CBP_CFP:
1099 		sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR;
1100 		break;
1101 	case DAI_INTEL_IPC3_SSP_FMT_CBC_CFC:
1102 		sscr1 |= SSCR1_SCFR;
1103 		cfs = true;
1104 		break;
1105 	case DAI_INTEL_IPC3_SSP_FMT_CBP_CFC:
1106 		sscr1 |= SSCR1_SCLKDIR;
1107 		/* FIXME: this mode has not been tested */
1108 
1109 		cfs = true;
1110 		break;
1111 	case DAI_INTEL_IPC3_SSP_FMT_CBC_CFP:
1112 		sscr1 |= SSCR1_SCFR | SSCR1_SFRMDIR;
1113 		/* FIXME: this mode has not been tested */
1114 		break;
1115 	default:
1116 		LOG_ERR("%s format & PROVIDER_MASK EINVAL", __func__);
1117 		ret = -EINVAL;
1118 		goto out;
1119 	}
1120 
1121 	/* clock signal polarity */
1122 	switch (config->format & DAI_INTEL_IPC3_SSP_FMT_INV_MASK) {
1123 	case DAI_INTEL_IPC3_SSP_FMT_NB_NF:
1124 		break;
1125 	case DAI_INTEL_IPC3_SSP_FMT_NB_IF:
1126 		inverted_frame = true; /* handled later with format */
1127 		break;
1128 	case DAI_INTEL_IPC3_SSP_FMT_IB_IF:
1129 		inverted_bclk = true; /* handled later with bclk idle */
1130 		inverted_frame = true; /* handled later with format */
1131 		break;
1132 	case DAI_INTEL_IPC3_SSP_FMT_IB_NF:
1133 		inverted_bclk = true; /* handled later with bclk idle */
1134 		break;
1135 	default:
1136 		LOG_ERR("%s format & INV_MASK EINVAL", __func__);
1137 		ret = -EINVAL;
1138 		goto out;
1139 	}
1140 
1141 	/* supporting bclk idle state */
1142 	if (ssp->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_IDLE_HIGH) {
1143 		/* bclk idle state high */
1144 		sspsp |= SSPSP_SCMODE((inverted_bclk ^ 0x3) & 0x3);
1145 	} else {
1146 		/* bclk idle state low */
1147 		sspsp |= SSPSP_SCMODE(inverted_bclk);
1148 	}
1149 
1150 	sscr0 |= SSCR0_MOD | SSCR0_ACS;
1151 
1152 	/* Additional hardware settings */
1153 
1154 	/* Receiver Time-out Interrupt Disabled/Enabled */
1155 	sscr1 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_TINTE) ?
1156 		SSCR1_TINTE : 0;
1157 
1158 	/* Peripheral Trailing Byte Interrupts Disable/Enable */
1159 	sscr1 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_PINTE) ?
1160 		SSCR1_PINTE : 0;
1161 
1162 	/* Enable/disable internal loopback. Output of transmit serial
1163 	 * shifter connected to input of receive serial shifter, internally.
1164 	 */
1165 	sscr1 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_LBM) ?
1166 		SSCR1_LBM : 0;
1167 
1168 	if (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_LBM) {
1169 		LOG_INF("%s going for loopback!", __func__);
1170 	} else {
1171 		LOG_INF("%s no loopback!", __func__);
1172 	}
1173 
1174 	/* Transmit data are driven at the same/opposite clock edge specified
1175 	 * in SSPSP.SCMODE[1:0]
1176 	 */
1177 	sscr2 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_SMTATF) ?
1178 		SSCR2_SMTATF : 0;
1179 
1180 	/* Receive data are sampled at the same/opposite clock edge specified
1181 	 * in SSPSP.SCMODE[1:0]
1182 	 */
1183 	sscr2 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_MMRATF) ?
1184 		SSCR2_MMRATF : 0;
1185 
1186 	/* Enable/disable the fix for PSP consumer mode TXD wait for frame
1187 	 * de-assertion before starting the second channel
1188 	 */
1189 	sscr2 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_PSPSTWFDFD) ?
1190 		SSCR2_PSPSTWFDFD : 0;
1191 
1192 	/* Enable/disable the fix for PSP provider mode FSRT with dummy stop &
1193 	 * frame end padding capability
1194 	 */
1195 	sscr2 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_PSPSRWFDFD) ?
1196 		SSCR2_PSPSRWFDFD : 0;
1197 
1198 	if (!ssp->params.mclk_rate ||
1199 	    ssp->params.mclk_rate > ft[DAI_INTEL_SSP_MAX_FREQ_INDEX].freq) {
1200 		LOG_ERR("%s invalid MCLK = %d Hz (valid < %d)", __func__,
1201 			ssp->params.mclk_rate,
1202 			ft[DAI_INTEL_SSP_MAX_FREQ_INDEX].freq);
1203 		ret = -EINVAL;
1204 		goto out;
1205 	}
1206 
1207 	if (!ssp->params.bclk_rate || ssp->params.bclk_rate > ssp->params.mclk_rate) {
1208 		LOG_ERR("%s BCLK %d Hz = 0 or > MCLK %d Hz", __func__,
1209 			ssp->params.bclk_rate, ssp->params.mclk_rate);
1210 		ret = -EINVAL;
1211 		goto out;
1212 	}
1213 
1214 	/* calc frame width based on BCLK and rate - must be divisable */
1215 	if (ssp->params.bclk_rate % ssp->params.fsync_rate) {
1216 		LOG_ERR("%s BCLK %d is not divisable by rate %d", __func__,
1217 			ssp->params.bclk_rate, ssp->params.fsync_rate);
1218 		ret = -EINVAL;
1219 		goto out;
1220 	}
1221 
1222 	/* must be enough BCLKs for data */
1223 	bdiv = ssp->params.bclk_rate / ssp->params.fsync_rate;
1224 	if (bdiv < ssp->params.tdm_slot_width * ssp->params.tdm_slots) {
1225 		LOG_ERR("%s not enough BCLKs need %d", __func__,
1226 			ssp->params.tdm_slot_width *
1227 			ssp->params.tdm_slots);
1228 		ret = -EINVAL;
1229 		goto out;
1230 	}
1231 
1232 	/* tdm_slot_width must be <= 38 for SSP */
1233 	if (ssp->params.tdm_slot_width > 38) {
1234 		LOG_ERR("%s tdm_slot_width %d > 38", __func__,
1235 			ssp->params.tdm_slot_width);
1236 		ret = -EINVAL;
1237 		goto out;
1238 	}
1239 
1240 	bdiv_min = ssp->params.tdm_slots *
1241 		   (ssp->params.tdm_per_slot_padding_flag ?
1242 		    ssp->params.tdm_slot_width : ssp->params.sample_valid_bits);
1243 	if (bdiv < bdiv_min) {
1244 		LOG_ERR("%s bdiv(%d) < bdiv_min(%d)", __func__,
1245 			bdiv, bdiv_min);
1246 		ret = -EINVAL;
1247 		goto out;
1248 	}
1249 
1250 	frame_end_padding = bdiv - bdiv_min;
1251 	if (frame_end_padding > SSPSP2_FEP_MASK) {
1252 		LOG_ERR("%s frame_end_padding too big: %u", __func__,
1253 			frame_end_padding);
1254 		ret = -EINVAL;
1255 		goto out;
1256 	}
1257 
1258 	/* format */
1259 	switch (config->format & DAI_INTEL_IPC3_SSP_FMT_FORMAT_MASK) {
1260 	case DAI_INTEL_IPC3_SSP_FMT_I2S:
1261 
1262 		start_delay = true;
1263 
1264 		sscr0 |= SSCR0_FRDC(ssp->params.tdm_slots);
1265 
1266 		if (bdiv % 2) {
1267 			LOG_ERR("%s bdiv %d is not divisible by 2", __func__, bdiv);
1268 			ret = -EINVAL;
1269 			goto out;
1270 		}
1271 
1272 		/* set asserted frame length to half frame length */
1273 		frame_len = bdiv / 2;
1274 
1275 		/*
1276 		 * handle frame polarity, I2S default is falling/active low,
1277 		 * non-inverted(inverted_frame=0) -- active low(SFRMP=0),
1278 		 * inverted(inverted_frame=1) -- rising/active high(SFRMP=1),
1279 		 * so, we should set SFRMP to inverted_frame.
1280 		 */
1281 		sspsp |= SSPSP_SFRMP(inverted_frame);
1282 
1283 		/*
1284 		 *  for I2S/LEFT_J, the padding has to happen at the end
1285 		 * of each slot
1286 		 */
1287 		if (frame_end_padding % 2) {
1288 			LOG_ERR("%s frame_end_padding %d is not divisible by 2",
1289 				__func__, frame_end_padding);
1290 			ret = -EINVAL;
1291 			goto out;
1292 		}
1293 
1294 		slot_end_padding = frame_end_padding / 2;
1295 
1296 		if (slot_end_padding > DAI_INTEL_IPC3_SSP_SLOT_PADDING_MAX) {
1297 			/* too big padding */
1298 			LOG_ERR("%s slot_end_padding > %d", __func__,
1299 				DAI_INTEL_IPC3_SSP_SLOT_PADDING_MAX);
1300 			ret = -EINVAL;
1301 			goto out;
1302 		}
1303 
1304 		sspsp |= SSPSP_DMYSTOP(slot_end_padding);
1305 		slot_end_padding >>= SSPSP_DMYSTOP_BITS;
1306 		sspsp |= SSPSP_EDMYSTOP(slot_end_padding);
1307 
1308 		break;
1309 
1310 	case DAI_INTEL_IPC3_SSP_FMT_LEFT_J:
1311 
1312 		/* default start_delay value is set to false */
1313 
1314 		sscr0 |= SSCR0_FRDC(ssp->params.tdm_slots);
1315 
1316 		/* LJDFD enable */
1317 		sscr2 &= ~SSCR2_LJDFD;
1318 
1319 		if (bdiv % 2) {
1320 			LOG_ERR("%s bdiv %d is not divisible by 2", __func__, bdiv);
1321 			ret = -EINVAL;
1322 			goto out;
1323 		}
1324 
1325 		/* set asserted frame length to half frame length */
1326 		frame_len = bdiv / 2;
1327 
1328 		/*
1329 		 * handle frame polarity, LEFT_J default is rising/active high,
1330 		 * non-inverted(inverted_frame=0) -- active high(SFRMP=1),
1331 		 * inverted(inverted_frame=1) -- falling/active low(SFRMP=0),
1332 		 * so, we should set SFRMP to !inverted_frame.
1333 		 */
1334 		sspsp |= SSPSP_SFRMP(!inverted_frame);
1335 
1336 		/*
1337 		 *  for I2S/LEFT_J, the padding has to happen at the end
1338 		 * of each slot
1339 		 */
1340 		if (frame_end_padding % 2) {
1341 			LOG_ERR("%s frame_end_padding %d is not divisible by 2",
1342 				__func__, frame_end_padding);
1343 			ret = -EINVAL;
1344 			goto out;
1345 		}
1346 
1347 		slot_end_padding = frame_end_padding / 2;
1348 
1349 		if (slot_end_padding > 15) {
1350 			/* can't handle padding over 15 bits */
1351 			LOG_ERR("%s slot_end_padding %d > 15 bits", __func__,
1352 				slot_end_padding);
1353 			ret = -EINVAL;
1354 			goto out;
1355 		}
1356 
1357 		sspsp |= SSPSP_DMYSTOP(slot_end_padding);
1358 		slot_end_padding >>= SSPSP_DMYSTOP_BITS;
1359 		sspsp |= SSPSP_EDMYSTOP(slot_end_padding);
1360 
1361 		break;
1362 	case DAI_INTEL_IPC3_SSP_FMT_DSP_A:
1363 
1364 		start_delay = true;
1365 
1366 		/* fallthrough */
1367 
1368 	case DAI_INTEL_IPC3_SSP_FMT_DSP_B:
1369 
1370 		/* default start_delay value is set to false */
1371 
1372 		sscr0 |= SSCR0_MOD | SSCR0_FRDC(ssp->params.tdm_slots);
1373 
1374 		/* set asserted frame length */
1375 		frame_len = 1; /* default */
1376 
1377 		if (cfs && ssp->params.frame_pulse_width > 0 &&
1378 		    ssp->params.frame_pulse_width <=
1379 		    DAI_INTEL_IPC3_SSP_FRAME_PULSE_WIDTH_MAX) {
1380 			frame_len = ssp->params.frame_pulse_width;
1381 		}
1382 
1383 		/* frame_pulse_width must less or equal 38 */
1384 		if (ssp->params.frame_pulse_width >
1385 			DAI_INTEL_IPC3_SSP_FRAME_PULSE_WIDTH_MAX) {
1386 			LOG_ERR("%s frame_pulse_width > %d", __func__,
1387 				DAI_INTEL_IPC3_SSP_FRAME_PULSE_WIDTH_MAX);
1388 			ret = -EINVAL;
1389 			goto out;
1390 		}
1391 		/*
1392 		 * handle frame polarity, DSP_B default is rising/active high,
1393 		 * non-inverted(inverted_frame=0) -- active high(SFRMP=1),
1394 		 * inverted(inverted_frame=1) -- falling/active low(SFRMP=0),
1395 		 * so, we should set SFRMP to !inverted_frame.
1396 		 */
1397 		sspsp |= SSPSP_SFRMP(!inverted_frame);
1398 
1399 		active_tx_slots = POPCOUNT(ssp->params.tx_slots);
1400 		active_rx_slots = POPCOUNT(ssp->params.rx_slots);
1401 
1402 		/*
1403 		 * handle TDM mode, TDM mode has padding at the end of
1404 		 * each slot. The amount of padding is equal to result of
1405 		 * subtracting slot width and valid bits per slot.
1406 		 */
1407 		if (ssp->params.tdm_per_slot_padding_flag) {
1408 			frame_end_padding = bdiv - ssp->params.tdm_slots *
1409 				ssp->params.tdm_slot_width;
1410 
1411 			slot_end_padding = ssp->params.tdm_slot_width -
1412 				ssp->params.sample_valid_bits;
1413 
1414 			if (slot_end_padding >
1415 				DAI_INTEL_IPC3_SSP_SLOT_PADDING_MAX) {
1416 				LOG_ERR("%s slot_end_padding > %d", __func__,
1417 					DAI_INTEL_IPC3_SSP_SLOT_PADDING_MAX);
1418 				ret = -EINVAL;
1419 				goto out;
1420 			}
1421 
1422 			sspsp |= SSPSP_DMYSTOP(slot_end_padding);
1423 			slot_end_padding >>= SSPSP_DMYSTOP_BITS;
1424 			sspsp |= SSPSP_EDMYSTOP(slot_end_padding);
1425 		}
1426 
1427 		sspsp2 |= (frame_end_padding & SSPSP2_FEP_MASK);
1428 
1429 		break;
1430 	default:
1431 		LOG_ERR("%s invalid format 0x%04x", __func__,
1432 			config->format);
1433 		ret = -EINVAL;
1434 		goto out;
1435 	}
1436 
1437 	if (start_delay) {
1438 		sspsp |= SSPSP_FSRT;
1439 	}
1440 
1441 	sspsp |= SSPSP_SFRMWDTH(frame_len);
1442 
1443 	data_size = ssp->params.sample_valid_bits;
1444 
1445 	if (data_size > 16) {
1446 		sscr0 |= (SSCR0_EDSS | SSCR0_DSIZE(data_size - 16));
1447 	} else {
1448 		sscr0 |= SSCR0_DSIZE(data_size);
1449 	}
1450 
1451 	/* setting TFT and RFT */
1452 	switch (ssp->params.sample_valid_bits) {
1453 	case 16:
1454 		/* use 2 bytes for each slot */
1455 		sample_width = 2;
1456 		break;
1457 	case 24:
1458 	case 32:
1459 		/* use 4 bytes for each slot */
1460 		sample_width = 4;
1461 		break;
1462 	default:
1463 		LOG_ERR("%s sample_valid_bits %d", __func__,
1464 			ssp->params.sample_valid_bits);
1465 		ret = -EINVAL;
1466 		goto out;
1467 	}
1468 
1469 	tft = MIN(DAI_INTEL_SSP_FIFO_DEPTH - DAI_INTEL_SSP_FIFO_WATERMARK,
1470 		  sample_width * active_tx_slots);
1471 	rft = MIN(DAI_INTEL_SSP_FIFO_DEPTH - DAI_INTEL_SSP_FIFO_WATERMARK,
1472 		  sample_width * active_rx_slots);
1473 
1474 	sscr3 |= SSCR3_TX(tft) | SSCR3_RX(rft);
1475 
1476 	sys_write32(sscr0, dai_base(dp) + SSCR0);
1477 	sys_write32(sscr1, dai_base(dp) + SSCR1);
1478 	sys_write32(sscr2, dai_base(dp) + SSCR2);
1479 	sys_write32(sscr3, dai_base(dp) + SSCR3);
1480 	sys_write32(sspsp, dai_base(dp) + SSPSP);
1481 	sys_write32(sspsp2, dai_base(dp) + SSPSP2);
1482 	sys_write32(ssioc, dai_base(dp) + SSIOC);
1483 	sys_write32(ssto, dai_base(dp) + SSTO);
1484 	sys_write32(sstsa, dai_base(dp) + SSTSA);
1485 	sys_write32(ssrsa, dai_base(dp) + SSRSA);
1486 
1487 	LOG_INF("%s sscr0 = 0x%08x, sscr1 = 0x%08x, ssto = 0x%08x, sspsp = 0x%0x",
1488 		__func__, sscr0, sscr1, ssto, sspsp);
1489 	LOG_INF("%s sscr2 = 0x%08x, sspsp2 = 0x%08x, sscr3 = 0x%08x, ssioc = 0x%08x",
1490 		__func__, sscr2, sspsp2, sscr3, ssioc);
1491 	LOG_INF("%s ssrsa = 0x%08x, sstsa = 0x%08x",
1492 		__func__, ssrsa, sstsa);
1493 
1494 	ssp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING;
1495 	ssp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING;
1496 
1497 clk:
1498 	switch (config->options & DAI_INTEL_IPC3_SSP_CONFIG_FLAGS_CMD_MASK) {
1499 	case DAI_INTEL_IPC3_SSP_CONFIG_FLAGS_HW_PARAMS:
1500 		if (ssp->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_MCLK_ES) {
1501 			ret = dai_ssp_mclk_prepare_enable(dp);
1502 			if (ret < 0) {
1503 				goto out;
1504 			}
1505 
1506 			ssp->clk_active |= SSP_CLK_MCLK_ES_REQ;
1507 
1508 			LOG_INF("%s hw_params stage: enabled MCLK clocks for SSP%d...",
1509 				__func__, dp->index);
1510 		}
1511 
1512 		if (ssp->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_ES) {
1513 			bool enable_sse = false;
1514 
1515 			if (!(ssp->clk_active & SSP_CLK_BCLK_ACTIVE)) {
1516 				enable_sse = true;
1517 			}
1518 
1519 			ret = dai_ssp_bclk_prepare_enable(dp);
1520 			if (ret < 0) {
1521 				goto out;
1522 			}
1523 
1524 			ssp->clk_active |= SSP_CLK_BCLK_ES_REQ;
1525 
1526 			if (enable_sse) {
1527 
1528 				/* enable TRSE/RSRE before SSE */
1529 				dai_ssp_update_bits(dp, SSCR1,
1530 						    SSCR1_TSRE | SSCR1_RSRE,
1531 						    SSCR1_TSRE | SSCR1_RSRE);
1532 
1533 				/* enable port */
1534 				dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, SSCR0_SSE);
1535 
1536 				LOG_INF("%s SSE set for SSP%d", __func__, dp->index);
1537 			}
1538 
1539 			LOG_INF("%s hw_params stage: enabled BCLK clocks for SSP%d...",
1540 				__func__, dp->index);
1541 		}
1542 		break;
1543 	case DAI_INTEL_IPC3_SSP_CONFIG_FLAGS_HW_FREE:
1544 		/* disable SSP port if no users */
1545 		if (ssp->state[DAI_DIR_CAPTURE] != DAI_STATE_PRE_RUNNING ||
1546 		    ssp->state[DAI_DIR_PLAYBACK] != DAI_STATE_PRE_RUNNING) {
1547 			LOG_INF("%s hw_free stage: ignore since SSP%d still in use",
1548 				__func__, dp->index);
1549 			break;
1550 		}
1551 
1552 		if (ssp->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_ES) {
1553 			LOG_INF("%s hw_free stage: releasing BCLK clocks for SSP%d...",
1554 				__func__, dp->index);
1555 			if (ssp->clk_active & SSP_CLK_BCLK_ACTIVE) {
1556 				/* clear TRSE/RSRE before SSE */
1557 				dai_ssp_update_bits(dp, SSCR1,
1558 						    SSCR1_TSRE | SSCR1_RSRE,
1559 						    0);
1560 
1561 				dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, 0);
1562 				LOG_INF("%s SSE clear for SSP%d", __func__, dp->index);
1563 			}
1564 			dai_ssp_bclk_disable_unprepare(dp);
1565 			ssp->clk_active &= ~SSP_CLK_BCLK_ES_REQ;
1566 		}
1567 		if (ssp->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_MCLK_ES) {
1568 			LOG_INF("%s hw_free stage: releasing MCLK clocks for SSP%d...",
1569 				__func__, dp->index);
1570 			dai_ssp_mclk_disable_unprepare(dp);
1571 			ssp->clk_active &= ~SSP_CLK_MCLK_ES_REQ;
1572 		}
1573 		break;
1574 	default:
1575 		break;
1576 	}
1577 out:
1578 
1579 	k_spin_unlock(&dp->lock, key);
1580 
1581 	return ret;
1582 }
1583 
dai_ssp_check_aux_data(struct ssp_intel_aux_tlv * aux_tlv,int aux_len,int parsed_len)1584 static int dai_ssp_check_aux_data(struct ssp_intel_aux_tlv *aux_tlv, int aux_len, int parsed_len)
1585 {
1586 	struct ssp_intel_sync_ctl *sync;
1587 	int size, size_left;
1588 
1589 	switch (aux_tlv->type) {
1590 	case SSP_MN_DIVIDER_CONTROLS:
1591 		size = sizeof(struct ssp_intel_mn_ctl);
1592 		break;
1593 	case SSP_DMA_CLK_CONTROLS:
1594 		size = sizeof(struct ssp_intel_clk_ctl);
1595 		break;
1596 	case SSP_DMA_TRANSMISSION_START:
1597 	case SSP_DMA_TRANSMISSION_STOP:
1598 		size = sizeof(struct ssp_intel_tr_ctl);
1599 	case SSP_DMA_ALWAYS_RUNNING_MODE:
1600 		size = sizeof(struct ssp_intel_run_ctl);
1601 		break;
1602 	case SSP_DMA_SYNC_DATA:
1603 		size = sizeof(struct ssp_intel_sync_ctl);
1604 		sync = (struct ssp_intel_sync_ctl *)&aux_tlv->val;
1605 		size += sync->count * sizeof(struct ssp_intel_node_ctl);
1606 		break;
1607 	case SSP_DMA_CLK_CONTROLS_EXT:
1608 		size = sizeof(struct ssp_intel_ext_ctl);
1609 		break;
1610 	case SSP_LINK_CLK_SOURCE:
1611 #ifdef CONFIG_SOC_SERIES_INTEL_ACE
1612 		size = sizeof(struct ssp_intel_link_ctl);
1613 		break;
1614 #else
1615 		return 0;
1616 #endif
1617 	default:
1618 		LOG_ERR("%s undefined aux data type %u", __func__, aux_tlv->type);
1619 		return -EINVAL;
1620 	}
1621 
1622 	/* check for malformed struct, size greater than aux_data or described in tlv */
1623 	size_left = aux_len - parsed_len - sizeof(struct ssp_intel_aux_tlv);
1624 	if (size > size_left || size != aux_tlv->size) {
1625 		LOG_ERR("%s malformed struct, size %d, size_left %d, tlv_size %d", __func__, size,
1626 			size_left, aux_tlv->size);
1627 		return -EINVAL;
1628 	}
1629 
1630 	return 0;
1631 }
1632 
dai_ssp_parse_aux_data(struct dai_intel_ssp * dp,const void * spec_config)1633 static int dai_ssp_parse_aux_data(struct dai_intel_ssp *dp, const void *spec_config)
1634 {
1635 	const struct dai_intel_ipc4_ssp_configuration_blob_ver_1_5 *blob = spec_config;
1636 	int aux_tlv_size = sizeof(struct ssp_intel_aux_tlv);
1637 	int hop, i, j, cfg_len, pre_aux_len, aux_len;
1638 	struct ssp_intel_aux_tlv *aux_tlv;
1639 	struct ssp_intel_mn_ctl *mn;
1640 	struct ssp_intel_clk_ctl *clk;
1641 	struct ssp_intel_tr_ctl *tr;
1642 	struct ssp_intel_run_ctl *run;
1643 	struct ssp_intel_node_ctl *node;
1644 	struct ssp_intel_sync_ctl *sync;
1645 	struct ssp_intel_ext_ctl *ext;
1646 #ifdef CONFIG_SOC_SERIES_INTEL_ACE
1647 	struct ssp_intel_link_ctl *link;
1648 #endif
1649 	uint8_t *aux_ptr;
1650 
1651 	cfg_len = blob->size;
1652 	pre_aux_len = sizeof(*blob) + blob->i2s_mclk_control.mdivrcnt * sizeof(uint32_t);
1653 	aux_len = cfg_len - pre_aux_len;
1654 	aux_ptr = (uint8_t *)blob + pre_aux_len;
1655 
1656 	if (aux_len <= 0)
1657 		return 0;
1658 
1659 	for (i = 0; i < aux_len; i += hop) {
1660 		aux_tlv = (struct ssp_intel_aux_tlv *)(aux_ptr);
1661 		if (dai_ssp_check_aux_data(aux_tlv, aux_len, i)) {
1662 			return -EINVAL;
1663 		}
1664 		switch (aux_tlv->type) {
1665 		case SSP_MN_DIVIDER_CONTROLS:
1666 			mn = (struct ssp_intel_mn_ctl *)&aux_tlv->val;
1667 			LOG_INF("%s mn div_m %u, div_n %u", __func__, mn->div_m, mn->div_n);
1668 			break;
1669 		case SSP_DMA_CLK_CONTROLS:
1670 			clk = (struct ssp_intel_clk_ctl *)&aux_tlv->val;
1671 			LOG_INF("%s clk start %u, stop %u", __func__, clk->start, clk->stop);
1672 			break;
1673 		case SSP_DMA_TRANSMISSION_START:
1674 		case SSP_DMA_TRANSMISSION_STOP:
1675 			tr = (struct ssp_intel_tr_ctl *)&aux_tlv->val;
1676 			LOG_INF("%s tr sampling frequency %u, bit_depth %u, channel_map %u,",
1677 				__func__, tr->sampling_frequency, tr->bit_depth, tr->channel_map);
1678 			LOG_INF("channel_config %u, interleaving_style %u, format %u",
1679 				tr->channel_config, tr->interleaving_style, tr->format);
1680 			break;
1681 		case SSP_DMA_ALWAYS_RUNNING_MODE:
1682 			run = (struct ssp_intel_run_ctl *)&aux_tlv->val;
1683 			LOG_INF("%s run enabled %u", __func__, run->enabled);
1684 			break;
1685 		case SSP_DMA_SYNC_DATA:
1686 			sync = (struct ssp_intel_sync_ctl *)&aux_tlv->val;
1687 			LOG_INF("%s sync sync_denominator %u, count %u", __func__,
1688 				sync->sync_denominator, sync->count);
1689 			node = (struct ssp_intel_node_ctl *)((uint8_t *)sync +
1690 							     sizeof(struct ssp_intel_sync_ctl));
1691 			for (j = 0; j < sync->count; j++) {
1692 				LOG_INF("%s node node_id %u, sampling_rate %u", __func__,
1693 					node->node_id, node->sampling_rate);
1694 				node++;
1695 			}
1696 			break;
1697 		case SSP_DMA_CLK_CONTROLS_EXT:
1698 			ext = (struct ssp_intel_ext_ctl *)&aux_tlv->val;
1699 			LOG_INF("%s ext ext_data %u", __func__, ext->ext_data);
1700 			break;
1701 		case SSP_LINK_CLK_SOURCE:
1702 #ifdef CONFIG_SOC_SERIES_INTEL_ACE
1703 			link = (struct ssp_intel_link_ctl *)&aux_tlv->val;
1704 
1705 #if CONFIG_SOC_INTEL_ACE15_MTPM
1706 			sys_write32(sys_read32(dai_ip_base(dp) + I2SLCTL_OFFSET) |
1707 				    I2CLCTL_MLCS(link->clock_source), dai_ip_base(dp) +
1708 				    I2SLCTL_OFFSET);
1709 #elif CONFIG_SOC_INTEL_ACE20_LNL
1710 			sys_write32(sys_read32(dai_i2svss_base(dp) + I2SLCTL_OFFSET) |
1711 				    I2CLCTL_MLCS(link->clock_source), dai_i2svss_base(dp) +
1712 				    I2SLCTL_OFFSET);
1713 #endif
1714 			LOG_INF("%s link clock_source %u", __func__, link->clock_source);
1715 #endif
1716 			break;
1717 		default:
1718 			LOG_ERR("%s undefined aux data type %u", __func__, aux_tlv->type);
1719 			return -EINVAL;
1720 		}
1721 
1722 		hop = aux_tlv->size + aux_tlv_size;
1723 		aux_ptr += hop;
1724 	}
1725 
1726 	return 0;
1727 }
1728 
dai_ssp_set_clock_control_ver_1_5(struct dai_intel_ssp * dp,const struct dai_intel_ipc4_ssp_mclk_config_2 * cc)1729 static int dai_ssp_set_clock_control_ver_1_5(struct dai_intel_ssp *dp,
1730 					     const struct dai_intel_ipc4_ssp_mclk_config_2 *cc)
1731 {
1732 	/* currently we only support 1 divider */
1733 	if (cc->mdivrcnt != 1) {
1734 		LOG_ERR("%s bad clock divider count %u", __func__,
1735 			cc->mdivrcnt);
1736 		return -EINVAL;
1737 	}
1738 
1739 	/* ssp blob is set by pcm_hw_params for ipc4 stream, so enable
1740 	 * mclk and bclk at this time.
1741 	 */
1742 	dai_ssp_mn_set_mclk_blob(dp, cc->mdivctlr, cc->mdivr[0]);
1743 
1744 	return 0;
1745 }
1746 
dai_ssp_set_clock_control_ver_1(struct dai_intel_ssp * dp,const struct dai_intel_ipc4_ssp_mclk_config * cc)1747 static int dai_ssp_set_clock_control_ver_1(struct dai_intel_ssp *dp,
1748 					   const struct dai_intel_ipc4_ssp_mclk_config *cc)
1749 {
1750 	/* ssp blob is set by pcm_hw_params for ipc4 stream, so enable
1751 	 * mclk and bclk at this time.
1752 	 */
1753 	dai_ssp_mn_set_mclk_blob(dp, cc->mdivc, cc->mdivr);
1754 
1755 	return 0;
1756 }
1757 
dai_ssp_set_reg_config(struct dai_intel_ssp * dp,const struct dai_config * cfg,const struct dai_intel_ipc4_ssp_config * regs)1758 static void dai_ssp_set_reg_config(struct dai_intel_ssp *dp, const struct dai_config *cfg,
1759 				   const struct dai_intel_ipc4_ssp_config *regs)
1760 {
1761 	struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
1762 	uint32_t ssc0, sstsa, ssrsa;
1763 
1764 	ssc0 = regs->ssc0;
1765 	sstsa = regs->sstsa;
1766 	ssrsa = regs->ssrsa;
1767 
1768 	sys_write32(ssc0, dai_base(dp) + SSCR0);
1769 	sys_write32(regs->ssc2 & ~SSCR2_SFRMEN, dai_base(dp) + SSCR2); /* hardware specific flow */
1770 	sys_write32(regs->ssc1, dai_base(dp) + SSCR1);
1771 	sys_write32(regs->ssc2 | SSCR2_SFRMEN, dai_base(dp) + SSCR2); /* hardware specific flow */
1772 	sys_write32(regs->ssc2, dai_base(dp) + SSCR2);
1773 	sys_write32(regs->ssc3, dai_base(dp) + SSCR3);
1774 	sys_write32(regs->sspsp, dai_base(dp) + SSPSP);
1775 	sys_write32(regs->sspsp2, dai_base(dp) + SSPSP2);
1776 	sys_write32(regs->ssioc, dai_base(dp) + SSIOC);
1777 	sys_write32(regs->sscto, dai_base(dp) + SSTO);
1778 	sys_write32(sstsa, dai_base(dp) + SSTSA);
1779 	sys_write32(ssrsa, dai_base(dp) + SSRSA);
1780 
1781 	LOG_INF("%s sscr0 = 0x%08x, sscr1 = 0x%08x, ssto = 0x%08x, sspsp = 0x%0x", __func__,
1782 		ssc0, regs->ssc1, regs->sscto, regs->sspsp);
1783 	LOG_INF("%s sscr2 = 0x%08x, sspsp2 = 0x%08x, sscr3 = 0x%08x", __func__,
1784 		regs->ssc2, regs->sspsp2, regs->ssc3);
1785 	LOG_INF("%s ssioc = 0x%08x, ssrsa = 0x%08x, sstsa = 0x%08x", __func__,
1786 		regs->ssioc, ssrsa, sstsa);
1787 
1788 	ssp->params.sample_valid_bits = SSCR0_DSIZE_GET(ssc0);
1789 	if (ssc0 & SSCR0_EDSS) {
1790 		ssp->params.sample_valid_bits += 16;
1791 	}
1792 
1793 	ssp->params.tdm_slots = SSCR0_FRDC_GET(ssc0);
1794 	ssp->params.tx_slots = SSTSA_GET(sstsa);
1795 	ssp->params.rx_slots = SSRSA_GET(ssrsa);
1796 	ssp->params.fsync_rate = cfg->rate;
1797 
1798 	ssp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING;
1799 	ssp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING;
1800 }
1801 
dai_ssp_set_config_blob(struct dai_intel_ssp * dp,const struct dai_config * cfg,const void * spec_config)1802 static int dai_ssp_set_config_blob(struct dai_intel_ssp *dp, const struct dai_config *cfg,
1803 				   const void *spec_config)
1804 {
1805 	const struct dai_intel_ipc4_ssp_configuration_blob_ver_1_5 *blob15 = spec_config;
1806 	const struct dai_intel_ipc4_ssp_configuration_blob *blob = spec_config;
1807 	struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
1808 	int err;
1809 
1810 	/* set config only once for playback or capture */
1811 	if (ssp->state[DAI_DIR_PLAYBACK] > DAI_STATE_READY ||
1812 	    ssp->state[DAI_DIR_CAPTURE] > DAI_STATE_READY)
1813 		return 0;
1814 
1815 	if (blob15->version == SSP_BLOB_VER_1_5) {
1816 		err = dai_ssp_parse_aux_data(dp, spec_config);
1817 		if (err)
1818 			return err;
1819 		dai_ssp_set_reg_config(dp, cfg, &blob15->i2s_ssp_config);
1820 		err = dai_ssp_set_clock_control_ver_1_5(dp, &blob15->i2s_mclk_control);
1821 		if (err)
1822 			return err;
1823 	} else {
1824 		dai_ssp_set_reg_config(dp, cfg, &blob->i2s_driver_config.i2s_config);
1825 		err = dai_ssp_set_clock_control_ver_1(dp, &blob->i2s_driver_config.mclk_config);
1826 		if (err)
1827 			return err;
1828 	}
1829 
1830 	ssp->clk_active |= SSP_CLK_MCLK_ES_REQ;
1831 	/* enable TRSE/RSRE before SSE */
1832 	dai_ssp_update_bits(dp, SSCR1, SSCR1_TSRE | SSCR1_RSRE, SSCR1_TSRE | SSCR1_RSRE);
1833 
1834 	/* enable port */
1835 	dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, SSCR0_SSE);
1836 	ssp->clk_active |= SSP_CLK_BCLK_ES_REQ;
1837 
1838 	return 0;
1839 }
1840 
1841 /*
1842  * Portion of the SSP configuration should be applied just before the
1843  * SSP dai is activated, for either power saving or params runtime
1844  * configurable flexibility.
1845  */
dai_ssp_pre_start(struct dai_intel_ssp * dp)1846 static int dai_ssp_pre_start(struct dai_intel_ssp *dp)
1847 {
1848 	struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
1849 	int ret = 0;
1850 
1851 	LOG_INF("%s", __func__);
1852 
1853 	/*
1854 	 * We will test if mclk/bclk is configured in
1855 	 * ssp_mclk/bclk_prepare_enable/disable functions
1856 	 */
1857 	if (!(ssp->clk_active & SSP_CLK_MCLK_ES_REQ)) {
1858 		/* MCLK config */
1859 		ret = dai_ssp_mclk_prepare_enable(dp);
1860 		if (ret < 0) {
1861 			return ret;
1862 		}
1863 	}
1864 
1865 	if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) {
1866 		ret = dai_ssp_bclk_prepare_enable(dp);
1867 	}
1868 
1869 	return ret;
1870 }
1871 
1872 /*
1873  * For power saving, we should do kinds of power release when the SSP
1874  * dai is changed to inactive, though the runtime param configuration
1875  * don't have to be reset.
1876  */
dai_ssp_post_stop(struct dai_intel_ssp * dp)1877 static void dai_ssp_post_stop(struct dai_intel_ssp *dp)
1878 {
1879 	struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
1880 
1881 	/* release clocks if SSP is inactive */
1882 	if (ssp->state[DAI_DIR_PLAYBACK] != DAI_STATE_RUNNING &&
1883 	    ssp->state[DAI_DIR_CAPTURE] != DAI_STATE_RUNNING) {
1884 		if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) {
1885 			LOG_INF("%s releasing BCLK clocks for SSP%d...",
1886 				__func__, dp->index);
1887 			dai_ssp_bclk_disable_unprepare(dp);
1888 		}
1889 		if (!(ssp->clk_active & SSP_CLK_MCLK_ES_REQ)) {
1890 			LOG_INF("%s releasing MCLK clocks for SSP%d...",
1891 				__func__, dp->index);
1892 			dai_ssp_mclk_disable_unprepare(dp);
1893 		}
1894 	}
1895 }
1896 
dai_ssp_early_start(struct dai_intel_ssp * dp,int direction)1897 static void dai_ssp_early_start(struct dai_intel_ssp *dp, int direction)
1898 {
1899 	struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
1900 	k_spinlock_key_t key;
1901 
1902 	key = k_spin_lock(&dp->lock);
1903 
1904 	/* request mclk/bclk */
1905 	dai_ssp_pre_start(dp);
1906 
1907 	if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) {
1908 		/* enable TRSE/RSRE before SSE */
1909 		dai_ssp_update_bits(dp, SSCR1,
1910 				    SSCR1_TSRE | SSCR1_RSRE,
1911 				    SSCR1_TSRE | SSCR1_RSRE);
1912 
1913 		/* enable port */
1914 		dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, SSCR0_SSE);
1915 		LOG_INF("%s SSE set for SSP%d", __func__, dp->index);
1916 	}
1917 
1918 	k_spin_unlock(&dp->lock, key);
1919 }
1920 
1921 /* start the SSP for either playback or capture */
dai_ssp_start(struct dai_intel_ssp * dp,int direction)1922 static void dai_ssp_start(struct dai_intel_ssp *dp, int direction)
1923 {
1924 	struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
1925 	k_spinlock_key_t key;
1926 
1927 	key = k_spin_lock(&dp->lock);
1928 
1929 	LOG_INF("%s", __func__);
1930 
1931 	/* enable DMA */
1932 	if (direction == DAI_DIR_PLAYBACK) {
1933 		dai_ssp_update_bits(dp, SSTSA, SSTSA_TXEN, SSTSA_TXEN);
1934 	} else {
1935 		dai_ssp_update_bits(dp, SSRSA, SSRSA_RXEN, SSRSA_RXEN);
1936 	}
1937 
1938 	ssp->state[direction] = DAI_STATE_RUNNING;
1939 
1940 	/*
1941 	 * Wait to get valid fifo status in clock consumer mode. TODO it's
1942 	 * uncertain which SSP clock consumer modes need the delay atm, but
1943 	 * these can be added here when confirmed.
1944 	 */
1945 	switch (ssp->config.format & DAI_INTEL_IPC3_SSP_FMT_CLOCK_PROVIDER_MASK) {
1946 	case DAI_INTEL_IPC3_SSP_FMT_CBC_CFC:
1947 		break;
1948 	default:
1949 		/* delay for all SSP consumed clocks atm - see above */
1950 		/* ssp_wait_delay(PLATFORM_SSP_DELAY); */
1951 		k_busy_wait(DAI_INTEL_SSP_PLATFORM_DELAY_US);
1952 		break;
1953 	}
1954 
1955 	k_spin_unlock(&dp->lock, key);
1956 }
1957 
1958 /* stop the SSP for either playback or capture */
dai_ssp_stop(struct dai_intel_ssp * dp,int direction)1959 static void dai_ssp_stop(struct dai_intel_ssp *dp, int direction)
1960 {
1961 	struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
1962 	k_spinlock_key_t key;
1963 
1964 	key = k_spin_lock(&dp->lock);
1965 
1966 	/*
1967 	 * Wait to get valid fifo status in clock consumer mode. TODO it's
1968 	 * uncertain which SSP clock consumer modes need the delay atm, but
1969 	 * these can be added here when confirmed.
1970 	 */
1971 	switch (ssp->config.format & DAI_INTEL_IPC3_SSP_FMT_CLOCK_PROVIDER_MASK) {
1972 	case DAI_INTEL_IPC3_SSP_FMT_CBC_CFC:
1973 		break;
1974 	default:
1975 		/* delay for all SSP consumed clocks atm - see above */
1976 		k_busy_wait(DAI_INTEL_SSP_PLATFORM_DELAY_US);
1977 		break;
1978 	}
1979 
1980 	/* stop Rx if neeed */
1981 	if (direction == DAI_DIR_CAPTURE &&
1982 	    ssp->state[DAI_DIR_CAPTURE] != DAI_STATE_PRE_RUNNING) {
1983 		dai_ssp_update_bits(dp, SSRSA, SSRSA_RXEN, 0);
1984 		dai_ssp_empty_rx_fifo(dp);
1985 		ssp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING;
1986 		LOG_INF("%s RX stop", __func__);
1987 	}
1988 
1989 	/* stop Tx if needed */
1990 	if (direction == DAI_DIR_PLAYBACK &&
1991 	    ssp->state[DAI_DIR_PLAYBACK] != DAI_STATE_PRE_RUNNING) {
1992 		dai_ssp_empty_tx_fifo(dp);
1993 		dai_ssp_update_bits(dp, SSTSA, SSTSA_TXEN, 0);
1994 		ssp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING;
1995 		LOG_INF("%sTX stop", __func__);
1996 	}
1997 
1998 	/* disable SSP port if no users */
1999 	if (ssp->state[DAI_DIR_CAPTURE] == DAI_STATE_PRE_RUNNING &&
2000 	    ssp->state[DAI_DIR_PLAYBACK] == DAI_STATE_PRE_RUNNING) {
2001 		bool clear_rse_bits = COND_CODE_1(CONFIG_INTEL_ADSP_CAVS,
2002 						 (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)),
2003 						 (true));
2004 		if (clear_rse_bits) {
2005 			/* clear TRSE/RSRE before SSE */
2006 			dai_ssp_update_bits(dp, SSCR1, SSCR1_TSRE | SSCR1_RSRE, 0);
2007 			dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, 0);
2008 			LOG_INF("%s SSE clear SSP%d", __func__, dp->index);
2009 		}
2010 	}
2011 
2012 	dai_ssp_post_stop(dp);
2013 
2014 	k_spin_unlock(&dp->lock, key);
2015 }
2016 
dai_ssp_pause(struct dai_intel_ssp * dp,int direction)2017 static void dai_ssp_pause(struct dai_intel_ssp *dp, int direction)
2018 {
2019 	struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
2020 
2021 	if (direction == DAI_DIR_CAPTURE) {
2022 		LOG_INF("%s RX", __func__);
2023 	} else {
2024 		LOG_INF("%s TX", __func__);
2025 	}
2026 
2027 	ssp->state[direction] = DAI_STATE_PAUSED;
2028 }
2029 
dai_ssp_trigger(const struct device * dev,enum dai_dir dir,enum dai_trigger_cmd cmd)2030 static int dai_ssp_trigger(const struct device *dev, enum dai_dir dir,
2031 			   enum dai_trigger_cmd cmd)
2032 {
2033 	struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data;
2034 	struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
2035 	int array_index = SSP_ARRAY_INDEX(dir);
2036 
2037 	LOG_DBG("%s cmd %d", __func__, cmd);
2038 
2039 	switch (cmd) {
2040 	case DAI_TRIGGER_START:
2041 		if (ssp->state[array_index] == DAI_STATE_PAUSED ||
2042 		    ssp->state[array_index] == DAI_STATE_PRE_RUNNING) {
2043 			dai_ssp_start(dp, array_index);
2044 		}
2045 		break;
2046 	case DAI_TRIGGER_STOP:
2047 		dai_ssp_stop(dp, array_index);
2048 		break;
2049 	case DAI_TRIGGER_PAUSE:
2050 		dai_ssp_pause(dp, array_index);
2051 		break;
2052 	case DAI_TRIGGER_PRE_START:
2053 		dai_ssp_early_start(dp, array_index);
2054 		break;
2055 	default:
2056 		break;
2057 	}
2058 
2059 	return 0;
2060 }
2061 
dai_ssp_config_get(const struct device * dev,struct dai_config * cfg,enum dai_dir dir)2062 static int dai_ssp_config_get(const struct device *dev, struct dai_config *cfg, enum dai_dir dir)
2063 {
2064 	struct dai_config *params = (struct dai_config *)dev->config;
2065 	struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data;
2066 	struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
2067 
2068 	if (!cfg) {
2069 		return -EINVAL;
2070 	}
2071 
2072 	if (!ssp) {
2073 		*cfg = *params;
2074 		return 0;
2075 	}
2076 
2077 	params->rate = ssp->params.fsync_rate;
2078 
2079 	if (dir == DAI_DIR_PLAYBACK) {
2080 		params->channels = POPCOUNT(ssp->params.tx_slots);
2081 	} else {
2082 		params->channels = POPCOUNT(ssp->params.rx_slots);
2083 	}
2084 
2085 	params->word_size = ssp->params.sample_valid_bits;
2086 
2087 	*cfg = *params;
2088 
2089 	return 0;
2090 }
2091 
dai_ssp_config_set(const struct device * dev,const struct dai_config * cfg,const void * bespoke_cfg)2092 static int dai_ssp_config_set(const struct device *dev, const struct dai_config *cfg,
2093 			      const void *bespoke_cfg)
2094 {
2095 	struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data;
2096 	int ret;
2097 
2098 	if (cfg->type == DAI_INTEL_SSP) {
2099 		ret = dai_ssp_set_config_tplg(dp, cfg, bespoke_cfg);
2100 	} else {
2101 		ret = dai_ssp_set_config_blob(dp, cfg, bespoke_cfg);
2102 	}
2103 	dai_ssp_program_channel_map(dp, cfg, dp->index);
2104 	return ret;
2105 }
2106 
dai_ssp_get_properties(const struct device * dev,enum dai_dir dir,int stream_id)2107 static const struct dai_properties *dai_ssp_get_properties(const struct device *dev,
2108 							   enum dai_dir dir, int stream_id)
2109 {
2110 	struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data;
2111 	struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
2112 	struct dai_properties *prop = &ssp->props;
2113 	int array_index = SSP_ARRAY_INDEX(dir);
2114 
2115 	prop->fifo_address = dp->plat_data.fifo[array_index].offset;
2116 	prop->dma_hs_id = dp->plat_data.fifo[array_index].handshake;
2117 
2118 	if (ssp->clk_active & SSP_CLK_BCLK_ACTIVE) {
2119 		prop->reg_init_delay = 0;
2120 	} else {
2121 		prop->reg_init_delay = ssp->params.bclk_delay;
2122 	}
2123 
2124 	LOG_INF("%s dai_index %u", __func__, dp->index);
2125 	LOG_INF("%s fifo %u", __func__, prop->fifo_address);
2126 	LOG_INF("%s handshake %u", __func__, prop->dma_hs_id);
2127 	LOG_INF("%s init delay %u", __func__, prop->reg_init_delay);
2128 
2129 	return prop;
2130 }
2131 
dai_ssp_probe(struct dai_intel_ssp * dp)2132 static int dai_ssp_probe(struct dai_intel_ssp *dp)
2133 {
2134 	struct dai_intel_ssp_pdata *ssp;
2135 
2136 	if (dai_get_drvdata(dp)) {
2137 		return -EEXIST; /* already created */
2138 	}
2139 
2140 	/* allocate private data */
2141 	ssp = k_calloc(1, sizeof(*ssp));
2142 	if (!ssp) {
2143 		LOG_ERR("%s alloc failed", __func__);
2144 		return -ENOMEM;
2145 	}
2146 	dai_set_drvdata(dp, ssp);
2147 
2148 	ssp->state[DAI_DIR_PLAYBACK] = DAI_STATE_READY;
2149 	ssp->state[DAI_DIR_CAPTURE] = DAI_STATE_READY;
2150 
2151 #if CONFIG_INTEL_MN
2152 	/* Reset M/N, power-gating functions need it */
2153 	dai_ssp_mn_reset_bclk_divider(dp, dp->index);
2154 #endif
2155 
2156 	/* Enable SSP power */
2157 	dai_ssp_pm_runtime_en_ssp_power(dp, dp->index);
2158 
2159 	/* Disable dynamic clock gating before touching any register */
2160 	dai_ssp_pm_runtime_dis_ssp_clk_gating(dp, dp->index);
2161 
2162 	dai_ssp_empty_rx_fifo(dp);
2163 
2164 	return 0;
2165 }
2166 
dai_ssp_remove(struct dai_intel_ssp * dp)2167 static int dai_ssp_remove(struct dai_intel_ssp *dp)
2168 {
2169 	dai_ssp_pm_runtime_en_ssp_clk_gating(dp, dp->index);
2170 
2171 	dai_ssp_mclk_disable_unprepare(dp);
2172 	dai_ssp_bclk_disable_unprepare(dp);
2173 
2174 	/* Disable SSP power */
2175 	dai_ssp_pm_runtime_dis_ssp_power(dp, dp->index);
2176 
2177 	k_free(dai_get_drvdata(dp));
2178 	dai_set_drvdata(dp, NULL);
2179 
2180 	return 0;
2181 }
2182 
ssp_pm_action(const struct device * dev,enum pm_device_action action)2183 static int ssp_pm_action(const struct device *dev, enum pm_device_action action)
2184 {
2185 	struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data;
2186 	switch (action) {
2187 	case PM_DEVICE_ACTION_SUSPEND:
2188 		dai_ssp_remove(dp);
2189 		break;
2190 	case PM_DEVICE_ACTION_RESUME:
2191 		dai_ssp_probe(dp);
2192 		break;
2193 	case PM_DEVICE_ACTION_TURN_OFF:
2194 	case PM_DEVICE_ACTION_TURN_ON:
2195 		/* All device pm is handled during resume and suspend */
2196 		break;
2197 	default:
2198 		return -ENOTSUP;
2199 	}
2200 
2201 	return 0;
2202 }
2203 
ssp_init(const struct device * dev)2204 static int ssp_init(const struct device *dev)
2205 {
2206 	if (pm_device_on_power_domain(dev)) {
2207 		pm_device_init_off(dev);
2208 	} else {
2209 		pm_device_init_suspended(dev);
2210 	}
2211 
2212 	return pm_device_runtime_enable(dev);
2213 }
2214 
2215 static struct dai_driver_api dai_intel_ssp_api_funcs = {
2216 	.probe			= pm_device_runtime_get,
2217 	.remove			= pm_device_runtime_put,
2218 	.config_set		= dai_ssp_config_set,
2219 	.config_get		= dai_ssp_config_get,
2220 	.trigger		= dai_ssp_trigger,
2221 	.get_properties		= dai_ssp_get_properties,
2222 };
2223 
2224 static struct dai_intel_ssp_freq_table ssp_freq_table[] = {
2225 	{ DT_PROP(DT_NODELABEL(audioclk), clock_frequency),
2226 	  DT_PROP(DT_NODELABEL(audioclk), clock_frequency) / 1000},
2227 	{ DT_PROP(DT_NODELABEL(sysclk), clock_frequency),
2228 	  DT_PROP(DT_NODELABEL(sysclk), clock_frequency) / 1000},
2229 	{ DT_PROP(DT_NODELABEL(pllclk), clock_frequency),
2230 	  DT_PROP(DT_NODELABEL(pllclk), clock_frequency) / 1000},
2231 };
2232 
2233 static uint32_t ssp_freq_sources[] = {
2234 	DAI_INTEL_SSP_CLOCK_AUDIO_CARDINAL,
2235 	DAI_INTEL_SSP_CLOCK_XTAL_OSCILLATOR,
2236 	DAI_INTEL_SSP_CLOCK_PLL_FIXED,
2237 };
2238 
2239 static struct dai_intel_ssp_mn ssp_mn_divider = {
2240 	.base = DT_REG_ADDR_BY_IDX(DT_NODELABEL(ssp0), 1),
2241 };
2242 
2243 static const char irq_name_level5_z[] = "level5";
2244 
2245 #define DAI_INTEL_SSP_DEVICE_INIT(n)						\
2246 	static struct dai_config dai_intel_ssp_config_##n = {			\
2247 		.type = DAI_INTEL_SSP,						\
2248 		.dai_index = n,							\
2249 	};									\
2250 	static struct dai_intel_ssp dai_intel_ssp_data_##n = {			\
2251 		.index = n,							\
2252 		.plat_data = {							\
2253 			.base =	DT_INST_REG_ADDR_BY_IDX(n, 0),			\
2254 			IF_ENABLED(DT_NODE_EXISTS(DT_NODELABEL(sspbase)),	\
2255 			(.ip_base = DT_REG_ADDR_BY_IDX(DT_NODELABEL(sspbase), 0),))\
2256 			.shim_base = DT_REG_ADDR_BY_IDX(DT_NODELABEL(shim), 0),	\
2257 			IF_ENABLED(DT_NODE_EXISTS(DT_NODELABEL(hdamlssp)),	\
2258 				(.hdamlssp_base = DT_REG_ADDR(DT_NODELABEL(hdamlssp)),))\
2259 			IF_ENABLED(DT_INST_PROP_HAS_IDX(n, i2svss, 0),	\
2260 				(.i2svss_base = DT_INST_PROP_BY_IDX(n, i2svss, 0),))\
2261 			.irq = n,						\
2262 			.irq_name = irq_name_level5_z,				\
2263 			.fifo[DAI_DIR_PLAYBACK].offset =			\
2264 				DT_INST_REG_ADDR_BY_IDX(n, 0) + SSDR,		\
2265 			.fifo[DAI_DIR_PLAYBACK].handshake =			\
2266 				DT_INST_DMAS_CELL_BY_NAME(n, tx, channel),	\
2267 			.fifo[DAI_DIR_CAPTURE].offset =				\
2268 				DT_INST_REG_ADDR_BY_IDX(n, 0) + SSDR,		\
2269 			.fifo[DAI_DIR_CAPTURE].handshake =			\
2270 				DT_INST_DMAS_CELL_BY_NAME(n, rx, channel),	\
2271 			.mn_inst = &ssp_mn_divider,				\
2272 			.ftable = ssp_freq_table,				\
2273 			.fsources = ssp_freq_sources,				\
2274 		},								\
2275 	};								\
2276 									\
2277 	PM_DEVICE_DT_INST_DEFINE(n, ssp_pm_action); \
2278 									\
2279 	DEVICE_DT_INST_DEFINE(n,					\
2280 			ssp_init, PM_DEVICE_DT_INST_GET(n),		\
2281 			&dai_intel_ssp_data_##n,			\
2282 			&dai_intel_ssp_config_##n,			\
2283 			POST_KERNEL, 32,				\
2284 			&dai_intel_ssp_api_funcs);
2285 
2286 DT_INST_FOREACH_STATUS_OKAY(DAI_INTEL_SSP_DEVICE_INIT)
2287