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