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