Lines Matching +full:tdm +full:- +full:data +full:- +full:pair

1 // SPDX-License-Identifier: GPL-2.0
3 // Driver for Microchip I2S Multi-channel controller
29 * ---- I2S Controller Register map ----
75 * ---- Control Register (Write-only) ----
86 * ---- Mode Register A (Read/Write) ----
135 /* Number of TDM Channels - 1 */
138 ((((ch) - 1) << 13) & MCHP_I2SMCC_MRA_NBCHAN_MASK)
145 /* TDM Frame Synchronization */
169 * ---- Mode Register B (Read/Write) ----
183 (((fls(no_words) - 1) << 8) & MCHP_I2SMCC_MRB_DMACHUNK_MASK)
190 * ---- Status Registers (Read-only) ----
196 * ---- Interrupt Enable/Disable/Mask/Status Registers A ----
198 #define MCHP_I2SMCC_INT_TXRDY_MASK(ch) GENMASK((ch) - 1, 0)
208 * ---- Interrupt Enable/Disable/Mask/Status Registers B ----
217 * ---- Version Register (Read-only) ----
225 * ---- DMA chunk size allowed ----
273 regmap_read(dev->regmap, MCHP_I2SMCC_IMRA, &imra); in mchp_i2s_mcc_interrupt()
274 regmap_read(dev->regmap, MCHP_I2SMCC_ISRA, &sra); in mchp_i2s_mcc_interrupt()
277 regmap_read(dev->regmap, MCHP_I2SMCC_IMRB, &imrb); in mchp_i2s_mcc_interrupt()
278 regmap_read(dev->regmap, MCHP_I2SMCC_ISRB, &srb); in mchp_i2s_mcc_interrupt()
288 if (dev->soc->has_fifo) { in mchp_i2s_mcc_interrupt()
292 idra |= pendinga & (MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels) | in mchp_i2s_mcc_interrupt()
293 MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)); in mchp_i2s_mcc_interrupt()
298 if ((!dev->soc->has_fifo && in mchp_i2s_mcc_interrupt()
299 (imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) && in mchp_i2s_mcc_interrupt()
300 (imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) == in mchp_i2s_mcc_interrupt()
301 (idra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels))) || in mchp_i2s_mcc_interrupt()
302 (dev->soc->has_fifo && imrb & MCHP_I2SMCC_INT_TXFFRDY)) { in mchp_i2s_mcc_interrupt()
303 dev->tx_rdy = 1; in mchp_i2s_mcc_interrupt()
304 wake_up_interruptible(&dev->wq_txrdy); in mchp_i2s_mcc_interrupt()
306 if ((!dev->soc->has_fifo && in mchp_i2s_mcc_interrupt()
307 (imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) && in mchp_i2s_mcc_interrupt()
308 (imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) == in mchp_i2s_mcc_interrupt()
309 (idra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels))) || in mchp_i2s_mcc_interrupt()
310 (dev->soc->has_fifo && imrb & MCHP_I2SMCC_INT_RXFFRDY)) { in mchp_i2s_mcc_interrupt()
311 dev->rx_rdy = 1; in mchp_i2s_mcc_interrupt()
312 wake_up_interruptible(&dev->wq_rxrdy); in mchp_i2s_mcc_interrupt()
314 if (dev->soc->has_fifo) in mchp_i2s_mcc_interrupt()
315 regmap_write(dev->regmap, MCHP_I2SMCC_IDRB, idrb); in mchp_i2s_mcc_interrupt()
317 regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, idra); in mchp_i2s_mcc_interrupt()
327 dev_dbg(dev->dev, "%s() clk_id=%d freq=%u dir=%d\n", in mchp_i2s_mcc_set_sysclk()
334 dev->sysclk = freq; in mchp_i2s_mcc_set_sysclk()
344 dev_dbg(dev->dev, "%s() ratio=%u\n", __func__, ratio); in mchp_i2s_mcc_set_bclk_ratio()
346 dev->frame_length = ratio; in mchp_i2s_mcc_set_bclk_ratio()
355 dev_dbg(dev->dev, "%s() fmt=%#x\n", __func__, fmt); in mchp_i2s_mcc_set_dai_fmt()
359 return -EINVAL; in mchp_i2s_mcc_set_dai_fmt()
363 return -EINVAL; in mchp_i2s_mcc_set_dai_fmt()
367 return -EINVAL; in mchp_i2s_mcc_set_dai_fmt()
369 dev->fmt = fmt; in mchp_i2s_mcc_set_dai_fmt()
381 dev_dbg(dev->dev, in mchp_i2s_mcc_set_dai_tdm_slot()
387 return -EINVAL; in mchp_i2s_mcc_set_dai_tdm_slot()
391 if (rx_mask != GENMASK(slots - 1, 0) || in mchp_i2s_mcc_set_dai_tdm_slot()
393 return -EINVAL; in mchp_i2s_mcc_set_dai_tdm_slot()
396 dev->tdm_slots = slots; in mchp_i2s_mcc_set_dai_tdm_slot()
397 dev->frame_length = slots * MCHP_I2MCC_TDM_SLOT_WIDTH; in mchp_i2s_mcc_set_dai_tdm_slot()
415 diff_rate = abs(rate - round_rate); in mchp_i2s_mcc_clk_get_rate_diff()
437 if (!dev->sysclk) in mchp_i2s_mcc_config_divs()
440 sysclk = dev->sysclk; in mchp_i2s_mcc_config_divs()
456 ret = mchp_i2s_mcc_clk_get_rate_diff(dev->gclk, clk_rate, in mchp_i2s_mcc_config_divs()
460 dev_err(dev->dev, "gclk error for rate %lu: %d", in mchp_i2s_mcc_config_divs()
464 dev_dbg(dev->dev, "found perfect rate on gclk: %lu\n", in mchp_i2s_mcc_config_divs()
470 ret = mchp_i2s_mcc_clk_get_rate_diff(dev->pclk, clk_rate, in mchp_i2s_mcc_config_divs()
474 dev_err(dev->dev, "pclk error for rate %lu: %d", in mchp_i2s_mcc_config_divs()
478 dev_dbg(dev->dev, "found perfect rate on pclk: %lu\n", in mchp_i2s_mcc_config_divs()
487 dev_err(dev->dev, "unable to change rate to clocks\n"); in mchp_i2s_mcc_config_divs()
488 return -EINVAL; in mchp_i2s_mcc_config_divs()
491 dev_dbg(dev->dev, "source CLK is %s with rate %lu, diff %lu\n", in mchp_i2s_mcc_config_divs()
492 best_clk == dev->pclk ? "pclk" : "gclk", in mchp_i2s_mcc_config_divs()
496 if (dev->sysclk) in mchp_i2s_mcc_config_divs()
500 if (best_clk == dev->gclk) in mchp_i2s_mcc_config_divs()
512 regmap_read(dev->regmap, MCHP_I2SMCC_SR, &sr); in mchp_i2s_mcc_is_running()
543 unsigned int frame_length = dev->frame_length; in mchp_i2s_mcc_hw_params()
547 bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); in mchp_i2s_mcc_hw_params()
549 dev_dbg(dev->dev, "%s() rate=%u format=%#x width=%u channels=%u period_bytes=%d\n", in mchp_i2s_mcc_hw_params()
553 switch (dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { in mchp_i2s_mcc_hw_params()
555 if (dev->tdm_slots) { in mchp_i2s_mcc_hw_params()
556 dev_err(dev->dev, "I2S with TDM is not supported\n"); in mchp_i2s_mcc_hw_params()
557 return -EINVAL; in mchp_i2s_mcc_hw_params()
562 if (dev->tdm_slots) { in mchp_i2s_mcc_hw_params()
563 dev_err(dev->dev, "Left-Justified with TDM is not supported\n"); in mchp_i2s_mcc_hw_params()
564 return -EINVAL; in mchp_i2s_mcc_hw_params()
572 dev_err(dev->dev, "unsupported bus format\n"); in mchp_i2s_mcc_hw_params()
573 return -EINVAL; in mchp_i2s_mcc_hw_params()
576 switch (dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { in mchp_i2s_mcc_hw_params()
580 if (dev->sysclk) in mchp_i2s_mcc_hw_params()
592 if (dev->sysclk) in mchp_i2s_mcc_hw_params()
593 dev_warn(dev->dev, "Unable to generate MCLK in Slave mode\n"); in mchp_i2s_mcc_hw_params()
596 dev_err(dev->dev, "unsupported master/slave mode\n"); in mchp_i2s_mcc_hw_params()
597 return -EINVAL; in mchp_i2s_mcc_hw_params()
600 if (dev->fmt & (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J)) { in mchp_i2s_mcc_hw_params()
602 if (channels > dev->soc->data_pin_pair_num * 2) { in mchp_i2s_mcc_hw_params()
603 dev_err(dev->dev, in mchp_i2s_mcc_hw_params()
606 return -EINVAL; in mchp_i2s_mcc_hw_params()
628 dev_err(dev->dev, "unsupported number of audio channels\n"); in mchp_i2s_mcc_hw_params()
629 return -EINVAL; in mchp_i2s_mcc_hw_params()
634 } else if (dev->fmt & SND_SOC_DAIFMT_DSP_A) { in mchp_i2s_mcc_hw_params()
635 mra |= MCHP_I2SMCC_MRA_WIRECFG_TDM(dev->tdm_data_pair); in mchp_i2s_mcc_hw_params()
637 if (dev->tdm_slots) { in mchp_i2s_mcc_hw_params()
638 if (channels % 2 && channels * 2 <= dev->tdm_slots) { in mchp_i2s_mcc_hw_params()
640 * Duplicate data for even-numbered channels in mchp_i2s_mcc_hw_params()
641 * to odd-numbered channels in mchp_i2s_mcc_hw_params()
648 channels = dev->tdm_slots; in mchp_i2s_mcc_hw_params()
663 dev->playback.maxburst = maxburst; in mchp_i2s_mcc_hw_params()
665 dev->capture.maxburst = maxburst; in mchp_i2s_mcc_hw_params()
693 dev_err(dev->dev, "unsupported size/endianness for audio samples\n"); in mchp_i2s_mcc_hw_params()
694 return -EINVAL; in mchp_i2s_mcc_hw_params()
702 dev_err(dev->dev, in mchp_i2s_mcc_hw_params()
709 if (dev->soc->has_fifo) in mchp_i2s_mcc_hw_params()
720 regmap_read(dev->regmap, MCHP_I2SMCC_MRA, &mra_cur); in mchp_i2s_mcc_hw_params()
721 regmap_read(dev->regmap, MCHP_I2SMCC_MRB, &mrb_cur); in mchp_i2s_mcc_hw_params()
723 return -EINVAL; in mchp_i2s_mcc_hw_params()
728 if (mra & MCHP_I2SMCC_MRA_SRCCLK_GCLK && !dev->gclk_use) { in mchp_i2s_mcc_hw_params()
730 ret = clk_set_rate(dev->gclk, rate); in mchp_i2s_mcc_hw_params()
732 dev_err(dev->dev, in mchp_i2s_mcc_hw_params()
738 ret = clk_prepare(dev->gclk); in mchp_i2s_mcc_hw_params()
740 dev_err(dev->dev, "unable to prepare GCLK: %d\n", ret); in mchp_i2s_mcc_hw_params()
743 dev->gclk_use = 1; in mchp_i2s_mcc_hw_params()
747 dev->channels = channels; in mchp_i2s_mcc_hw_params()
749 ret = regmap_write(dev->regmap, MCHP_I2SMCC_MRA, mra); in mchp_i2s_mcc_hw_params()
751 if (dev->gclk_use) { in mchp_i2s_mcc_hw_params()
752 clk_unprepare(dev->gclk); in mchp_i2s_mcc_hw_params()
753 dev->gclk_use = 0; in mchp_i2s_mcc_hw_params()
757 return regmap_write(dev->regmap, MCHP_I2SMCC_MRB, mrb); in mchp_i2s_mcc_hw_params()
764 bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); in mchp_i2s_mcc_hw_free()
768 err = wait_event_interruptible_timeout(dev->wq_txrdy, in mchp_i2s_mcc_hw_free()
769 dev->tx_rdy, in mchp_i2s_mcc_hw_free()
772 dev_warn_once(dev->dev, in mchp_i2s_mcc_hw_free()
774 if (dev->soc->has_fifo) in mchp_i2s_mcc_hw_free()
775 regmap_write(dev->regmap, MCHP_I2SMCC_IDRB, in mchp_i2s_mcc_hw_free()
778 regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, in mchp_i2s_mcc_hw_free()
779 MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)); in mchp_i2s_mcc_hw_free()
781 dev->tx_rdy = 1; in mchp_i2s_mcc_hw_free()
784 err = wait_event_interruptible_timeout(dev->wq_rxrdy, in mchp_i2s_mcc_hw_free()
785 dev->rx_rdy, in mchp_i2s_mcc_hw_free()
788 dev_warn_once(dev->dev, in mchp_i2s_mcc_hw_free()
790 if (dev->soc->has_fifo) in mchp_i2s_mcc_hw_free()
791 regmap_write(dev->regmap, MCHP_I2SMCC_IDRB, in mchp_i2s_mcc_hw_free()
794 regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, in mchp_i2s_mcc_hw_free()
795 MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)); in mchp_i2s_mcc_hw_free()
796 dev->rx_rdy = 1; in mchp_i2s_mcc_hw_free()
801 regmap_write(dev->regmap, MCHP_I2SMCC_CR, MCHP_I2SMCC_CR_CKDIS); in mchp_i2s_mcc_hw_free()
803 if (dev->gclk_running) { in mchp_i2s_mcc_hw_free()
804 clk_disable(dev->gclk); in mchp_i2s_mcc_hw_free()
805 dev->gclk_running = 0; in mchp_i2s_mcc_hw_free()
807 if (dev->gclk_use) { in mchp_i2s_mcc_hw_free()
808 clk_unprepare(dev->gclk); in mchp_i2s_mcc_hw_free()
809 dev->gclk_use = 0; in mchp_i2s_mcc_hw_free()
820 bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); in mchp_i2s_mcc_trigger()
838 regmap_read(dev->regmap, MCHP_I2SMCC_SR, &sr); in mchp_i2s_mcc_trigger()
841 dev->tx_rdy = 0; in mchp_i2s_mcc_trigger()
844 * to assure all data is sent in mchp_i2s_mcc_trigger()
846 if (dev->soc->has_fifo) in mchp_i2s_mcc_trigger()
849 iera = MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels); in mchp_i2s_mcc_trigger()
852 dev->rx_rdy = 0; in mchp_i2s_mcc_trigger()
855 * to assure all data is received in mchp_i2s_mcc_trigger()
857 if (dev->soc->has_fifo) in mchp_i2s_mcc_trigger()
860 iera = MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels); in mchp_i2s_mcc_trigger()
864 return -EINVAL; in mchp_i2s_mcc_trigger()
867 if ((cr & MCHP_I2SMCC_CR_CKEN) && dev->gclk_use && in mchp_i2s_mcc_trigger()
868 !dev->gclk_running) { in mchp_i2s_mcc_trigger()
869 err = clk_enable(dev->gclk); in mchp_i2s_mcc_trigger()
871 dev_err_once(dev->dev, "failed to enable GCLK: %d\n", in mchp_i2s_mcc_trigger()
874 dev->gclk_running = 1; in mchp_i2s_mcc_trigger()
878 if (dev->soc->has_fifo) in mchp_i2s_mcc_trigger()
879 regmap_write(dev->regmap, MCHP_I2SMCC_IERB, ierb); in mchp_i2s_mcc_trigger()
881 regmap_write(dev->regmap, MCHP_I2SMCC_IERA, iera); in mchp_i2s_mcc_trigger()
882 regmap_write(dev->regmap, MCHP_I2SMCC_CR, cr); in mchp_i2s_mcc_trigger()
894 return regmap_write(dev->regmap, MCHP_I2SMCC_CR, in mchp_i2s_mcc_startup()
905 init_waitqueue_head(&dev->wq_txrdy); in mchp_i2s_mcc_dai_probe()
906 init_waitqueue_head(&dev->wq_rxrdy); in mchp_i2s_mcc_dai_probe()
907 dev->tx_rdy = 1; in mchp_i2s_mcc_dai_probe()
908 dev->rx_rdy = 1; in mchp_i2s_mcc_dai_probe()
910 snd_soc_dai_init_dma_data(dai, &dev->playback, &dev->capture); in mchp_i2s_mcc_dai_probe()
959 .name = "mchp-i2s-mcc",
975 .compatible = "microchip,sam9x60-i2smcc",
976 .data = &mchp_i2s_mcc_sam9x60,
979 .compatible = "microchip,sama7g5-i2smcc",
980 .data = &mchp_i2s_mcc_sama7g5,
992 if (!dev->soc) { in mchp_i2s_mcc_soc_data_parse()
993 dev_err(&pdev->dev, "failed to get soc data\n"); in mchp_i2s_mcc_soc_data_parse()
994 return -ENODEV; in mchp_i2s_mcc_soc_data_parse()
997 if (dev->soc->data_pin_pair_num == 1) in mchp_i2s_mcc_soc_data_parse()
1000 err = of_property_read_u8(pdev->dev.of_node, "microchip,tdm-data-pair", in mchp_i2s_mcc_soc_data_parse()
1001 &dev->tdm_data_pair); in mchp_i2s_mcc_soc_data_parse()
1002 if (err < 0 && err != -EINVAL) { in mchp_i2s_mcc_soc_data_parse()
1003 dev_err(&pdev->dev, in mchp_i2s_mcc_soc_data_parse()
1004 "bad property data for 'microchip,tdm-data-pair': %d", in mchp_i2s_mcc_soc_data_parse()
1008 if (err == -EINVAL) { in mchp_i2s_mcc_soc_data_parse()
1009 dev_info(&pdev->dev, in mchp_i2s_mcc_soc_data_parse()
1010 "'microchip,tdm-data-pair' not found; assuming DIN/DOUT 0 for TDM\n"); in mchp_i2s_mcc_soc_data_parse()
1011 dev->tdm_data_pair = 0; in mchp_i2s_mcc_soc_data_parse()
1013 if (dev->tdm_data_pair > dev->soc->data_pin_pair_num - 1) { in mchp_i2s_mcc_soc_data_parse()
1014 dev_err(&pdev->dev, in mchp_i2s_mcc_soc_data_parse()
1015 "invalid value for 'microchip,tdm-data-pair': %d\n", in mchp_i2s_mcc_soc_data_parse()
1016 dev->tdm_data_pair); in mchp_i2s_mcc_soc_data_parse()
1017 return -EINVAL; in mchp_i2s_mcc_soc_data_parse()
1019 dev_dbg(&pdev->dev, "TMD format on DIN/DOUT %d pins\n", in mchp_i2s_mcc_soc_data_parse()
1020 dev->tdm_data_pair); in mchp_i2s_mcc_soc_data_parse()
1036 dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); in mchp_i2s_mcc_probe()
1038 return -ENOMEM; in mchp_i2s_mcc_probe()
1044 regmap = devm_regmap_init_mmio(&pdev->dev, base, in mchp_i2s_mcc_probe()
1053 err = devm_request_irq(&pdev->dev, irq, mchp_i2s_mcc_interrupt, 0, in mchp_i2s_mcc_probe()
1054 dev_name(&pdev->dev), dev); in mchp_i2s_mcc_probe()
1058 dev->pclk = devm_clk_get(&pdev->dev, "pclk"); in mchp_i2s_mcc_probe()
1059 if (IS_ERR(dev->pclk)) { in mchp_i2s_mcc_probe()
1060 err = PTR_ERR(dev->pclk); in mchp_i2s_mcc_probe()
1061 dev_err(&pdev->dev, in mchp_i2s_mcc_probe()
1067 dev->gclk = devm_clk_get(&pdev->dev, "gclk"); in mchp_i2s_mcc_probe()
1068 if (IS_ERR(dev->gclk)) { in mchp_i2s_mcc_probe()
1069 if (PTR_ERR(dev->gclk) == -EPROBE_DEFER) in mchp_i2s_mcc_probe()
1070 return -EPROBE_DEFER; in mchp_i2s_mcc_probe()
1071 dev_warn(&pdev->dev, in mchp_i2s_mcc_probe()
1073 dev->gclk = NULL; in mchp_i2s_mcc_probe()
1076 dev->soc = of_device_get_match_data(&pdev->dev); in mchp_i2s_mcc_probe()
1081 dev->dev = &pdev->dev; in mchp_i2s_mcc_probe()
1082 dev->regmap = regmap; in mchp_i2s_mcc_probe()
1085 err = clk_prepare_enable(dev->pclk); in mchp_i2s_mcc_probe()
1087 dev_err(&pdev->dev, in mchp_i2s_mcc_probe()
1092 err = devm_snd_soc_register_component(&pdev->dev, in mchp_i2s_mcc_probe()
1096 dev_err(&pdev->dev, "failed to register DAI: %d\n", err); in mchp_i2s_mcc_probe()
1097 clk_disable_unprepare(dev->pclk); in mchp_i2s_mcc_probe()
1101 dev->playback.addr = (dma_addr_t)mem->start + MCHP_I2SMCC_THR; in mchp_i2s_mcc_probe()
1102 dev->capture.addr = (dma_addr_t)mem->start + MCHP_I2SMCC_RHR; in mchp_i2s_mcc_probe()
1104 err = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); in mchp_i2s_mcc_probe()
1106 dev_err(&pdev->dev, "failed to register PCM: %d\n", err); in mchp_i2s_mcc_probe()
1107 clk_disable_unprepare(dev->pclk); in mchp_i2s_mcc_probe()
1112 regmap_read(dev->regmap, MCHP_I2SMCC_VERSION, &version); in mchp_i2s_mcc_probe()
1113 dev_info(&pdev->dev, "hw version: %#lx\n", in mchp_i2s_mcc_probe()
1123 clk_disable_unprepare(dev->pclk); in mchp_i2s_mcc_remove()
1136 MODULE_DESCRIPTION("Microchip I2S Multi-Channel Controller driver");