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_CLOCKS_CELL_BY_IDX(inst, clock_idx, name)
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 retrieve the SYNC direction. Use this macro when you know for sure
214  * you have 1 SYNC direction with 1 ASYNC direction.
215  */
216 #define SAI_TX_RX_GET_SYNC_DIR(cfg)\
217 	((cfg)->tx_sync_mode == kSAI_ModeSync ? DAI_DIR_TX : DAI_DIR_RX)
218 
219 /* used to retrieve the ASYNC direction. Use this macro when you know for sure
220  * you have 1 SYNC direction with 1 ASYNC direction.
221  */
222 #define SAI_TX_RX_GET_ASYNC_DIR(cfg)\
223 	((cfg)->tx_sync_mode == kSAI_ModeAsync ? DAI_DIR_TX : DAI_DIR_RX)
224 
225 /* used to check if transmitter/receiver is SW enabled */
226 #define SAI_TX_RX_DIR_IS_SW_ENABLED(dir, data)\
227 	((dir) == DAI_DIR_TX ? data->tx_enabled : data->rx_enabled)
228 
229 /* used to compute the mask for the transmission/receive lines based on
230  * the index passed from the DTS.
231  */
232 #define SAI_TX_RX_DLINE_MASK(dir, cfg)\
233 	((dir) == DAI_DIR_TX ? BIT((cfg)->tx_dline) : BIT((cfg)->rx_dline))
234 
235 struct sai_clock_data {
236 	uint32_t *clocks;
237 	uint32_t clock_num;
238 	/* assumption: all clocks belong to the same producer */
239 	const struct device *dev;
240 	const char **clock_names;
241 };
242 
243 struct sai_data {
244 	mm_reg_t regmap;
245 	sai_transceiver_t rx_config;
246 	sai_transceiver_t tx_config;
247 	bool tx_enabled;
248 	bool rx_enabled;
249 	enum dai_state tx_state;
250 	enum dai_state rx_state;
251 	struct dai_config cfg;
252 };
253 
254 struct sai_config {
255 	uint32_t regmap_phys;
256 	uint32_t regmap_size;
257 	struct sai_clock_data clk_data;
258 	bool mclk_is_output;
259 	/* if the tx/rx-fifo-watermark properties are not specified, it's going
260 	 * to be assumed that the watermark should be set to half of the FIFO
261 	 * size.
262 	 */
263 	uint32_t rx_fifo_watermark;
264 	uint32_t tx_fifo_watermark;
265 	const struct dai_properties *tx_props;
266 	const struct dai_properties *rx_props;
267 	uint32_t dai_index;
268 	/* RX synchronization mode - may be SYNC or ASYNC */
269 	sai_sync_mode_t rx_sync_mode;
270 	/* TX synchronization mode - may be SYNC or ASYNC */
271 	sai_sync_mode_t tx_sync_mode;
272 	void (*irq_config)(void);
273 	uint32_t tx_dline;
274 	uint32_t rx_dline;
275 	const struct pinctrl_dev_config *pincfg;
276 };
277 
278 /* this needs to perfectly match SOF's struct sof_ipc_dai_sai_params */
279 struct sai_bespoke_config {
280 	uint32_t reserved0;
281 
282 	uint16_t reserved1;
283 	uint16_t mclk_id;
284 	uint32_t mclk_direction;
285 
286 	/* CLOCK-related data */
287 	uint32_t mclk_rate;
288 	uint32_t fsync_rate;
289 	uint32_t bclk_rate;
290 
291 	/* TDM-related data */
292 	uint32_t tdm_slots;
293 	uint32_t rx_slots;
294 	uint32_t tx_slots;
295 	uint16_t tdm_slot_width;
296 	uint16_t reserved2;
297 };
298 
299 #ifdef CONFIG_SAI_HAS_MCLK_CONFIG_OPTION
get_msel(sai_bclk_source_t bclk_source,uint32_t * msel)300 static int get_msel(sai_bclk_source_t bclk_source, uint32_t *msel)
301 {
302 	switch (bclk_source) {
303 	case kSAI_BclkSourceMclkOption1:
304 		*msel = 0;
305 		break;
306 	case kSAI_BclkSourceMclkOption2:
307 		*msel = (0x2 << SAI_MCLK_MCR_MSEL_SHIFT);
308 		break;
309 	case kSAI_BclkSourceMclkOption3:
310 		*msel = (0x3 << SAI_MCLK_MCR_MSEL_SHIFT);
311 		break;
312 	default:
313 		return -EINVAL;
314 	}
315 
316 	return 0;
317 }
318 
set_msel(uint32_t regmap,int msel)319 static void set_msel(uint32_t regmap, int msel)
320 {
321 	UINT_TO_I2S(regmap)->MCR &= ~SAI_MCLK_MCR_MSEL_MASK;
322 	UINT_TO_I2S(regmap)->MCR |= msel;
323 }
324 
clk_lookup_by_name(const struct sai_clock_data * clk_data,char * name)325 static int clk_lookup_by_name(const struct sai_clock_data *clk_data, char *name)
326 {
327 	int i;
328 
329 	for (i = 0; i < clk_data->clock_num; i++) {
330 		if (!strcmp(name, clk_data->clock_names[i])) {
331 			return i;
332 		}
333 	}
334 
335 	return -EINVAL;
336 }
337 
get_mclk_rate(const struct sai_clock_data * clk_data,sai_bclk_source_t bclk_source,uint32_t * rate)338 static int get_mclk_rate(const struct sai_clock_data *clk_data,
339 			 sai_bclk_source_t bclk_source,
340 			 uint32_t *rate)
341 {
342 	int clk_idx;
343 	char *clk_name;
344 
345 	switch (bclk_source) {
346 	case kSAI_BclkSourceMclkOption1:
347 		clk_name = "mclk1";
348 		break;
349 	case kSAI_BclkSourceMclkOption2:
350 		clk_name = "mclk2";
351 		break;
352 	case kSAI_BclkSourceMclkOption3:
353 		clk_name = "mclk3";
354 		break;
355 	default:
356 		LOG_ERR("invalid bitclock source: %d", bclk_source);
357 		return -EINVAL;
358 	}
359 
360 	clk_idx = clk_lookup_by_name(clk_data, clk_name);
361 	if (clk_idx < 0) {
362 		LOG_ERR("failed to get clock index for %s", clk_name);
363 		return clk_idx;
364 	}
365 
366 	return clock_control_get_rate(clk_data->dev,
367 				      UINT_TO_POINTER(clk_data->clocks[clk_idx]),
368 				      rate);
369 }
370 #endif /* CONFIG_SAI_HAS_MCLK_CONFIG_OPTION */
371 
get_bclk_default_config(sai_bit_clock_t * cfg)372 static inline void get_bclk_default_config(sai_bit_clock_t *cfg)
373 {
374 	memset(cfg, 0, sizeof(sai_bit_clock_t));
375 
376 	/* by default, BCLK has the following properties:
377 	 *
378 	 *	1) BCLK is active HIGH.
379 	 *	2) BCLK uses MCLK1 source. (only applicable to master mode)
380 	 *	3) No source swap.
381 	 *	4) No input delay.
382 	 */
383 	cfg->bclkPolarity = kSAI_PolarityActiveHigh;
384 	cfg->bclkSource = kSAI_BclkSourceMclkOption1;
385 }
386 
get_fsync_default_config(sai_frame_sync_t * cfg)387 static inline void get_fsync_default_config(sai_frame_sync_t *cfg)
388 {
389 	memset(cfg, 0, sizeof(sai_frame_sync_t));
390 
391 	/* by default, FSYNC has the following properties:
392 	 *
393 	 *	1) FSYNC is asserted one bit early with respect to the next
394 	 *	frame.
395 	 *	2) FSYNC is active HIGH.
396 	 */
397 	cfg->frameSyncEarly = true;
398 	cfg->frameSyncPolarity = kSAI_PolarityActiveHigh;
399 }
400 
get_serial_default_config(sai_serial_data_t * cfg)401 static inline void get_serial_default_config(sai_serial_data_t *cfg)
402 {
403 	memset(cfg, 0, sizeof(sai_serial_data_t));
404 
405 	/* by default, the serial configuration has the following quirks:
406 	 *
407 	 * 1) Data pin is not tri-stated.
408 	 * 2) MSB is first.
409 	 */
410 	/* note: this is equivalent to checking if the SAI has xCR4's CHMOD bit */
411 #if FSL_FEATURE_SAI_HAS_CHANNEL_MODE
412 	cfg->dataMode = kSAI_DataPinStateOutputZero;
413 #endif /* FSL_FEATURE_SAI_HAS_CHANNEL_MODE */
414 	cfg->dataOrder = kSAI_DataMSB;
415 }
416 
get_fifo_default_config(sai_fifo_t * cfg)417 static inline void get_fifo_default_config(sai_fifo_t *cfg)
418 {
419 	memset(cfg, 0, sizeof(sai_fifo_t));
420 }
421 
sai_get_state(enum dai_dir dir,struct sai_data * data)422 static inline uint32_t sai_get_state(enum dai_dir dir,
423 				     struct sai_data *data)
424 {
425 	if (dir == DAI_DIR_RX) {
426 		return data->rx_state;
427 	} else {
428 		return data->tx_state;
429 	}
430 }
431 
sai_update_state(enum dai_dir dir,struct sai_data * data,enum dai_state new_state)432 static int sai_update_state(enum dai_dir dir,
433 			    struct sai_data *data,
434 			    enum dai_state new_state)
435 {
436 	enum dai_state old_state = sai_get_state(dir, data);
437 
438 	LOG_DBG("attempting to transition from %d to %d", old_state, new_state);
439 
440 	/* check if transition is possible */
441 	switch (new_state) {
442 	case DAI_STATE_NOT_READY:
443 		/* this shouldn't be possible */
444 		return -EPERM;
445 	case DAI_STATE_READY:
446 		if (old_state != DAI_STATE_NOT_READY &&
447 		    old_state != DAI_STATE_READY &&
448 		    old_state != DAI_STATE_STOPPING) {
449 			return -EPERM;
450 		}
451 		break;
452 	case DAI_STATE_RUNNING:
453 		if (old_state != DAI_STATE_PAUSED &&
454 		    old_state != DAI_STATE_STOPPING &&
455 		    old_state != DAI_STATE_READY) {
456 			return -EPERM;
457 		}
458 		break;
459 	case DAI_STATE_PAUSED:
460 		if (old_state != DAI_STATE_RUNNING) {
461 			return -EPERM;
462 		}
463 		break;
464 	case DAI_STATE_STOPPING:
465 		if (old_state != DAI_STATE_READY &&
466 		    old_state != DAI_STATE_RUNNING &&
467 		    old_state != DAI_STATE_PAUSED) {
468 			return -EPERM;
469 		}
470 		break;
471 	case DAI_STATE_ERROR:
472 	case DAI_STATE_PRE_RUNNING:
473 		/* these states are not used so transitioning to them
474 		 * is considered invalid.
475 		 */
476 	default:
477 		return -EINVAL;
478 	}
479 
480 	if (dir == DAI_DIR_RX) {
481 		data->rx_state = new_state;
482 	} else {
483 		data->tx_state = new_state;
484 	}
485 
486 	return 0;
487 }
488 
sai_tx_rx_force_disable(enum dai_dir dir,uint32_t regmap)489 static inline void sai_tx_rx_force_disable(enum dai_dir dir,
490 					   uint32_t regmap)
491 {
492 	I2S_Type *base = UINT_TO_I2S(regmap);
493 
494 	if (dir == DAI_DIR_RX) {
495 		base->RCSR = ((base->RCSR & 0xFFE3FFFFU) & (~I2S_RCSR_RE_MASK));
496 	} else {
497 		base->TCSR = ((base->TCSR & 0xFFE3FFFFU) & (~I2S_TCSR_TE_MASK));
498 	}
499 }
500 
sai_tx_rx_sw_enable_disable(enum dai_dir dir,struct sai_data * data,bool enable)501 static inline void sai_tx_rx_sw_enable_disable(enum dai_dir dir,
502 					       struct sai_data *data,
503 					       bool enable)
504 {
505 	if (dir == DAI_DIR_RX) {
506 		data->rx_enabled = enable;
507 	} else {
508 		data->tx_enabled = enable;
509 	}
510 }
511 
count_leading_zeros(uint32_t word)512 static inline int count_leading_zeros(uint32_t word)
513 {
514 	int num = 0;
515 
516 	while (word) {
517 		if (!(word & 0x1)) {
518 			num++;
519 		} else {
520 			break;
521 		}
522 
523 		word = word >> 1;
524 	}
525 
526 	return num;
527 }
528 
sai_tx_rx_set_dline_mask(enum dai_dir dir,uint32_t regmap,uint32_t mask)529 static inline void sai_tx_rx_set_dline_mask(enum dai_dir dir, uint32_t regmap, uint32_t mask)
530 {
531 	I2S_Type *base = UINT_TO_I2S(regmap);
532 
533 	if (dir == DAI_DIR_RX) {
534 		base->RCR3 &= ~I2S_RCR3_RCE_MASK;
535 		base->RCR3 |= I2S_RCR3_RCE(mask);
536 	} else {
537 		base->TCR3 &= ~I2S_TCR3_TCE_MASK;
538 		base->TCR3 |= I2S_TCR3_TCE(mask);
539 	}
540 }
541 
sai_dump_register_data(uint32_t regmap)542 static inline void sai_dump_register_data(uint32_t regmap)
543 {
544 	I2S_Type *base = UINT_TO_I2S(regmap);
545 
546 	LOG_DBG("TCSR: 0x%x", base->TCSR);
547 	LOG_DBG("RCSR: 0x%x", base->RCSR);
548 
549 	LOG_DBG("TCR1: 0x%x", base->TCR1);
550 	LOG_DBG("RCR1: 0x%x", base->RCR1);
551 
552 	LOG_DBG("TCR2: 0x%x", base->TCR2);
553 	LOG_DBG("RCR2: 0x%x", base->RCR2);
554 
555 	LOG_DBG("TCR3: 0x%x", base->TCR3);
556 	LOG_DBG("RCR3: 0x%x", base->RCR3);
557 
558 	LOG_DBG("TCR4: 0x%x", base->TCR4);
559 	LOG_DBG("RCR4: 0x%x", base->RCR4);
560 
561 	LOG_DBG("TCR5: 0x%x", base->TCR5);
562 	LOG_DBG("RCR5: 0x%x", base->RCR5);
563 
564 	LOG_DBG("TMR: 0x%x", base->TMR);
565 	LOG_DBG("RMR: 0x%x", base->RMR);
566 
567 #ifdef CONFIG_SAI_HAS_MCLK_CONFIG_OPTION
568 	LOG_DBG("MCR: 0x%x", base->MCR);
569 #endif /* CONFIG_SAI_HAS_MCLK_CONFIG_OPTION */
570 }
571 
572 #endif /* ZEPHYR_DRIVERS_DAI_NXP_SAI_H_ */
573