Lines Matching full:sai

3 // Freescale ALSA SoC Digital Audio Interface (SAI) driver.
44 * SAI supports synchronous mode using bit/frame clocks of either Transmitter's
48 * @sai: SAI context
51 static inline bool fsl_sai_dir_is_synced(struct fsl_sai *sai, int dir) in fsl_sai_dir_is_synced() argument
56 return !sai->synchronous[dir] && sai->synchronous[adir]; in fsl_sai_dir_is_synced()
61 struct fsl_sai *sai = (struct fsl_sai *)devid; in fsl_sai_isr() local
62 unsigned int ofs = sai->soc_data->reg_offset; in fsl_sai_isr()
63 struct device *dev = &sai->pdev->dev; in fsl_sai_isr()
75 regmap_read(sai->regmap, FSL_SAI_TCSR(ofs), &xcsr); in fsl_sai_isr()
105 regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), flags | xcsr); in fsl_sai_isr()
109 regmap_read(sai->regmap, FSL_SAI_RCSR(ofs), &xcsr); in fsl_sai_isr()
139 regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), flags | xcsr); in fsl_sai_isr()
151 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); in fsl_sai_set_dai_tdm_slot() local
153 sai->slots = slots; in fsl_sai_set_dai_tdm_slot()
154 sai->slot_width = slot_width; in fsl_sai_set_dai_tdm_slot()
162 struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai); in fsl_sai_set_dai_bclk_ratio() local
164 sai->bclk_ratio = ratio; in fsl_sai_set_dai_bclk_ratio()
172 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); in fsl_sai_set_dai_sysclk_tr() local
173 unsigned int ofs = sai->soc_data->reg_offset; in fsl_sai_set_dai_sysclk_tr()
194 regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs), in fsl_sai_set_dai_sysclk_tr()
226 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); in fsl_sai_set_dai_fmt_tr() local
227 unsigned int ofs = sai->soc_data->reg_offset; in fsl_sai_set_dai_fmt_tr()
231 if (!sai->is_lsb_first) in fsl_sai_set_dai_fmt_tr()
262 sai->is_dsp_mode = true; in fsl_sai_set_dai_fmt_tr()
270 sai->is_dsp_mode = true; in fsl_sai_set_dai_fmt_tr()
305 sai->is_slave_mode = false; in fsl_sai_set_dai_fmt_tr()
308 sai->is_slave_mode = true; in fsl_sai_set_dai_fmt_tr()
312 sai->is_slave_mode = false; in fsl_sai_set_dai_fmt_tr()
316 sai->is_slave_mode = true; in fsl_sai_set_dai_fmt_tr()
322 regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs), in fsl_sai_set_dai_fmt_tr()
324 regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), in fsl_sai_set_dai_fmt_tr()
350 struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai); in fsl_sai_set_bclk() local
351 unsigned int ofs = sai->soc_data->reg_offset; in fsl_sai_set_bclk()
360 if (sai->is_slave_mode) in fsl_sai_set_bclk()
368 id = sai->soc_data->mclk0_is_mclk1 ? 1 : 0; in fsl_sai_set_bclk()
371 clk_rate = clk_get_rate(sai->mclk_clk[id]); in fsl_sai_set_bclk()
397 sai->mclk_id[tx] = id; in fsl_sai_set_bclk()
418 * 4) For Tx and Rx are both Synchronous with another SAI, we just in fsl_sai_set_bclk()
421 if (fsl_sai_dir_is_synced(sai, adir)) { in fsl_sai_set_bclk()
422 regmap_update_bits(sai->regmap, FSL_SAI_xCR2(!tx, ofs), in fsl_sai_set_bclk()
424 FSL_SAI_CR2_MSEL(sai->mclk_id[tx])); in fsl_sai_set_bclk()
425 regmap_update_bits(sai->regmap, FSL_SAI_xCR2(!tx, ofs), in fsl_sai_set_bclk()
427 } else if (!sai->synchronous[dir]) { in fsl_sai_set_bclk()
428 regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs), in fsl_sai_set_bclk()
430 FSL_SAI_CR2_MSEL(sai->mclk_id[tx])); in fsl_sai_set_bclk()
431 regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs), in fsl_sai_set_bclk()
436 sai->mclk_id[tx], savediv, savesub); in fsl_sai_set_bclk()
445 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); in fsl_sai_hw_params() local
446 unsigned int ofs = sai->soc_data->reg_offset; in fsl_sai_hw_params()
457 if (sai->slots) in fsl_sai_hw_params()
458 slots = sai->slots; in fsl_sai_hw_params()
460 if (sai->slot_width) in fsl_sai_hw_params()
461 slot_width = sai->slot_width; in fsl_sai_hw_params()
465 if (!sai->is_slave_mode) { in fsl_sai_hw_params()
466 if (sai->bclk_ratio) in fsl_sai_hw_params()
468 sai->bclk_ratio * in fsl_sai_hw_params()
478 if (!(sai->mclk_streams & BIT(substream->stream))) { in fsl_sai_hw_params()
479 ret = clk_prepare_enable(sai->mclk_clk[sai->mclk_id[tx]]); in fsl_sai_hw_params()
483 sai->mclk_streams |= BIT(substream->stream); in fsl_sai_hw_params()
487 if (!sai->is_dsp_mode) in fsl_sai_hw_params()
493 if (sai->is_lsb_first) in fsl_sai_hw_params()
505 * For SAI master mode, when Tx(Rx) sync with Rx(Tx) clock, Rx(Tx) will in fsl_sai_hw_params()
510 if (!sai->is_slave_mode && fsl_sai_dir_is_synced(sai, adir)) { in fsl_sai_hw_params()
511 regmap_update_bits(sai->regmap, FSL_SAI_xCR4(!tx, ofs), in fsl_sai_hw_params()
515 regmap_update_bits(sai->regmap, FSL_SAI_xCR5(!tx, ofs), in fsl_sai_hw_params()
520 regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs), in fsl_sai_hw_params()
523 regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), in fsl_sai_hw_params()
527 regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx, ofs), in fsl_sai_hw_params()
530 regmap_write(sai->regmap, FSL_SAI_xMR(tx), in fsl_sai_hw_params()
539 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); in fsl_sai_hw_free() local
541 unsigned int ofs = sai->soc_data->reg_offset; in fsl_sai_hw_free()
543 regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs), in fsl_sai_hw_free()
546 if (!sai->is_slave_mode && in fsl_sai_hw_free()
547 sai->mclk_streams & BIT(substream->stream)) { in fsl_sai_hw_free()
548 clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[tx]]); in fsl_sai_hw_free()
549 sai->mclk_streams &= ~BIT(substream->stream); in fsl_sai_hw_free()
555 static void fsl_sai_config_disable(struct fsl_sai *sai, int dir) in fsl_sai_config_disable() argument
557 unsigned int ofs = sai->soc_data->reg_offset; in fsl_sai_config_disable()
561 regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), in fsl_sai_config_disable()
567 regmap_read(sai->regmap, FSL_SAI_xCSR(tx, ofs), &xcsr); in fsl_sai_config_disable()
570 regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), in fsl_sai_config_disable()
574 * For sai master mode, after several open/close sai, in fsl_sai_config_disable()
578 * next sai version. in fsl_sai_config_disable()
580 if (!sai->is_slave_mode) { in fsl_sai_config_disable()
582 regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_SR); in fsl_sai_config_disable()
584 regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), 0); in fsl_sai_config_disable()
591 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); in fsl_sai_trigger() local
592 unsigned int ofs = sai->soc_data->reg_offset; in fsl_sai_trigger()
604 regmap_update_bits(sai->regmap, FSL_SAI_TCR2(ofs), FSL_SAI_CR2_SYNC, in fsl_sai_trigger()
605 sai->synchronous[TX] ? FSL_SAI_CR2_SYNC : 0); in fsl_sai_trigger()
606 regmap_update_bits(sai->regmap, FSL_SAI_RCR2(ofs), FSL_SAI_CR2_SYNC, in fsl_sai_trigger()
607 sai->synchronous[RX] ? FSL_SAI_CR2_SYNC : 0); in fsl_sai_trigger()
617 regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), in fsl_sai_trigger()
620 regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), in fsl_sai_trigger()
633 if (fsl_sai_dir_is_synced(sai, adir)) in fsl_sai_trigger()
634 regmap_update_bits(sai->regmap, FSL_SAI_xCSR((!tx), ofs), in fsl_sai_trigger()
637 regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), in fsl_sai_trigger()
643 regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), in fsl_sai_trigger()
645 regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), in fsl_sai_trigger()
649 regmap_read(sai->regmap, FSL_SAI_xCSR(!tx, ofs), &xcsr); in fsl_sai_trigger()
655 if (fsl_sai_dir_is_synced(sai, adir) && !(xcsr & FSL_SAI_CSR_FRDE)) in fsl_sai_trigger()
656 fsl_sai_config_disable(sai, adir); in fsl_sai_trigger()
664 if (!fsl_sai_dir_is_synced(sai, dir) || !(xcsr & FSL_SAI_CSR_FRDE)) in fsl_sai_trigger()
665 fsl_sai_config_disable(sai, dir); in fsl_sai_trigger()
678 struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); in fsl_sai_startup() local
686 if (sai->soc_data->use_edma) in fsl_sai_startup()
689 tx ? sai->dma_params_tx.maxburst : in fsl_sai_startup()
690 sai->dma_params_rx.maxburst); in fsl_sai_startup()
711 struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev); in fsl_sai_dai_probe() local
712 unsigned int ofs = sai->soc_data->reg_offset; in fsl_sai_dai_probe()
715 regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_SR); in fsl_sai_dai_probe()
716 regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_SR); in fsl_sai_dai_probe()
718 regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), 0); in fsl_sai_dai_probe()
719 regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), 0); in fsl_sai_dai_probe()
721 regmap_update_bits(sai->regmap, FSL_SAI_TCR1(ofs), in fsl_sai_dai_probe()
722 FSL_SAI_CR1_RFW_MASK(sai->soc_data->fifo_depth), in fsl_sai_dai_probe()
723 sai->soc_data->fifo_depth - FSL_SAI_MAXBURST_TX); in fsl_sai_dai_probe()
724 regmap_update_bits(sai->regmap, FSL_SAI_RCR1(ofs), in fsl_sai_dai_probe()
725 FSL_SAI_CR1_RFW_MASK(sai->soc_data->fifo_depth), in fsl_sai_dai_probe()
728 snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx, in fsl_sai_dai_probe()
729 &sai->dma_params_rx); in fsl_sai_dai_probe()
758 .name = "fsl-sai",
811 struct fsl_sai *sai = dev_get_drvdata(dev); in fsl_sai_readable_reg() local
812 unsigned int ofs = sai->soc_data->reg_offset; in fsl_sai_readable_reg()
867 struct fsl_sai *sai = dev_get_drvdata(dev); in fsl_sai_volatile_reg() local
868 unsigned int ofs = sai->soc_data->reg_offset; in fsl_sai_volatile_reg()
910 struct fsl_sai *sai = dev_get_drvdata(dev); in fsl_sai_writeable_reg() local
911 unsigned int ofs = sai->soc_data->reg_offset; in fsl_sai_writeable_reg()
957 struct fsl_sai *sai = dev_get_drvdata(dev); in fsl_sai_check_version() local
958 unsigned char ofs = sai->soc_data->reg_offset; in fsl_sai_check_version()
965 ret = regmap_read(sai->regmap, FSL_SAI_VERID, &val); in fsl_sai_check_version()
971 sai->verid.major = (val & FSL_SAI_VERID_MAJOR_MASK) >> in fsl_sai_check_version()
973 sai->verid.minor = (val & FSL_SAI_VERID_MINOR_MASK) >> in fsl_sai_check_version()
975 sai->verid.feature = val & FSL_SAI_VERID_FEATURE_MASK; in fsl_sai_check_version()
977 ret = regmap_read(sai->regmap, FSL_SAI_PARAM, &val); in fsl_sai_check_version()
984 sai->param.slot_num = 1 << in fsl_sai_check_version()
988 sai->param.fifo_depth = 1 << in fsl_sai_check_version()
992 sai->param.dataline = val & FSL_SAI_PARAM_DLN_MASK; in fsl_sai_check_version()
1003 struct fsl_sai *sai; in fsl_sai_probe() local
1011 sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL); in fsl_sai_probe()
1012 if (!sai) in fsl_sai_probe()
1015 sai->pdev = pdev; in fsl_sai_probe()
1016 sai->soc_data = of_device_get_match_data(&pdev->dev); in fsl_sai_probe()
1018 sai->is_lsb_first = of_property_read_bool(np, "lsb-first"); in fsl_sai_probe()
1024 if (sai->soc_data->reg_offset == 8) { in fsl_sai_probe()
1031 sai->regmap = devm_regmap_init_mmio(&pdev->dev, base, &fsl_sai_regmap_config); in fsl_sai_probe()
1032 if (IS_ERR(sai->regmap)) { in fsl_sai_probe()
1034 return PTR_ERR(sai->regmap); in fsl_sai_probe()
1037 sai->bus_clk = devm_clk_get(&pdev->dev, "bus"); in fsl_sai_probe()
1039 if (IS_ERR(sai->bus_clk) && PTR_ERR(sai->bus_clk) != -EPROBE_DEFER) in fsl_sai_probe()
1040 sai->bus_clk = devm_clk_get(&pdev->dev, "sai"); in fsl_sai_probe()
1041 if (IS_ERR(sai->bus_clk)) { in fsl_sai_probe()
1043 PTR_ERR(sai->bus_clk)); in fsl_sai_probe()
1045 return PTR_ERR(sai->bus_clk); in fsl_sai_probe()
1050 sai->mclk_clk[i] = devm_clk_get(&pdev->dev, tmp); in fsl_sai_probe()
1051 if (IS_ERR(sai->mclk_clk[i])) { in fsl_sai_probe()
1053 i + 1, PTR_ERR(sai->mclk_clk[i])); in fsl_sai_probe()
1054 sai->mclk_clk[i] = NULL; in fsl_sai_probe()
1058 if (sai->soc_data->mclk0_is_mclk1) in fsl_sai_probe()
1059 sai->mclk_clk[0] = sai->mclk_clk[1]; in fsl_sai_probe()
1061 sai->mclk_clk[0] = sai->bus_clk; in fsl_sai_probe()
1068 np->name, sai); in fsl_sai_probe()
1074 memcpy(&sai->cpu_dai_drv, &fsl_sai_dai_template, in fsl_sai_probe()
1078 sai->synchronous[RX] = true; in fsl_sai_probe()
1079 sai->synchronous[TX] = false; in fsl_sai_probe()
1080 sai->cpu_dai_drv.symmetric_rate = 1; in fsl_sai_probe()
1081 sai->cpu_dai_drv.symmetric_channels = 1; in fsl_sai_probe()
1082 sai->cpu_dai_drv.symmetric_sample_bits = 1; in fsl_sai_probe()
1084 if (of_find_property(np, "fsl,sai-synchronous-rx", NULL) && in fsl_sai_probe()
1085 of_find_property(np, "fsl,sai-asynchronous", NULL)) { in fsl_sai_probe()
1091 if (of_find_property(np, "fsl,sai-synchronous-rx", NULL)) { in fsl_sai_probe()
1093 sai->synchronous[RX] = false; in fsl_sai_probe()
1094 sai->synchronous[TX] = true; in fsl_sai_probe()
1095 } else if (of_find_property(np, "fsl,sai-asynchronous", NULL)) { in fsl_sai_probe()
1097 sai->synchronous[RX] = false; in fsl_sai_probe()
1098 sai->synchronous[TX] = false; in fsl_sai_probe()
1099 sai->cpu_dai_drv.symmetric_rate = 0; in fsl_sai_probe()
1100 sai->cpu_dai_drv.symmetric_channels = 0; in fsl_sai_probe()
1101 sai->cpu_dai_drv.symmetric_sample_bits = 0; in fsl_sai_probe()
1104 if (of_find_property(np, "fsl,sai-mclk-direction-output", NULL) && in fsl_sai_probe()
1105 of_device_is_compatible(np, "fsl,imx6ul-sai")) { in fsl_sai_probe()
1112 index = of_alias_get_id(np, "sai"); in fsl_sai_probe()
1120 sai->dma_params_rx.addr = res->start + FSL_SAI_RDR0; in fsl_sai_probe()
1121 sai->dma_params_tx.addr = res->start + FSL_SAI_TDR0; in fsl_sai_probe()
1122 sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX; in fsl_sai_probe()
1123 sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX; in fsl_sai_probe()
1125 platform_set_drvdata(pdev, sai); in fsl_sai_probe()
1139 /* Get sai version */ in fsl_sai_probe()
1142 dev_warn(&pdev->dev, "Error reading SAI version: %d\n", ret); in fsl_sai_probe()
1145 if (of_find_property(np, "fsl,sai-mclk-direction-output", NULL) && in fsl_sai_probe()
1146 sai->verid.major >= 3 && sai->verid.minor >= 1) { in fsl_sai_probe()
1147 regmap_update_bits(sai->regmap, FSL_SAI_MCTL, in fsl_sai_probe()
1159 if (sai->soc_data->use_imx_pcm) { in fsl_sai_probe()
1170 &sai->cpu_dai_drv, 1); in fsl_sai_probe()
1240 { .compatible = "fsl,vf610-sai", .data = &fsl_sai_vf610_data },
1241 { .compatible = "fsl,imx6sx-sai", .data = &fsl_sai_imx6sx_data },
1242 { .compatible = "fsl,imx6ul-sai", .data = &fsl_sai_imx6sx_data },
1243 { .compatible = "fsl,imx7ulp-sai", .data = &fsl_sai_imx7ulp_data },
1244 { .compatible = "fsl,imx8mq-sai", .data = &fsl_sai_imx8mq_data },
1245 { .compatible = "fsl,imx8qm-sai", .data = &fsl_sai_imx8qm_data },
1252 struct fsl_sai *sai = dev_get_drvdata(dev); in fsl_sai_runtime_suspend() local
1254 if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE)) in fsl_sai_runtime_suspend()
1255 clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[0]]); in fsl_sai_runtime_suspend()
1257 if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_PLAYBACK)) in fsl_sai_runtime_suspend()
1258 clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[1]]); in fsl_sai_runtime_suspend()
1260 clk_disable_unprepare(sai->bus_clk); in fsl_sai_runtime_suspend()
1262 if (sai->soc_data->flags & PMQOS_CPU_LATENCY) in fsl_sai_runtime_suspend()
1263 cpu_latency_qos_remove_request(&sai->pm_qos_req); in fsl_sai_runtime_suspend()
1265 regcache_cache_only(sai->regmap, true); in fsl_sai_runtime_suspend()
1272 struct fsl_sai *sai = dev_get_drvdata(dev); in fsl_sai_runtime_resume() local
1273 unsigned int ofs = sai->soc_data->reg_offset; in fsl_sai_runtime_resume()
1276 ret = clk_prepare_enable(sai->bus_clk); in fsl_sai_runtime_resume()
1282 if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_PLAYBACK)) { in fsl_sai_runtime_resume()
1283 ret = clk_prepare_enable(sai->mclk_clk[sai->mclk_id[1]]); in fsl_sai_runtime_resume()
1288 if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE)) { in fsl_sai_runtime_resume()
1289 ret = clk_prepare_enable(sai->mclk_clk[sai->mclk_id[0]]); in fsl_sai_runtime_resume()
1294 if (sai->soc_data->flags & PMQOS_CPU_LATENCY) in fsl_sai_runtime_resume()
1295 cpu_latency_qos_add_request(&sai->pm_qos_req, 0); in fsl_sai_runtime_resume()
1297 regcache_cache_only(sai->regmap, false); in fsl_sai_runtime_resume()
1298 regcache_mark_dirty(sai->regmap); in fsl_sai_runtime_resume()
1299 regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_SR); in fsl_sai_runtime_resume()
1300 regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_SR); in fsl_sai_runtime_resume()
1302 regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), 0); in fsl_sai_runtime_resume()
1303 regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), 0); in fsl_sai_runtime_resume()
1305 ret = regcache_sync(sai->regmap); in fsl_sai_runtime_resume()
1312 if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE)) in fsl_sai_runtime_resume()
1313 clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[0]]); in fsl_sai_runtime_resume()
1315 if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_PLAYBACK)) in fsl_sai_runtime_resume()
1316 clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[1]]); in fsl_sai_runtime_resume()
1318 clk_disable_unprepare(sai->bus_clk); in fsl_sai_runtime_resume()
1334 .name = "fsl-sai",
1341 MODULE_DESCRIPTION("Freescale Soc SAI Interface");
1343 MODULE_ALIAS("platform:fsl-sai");