1 /* Copyright 2023 NXP
2  *
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #ifndef ZEPHYR_DRIVERS_DAI_NXP_SAI_H_
7 #define ZEPHYR_DRIVERS_DAI_NXP_SAI_H_
8 
9 #include <zephyr/drivers/clock_control.h>
10 #include <zephyr/drivers/pinctrl.h>
11 #include <zephyr/logging/log.h>
12 #include <fsl_sai.h>
13 
14 LOG_MODULE_REGISTER(nxp_dai_sai);
15 
16 #ifdef CONFIG_SAI_HAS_MCLK_CONFIG_OPTION
17 #define SAI_MCLK_MCR_MSEL_SHIFT 24
18 #define SAI_MCLK_MCR_MSEL_MASK GENMASK(24, 25)
19 #endif /* CONFIG_SAI_HAS_MCLK_CONFIG_OPTION */
20 /* workaround the fact that device_map() doesn't exist for SoCs with no MMU */
21 #ifndef DEVICE_MMIO_IS_IN_RAM
22 #define device_map(virt, phys, size, flags) *(virt) = (phys)
23 #endif /* DEVICE_MMIO_IS_IN_RAM */
24 
25 /* used to convert an uint to I2S_Type * */
26 #define UINT_TO_I2S(x) ((I2S_Type *)(uintptr_t)(x))
27 
28 /* macros used for parsing DTS data */
29 
30 /* used instead of IDENTITY because LISTIFY expects the used macro function
31  * to also take a variable number of arguments.
32  */
33 #define IDENTITY_VARGS(V, ...) IDENTITY(V)
34 
35 /* used to generate the list of clock indexes */
36 #define _SAI_CLOCK_INDEX_ARRAY(inst)\
37 	LISTIFY(DT_INST_PROP_LEN_OR(inst, clocks, 0), IDENTITY_VARGS, (,))
38 
39 /* used to retrieve a clock's ID using its index generated via _SAI_CLOCK_INDEX_ARRAY */
40 #define _SAI_GET_CLOCK_ID(clock_idx, inst)\
41 	DT_INST_PHA_BY_IDX_OR(inst, clocks, clock_idx, name, 0x0)
42 
43 /* used to retrieve a clock's name using its index generated via _SAI_CLOCK_INDEX_ARRAY */
44 #define _SAI_GET_CLOCK_NAME(clock_idx, inst)\
45 	DT_INST_PROP_BY_IDX(inst, clock_names, clock_idx)
46 
47 /* used to convert the clocks property into an array of clock IDs */
48 #define _SAI_CLOCK_ID_ARRAY(inst)\
49 	FOR_EACH_FIXED_ARG(_SAI_GET_CLOCK_ID, (,), inst, _SAI_CLOCK_INDEX_ARRAY(inst))
50 
51 /* used to convert the clock-names property into an array of clock names */
52 #define _SAI_CLOCK_NAME_ARRAY(inst)\
53 	FOR_EACH_FIXED_ARG(_SAI_GET_CLOCK_NAME, (,), inst, _SAI_CLOCK_INDEX_ARRAY(inst))
54 
55 /* used to convert a clocks property into an array of clock IDs. If the property
56  * is not specified then this macro will return {}.
57  */
58 #define _SAI_GET_CLOCK_ARRAY(inst)\
59 	COND_CODE_1(DT_NODE_HAS_PROP(DT_INST(inst, nxp_dai_sai), clocks),\
60 		    ({ _SAI_CLOCK_ID_ARRAY(inst) }),\
61 		    ({ }))
62 
63 /* used to retrieve a const struct device *dev pointing to the clock controller.
64  * It is assumed that all SAI clocks come from a single clock provider.
65  * This macro returns a NULL if the clocks property doesn't exist.
66  */
67 #define _SAI_GET_CLOCK_CONTROLLER(inst)\
68 	COND_CODE_1(DT_NODE_HAS_PROP(DT_INST(inst, nxp_dai_sai), clocks),\
69 		    (DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst))),\
70 		    (NULL))
71 
72 /* used to convert a clock-names property into an array of clock names. If the
73  * property is not specified then this macro will return {}.
74  */
75 #define _SAI_GET_CLOCK_NAMES(inst)\
76 	COND_CODE_1(DT_NODE_HAS_PROP(DT_INST(inst, nxp_dai_sai), clocks),\
77 		    ({ _SAI_CLOCK_NAME_ARRAY(inst) }),\
78 		    ({ }))
79 
80 /* used to declare a struct clock_data */
81 #define SAI_CLOCK_DATA_DECLARE(inst)					\
82 {									\
83 	.clocks = (uint32_t [])_SAI_GET_CLOCK_ARRAY(inst),		\
84 	.clock_num = DT_INST_PROP_LEN_OR(inst, clocks, 0),		\
85 	.dev = _SAI_GET_CLOCK_CONTROLLER(inst),				\
86 	.clock_names = (const char *[])_SAI_GET_CLOCK_NAMES(inst),	\
87 }
88 
89 /* used to parse the tx-fifo-watermark property. If said property is not
90  * specified then this macro will return half of the number of words in the
91  * FIFO.
92  */
93 #define SAI_TX_FIFO_WATERMARK(inst)\
94 	DT_INST_PROP_OR(inst, tx_fifo_watermark,\
95 			FSL_FEATURE_SAI_FIFO_COUNTn(UINT_TO_I2S(DT_INST_REG_ADDR(inst))) / 2)
96 
97 /* used to parse the rx-fifo-watermark property. If said property is not
98  * specified then this macro will return half of the number of words in the
99  * FIFO.
100  */
101 #define SAI_RX_FIFO_WATERMARK(inst)\
102 	DT_INST_PROP_OR(inst, rx_fifo_watermark,\
103 			FSL_FEATURE_SAI_FIFO_COUNTn(UINT_TO_I2S(DT_INST_REG_ADDR(inst))) / 2)
104 
105 /* used to retrieve TDR0's address based on SAI's physical address */
106 #define SAI_TX_FIFO_BASE(inst, idx)\
107 	POINTER_TO_UINT(&(UINT_TO_I2S(DT_INST_REG_ADDR(inst))->TDR[idx]))
108 
109 /* used to retrieve RDR0's address based on SAI's physical address */
110 #define SAI_RX_FIFO_BASE(inst, idx)\
111 	POINTER_TO_UINT(&(UINT_TO_I2S(DT_INST_REG_ADDR(inst))->RDR[idx]))
112 
113 /* internal macro used to retrieve the default TX/RX FIFO's size (in FIFO words) */
114 #define _SAI_FIFO_DEPTH(inst)\
115 	FSL_FEATURE_SAI_FIFO_COUNTn(UINT_TO_I2S(DT_INST_REG_ADDR(inst)))
116 
117 /* used to retrieve the TX/RX FIFO's size (in FIFO words) */
118 #define SAI_FIFO_DEPTH(inst)\
119 	DT_INST_PROP_OR(inst, fifo_depth, _SAI_FIFO_DEPTH(inst))
120 
121 /* used to retrieve the DMA MUX for transmitter */
122 #define SAI_TX_DMA_MUX(inst)\
123 	FSL_FEATURE_SAI_TX_DMA_MUXn(UINT_TO_I2S(DT_INST_REG_ADDR(inst)))
124 
125 /* used to retrieve the DMA MUX for receiver */
126 #define SAI_RX_DMA_MUX(inst)\
127 	FSL_FEATURE_SAI_RX_DMA_MUXn(UINT_TO_I2S(DT_INST_REG_ADDR(inst)))
128 
129 /* used to retrieve the synchronization mode of the transmitter. If this
130  * property is not specified, ASYNC mode will be used.
131  */
132 #define SAI_TX_SYNC_MODE(inst)\
133 	DT_INST_PROP_OR(inst, tx_sync_mode, kSAI_ModeAsync)
134 
135 /* used to retrieve the synchronization mode of the receiver. If this property
136  * is not specified, ASYNC mode will be used.
137  */
138 #define SAI_RX_SYNC_MODE(inst)\
139 	DT_INST_PROP_OR(inst, rx_sync_mode, kSAI_ModeAsync)
140 
141 /* used to retrieve the handshake value for given direction. The handshake
142  * is computed as follows:
143  *	handshake = CHANNEL_ID | (MUX_VALUE << 8)
144  * The channel ID and MUX value are each encoded in 8 bits.
145  */
146 #define SAI_TX_RX_DMA_HANDSHAKE(inst, dir)\
147 	((DT_INST_DMAS_CELL_BY_NAME(inst, dir, channel) & GENMASK(7, 0)) |\
148 	 ((DT_INST_DMAS_CELL_BY_NAME(inst, dir, mux) << 8) & GENMASK(15, 8)))
149 
150 /* used to retrieve the number of supported transmission/receive lines */
151 #define SAI_DLINE_COUNT(inst)\
152 	FSL_FEATURE_SAI_CHANNEL_COUNTn(UINT_TO_I2S(DT_INST_REG_ADDR(inst)))
153 
154 /* used to retrieve the index of the transmission line */
155 #define SAI_TX_DLINE_INDEX(inst) DT_INST_PROP_OR(inst, tx_dataline, 0)
156 
157 /* used to retrieve the index of the receive line */
158 #define SAI_RX_DLINE_INDEX(inst) DT_INST_PROP_OR(inst, rx_dataline, 0)
159 
160 /* utility macros */
161 
162 /* invert a clock's polarity. This works because a clock's polarity is expressed
163  * as a 0 or as a 1.
164  */
165 #define SAI_INVERT_POLARITY(polarity) (polarity) = !(polarity)
166 
167 /* used to issue a software reset of the transmitter/receiver */
168 #define SAI_TX_RX_SW_RESET(dir, regmap)\
169 	((dir) == DAI_DIR_RX ? SAI_RxSoftwareReset(UINT_TO_I2S(regmap), kSAI_ResetTypeSoftware) :\
170 	 SAI_TxSoftwareReset(UINT_TO_I2S(regmap), kSAI_ResetTypeSoftware))
171 
172 /* used to enable/disable the transmitter/receiver.
173  * When enabling the SYNC component, the ASYNC component will also be enabled.
174  * Attempting to disable the SYNC component will fail unless the SYNC bit is
175  * cleared. It is recommended to use sai_tx_rx_force_disable() instead of this
176  * macro when disabling transmitter/receiver.
177  */
178 #define SAI_TX_RX_ENABLE_DISABLE(dir, regmap, enable)\
179 	((dir) == DAI_DIR_RX ? SAI_RxEnable(UINT_TO_I2S(regmap), enable) :\
180 	 SAI_TxEnable(UINT_TO_I2S(regmap), enable))
181 
182 /* used to enable/disable the DMA requests for transmitter/receiver */
183 #define SAI_TX_RX_DMA_ENABLE_DISABLE(dir, regmap, enable)\
184 	((dir) == DAI_DIR_RX ? SAI_RxEnableDMA(UINT_TO_I2S(regmap),\
185 					       kSAI_FIFORequestDMAEnable, enable) :\
186 	SAI_TxEnableDMA(UINT_TO_I2S(regmap), kSAI_FIFORequestDMAEnable, enable))
187 
188 /* used to check if the hardware transmitter/receiver is enabled */
189 #define SAI_TX_RX_IS_HW_ENABLED(dir, regmap)\
190 	((dir) == DAI_DIR_RX ? (UINT_TO_I2S(regmap)->RCSR & I2S_RCSR_RE_MASK) : \
191 	 (UINT_TO_I2S(regmap)->TCSR & I2S_TCSR_TE_MASK))
192 
193 /* used to enable various transmitter/receiver interrupts */
194 #define _SAI_TX_RX_ENABLE_IRQ(dir, regmap, which)\
195 	((dir) == DAI_DIR_RX ? SAI_RxEnableInterrupts(UINT_TO_I2S(regmap), which) : \
196 	 SAI_TxEnableInterrupts(UINT_TO_I2S(regmap), which))
197 
198 /* used to disable various transmitter/receiver interrupts */
199 #define _SAI_TX_RX_DISABLE_IRQ(dir, regmap, which)\
200 	((dir) == DAI_DIR_RX ? SAI_RxDisableInterrupts(UINT_TO_I2S(regmap), which) : \
201 	 SAI_TxDisableInterrupts(UINT_TO_I2S(regmap), which))
202 
203 /* used to enable/disable various transmitter/receiver interrupts */
204 #define SAI_TX_RX_ENABLE_DISABLE_IRQ(dir, regmap, which, enable)\
205 	((enable == true) ? _SAI_TX_RX_ENABLE_IRQ(dir, regmap, which) :\
206 	 _SAI_TX_RX_DISABLE_IRQ(dir, regmap, which))
207 
208 /* used to check if a status flag is set */
209 #define SAI_TX_RX_STATUS_IS_SET(dir, regmap, which)\
210 	((dir) == DAI_DIR_RX ? ((UINT_TO_I2S(regmap))->RCSR & (which)) : \
211 	 ((UINT_TO_I2S(regmap))->TCSR & (which)))
212 
213 /* used to clear status flags */
214 #define SAI_TX_RX_STATUS_CLEAR(dir, regmap, which)						\
215 	((dir) == DAI_DIR_RX ? SAI_RxClearStatusFlags(UINT_TO_I2S(regmap), which)		\
216 			     : SAI_TxClearStatusFlags(UINT_TO_I2S(regmap), which))
217 
218 /* used to retrieve the SYNC direction. Use this macro when you know for sure
219  * you have 1 SYNC direction with 1 ASYNC direction.
220  */
221 #define SAI_TX_RX_GET_SYNC_DIR(cfg)\
222 	((cfg)->tx_sync_mode == kSAI_ModeSync ? DAI_DIR_TX : DAI_DIR_RX)
223 
224 /* used to retrieve the ASYNC direction. Use this macro when you know for sure
225  * you have 1 SYNC direction with 1 ASYNC direction.
226  */
227 #define SAI_TX_RX_GET_ASYNC_DIR(cfg)\
228 	((cfg)->tx_sync_mode == kSAI_ModeAsync ? DAI_DIR_TX : DAI_DIR_RX)
229 
230 /* used to check if transmitter/receiver is SW enabled */
231 #define SAI_TX_RX_DIR_IS_SW_ENABLED(dir, data)\
232 	((dir) == DAI_DIR_TX ? data->tx_enabled : data->rx_enabled)
233 
234 /* used to compute the mask for the transmission/receive lines based on
235  * the index passed from the DTS.
236  */
237 #define SAI_TX_RX_DLINE_MASK(dir, cfg)\
238 	((dir) == DAI_DIR_TX ? BIT((cfg)->tx_dline) : BIT((cfg)->rx_dline))
239 
240 struct sai_clock_data {
241 	uint32_t *clocks;
242 	uint32_t clock_num;
243 	/* assumption: all clocks belong to the same producer */
244 	const struct device *dev;
245 	const char **clock_names;
246 };
247 
248 struct sai_data {
249 	mm_reg_t regmap;
250 	sai_transceiver_t rx_config;
251 	sai_transceiver_t tx_config;
252 	bool tx_enabled;
253 	bool rx_enabled;
254 	enum dai_state tx_state;
255 	enum dai_state rx_state;
256 	struct dai_config cfg;
257 };
258 
259 struct sai_config {
260 	uint32_t regmap_phys;
261 	uint32_t regmap_size;
262 	uint32_t irq;
263 	struct sai_clock_data clk_data;
264 	bool mclk_is_output;
265 	/* if the tx/rx-fifo-watermark properties are not specified, it's going
266 	 * to be assumed that the watermark should be set to half of the FIFO
267 	 * size.
268 	 */
269 	uint32_t rx_fifo_watermark;
270 	uint32_t tx_fifo_watermark;
271 	const struct dai_properties *tx_props;
272 	const struct dai_properties *rx_props;
273 	uint32_t dai_index;
274 	/* RX synchronization mode - may be SYNC or ASYNC */
275 	sai_sync_mode_t rx_sync_mode;
276 	/* TX synchronization mode - may be SYNC or ASYNC */
277 	sai_sync_mode_t tx_sync_mode;
278 	void (*irq_config)(void);
279 	uint32_t tx_dline;
280 	uint32_t rx_dline;
281 	const struct pinctrl_dev_config *pincfg;
282 };
283 
284 /* this needs to perfectly match SOF's struct sof_ipc_dai_sai_params */
285 struct sai_bespoke_config {
286 	uint32_t reserved0;
287 
288 	uint16_t reserved1;
289 	uint16_t mclk_id;
290 	uint32_t mclk_direction;
291 
292 	/* CLOCK-related data */
293 	uint32_t mclk_rate;
294 	uint32_t fsync_rate;
295 	uint32_t bclk_rate;
296 
297 	/* TDM-related data */
298 	uint32_t tdm_slots;
299 	uint32_t rx_slots;
300 	uint32_t tx_slots;
301 	uint16_t tdm_slot_width;
302 	uint16_t reserved2;
303 };
304 
305 #ifdef CONFIG_SAI_HAS_MCLK_CONFIG_OPTION
get_msel(sai_bclk_source_t bclk_source,uint32_t * msel)306 static int get_msel(sai_bclk_source_t bclk_source, uint32_t *msel)
307 {
308 	switch (bclk_source) {
309 	case kSAI_BclkSourceMclkOption1:
310 		*msel = 0;
311 		break;
312 	case kSAI_BclkSourceMclkOption2:
313 		*msel = (0x2 << SAI_MCLK_MCR_MSEL_SHIFT);
314 		break;
315 	case kSAI_BclkSourceMclkOption3:
316 		*msel = (0x3 << SAI_MCLK_MCR_MSEL_SHIFT);
317 		break;
318 	default:
319 		return -EINVAL;
320 	}
321 
322 	return 0;
323 }
324 
set_msel(uint32_t regmap,int msel)325 static void set_msel(uint32_t regmap, int msel)
326 {
327 	UINT_TO_I2S(regmap)->MCR &= ~SAI_MCLK_MCR_MSEL_MASK;
328 	UINT_TO_I2S(regmap)->MCR |= msel;
329 }
330 
clk_lookup_by_name(const struct sai_clock_data * clk_data,char * name)331 static int clk_lookup_by_name(const struct sai_clock_data *clk_data, char *name)
332 {
333 	int i;
334 
335 	for (i = 0; i < clk_data->clock_num; i++) {
336 		if (!strcmp(name, clk_data->clock_names[i])) {
337 			return i;
338 		}
339 	}
340 
341 	return -EINVAL;
342 }
343 
get_mclk_rate(const struct sai_clock_data * clk_data,sai_bclk_source_t bclk_source,uint32_t * rate)344 static int get_mclk_rate(const struct sai_clock_data *clk_data,
345 			 sai_bclk_source_t bclk_source,
346 			 uint32_t *rate)
347 {
348 	int clk_idx;
349 	char *clk_name;
350 
351 	switch (bclk_source) {
352 	case kSAI_BclkSourceMclkOption1:
353 		clk_name = "mclk1";
354 		break;
355 	case kSAI_BclkSourceMclkOption2:
356 		clk_name = "mclk2";
357 		break;
358 	case kSAI_BclkSourceMclkOption3:
359 		clk_name = "mclk3";
360 		break;
361 	default:
362 		LOG_ERR("invalid bitclock source: %d", bclk_source);
363 		return -EINVAL;
364 	}
365 
366 	clk_idx = clk_lookup_by_name(clk_data, clk_name);
367 	if (clk_idx < 0) {
368 		LOG_ERR("failed to get clock index for %s", clk_name);
369 		return clk_idx;
370 	}
371 
372 	return clock_control_get_rate(clk_data->dev,
373 				      UINT_TO_POINTER(clk_data->clocks[clk_idx]),
374 				      rate);
375 }
376 #endif /* CONFIG_SAI_HAS_MCLK_CONFIG_OPTION */
377 
get_bclk_default_config(sai_bit_clock_t * cfg)378 static inline void get_bclk_default_config(sai_bit_clock_t *cfg)
379 {
380 	memset(cfg, 0, sizeof(sai_bit_clock_t));
381 
382 	/* by default, BCLK has the following properties:
383 	 *
384 	 *	1) BCLK is active HIGH.
385 	 *	2) BCLK uses MCLK1 source. (only applicable to master mode)
386 	 *	3) No source swap.
387 	 *	4) No input delay.
388 	 */
389 	cfg->bclkPolarity = kSAI_PolarityActiveHigh;
390 	cfg->bclkSource = kSAI_BclkSourceMclkOption1;
391 }
392 
get_fsync_default_config(sai_frame_sync_t * cfg)393 static inline void get_fsync_default_config(sai_frame_sync_t *cfg)
394 {
395 	memset(cfg, 0, sizeof(sai_frame_sync_t));
396 
397 	/* by default, FSYNC has the following properties:
398 	 *
399 	 *	1) FSYNC is asserted one bit early with respect to the next
400 	 *	frame.
401 	 *	2) FSYNC is active HIGH.
402 	 */
403 	cfg->frameSyncEarly = true;
404 	cfg->frameSyncPolarity = kSAI_PolarityActiveHigh;
405 }
406 
get_serial_default_config(sai_serial_data_t * cfg)407 static inline void get_serial_default_config(sai_serial_data_t *cfg)
408 {
409 	memset(cfg, 0, sizeof(sai_serial_data_t));
410 
411 	/* by default, the serial configuration has the following quirks:
412 	 *
413 	 * 1) Data pin is not tri-stated.
414 	 * 2) MSB is first.
415 	 */
416 	/* note: this is equivalent to checking if the SAI has xCR4's CHMOD bit */
417 #if FSL_FEATURE_SAI_HAS_CHANNEL_MODE
418 	cfg->dataMode = kSAI_DataPinStateOutputZero;
419 #endif /* FSL_FEATURE_SAI_HAS_CHANNEL_MODE */
420 	cfg->dataOrder = kSAI_DataMSB;
421 }
422 
get_fifo_default_config(sai_fifo_t * cfg)423 static inline void get_fifo_default_config(sai_fifo_t *cfg)
424 {
425 	memset(cfg, 0, sizeof(sai_fifo_t));
426 }
427 
sai_get_state(enum dai_dir dir,struct sai_data * data)428 static inline uint32_t sai_get_state(enum dai_dir dir,
429 				     struct sai_data *data)
430 {
431 	if (dir == DAI_DIR_RX) {
432 		return data->rx_state;
433 	} else {
434 		return data->tx_state;
435 	}
436 }
437 
sai_update_state(enum dai_dir dir,struct sai_data * data,enum dai_state new_state)438 static int sai_update_state(enum dai_dir dir,
439 			    struct sai_data *data,
440 			    enum dai_state new_state)
441 {
442 	enum dai_state old_state = sai_get_state(dir, data);
443 
444 	LOG_DBG("attempting to transition from %d to %d", old_state, new_state);
445 
446 	/* check if transition is possible */
447 	switch (new_state) {
448 	case DAI_STATE_NOT_READY:
449 		/* this shouldn't be possible */
450 		return -EPERM;
451 	case DAI_STATE_READY:
452 		if (old_state != DAI_STATE_NOT_READY &&
453 		    old_state != DAI_STATE_READY &&
454 		    old_state != DAI_STATE_STOPPING) {
455 			return -EPERM;
456 		}
457 		break;
458 	case DAI_STATE_RUNNING:
459 		if (old_state != DAI_STATE_PAUSED &&
460 		    old_state != DAI_STATE_STOPPING &&
461 		    old_state != DAI_STATE_READY) {
462 			return -EPERM;
463 		}
464 		break;
465 	case DAI_STATE_PAUSED:
466 		if (old_state != DAI_STATE_RUNNING) {
467 			return -EPERM;
468 		}
469 		break;
470 	case DAI_STATE_STOPPING:
471 		if (old_state != DAI_STATE_READY &&
472 		    old_state != DAI_STATE_RUNNING &&
473 		    old_state != DAI_STATE_PAUSED) {
474 			return -EPERM;
475 		}
476 		break;
477 	case DAI_STATE_ERROR:
478 	case DAI_STATE_PRE_RUNNING:
479 		/* these states are not used so transitioning to them
480 		 * is considered invalid.
481 		 */
482 	default:
483 		return -EINVAL;
484 	}
485 
486 	if (dir == DAI_DIR_RX) {
487 		data->rx_state = new_state;
488 	} else {
489 		data->tx_state = new_state;
490 	}
491 
492 	return 0;
493 }
494 
sai_tx_rx_force_disable(enum dai_dir dir,uint32_t regmap)495 static inline void sai_tx_rx_force_disable(enum dai_dir dir,
496 					   uint32_t regmap)
497 {
498 	I2S_Type *base = UINT_TO_I2S(regmap);
499 
500 	if (dir == DAI_DIR_RX) {
501 		base->RCSR = ((base->RCSR & 0xFFE3FFFFU) & (~I2S_RCSR_RE_MASK));
502 	} else {
503 		base->TCSR = ((base->TCSR & 0xFFE3FFFFU) & (~I2S_TCSR_TE_MASK));
504 	}
505 }
506 
sai_tx_rx_sw_enable_disable(enum dai_dir dir,struct sai_data * data,bool enable)507 static inline void sai_tx_rx_sw_enable_disable(enum dai_dir dir,
508 					       struct sai_data *data,
509 					       bool enable)
510 {
511 	if (dir == DAI_DIR_RX) {
512 		data->rx_enabled = enable;
513 	} else {
514 		data->tx_enabled = enable;
515 	}
516 }
517 
count_leading_zeros(uint32_t word)518 static inline int count_leading_zeros(uint32_t word)
519 {
520 	int num = 0;
521 
522 	while (word) {
523 		if (!(word & 0x1)) {
524 			num++;
525 		} else {
526 			break;
527 		}
528 
529 		word = word >> 1;
530 	}
531 
532 	return num;
533 }
534 
sai_tx_rx_set_dline_mask(enum dai_dir dir,uint32_t regmap,uint32_t mask)535 static inline void sai_tx_rx_set_dline_mask(enum dai_dir dir, uint32_t regmap, uint32_t mask)
536 {
537 	I2S_Type *base = UINT_TO_I2S(regmap);
538 
539 	if (dir == DAI_DIR_RX) {
540 		base->RCR3 &= ~I2S_RCR3_RCE_MASK;
541 		base->RCR3 |= I2S_RCR3_RCE(mask);
542 	} else {
543 		base->TCR3 &= ~I2S_TCR3_TCE_MASK;
544 		base->TCR3 |= I2S_TCR3_TCE(mask);
545 	}
546 }
547 
sai_dump_register_data(uint32_t regmap)548 static inline void sai_dump_register_data(uint32_t regmap)
549 {
550 	I2S_Type *base = UINT_TO_I2S(regmap);
551 
552 	LOG_DBG("TCSR: 0x%x", base->TCSR);
553 	LOG_DBG("RCSR: 0x%x", base->RCSR);
554 
555 	LOG_DBG("TCR1: 0x%x", base->TCR1);
556 	LOG_DBG("RCR1: 0x%x", base->RCR1);
557 
558 	LOG_DBG("TCR2: 0x%x", base->TCR2);
559 	LOG_DBG("RCR2: 0x%x", base->RCR2);
560 
561 	LOG_DBG("TCR3: 0x%x", base->TCR3);
562 	LOG_DBG("RCR3: 0x%x", base->RCR3);
563 
564 	LOG_DBG("TCR4: 0x%x", base->TCR4);
565 	LOG_DBG("RCR4: 0x%x", base->RCR4);
566 
567 	LOG_DBG("TCR5: 0x%x", base->TCR5);
568 	LOG_DBG("RCR5: 0x%x", base->RCR5);
569 
570 	LOG_DBG("TMR: 0x%x", base->TMR);
571 	LOG_DBG("RMR: 0x%x", base->RMR);
572 
573 #ifdef CONFIG_SAI_HAS_MCLK_CONFIG_OPTION
574 	LOG_DBG("MCR: 0x%x", base->MCR);
575 #endif /* CONFIG_SAI_HAS_MCLK_CONFIG_OPTION */
576 }
577 
578 #endif /* ZEPHYR_DRIVERS_DAI_NXP_SAI_H_ */
579