Lines Matching +full:rx +full:- +full:sync +full:- +full:mode

4  * SPDX-License-Identifier: Apache-2.0
53 cfg = dev->config; in sai_mclk_config()
54 data = dev->data; in sai_mclk_config()
56 mclk_config.mclkOutputEnable = cfg->mclk_is_output; in sai_mclk_config()
65 ret = get_mclk_rate(&cfg->clk_data, bclk_source, &mclk_rate); in sai_mclk_config()
73 LOG_DBG("target MCLK is %u", bespoke->mclk_rate); in sai_mclk_config()
79 mclk_config.mclkHz = bespoke->mclk_rate; in sai_mclk_config()
82 SAI_SetMasterClockConfig(UINT_TO_I2S(data->regmap), &mclk_config); in sai_mclk_config()
84 set_msel(data->regmap, msel); in sai_mclk_config()
96 data = dev->data; in sai_isr()
99 if (SAI_TX_RX_STATUS_IS_SET(DAI_DIR_TX, data->regmap, kSAI_FIFOErrorFlag)) { in sai_isr()
101 SAI_TX_RX_STATUS_CLEAR(DAI_DIR_TX, data->regmap, kSAI_FIFOErrorFlag); in sai_isr()
104 /* check for RX FIFO error */ in sai_isr()
105 if (SAI_TX_RX_STATUS_IS_SET(DAI_DIR_RX, data->regmap, kSAI_FIFOErrorFlag)) { in sai_isr()
107 SAI_TX_RX_STATUS_CLEAR(DAI_DIR_RX, data->regmap, kSAI_FIFOErrorFlag); in sai_isr()
115 struct sai_data *data = dev->data; in sai_config_get()
118 memcpy(cfg, &data->cfg, sizeof(*cfg)); in sai_config_get()
126 const struct sai_config *cfg = dev->config; in sai_get_properties()
130 return cfg->rx_props; in sai_get_properties()
132 return cfg->tx_props; in sai_get_properties()
143 * 1) TX and RX operate in the same mode: master/slave. As such,
144 * there's no need to check the mode for both directions.
146 * 2) Only one of the directions can operate in SYNC mode at a
149 * 3) What this piece of code does is it makes the SYNC direction
153 * +--------+ +--------+
154 * | TX | | RX |
156 * +--------+ +--------+
162 * +---------+ +---------+
163 * | TX BCLK | | RX BCLK |
165 * +---------+ +---------+
175 * the MCLK on RX's side.
180 * IMPORTANT1: in the above diagram and information, RX is SYNC
181 * with TX. The same applies if RX is SYNC with TX. Also, this
195 if (tx_config->masterSlave == kSAI_Master && in sai_config_set_err_051421()
196 bespoke->mclk_rate == bespoke->bclk_rate) { in sai_config_set_err_051421()
197 if (cfg->tx_sync_mode == kSAI_ModeSync) { in sai_config_set_err_051421()
198 base->TCR2 |= I2S_TCR2_BCI(1); in sai_config_set_err_051421()
201 if (cfg->rx_sync_mode == kSAI_ModeSync) { in sai_config_set_err_051421()
202 base->RCR2 |= I2S_RCR2_BCI(1); in sai_config_set_err_051421()
218 if (cfg->type != DAI_IMX_SAI) { in sai_config_set()
219 LOG_ERR("wrong DAI type: %d", cfg->type); in sai_config_set()
220 return -EINVAL; in sai_config_set()
224 data = dev->data; in sai_config_set()
225 sai_cfg = dev->config; in sai_config_set()
226 rx_config = &data->rx_config; in sai_config_set()
227 tx_config = &data->tx_config; in sai_config_set()
241 LOG_ERR("failed to update RX state. Reason: %d", ret); in sai_config_set()
246 if (bespoke->bclk_rate != in sai_config_set()
247 (bespoke->fsync_rate * bespoke->tdm_slot_width * bespoke->tdm_slots)) { in sai_config_set()
248 LOG_ERR("bad BCLK value: %d", bespoke->bclk_rate); in sai_config_set()
249 return -EINVAL; in sai_config_set()
253 if (count_leading_zeros(~bespoke->tx_slots) != bespoke->tdm_slots || in sai_config_set()
254 count_leading_zeros(~bespoke->rx_slots) != bespoke->tdm_slots) { in sai_config_set()
255 LOG_ERR("number of TX/RX slots doesn't match number of TDM slots"); in sai_config_set()
256 return -EINVAL; in sai_config_set()
260 get_bclk_default_config(&tx_config->bitClock); in sai_config_set()
261 get_fsync_default_config(&tx_config->frameSync); in sai_config_set()
262 get_serial_default_config(&tx_config->serialData); in sai_config_set()
263 get_fifo_default_config(&tx_config->fifo); in sai_config_set()
271 * the direction (TX/RX) we're enabling. Enabling the in sai_config_set()
273 * overrun/underrun when working with a SYNC direction. in sai_config_set()
275 * note3: the TX/RX data line shall be enabled/disabled in sai_config_set()
278 * the SYNC direction which would lead to a FIFO underrun. in sai_config_set()
280 tx_config->channelMask = 0x0; in sai_config_set()
283 tx_config->bitClock.bclkSource = kSAI_BclkSourceMclkOption1; in sai_config_set()
286 tx_config->frameSync.frameSyncWidth = bespoke->tdm_slot_width; in sai_config_set()
289 tx_config->serialData.dataWord0Length = bespoke->tdm_slot_width; in sai_config_set()
290 tx_config->serialData.dataWordNLength = bespoke->tdm_slot_width; in sai_config_set()
291 tx_config->serialData.dataFirstBitShifted = bespoke->tdm_slot_width; in sai_config_set()
292 tx_config->serialData.dataWordNum = bespoke->tdm_slots; in sai_config_set()
295 switch (cfg->format & DAI_FORMAT_CLOCK_PROVIDER_MASK) { in sai_config_set()
297 tx_config->masterSlave = kSAI_Slave; in sai_config_set()
300 tx_config->masterSlave = kSAI_Master; in sai_config_set()
305 cfg->format & DAI_FORMAT_CLOCK_PROVIDER_MASK); in sai_config_set()
306 return -ENOTSUP; in sai_config_set()
309 cfg->format & DAI_FORMAT_CLOCK_PROVIDER_MASK); in sai_config_set()
310 return -EINVAL; in sai_config_set()
313 LOG_DBG("SAI is in %d mode", tx_config->masterSlave); in sai_config_set()
316 switch (cfg->format & DAI_FORMAT_PROTOCOL_MASK) { in sai_config_set()
319 tx_config->bitClock.bclkPolarity = kSAI_PolarityActiveLow; in sai_config_set()
321 tx_config->frameSync.frameSyncPolarity = kSAI_PolarityActiveLow; in sai_config_set()
325 tx_config->frameSync.frameSyncWidth = 1; in sai_config_set()
327 tx_config->bitClock.bclkPolarity = kSAI_PolarityActiveLow; in sai_config_set()
331 cfg->format & DAI_FORMAT_PROTOCOL_MASK); in sai_config_set()
332 return -EINVAL; in sai_config_set()
336 cfg->format & DAI_FORMAT_PROTOCOL_MASK); in sai_config_set()
339 switch (cfg->format & DAI_FORMAT_CLOCK_INVERSION_MASK) { in sai_config_set()
341 SAI_INVERT_POLARITY(tx_config->bitClock.bclkPolarity); in sai_config_set()
342 SAI_INVERT_POLARITY(tx_config->frameSync.frameSyncPolarity); in sai_config_set()
345 SAI_INVERT_POLARITY(tx_config->bitClock.bclkPolarity); in sai_config_set()
348 SAI_INVERT_POLARITY(tx_config->frameSync.frameSyncPolarity); in sai_config_set()
355 cfg->format & DAI_FORMAT_CLOCK_INVERSION_MASK); in sai_config_set()
356 return -EINVAL; in sai_config_set()
359 LOG_DBG("FSYNC polarity: %d", tx_config->frameSync.frameSyncPolarity); in sai_config_set()
360 LOG_DBG("BCLK polarity: %d", tx_config->bitClock.bclkPolarity); in sai_config_set()
365 tx_config->serialData.dataMaskedWord = ~bespoke->tx_slots; in sai_config_set()
366 rx_config->serialData.dataMaskedWord = ~bespoke->rx_slots; in sai_config_set()
368 tx_config->fifo.fifoWatermark = sai_cfg->tx_fifo_watermark - 1; in sai_config_set()
369 rx_config->fifo.fifoWatermark = sai_cfg->rx_fifo_watermark - 1; in sai_config_set()
371 LOG_DBG("RX watermark: %d", sai_cfg->rx_fifo_watermark); in sai_config_set()
372 LOG_DBG("TX watermark: %d", sai_cfg->tx_fifo_watermark); in sai_config_set()
374 /* set the synchronization mode based on data passed from the DTS */ in sai_config_set()
375 tx_config->syncMode = sai_cfg->tx_sync_mode; in sai_config_set()
376 rx_config->syncMode = sai_cfg->rx_sync_mode; in sai_config_set()
385 SAI_RxSetConfig(UINT_TO_I2S(data->regmap), rx_config); in sai_config_set()
386 SAI_TxSetConfig(UINT_TO_I2S(data->regmap), tx_config); in sai_config_set()
389 * 1) TX and RX operate in the same mode: master or slave. in sai_config_set()
395 if (tx_config->masterSlave == kSAI_Master) { in sai_config_set()
396 SAI_TxSetBitClockRate(UINT_TO_I2S(data->regmap), bespoke->mclk_rate, in sai_config_set()
397 bespoke->fsync_rate, bespoke->tdm_slot_width, in sai_config_set()
398 bespoke->tdm_slots); in sai_config_set()
400 SAI_RxSetBitClockRate(UINT_TO_I2S(data->regmap), bespoke->mclk_rate, in sai_config_set()
401 bespoke->fsync_rate, bespoke->tdm_slot_width, in sai_config_set()
402 bespoke->tdm_slots); in sai_config_set()
406 ret = sai_mclk_config(dev, tx_config->bitClock.bclkSource, bespoke); in sai_config_set()
415 sai_config_set_err_051421(UINT_TO_I2S(data->regmap), in sai_config_set()
431 data->cfg.rate = bespoke->fsync_rate; in sai_config_set()
440 data->cfg.channels = bespoke->tdm_slots; in sai_config_set()
442 sai_dump_register_data(data->regmap); in sai_config_set()
465 * is not disabled before the SYNC direction, we can force in sai_dir_disable()
468 sai_tx_rx_force_disable(dir, data->regmap); in sai_dir_disable()
472 * states can be obtained by reading data->tx/rx_enabled, while in sai_dir_disable()
479 return WAIT_FOR(!SAI_TX_RX_IS_HW_ENABLED(dir, data->regmap), in sai_dir_disable()
494 return -EINVAL; in sai_tx_rx_disable()
497 if (cfg->tx_sync_mode == kSAI_ModeAsync && in sai_tx_rx_disable()
498 cfg->rx_sync_mode == kSAI_ModeAsync) { in sai_tx_rx_disable()
502 return -ETIMEDOUT; in sai_tx_rx_disable()
513 return -ETIMEDOUT; in sai_tx_rx_disable()
521 return -ETIMEDOUT; in sai_tx_rx_disable()
530 return -ETIMEDOUT; in sai_tx_rx_disable()
546 data = dev->data; in sai_trigger_pause()
547 cfg = dev->config; in sai_trigger_pause()
551 return -EINVAL; in sai_trigger_pause()
569 /* disable TX/RX data line */ in sai_trigger_pause()
570 sai_tx_rx_set_dline_mask(dir, data->regmap, 0x0); in sai_trigger_pause()
572 /* update the software state of TX/RX */ in sai_trigger_pause()
586 data = dev->data; in sai_trigger_stop()
587 cfg = dev->config; in sai_trigger_stop()
592 return -EINVAL; in sai_trigger_stop()
618 /* update the software state of TX/RX */ in sai_trigger_stop()
621 /* disable TX/RX data line */ in sai_trigger_stop()
622 sai_tx_rx_set_dline_mask(dir, data->regmap, 0x0); in sai_trigger_stop()
626 SAI_TX_RX_DMA_ENABLE_DISABLE(dir, data->regmap, false); in sai_trigger_stop()
629 SAI_TX_RX_ENABLE_DISABLE_IRQ(dir, data->regmap, in sai_trigger_stop()
632 irq_disable(cfg->irq); in sai_trigger_stop()
639 * SYNC and ASYNC for each direction. As such, there are 4 possible combinations
641 * a) TX ASYNC, RX ASYNC
642 * b) TX SYNC, RX ASYNC
643 * c) TX ASYNC, RX SYNC
644 * d) TX SYNC, RX SYNC
653 * b) The SYNC direction. This is, well, the direction that's in SYNC with the other
657 * Of course, the target direction may differ from the SYNC or ASYNC directions, but it
658 * can't differ from both of them at the same time (i.e: TARGET != SYNC AND TARGET != ASYNC).
660 * If the target direction is the same as the SYNC direction then we can safely perform the
666 * software reset on it only if the SYNC direction wasn't software enabled (i.e: through an
674 if (cfg->tx_sync_mode == kSAI_ModeAsync && in sai_tx_rx_sw_reset()
675 cfg->rx_sync_mode == kSAI_ModeAsync) { in sai_tx_rx_sw_reset()
679 SAI_TX_RX_SW_RESET(dir, data->regmap); in sai_tx_rx_sw_reset()
685 SAI_TX_RX_SW_RESET(sync_dir, data->regmap); in sai_tx_rx_sw_reset()
688 SAI_TX_RX_SW_RESET(async_dir, data->regmap); in sai_tx_rx_sw_reset()
692 SAI_TX_RX_SW_RESET(async_dir, data->regmap); in sai_tx_rx_sw_reset()
706 data = dev->data; in sai_trigger_start()
707 cfg = dev->config; in sai_trigger_start()
710 /* TX and RX should be triggered independently */ in sai_trigger_start()
713 return -EINVAL; in sai_trigger_start()
727 * skip this part and go directly to the TX/RX in sai_trigger_start()
743 irq_enable(cfg->irq); in sai_trigger_start()
746 SAI_TX_RX_ENABLE_DISABLE_IRQ(dir, data->regmap, in sai_trigger_start()
751 for (i = 0; i < data->cfg.channels; i++) { in sai_trigger_start()
752 SAI_WriteData(UINT_TO_I2S(data->regmap), cfg->tx_dline, 0x0); in sai_trigger_start()
756 /* TODO: for now, only DMA mode is supported */ in sai_trigger_start()
757 SAI_TX_RX_DMA_ENABLE_DISABLE(dir, data->regmap, true); in sai_trigger_start()
760 /* enable TX/RX data line. This translates to TX_DLINE0/RX_DLINE0 in sai_trigger_start()
765 sai_tx_rx_set_dline_mask(dir, data->regmap, in sai_trigger_start()
769 SAI_TX_RX_ENABLE_DISABLE(dir, data->regmap, true); in sai_trigger_start()
771 /* update the software state of TX/RX */ in sai_trigger_start()
803 return -EINVAL; in sai_trigger()
836 cfg = dev->config; in sai_clks_enable_disable()
838 for (i = 0; i < cfg->clk_data.clock_num; i++) { in sai_clks_enable_disable()
839 clk_id = UINT_TO_POINTER(cfg->clk_data.clocks[i]); in sai_clks_enable_disable()
842 ret = clock_control_on(cfg->clk_data.dev, clk_id); in sai_clks_enable_disable()
844 ret = clock_control_off(cfg->clk_data.dev, clk_id); in sai_clks_enable_disable()
849 cfg->clk_data.clocks[i], ret); in sai_clks_enable_disable()
872 return -ENOTSUP; in sai_pm_action()
884 cfg = dev->config; in sai_init()
885 data = dev->data; in sai_init()
887 device_map(&data->regmap, cfg->regmap_phys, cfg->regmap_size, K_MEM_CACHE_NONE); in sai_init()
896 /* note: optional operation so -ENOENT is allowed (i.e: we in sai_init()
899 ret = pinctrl_apply_state(cfg->pincfg, PINCTRL_STATE_DEFAULT); in sai_init()
900 if (ret < 0 && ret != -ENOENT) { in sai_init()
904 /* set TX/RX default states */ in sai_init()
905 data->tx_state = DAI_STATE_NOT_READY; in sai_init()
906 data->rx_state = DAI_STATE_NOT_READY; in sai_init()
909 cfg->irq_config(); in sai_init()
924 "invalid RX FIFO watermark"); \
936 "transmitter and receiver can't be both SYNC with each other"); \
938 BUILD_ASSERT(SAI_DLINE_COUNT(inst) != -1, \
947 "invalid RX data line index"); \
958 .dma_hs_id = SAI_TX_RX_DMA_HANDSHAKE(inst, rx), \