Lines Matching +full:sai +full:- +full:synchronous +full:- +full:rx

1 // SPDX-License-Identifier: GPL-2.0+
3 // Freescale ALSA SoC Digital Audio Interface (SAI) driver.
5 // Copyright 2012-2015 Freescale Semiconductor, Inc.
23 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
27 #include "imx-pcm.h"
45 * fsl_sai_dir_is_synced - Check if stream is synced by the opposite stream
47 * SAI supports synchronous mode using bit/frame clocks of either Transmitter's
51 * @sai: SAI context
54 static inline bool fsl_sai_dir_is_synced(struct fsl_sai *sai, int dir) in fsl_sai_dir_is_synced() argument
56 int adir = (dir == TX) ? RX : TX; in fsl_sai_dir_is_synced()
59 return !sai->synchronous[dir] && sai->synchronous[adir]; in fsl_sai_dir_is_synced()
62 static struct pinctrl_state *fsl_sai_get_pins_state(struct fsl_sai *sai, u32 bclk) in fsl_sai_get_pins_state() argument
66 if (sai->is_pdm_mode) { in fsl_sai_get_pins_state()
69 state = pinctrl_lookup_state(sai->pinctrl, "dsd512"); in fsl_sai_get_pins_state()
73 state = pinctrl_lookup_state(sai->pinctrl, "dsd"); in fsl_sai_get_pins_state()
77 state = pinctrl_lookup_state(sai->pinctrl, "pcm_b2m"); in fsl_sai_get_pins_state()
82 state = pinctrl_lookup_state(sai->pinctrl, "default"); in fsl_sai_get_pins_state()
89 struct fsl_sai *sai = (struct fsl_sai *)devid; in fsl_sai_isr() local
90 unsigned int ofs = sai->soc_data->reg_offset; in fsl_sai_isr()
91 struct device *dev = &sai->pdev->dev; in fsl_sai_isr()
103 regmap_read(sai->regmap, FSL_SAI_TCSR(ofs), &xcsr); in fsl_sai_isr()
130 regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), flags | xcsr); in fsl_sai_isr()
133 /* Rx IRQ */ in fsl_sai_isr()
134 regmap_read(sai->regmap, FSL_SAI_RCSR(ofs), &xcsr); in fsl_sai_isr()
143 dev_dbg(dev, "isr: Start of Rx word detected\n"); in fsl_sai_isr()
146 dev_dbg(dev, "isr: Rx Frame sync error detected\n"); in fsl_sai_isr()
161 regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), flags | xcsr); in fsl_sai_isr()
170 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); in fsl_sai_set_dai_tdm_slot() local
172 sai->slots = slots; in fsl_sai_set_dai_tdm_slot()
173 sai->slot_width = slot_width; in fsl_sai_set_dai_tdm_slot()
181 struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai); in fsl_sai_set_dai_bclk_ratio() local
183 sai->bclk_ratio = ratio; in fsl_sai_set_dai_bclk_ratio()
191 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); in fsl_sai_set_dai_sysclk_tr() local
192 unsigned int ofs = sai->soc_data->reg_offset; in fsl_sai_set_dai_sysclk_tr()
209 return -EINVAL; in fsl_sai_set_dai_sysclk_tr()
212 regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs), in fsl_sai_set_dai_sysclk_tr()
220 struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai); in fsl_sai_set_mclk_rate() local
223 fsl_asoc_reparent_pll_clocks(dai->dev, sai->mclk_clk[clk_id], in fsl_sai_set_mclk_rate()
224 sai->pll8k_clk, sai->pll11k_clk, freq); in fsl_sai_set_mclk_rate()
226 ret = clk_set_rate(sai->mclk_clk[clk_id], freq); in fsl_sai_set_mclk_rate()
228 dev_err(dai->dev, "failed to set clock rate (%u): %d\n", freq, ret); in fsl_sai_set_mclk_rate()
236 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); in fsl_sai_set_dai_sysclk() local
244 dev_err(cpu_dai->dev, "Unknown clock id: %d\n", clk_id); in fsl_sai_set_dai_sysclk()
245 return -EINVAL; in fsl_sai_set_dai_sysclk()
248 if (IS_ERR_OR_NULL(sai->mclk_clk[clk_id])) { in fsl_sai_set_dai_sysclk()
249 dev_err(cpu_dai->dev, "Unassigned clock: %d\n", clk_id); in fsl_sai_set_dai_sysclk()
250 return -EINVAL; in fsl_sai_set_dai_sysclk()
253 if (sai->mclk_streams == 0) { in fsl_sai_set_dai_sysclk()
262 dev_err(cpu_dai->dev, "Cannot set tx sysclk: %d\n", ret); in fsl_sai_set_dai_sysclk()
268 dev_err(cpu_dai->dev, "Cannot set rx sysclk: %d\n", ret); in fsl_sai_set_dai_sysclk()
276 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); in fsl_sai_set_dai_fmt_tr() local
277 unsigned int ofs = sai->soc_data->reg_offset; in fsl_sai_set_dai_fmt_tr()
280 if (!sai->is_lsb_first) in fsl_sai_set_dai_fmt_tr()
283 sai->is_pdm_mode = false; in fsl_sai_set_dai_fmt_tr()
284 sai->is_dsp_mode = false; in fsl_sai_set_dai_fmt_tr()
313 sai->is_dsp_mode = true; in fsl_sai_set_dai_fmt_tr()
321 sai->is_dsp_mode = true; in fsl_sai_set_dai_fmt_tr()
326 sai->is_pdm_mode = true; in fsl_sai_set_dai_fmt_tr()
331 return -EINVAL; in fsl_sai_set_dai_fmt_tr()
353 return -EINVAL; in fsl_sai_set_dai_fmt_tr()
361 sai->is_consumer_mode = false; in fsl_sai_set_dai_fmt_tr()
364 sai->is_consumer_mode = true; in fsl_sai_set_dai_fmt_tr()
368 sai->is_consumer_mode = false; in fsl_sai_set_dai_fmt_tr()
372 sai->is_consumer_mode = true; in fsl_sai_set_dai_fmt_tr()
375 return -EINVAL; in fsl_sai_set_dai_fmt_tr()
378 regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs), in fsl_sai_set_dai_fmt_tr()
380 regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), in fsl_sai_set_dai_fmt_tr()
393 dev_err(cpu_dai->dev, "Cannot set tx format: %d\n", ret); in fsl_sai_set_dai_fmt()
399 dev_err(cpu_dai->dev, "Cannot set rx format: %d\n", ret); in fsl_sai_set_dai_fmt()
406 struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai); in fsl_sai_set_bclk() local
407 unsigned int reg, ofs = sai->soc_data->reg_offset; in fsl_sai_set_bclk()
410 int adir = tx ? RX : TX; in fsl_sai_set_bclk()
411 int dir = tx ? TX : RX; in fsl_sai_set_bclk()
413 bool support_1_1_ratio = sai->verid.version >= 0x0301; in fsl_sai_set_bclk()
416 if (sai->is_consumer_mode) in fsl_sai_set_bclk()
424 id = sai->soc_data->mclk0_is_mclk1 ? 1 : 0; in fsl_sai_set_bclk()
429 clk_rate = clk_get_rate(sai->mclk_clk[id]); in fsl_sai_set_bclk()
441 diff = abs((long)clk_rate - ratio * freq); in fsl_sai_set_bclk()
450 dev_dbg(dai->dev, in fsl_sai_set_bclk()
457 sai->mclk_id[tx] = id; in fsl_sai_set_bclk()
466 dev_err(dai->dev, "failed to derive required %cx rate: %d\n", in fsl_sai_set_bclk()
468 return -EINVAL; in fsl_sai_set_bclk()
471 dev_dbg(dai->dev, "best fit: clock id=%d, div=%d, deviation =%d\n", in fsl_sai_set_bclk()
472 sai->mclk_id[tx], savediv, bestdiff); in fsl_sai_set_bclk()
477 * 2) For Tx sync with Rx clock, we must set RCR2 register for playback in fsl_sai_set_bclk()
479 * 3) For Rx sync with Tx clock, we must set TCR2 register for playback in fsl_sai_set_bclk()
481 * 4) For Tx and Rx are both Synchronous with another SAI, we just in fsl_sai_set_bclk()
484 if (fsl_sai_dir_is_synced(sai, adir)) in fsl_sai_set_bclk()
486 else if (!sai->synchronous[dir]) in fsl_sai_set_bclk()
491 regmap_update_bits(sai->regmap, reg, FSL_SAI_CR2_MSEL_MASK, in fsl_sai_set_bclk()
492 FSL_SAI_CR2_MSEL(sai->mclk_id[tx])); in fsl_sai_set_bclk()
495 regmap_update_bits(sai->regmap, reg, in fsl_sai_set_bclk()
498 if (fsl_sai_dir_is_synced(sai, adir)) in fsl_sai_set_bclk()
499 regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs), in fsl_sai_set_bclk()
502 regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs), in fsl_sai_set_bclk()
505 regmap_update_bits(sai->regmap, reg, in fsl_sai_set_bclk()
507 savediv / 2 - 1); in fsl_sai_set_bclk()
517 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); in fsl_sai_hw_params() local
518 unsigned int ofs = sai->soc_data->reg_offset; in fsl_sai_hw_params()
519 bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; in fsl_sai_hw_params()
522 struct fsl_sai_dl_cfg *dl_cfg = sai->dl_cfg; in fsl_sai_hw_params()
525 int dl_cfg_cnt = sai->dl_cfg_cnt; in fsl_sai_hw_params()
530 int adir = tx ? RX : TX; in fsl_sai_hw_params()
535 if (sai->slot_width) in fsl_sai_hw_params()
536 slot_width = sai->slot_width; in fsl_sai_hw_params()
538 if (sai->slots) in fsl_sai_hw_params()
539 slots = sai->slots; in fsl_sai_hw_params()
540 else if (sai->bclk_ratio) in fsl_sai_hw_params()
541 slots = sai->bclk_ratio / slot_width; in fsl_sai_hw_params()
549 if (sai->is_pdm_mode) { in fsl_sai_hw_params()
562 dev_err(cpu_dai->dev, "channel not supported\n"); in fsl_sai_hw_params()
563 return -EINVAL; in fsl_sai_hw_params()
566 bclk = params_rate(params) * (sai->bclk_ratio ? sai->bclk_ratio : slots * slot_width); in fsl_sai_hw_params()
568 if (!IS_ERR_OR_NULL(sai->pinctrl)) { in fsl_sai_hw_params()
569 sai->pins_state = fsl_sai_get_pins_state(sai, bclk); in fsl_sai_hw_params()
570 if (!IS_ERR_OR_NULL(sai->pins_state)) { in fsl_sai_hw_params()
571 ret = pinctrl_select_state(sai->pinctrl, sai->pins_state); in fsl_sai_hw_params()
573 dev_err(cpu_dai->dev, "failed to set proper pins state: %d\n", ret); in fsl_sai_hw_params()
579 if (!sai->is_consumer_mode) { in fsl_sai_hw_params()
585 if (!(sai->mclk_streams & BIT(substream->stream))) { in fsl_sai_hw_params()
586 ret = clk_prepare_enable(sai->mclk_clk[sai->mclk_id[tx]]); in fsl_sai_hw_params()
590 sai->mclk_streams |= BIT(substream->stream); in fsl_sai_hw_params()
594 if (!sai->is_dsp_mode && !sai->is_pdm_mode) in fsl_sai_hw_params()
600 if (sai->is_lsb_first || sai->is_pdm_mode) in fsl_sai_hw_params()
603 val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1); in fsl_sai_hw_params()
610 /* Set to output mode to avoid tri-stated data pins */ in fsl_sai_hw_params()
615 * For SAI provider mode, when Tx(Rx) sync with Rx(Tx) clock, Rx(Tx) will in fsl_sai_hw_params()
616 * generate bclk and frame clock for Tx(Rx), we should set RCR4(TCR4), in fsl_sai_hw_params()
620 if (!sai->is_consumer_mode && fsl_sai_dir_is_synced(sai, adir)) { in fsl_sai_hw_params()
621 regmap_update_bits(sai->regmap, FSL_SAI_xCR4(!tx, ofs), in fsl_sai_hw_params()
625 regmap_update_bits(sai->regmap, FSL_SAI_xCR5(!tx, ofs), in fsl_sai_hw_params()
632 * - Can't used for singel dataline/FIFO case except the FIFO0 in fsl_sai_hw_params()
633 * - Can't used for multi dataline/FIFO case except the enabled FIFOs in fsl_sai_hw_params()
638 if (hweight8(dl_cfg[dl_cfg_idx].mask[tx]) <= 1 || sai->is_multi_fifo_dma) in fsl_sai_hw_params()
639 regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), in fsl_sai_hw_params()
642 regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), in fsl_sai_hw_params()
645 dma_params = tx ? &sai->dma_params_tx : &sai->dma_params_rx; in fsl_sai_hw_params()
646 dma_params->addr = sai->res->start + FSL_SAI_xDR0(tx) + in fsl_sai_hw_params()
649 if (sai->is_multi_fifo_dma) { in fsl_sai_hw_params()
650 sai->audio_config[tx].words_per_fifo = min(slots, channels); in fsl_sai_hw_params()
652 sai->audio_config[tx].n_fifos_dst = pins; in fsl_sai_hw_params()
653 sai->audio_config[tx].stride_fifos_dst = dl_cfg[dl_cfg_idx].next_off[tx]; in fsl_sai_hw_params()
655 sai->audio_config[tx].n_fifos_src = pins; in fsl_sai_hw_params()
656 sai->audio_config[tx].stride_fifos_src = dl_cfg[dl_cfg_idx].next_off[tx]; in fsl_sai_hw_params()
658 dma_params->maxburst = sai->audio_config[tx].words_per_fifo * pins; in fsl_sai_hw_params()
659 dma_params->peripheral_config = &sai->audio_config[tx]; in fsl_sai_hw_params()
660 dma_params->peripheral_size = sizeof(sai->audio_config[tx]); in fsl_sai_hw_params()
662 watermark = tx ? (sai->soc_data->fifo_depth - dma_params->maxburst) : in fsl_sai_hw_params()
663 (dma_params->maxburst - 1); in fsl_sai_hw_params()
664 regmap_update_bits(sai->regmap, FSL_SAI_xCR1(tx, ofs), in fsl_sai_hw_params()
665 FSL_SAI_CR1_RFW_MASK(sai->soc_data->fifo_depth), in fsl_sai_hw_params()
670 for (i = 0; i < sai->soc_data->pins; i++) { in fsl_sai_hw_params()
671 trce_mask = (1 << (i + 1)) - 1; in fsl_sai_hw_params()
676 regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs), in fsl_sai_hw_params()
689 if (sai->soc_data->mclk_with_tere && sai->mclk_direction_output && in fsl_sai_hw_params()
690 !sai->is_consumer_mode) in fsl_sai_hw_params()
691 regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), in fsl_sai_hw_params()
694 regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), in fsl_sai_hw_params()
698 regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx, ofs), in fsl_sai_hw_params()
703 if (sai->soc_data->mclk_with_tere && sai->mclk_direction_output && in fsl_sai_hw_params()
704 !sai->is_consumer_mode) in fsl_sai_hw_params()
705 regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), in fsl_sai_hw_params()
708 regmap_write(sai->regmap, FSL_SAI_xMR(tx), in fsl_sai_hw_params()
709 ~0UL - ((1 << min(channels, slots)) - 1)); in fsl_sai_hw_params()
717 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); in fsl_sai_hw_free() local
718 bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; in fsl_sai_hw_free()
719 unsigned int ofs = sai->soc_data->reg_offset; in fsl_sai_hw_free()
722 regmap_write(sai->regmap, FSL_SAI_xMR(tx), 0); in fsl_sai_hw_free()
724 regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs), in fsl_sai_hw_free()
727 if (!sai->is_consumer_mode && in fsl_sai_hw_free()
728 sai->mclk_streams & BIT(substream->stream)) { in fsl_sai_hw_free()
729 clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[tx]]); in fsl_sai_hw_free()
730 sai->mclk_streams &= ~BIT(substream->stream); in fsl_sai_hw_free()
736 static void fsl_sai_config_disable(struct fsl_sai *sai, int dir) in fsl_sai_config_disable() argument
738 unsigned int ofs = sai->soc_data->reg_offset; in fsl_sai_config_disable()
742 if (sai->soc_data->mclk_with_tere && sai->mclk_direction_output) in fsl_sai_config_disable()
747 regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), in fsl_sai_config_disable()
753 regmap_read(sai->regmap, FSL_SAI_xCSR(tx, ofs), &xcsr); in fsl_sai_config_disable()
754 } while (--count && xcsr & FSL_SAI_CSR_TERE); in fsl_sai_config_disable()
756 regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), in fsl_sai_config_disable()
760 * For sai master mode, after several open/close sai, in fsl_sai_config_disable()
764 * next sai version. in fsl_sai_config_disable()
766 if (!sai->is_consumer_mode) { in fsl_sai_config_disable()
768 regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_SR); in fsl_sai_config_disable()
770 regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), 0); in fsl_sai_config_disable()
777 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); in fsl_sai_trigger() local
778 unsigned int ofs = sai->soc_data->reg_offset; in fsl_sai_trigger()
780 bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; in fsl_sai_trigger()
781 int adir = tx ? RX : TX; in fsl_sai_trigger()
782 int dir = tx ? TX : RX; in fsl_sai_trigger()
786 * Asynchronous mode: Clear SYNC for both Tx and Rx. in fsl_sai_trigger()
787 * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx. in fsl_sai_trigger()
788 * Tx sync with Rx clocks: Clear SYNC for Rx, set it for Tx. in fsl_sai_trigger()
790 regmap_update_bits(sai->regmap, FSL_SAI_TCR2(ofs), FSL_SAI_CR2_SYNC, in fsl_sai_trigger()
791 sai->synchronous[TX] ? FSL_SAI_CR2_SYNC : 0); in fsl_sai_trigger()
792 regmap_update_bits(sai->regmap, FSL_SAI_RCR2(ofs), FSL_SAI_CR2_SYNC, in fsl_sai_trigger()
793 sai->synchronous[RX] ? FSL_SAI_CR2_SYNC : 0); in fsl_sai_trigger()
803 regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), in fsl_sai_trigger()
806 regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), in fsl_sai_trigger()
809 * Enable the opposite direction for synchronous mode in fsl_sai_trigger()
810 * 1. Tx sync with Rx: only set RE for Rx; set TE & RE for Tx in fsl_sai_trigger()
811 * 2. Rx sync with Tx: only set TE for Tx; set RE & TE for Rx in fsl_sai_trigger()
819 if (fsl_sai_dir_is_synced(sai, adir)) in fsl_sai_trigger()
820 regmap_update_bits(sai->regmap, FSL_SAI_xCSR((!tx), ofs), in fsl_sai_trigger()
823 regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), in fsl_sai_trigger()
829 regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), in fsl_sai_trigger()
831 regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), in fsl_sai_trigger()
835 regmap_read(sai->regmap, FSL_SAI_xCSR(!tx, ofs), &xcsr); in fsl_sai_trigger()
838 * If opposite stream provides clocks for synchronous mode and in fsl_sai_trigger()
841 if (fsl_sai_dir_is_synced(sai, adir) && !(xcsr & FSL_SAI_CSR_FRDE)) in fsl_sai_trigger()
842 fsl_sai_config_disable(sai, adir); in fsl_sai_trigger()
846 * 1. current stream doesn't provide clocks for synchronous mode in fsl_sai_trigger()
847 * 2. current stream provides clocks for synchronous mode but no in fsl_sai_trigger()
850 if (!fsl_sai_dir_is_synced(sai, dir) || !(xcsr & FSL_SAI_CSR_FRDE)) in fsl_sai_trigger()
851 fsl_sai_config_disable(sai, dir); in fsl_sai_trigger()
855 return -EINVAL; in fsl_sai_trigger()
864 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); in fsl_sai_startup() local
865 bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; in fsl_sai_startup()
870 * tx/rx maxburst in fsl_sai_startup()
872 if (sai->soc_data->use_edma) in fsl_sai_startup()
873 snd_pcm_hw_constraint_step(substream->runtime, 0, in fsl_sai_startup()
875 tx ? sai->dma_params_tx.maxburst : in fsl_sai_startup()
876 sai->dma_params_rx.maxburst); in fsl_sai_startup()
878 ret = snd_pcm_hw_constraint_list(substream->runtime, 0, in fsl_sai_startup()
886 struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev); in fsl_sai_dai_probe() local
887 unsigned int ofs = sai->soc_data->reg_offset; in fsl_sai_dai_probe()
889 /* Software Reset for both Tx and Rx */ in fsl_sai_dai_probe()
890 regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_SR); in fsl_sai_dai_probe()
891 regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_SR); in fsl_sai_dai_probe()
893 regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), 0); in fsl_sai_dai_probe()
894 regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), 0); in fsl_sai_dai_probe()
896 regmap_update_bits(sai->regmap, FSL_SAI_TCR1(ofs), in fsl_sai_dai_probe()
897 FSL_SAI_CR1_RFW_MASK(sai->soc_data->fifo_depth), in fsl_sai_dai_probe()
898 sai->soc_data->fifo_depth - sai->dma_params_tx.maxburst); in fsl_sai_dai_probe()
899 regmap_update_bits(sai->regmap, FSL_SAI_RCR1(ofs), in fsl_sai_dai_probe()
900 FSL_SAI_CR1_RFW_MASK(sai->soc_data->fifo_depth), in fsl_sai_dai_probe()
901 sai->dma_params_rx.maxburst - 1); in fsl_sai_dai_probe()
903 snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx, in fsl_sai_dai_probe()
904 &sai->dma_params_rx); in fsl_sai_dai_probe()
923 struct fsl_sai *sai = snd_soc_component_get_drvdata(component); in fsl_sai_dai_resume() local
924 struct device *dev = &sai->pdev->dev; in fsl_sai_dai_resume()
927 if (!IS_ERR_OR_NULL(sai->pinctrl) && !IS_ERR_OR_NULL(sai->pins_state)) { in fsl_sai_dai_resume()
928 ret = pinctrl_select_state(sai->pinctrl, sai->pins_state); in fsl_sai_dai_resume()
940 .stream_name = "CPU-Playback",
949 .stream_name = "CPU-Capture",
961 .name = "fsl-sai",
1016 struct fsl_sai *sai = dev_get_drvdata(dev); in fsl_sai_readable_reg() local
1017 unsigned int ofs = sai->soc_data->reg_offset; in fsl_sai_readable_reg()
1072 struct fsl_sai *sai = dev_get_drvdata(dev); in fsl_sai_volatile_reg() local
1073 unsigned int ofs = sai->soc_data->reg_offset; in fsl_sai_volatile_reg()
1115 struct fsl_sai *sai = dev_get_drvdata(dev); in fsl_sai_writeable_reg() local
1116 unsigned int ofs = sai->soc_data->reg_offset; in fsl_sai_writeable_reg()
1162 struct fsl_sai *sai = dev_get_drvdata(dev); in fsl_sai_check_version() local
1163 unsigned char ofs = sai->soc_data->reg_offset; in fsl_sai_check_version()
1170 ret = regmap_read(sai->regmap, FSL_SAI_VERID, &val); in fsl_sai_check_version()
1176 sai->verid.version = val & in fsl_sai_check_version()
1178 sai->verid.version >>= FSL_SAI_VERID_MINOR_SHIFT; in fsl_sai_check_version()
1179 sai->verid.feature = val & FSL_SAI_VERID_FEATURE_MASK; in fsl_sai_check_version()
1181 ret = regmap_read(sai->regmap, FSL_SAI_PARAM, &val); in fsl_sai_check_version()
1188 sai->param.slot_num = 1 << in fsl_sai_check_version()
1192 sai->param.fifo_depth = 1 << in fsl_sai_check_version()
1196 sai->param.dataline = val & FSL_SAI_PARAM_DLN_MASK; in fsl_sai_check_version()
1211 offset = nbidx - fbidx - 1; in fsl_sai_calc_dl_off()
1213 return (offset < 0 || offset >= (FSL_SAI_DL_NUM - 1) ? 0 : offset); in fsl_sai_calc_dl_off()
1219 * I2S(1) or PDM(2), second one is dataline mask for 'rx', third one is
1224 * It means I2S type rx mask is 0xff, tx mask is 0xff, PDM type
1225 * rx mask is 0xff, tx mask is 0x11 (dataline 1 and 4 enabled).
1228 static int fsl_sai_read_dlcfg(struct fsl_sai *sai) in fsl_sai_read_dlcfg() argument
1230 struct platform_device *pdev = sai->pdev; in fsl_sai_read_dlcfg()
1231 struct device_node *np = pdev->dev.of_node; in fsl_sai_read_dlcfg()
1232 struct device *dev = &pdev->dev; in fsl_sai_read_dlcfg()
1238 u32 rx, tx, type; in fsl_sai_read_dlcfg() local
1246 return -EINVAL; in fsl_sai_read_dlcfg()
1251 cfg = devm_kzalloc(&pdev->dev, (num_cfg + 1) * sizeof(*cfg), GFP_KERNEL); in fsl_sai_read_dlcfg()
1253 return -ENOMEM; in fsl_sai_read_dlcfg()
1256 soc_dl = BIT(sai->soc_data->pins) - 1; in fsl_sai_read_dlcfg()
1258 cfg[0].pins[0] = sai->soc_data->pins; in fsl_sai_read_dlcfg()
1263 cfg[0].pins[1] = sai->soc_data->pins; in fsl_sai_read_dlcfg()
1276 return -EINVAL; in fsl_sai_read_dlcfg()
1278 ret = of_property_read_u32_index(np, propname, index++, &rx); in fsl_sai_read_dlcfg()
1280 return -EINVAL; in fsl_sai_read_dlcfg()
1284 return -EINVAL; in fsl_sai_read_dlcfg()
1286 if ((rx & ~soc_dl) || (tx & ~soc_dl)) { in fsl_sai_read_dlcfg()
1288 return -EINVAL; in fsl_sai_read_dlcfg()
1291 rx = rx & soc_dl; in fsl_sai_read_dlcfg()
1295 cfg[i].pins[0] = hweight8(rx); in fsl_sai_read_dlcfg()
1296 cfg[i].mask[0] = rx; in fsl_sai_read_dlcfg()
1297 dl_mask = rx; in fsl_sai_read_dlcfg()
1299 cfg[i].next_off[0] = fsl_sai_calc_dl_off(rx); in fsl_sai_read_dlcfg()
1308 sai->dl_cfg = cfg; in fsl_sai_read_dlcfg()
1309 sai->dl_cfg_cnt = num_cfg + 1; in fsl_sai_read_dlcfg()
1318 struct device_node *np = pdev->dev.of_node; in fsl_sai_probe()
1319 struct device *dev = &pdev->dev; in fsl_sai_probe()
1320 struct fsl_sai *sai; in fsl_sai_probe() local
1328 sai = devm_kzalloc(dev, sizeof(*sai), GFP_KERNEL); in fsl_sai_probe()
1329 if (!sai) in fsl_sai_probe()
1330 return -ENOMEM; in fsl_sai_probe()
1332 sai->pdev = pdev; in fsl_sai_probe()
1333 sai->soc_data = of_device_get_match_data(dev); in fsl_sai_probe()
1335 sai->is_lsb_first = of_property_read_bool(np, "lsb-first"); in fsl_sai_probe()
1337 base = devm_platform_get_and_ioremap_resource(pdev, 0, &sai->res); in fsl_sai_probe()
1341 if (sai->soc_data->reg_offset == 8) { in fsl_sai_probe()
1348 sai->regmap = devm_regmap_init_mmio(dev, base, &fsl_sai_regmap_config); in fsl_sai_probe()
1349 if (IS_ERR(sai->regmap)) { in fsl_sai_probe()
1351 return PTR_ERR(sai->regmap); in fsl_sai_probe()
1354 sai->bus_clk = devm_clk_get(dev, "bus"); in fsl_sai_probe()
1356 if (IS_ERR(sai->bus_clk) && PTR_ERR(sai->bus_clk) != -EPROBE_DEFER) in fsl_sai_probe()
1357 sai->bus_clk = devm_clk_get(dev, "sai"); in fsl_sai_probe()
1358 if (IS_ERR(sai->bus_clk)) { in fsl_sai_probe()
1360 PTR_ERR(sai->bus_clk)); in fsl_sai_probe()
1361 /* -EPROBE_DEFER */ in fsl_sai_probe()
1362 return PTR_ERR(sai->bus_clk); in fsl_sai_probe()
1367 sai->mclk_clk[i] = devm_clk_get(dev, tmp); in fsl_sai_probe()
1368 if (IS_ERR(sai->mclk_clk[i])) { in fsl_sai_probe()
1370 i, PTR_ERR(sai->mclk_clk[i])); in fsl_sai_probe()
1371 sai->mclk_clk[i] = NULL; in fsl_sai_probe()
1375 if (sai->soc_data->mclk0_is_mclk1) in fsl_sai_probe()
1376 sai->mclk_clk[0] = sai->mclk_clk[1]; in fsl_sai_probe()
1378 sai->mclk_clk[0] = sai->bus_clk; in fsl_sai_probe()
1380 fsl_asoc_get_pll_clocks(&pdev->dev, &sai->pll8k_clk, in fsl_sai_probe()
1381 &sai->pll11k_clk); in fsl_sai_probe()
1385 if (!sai->soc_data->use_edma && !ret && dmas[2] == IMX_DMATYPE_MULTI_SAI) in fsl_sai_probe()
1386 sai->is_multi_fifo_dma = true; in fsl_sai_probe()
1388 /* read dataline mask for rx and tx*/ in fsl_sai_probe()
1389 ret = fsl_sai_read_dlcfg(sai); in fsl_sai_probe()
1400 np->name, sai); in fsl_sai_probe()
1406 memcpy(&sai->cpu_dai_drv, &fsl_sai_dai_template, in fsl_sai_probe()
1409 /* Sync Tx with Rx as default by following old DT binding */ in fsl_sai_probe()
1410 sai->synchronous[RX] = true; in fsl_sai_probe()
1411 sai->synchronous[TX] = false; in fsl_sai_probe()
1412 sai->cpu_dai_drv.symmetric_rate = 1; in fsl_sai_probe()
1413 sai->cpu_dai_drv.symmetric_channels = 1; in fsl_sai_probe()
1414 sai->cpu_dai_drv.symmetric_sample_bits = 1; in fsl_sai_probe()
1416 if (of_property_read_bool(np, "fsl,sai-synchronous-rx") && in fsl_sai_probe()
1417 of_property_read_bool(np, "fsl,sai-asynchronous")) { in fsl_sai_probe()
1418 /* error out if both synchronous and asynchronous are present */ in fsl_sai_probe()
1419 dev_err(dev, "invalid binding for synchronous mode\n"); in fsl_sai_probe()
1420 return -EINVAL; in fsl_sai_probe()
1423 if (of_property_read_bool(np, "fsl,sai-synchronous-rx")) { in fsl_sai_probe()
1424 /* Sync Rx with Tx */ in fsl_sai_probe()
1425 sai->synchronous[RX] = false; in fsl_sai_probe()
1426 sai->synchronous[TX] = true; in fsl_sai_probe()
1427 } else if (of_property_read_bool(np, "fsl,sai-asynchronous")) { in fsl_sai_probe()
1429 sai->synchronous[RX] = false; in fsl_sai_probe()
1430 sai->synchronous[TX] = false; in fsl_sai_probe()
1431 sai->cpu_dai_drv.symmetric_rate = 0; in fsl_sai_probe()
1432 sai->cpu_dai_drv.symmetric_channels = 0; in fsl_sai_probe()
1433 sai->cpu_dai_drv.symmetric_sample_bits = 0; in fsl_sai_probe()
1436 sai->mclk_direction_output = of_property_read_bool(np, "fsl,sai-mclk-direction-output"); in fsl_sai_probe()
1438 if (sai->mclk_direction_output && in fsl_sai_probe()
1439 of_device_is_compatible(np, "fsl,imx6ul-sai")) { in fsl_sai_probe()
1440 gpr = syscon_regmap_lookup_by_compatible("fsl,imx6ul-iomuxc-gpr"); in fsl_sai_probe()
1446 index = of_alias_get_id(np, "sai"); in fsl_sai_probe()
1454 sai->dma_params_rx.addr = sai->res->start + FSL_SAI_RDR0; in fsl_sai_probe()
1455 sai->dma_params_tx.addr = sai->res->start + FSL_SAI_TDR0; in fsl_sai_probe()
1456 sai->dma_params_rx.maxburst = in fsl_sai_probe()
1457 sai->soc_data->max_burst[RX] ? sai->soc_data->max_burst[RX] : FSL_SAI_MAXBURST_RX; in fsl_sai_probe()
1458 sai->dma_params_tx.maxburst = in fsl_sai_probe()
1459 sai->soc_data->max_burst[TX] ? sai->soc_data->max_burst[TX] : FSL_SAI_MAXBURST_TX; in fsl_sai_probe()
1461 sai->pinctrl = devm_pinctrl_get(&pdev->dev); in fsl_sai_probe()
1463 platform_set_drvdata(pdev, sai); in fsl_sai_probe()
1475 /* Get sai version */ in fsl_sai_probe()
1478 dev_warn(dev, "Error reading SAI version: %d\n", ret); in fsl_sai_probe()
1481 if (sai->mclk_direction_output && in fsl_sai_probe()
1482 sai->soc_data->max_register >= FSL_SAI_MCTL) { in fsl_sai_probe()
1483 regmap_update_bits(sai->regmap, FSL_SAI_MCTL, in fsl_sai_probe()
1488 if (ret < 0 && ret != -ENOSYS) in fsl_sai_probe()
1495 if (sai->soc_data->use_imx_pcm) { in fsl_sai_probe()
1500 dev_err(dev, "Error: You must enable the imx-pcm-dma support!\n"); in fsl_sai_probe()
1512 &sai->cpu_dai_drv, 1); in fsl_sai_probe()
1529 pm_runtime_disable(&pdev->dev); in fsl_sai_remove()
1530 if (!pm_runtime_status_suspended(&pdev->dev)) in fsl_sai_remove()
1531 fsl_sai_runtime_suspend(&pdev->dev); in fsl_sai_remove()
1647 { .compatible = "fsl,vf610-sai", .data = &fsl_sai_vf610_data },
1648 { .compatible = "fsl,imx6sx-sai", .data = &fsl_sai_imx6sx_data },
1649 { .compatible = "fsl,imx6ul-sai", .data = &fsl_sai_imx6sx_data },
1650 { .compatible = "fsl,imx7ulp-sai", .data = &fsl_sai_imx7ulp_data },
1651 { .compatible = "fsl,imx8mq-sai", .data = &fsl_sai_imx8mq_data },
1652 { .compatible = "fsl,imx8qm-sai", .data = &fsl_sai_imx8qm_data },
1653 { .compatible = "fsl,imx8mm-sai", .data = &fsl_sai_imx8mm_data },
1654 { .compatible = "fsl,imx8mp-sai", .data = &fsl_sai_imx8mp_data },
1655 { .compatible = "fsl,imx8ulp-sai", .data = &fsl_sai_imx8ulp_data },
1656 { .compatible = "fsl,imx8mn-sai", .data = &fsl_sai_imx8mn_data },
1657 { .compatible = "fsl,imx93-sai", .data = &fsl_sai_imx93_data },
1664 struct fsl_sai *sai = dev_get_drvdata(dev); in fsl_sai_runtime_suspend() local
1666 if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE)) in fsl_sai_runtime_suspend()
1667 clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[0]]); in fsl_sai_runtime_suspend()
1669 if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_PLAYBACK)) in fsl_sai_runtime_suspend()
1670 clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[1]]); in fsl_sai_runtime_suspend()
1672 clk_disable_unprepare(sai->bus_clk); in fsl_sai_runtime_suspend()
1674 if (sai->soc_data->flags & PMQOS_CPU_LATENCY) in fsl_sai_runtime_suspend()
1675 cpu_latency_qos_remove_request(&sai->pm_qos_req); in fsl_sai_runtime_suspend()
1677 regcache_cache_only(sai->regmap, true); in fsl_sai_runtime_suspend()
1684 struct fsl_sai *sai = dev_get_drvdata(dev); in fsl_sai_runtime_resume() local
1685 unsigned int ofs = sai->soc_data->reg_offset; in fsl_sai_runtime_resume()
1688 ret = clk_prepare_enable(sai->bus_clk); in fsl_sai_runtime_resume()
1694 if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_PLAYBACK)) { in fsl_sai_runtime_resume()
1695 ret = clk_prepare_enable(sai->mclk_clk[sai->mclk_id[1]]); in fsl_sai_runtime_resume()
1700 if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE)) { in fsl_sai_runtime_resume()
1701 ret = clk_prepare_enable(sai->mclk_clk[sai->mclk_id[0]]); in fsl_sai_runtime_resume()
1706 if (sai->soc_data->flags & PMQOS_CPU_LATENCY) in fsl_sai_runtime_resume()
1707 cpu_latency_qos_add_request(&sai->pm_qos_req, 0); in fsl_sai_runtime_resume()
1709 regcache_cache_only(sai->regmap, false); in fsl_sai_runtime_resume()
1710 regcache_mark_dirty(sai->regmap); in fsl_sai_runtime_resume()
1711 regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_SR); in fsl_sai_runtime_resume()
1712 regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_SR); in fsl_sai_runtime_resume()
1714 regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), 0); in fsl_sai_runtime_resume()
1715 regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), 0); in fsl_sai_runtime_resume()
1717 ret = regcache_sync(sai->regmap); in fsl_sai_runtime_resume()
1721 if (sai->soc_data->mclk_with_tere && sai->mclk_direction_output) in fsl_sai_runtime_resume()
1722 regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs), in fsl_sai_runtime_resume()
1728 if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE)) in fsl_sai_runtime_resume()
1729 clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[0]]); in fsl_sai_runtime_resume()
1731 if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_PLAYBACK)) in fsl_sai_runtime_resume()
1732 clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[1]]); in fsl_sai_runtime_resume()
1734 clk_disable_unprepare(sai->bus_clk); in fsl_sai_runtime_resume()
1750 .name = "fsl-sai",
1757 MODULE_DESCRIPTION("Freescale Soc SAI Interface");
1759 MODULE_ALIAS("platform:fsl-sai");