Lines Matching +full:pclk +full:- +full:sample

1 // SPDX-License-Identifier: GPL-2.0
3 // Driver for Microchip I2S Multi-channel controller
28 * ---- I2S Controller Register map ----
74 * ---- Control Register (Write-only) ----
85 * ---- Mode Register A (Read/Write) ----
124 /* x sample transmitted when underrun */
125 #define MCHP_I2SMCC_MRA_TXSAME_ZERO (0 << 11) /* Zero sample */
126 #define MCHP_I2SMCC_MRA_TXSAME_PREVIOUS (1 << 11) /* Previous sample */
132 /* Number of TDM Channels - 1 */
135 ((((ch) - 1) << 13) & MCHP_I2SMCC_MRA_NBCHAN_MASK)
166 * ---- Mode Register B (Read/Write) ----
180 (((fls(no_words) - 1) << 8) & MCHP_I2SMCC_MRB_DMACHUNK_MASK)
187 * ---- Status Registers (Read-only) ----
193 * ---- Interrupt Enable/Disable/Mask/Status Registers A ----
195 #define MCHP_I2SMCC_INT_TXRDY_MASK(ch) GENMASK((ch) - 1, 0)
205 * ---- Interrupt Enable/Disable/Mask/Status Registers B ----
214 * ---- Version Register (Read-only) ----
233 struct clk *pclk; member
254 regmap_read(dev->regmap, MCHP_I2SMCC_IMRA, &imra); in mchp_i2s_mcc_interrupt()
255 regmap_read(dev->regmap, MCHP_I2SMCC_ISRA, &sra); in mchp_i2s_mcc_interrupt()
258 regmap_read(dev->regmap, MCHP_I2SMCC_IMRB, &imrb); in mchp_i2s_mcc_interrupt()
259 regmap_read(dev->regmap, MCHP_I2SMCC_ISRB, &srb); in mchp_i2s_mcc_interrupt()
269 idra |= pendinga & (MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels) | in mchp_i2s_mcc_interrupt()
270 MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)); in mchp_i2s_mcc_interrupt()
274 if ((imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) && in mchp_i2s_mcc_interrupt()
275 (imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) == in mchp_i2s_mcc_interrupt()
276 (idra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels))) { in mchp_i2s_mcc_interrupt()
277 dev->tx_rdy = 1; in mchp_i2s_mcc_interrupt()
278 wake_up_interruptible(&dev->wq_txrdy); in mchp_i2s_mcc_interrupt()
280 if ((imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) && in mchp_i2s_mcc_interrupt()
281 (imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) == in mchp_i2s_mcc_interrupt()
282 (idra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels))) { in mchp_i2s_mcc_interrupt()
283 dev->rx_rdy = 1; in mchp_i2s_mcc_interrupt()
284 wake_up_interruptible(&dev->wq_rxrdy); in mchp_i2s_mcc_interrupt()
286 regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, idra); in mchp_i2s_mcc_interrupt()
296 dev_dbg(dev->dev, "%s() clk_id=%d freq=%u dir=%d\n", in mchp_i2s_mcc_set_sysclk()
303 dev->sysclk = freq; in mchp_i2s_mcc_set_sysclk()
313 dev_dbg(dev->dev, "%s() ratio=%u\n", __func__, ratio); in mchp_i2s_mcc_set_bclk_ratio()
315 dev->frame_length = ratio; in mchp_i2s_mcc_set_bclk_ratio()
324 dev_dbg(dev->dev, "%s() fmt=%#x\n", __func__, fmt); in mchp_i2s_mcc_set_dai_fmt()
328 return -EINVAL; in mchp_i2s_mcc_set_dai_fmt()
332 return -EINVAL; in mchp_i2s_mcc_set_dai_fmt()
336 return -EINVAL; in mchp_i2s_mcc_set_dai_fmt()
338 dev->fmt = fmt; in mchp_i2s_mcc_set_dai_fmt()
350 dev_dbg(dev->dev, in mchp_i2s_mcc_set_dai_tdm_slot()
356 return -EINVAL; in mchp_i2s_mcc_set_dai_tdm_slot()
360 if (rx_mask != GENMASK(slots - 1, 0) || in mchp_i2s_mcc_set_dai_tdm_slot()
362 return -EINVAL; in mchp_i2s_mcc_set_dai_tdm_slot()
365 dev->tdm_slots = slots; in mchp_i2s_mcc_set_dai_tdm_slot()
366 dev->frame_length = slots * MCHP_I2MCC_TDM_SLOT_WIDTH; in mchp_i2s_mcc_set_dai_tdm_slot()
384 diff_rate = abs(rate - round_rate); in mchp_i2s_mcc_clk_get_rate_diff()
406 if (!dev->sysclk) in mchp_i2s_mcc_config_divs()
409 sysclk = dev->sysclk; in mchp_i2s_mcc_config_divs()
425 ret = mchp_i2s_mcc_clk_get_rate_diff(dev->gclk, clk_rate, in mchp_i2s_mcc_config_divs()
429 dev_err(dev->dev, "gclk error for rate %lu: %d", in mchp_i2s_mcc_config_divs()
433 dev_dbg(dev->dev, "found perfect rate on gclk: %lu\n", in mchp_i2s_mcc_config_divs()
439 ret = mchp_i2s_mcc_clk_get_rate_diff(dev->pclk, clk_rate, in mchp_i2s_mcc_config_divs()
443 dev_err(dev->dev, "pclk error for rate %lu: %d", in mchp_i2s_mcc_config_divs()
447 dev_dbg(dev->dev, "found perfect rate on pclk: %lu\n", in mchp_i2s_mcc_config_divs()
456 dev_err(dev->dev, "unable to change rate to clocks\n"); in mchp_i2s_mcc_config_divs()
457 return -EINVAL; in mchp_i2s_mcc_config_divs()
460 dev_dbg(dev->dev, "source CLK is %s with rate %lu, diff %lu\n", in mchp_i2s_mcc_config_divs()
461 best_clk == dev->pclk ? "pclk" : "gclk", in mchp_i2s_mcc_config_divs()
465 if (dev->sysclk) in mchp_i2s_mcc_config_divs()
469 if (best_clk == dev->gclk) in mchp_i2s_mcc_config_divs()
481 regmap_read(dev->regmap, MCHP_I2SMCC_SR, &sr); in mchp_i2s_mcc_is_running()
494 unsigned int frame_length = dev->frame_length; in mchp_i2s_mcc_hw_params()
498 bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); in mchp_i2s_mcc_hw_params()
500 dev_dbg(dev->dev, "%s() rate=%u format=%#x width=%u channels=%u\n", in mchp_i2s_mcc_hw_params()
504 switch (dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { in mchp_i2s_mcc_hw_params()
506 if (dev->tdm_slots) { in mchp_i2s_mcc_hw_params()
507 dev_err(dev->dev, "I2S with TDM is not supported\n"); in mchp_i2s_mcc_hw_params()
508 return -EINVAL; in mchp_i2s_mcc_hw_params()
513 if (dev->tdm_slots) { in mchp_i2s_mcc_hw_params()
514 dev_err(dev->dev, "Left-Justified with TDM is not supported\n"); in mchp_i2s_mcc_hw_params()
515 return -EINVAL; in mchp_i2s_mcc_hw_params()
523 dev_err(dev->dev, "unsupported bus format\n"); in mchp_i2s_mcc_hw_params()
524 return -EINVAL; in mchp_i2s_mcc_hw_params()
527 switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) { in mchp_i2s_mcc_hw_params()
531 if (dev->sysclk) in mchp_i2s_mcc_hw_params()
543 if (dev->sysclk) in mchp_i2s_mcc_hw_params()
544 dev_warn(dev->dev, "Unable to generate MCLK in Slave mode\n"); in mchp_i2s_mcc_hw_params()
547 dev_err(dev->dev, "unsupported master/slave mode\n"); in mchp_i2s_mcc_hw_params()
548 return -EINVAL; in mchp_i2s_mcc_hw_params()
551 if (dev->fmt & (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J)) { in mchp_i2s_mcc_hw_params()
562 dev_err(dev->dev, "unsupported number of audio channels\n"); in mchp_i2s_mcc_hw_params()
563 return -EINVAL; in mchp_i2s_mcc_hw_params()
568 } else if (dev->fmt & SND_SOC_DAIFMT_DSP_A) { in mchp_i2s_mcc_hw_params()
569 if (dev->tdm_slots) { in mchp_i2s_mcc_hw_params()
570 if (channels % 2 && channels * 2 <= dev->tdm_slots) { in mchp_i2s_mcc_hw_params()
572 * Duplicate data for even-numbered channels in mchp_i2s_mcc_hw_params()
573 * to odd-numbered channels in mchp_i2s_mcc_hw_params()
580 channels = dev->tdm_slots; in mchp_i2s_mcc_hw_params()
594 dev->playback.maxburst = 1 << (fls(channels) - 1); in mchp_i2s_mcc_hw_params()
596 dev->capture.maxburst = 1 << (fls(channels) - 1); in mchp_i2s_mcc_hw_params()
624 dev_err(dev->dev, "unsupported size/endianness for audio samples\n"); in mchp_i2s_mcc_hw_params()
625 return -EINVAL; in mchp_i2s_mcc_hw_params()
633 dev_err(dev->dev, in mchp_i2s_mcc_hw_params()
647 regmap_read(dev->regmap, MCHP_I2SMCC_MRA, &mra_cur); in mchp_i2s_mcc_hw_params()
648 regmap_read(dev->regmap, MCHP_I2SMCC_MRB, &mrb_cur); in mchp_i2s_mcc_hw_params()
650 return -EINVAL; in mchp_i2s_mcc_hw_params()
655 if (mra & MCHP_I2SMCC_MRA_SRCCLK_GCLK && !dev->gclk_use) { in mchp_i2s_mcc_hw_params()
657 ret = clk_set_rate(dev->gclk, rate); in mchp_i2s_mcc_hw_params()
659 dev_err(dev->dev, in mchp_i2s_mcc_hw_params()
665 ret = clk_prepare(dev->gclk); in mchp_i2s_mcc_hw_params()
667 dev_err(dev->dev, "unable to prepare GCLK: %d\n", ret); in mchp_i2s_mcc_hw_params()
670 dev->gclk_use = 1; in mchp_i2s_mcc_hw_params()
674 dev->channels = channels; in mchp_i2s_mcc_hw_params()
676 ret = regmap_write(dev->regmap, MCHP_I2SMCC_MRA, mra); in mchp_i2s_mcc_hw_params()
678 if (dev->gclk_use) { in mchp_i2s_mcc_hw_params()
679 clk_unprepare(dev->gclk); in mchp_i2s_mcc_hw_params()
680 dev->gclk_use = 0; in mchp_i2s_mcc_hw_params()
684 return regmap_write(dev->regmap, MCHP_I2SMCC_MRB, mrb); in mchp_i2s_mcc_hw_params()
691 bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); in mchp_i2s_mcc_hw_free()
695 err = wait_event_interruptible_timeout(dev->wq_txrdy, in mchp_i2s_mcc_hw_free()
696 dev->tx_rdy, in mchp_i2s_mcc_hw_free()
699 dev_warn_once(dev->dev, in mchp_i2s_mcc_hw_free()
701 regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, in mchp_i2s_mcc_hw_free()
702 MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)); in mchp_i2s_mcc_hw_free()
703 dev->tx_rdy = 1; in mchp_i2s_mcc_hw_free()
706 err = wait_event_interruptible_timeout(dev->wq_rxrdy, in mchp_i2s_mcc_hw_free()
707 dev->rx_rdy, in mchp_i2s_mcc_hw_free()
710 dev_warn_once(dev->dev, in mchp_i2s_mcc_hw_free()
712 regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, in mchp_i2s_mcc_hw_free()
713 MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)); in mchp_i2s_mcc_hw_free()
714 dev->rx_rdy = 1; in mchp_i2s_mcc_hw_free()
719 regmap_write(dev->regmap, MCHP_I2SMCC_CR, MCHP_I2SMCC_CR_CKDIS); in mchp_i2s_mcc_hw_free()
721 if (dev->gclk_running) { in mchp_i2s_mcc_hw_free()
722 clk_disable(dev->gclk); in mchp_i2s_mcc_hw_free()
723 dev->gclk_running = 0; in mchp_i2s_mcc_hw_free()
725 if (dev->gclk_use) { in mchp_i2s_mcc_hw_free()
726 clk_unprepare(dev->gclk); in mchp_i2s_mcc_hw_free()
727 dev->gclk_use = 0; in mchp_i2s_mcc_hw_free()
738 bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); in mchp_i2s_mcc_trigger()
756 regmap_read(dev->regmap, MCHP_I2SMCC_SR, &sr); in mchp_i2s_mcc_trigger()
759 dev->tx_rdy = 0; in mchp_i2s_mcc_trigger()
764 iera = MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels); in mchp_i2s_mcc_trigger()
767 dev->rx_rdy = 0; in mchp_i2s_mcc_trigger()
772 iera = MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels); in mchp_i2s_mcc_trigger()
776 return -EINVAL; in mchp_i2s_mcc_trigger()
779 if ((cr & MCHP_I2SMCC_CR_CKEN) && dev->gclk_use && in mchp_i2s_mcc_trigger()
780 !dev->gclk_running) { in mchp_i2s_mcc_trigger()
781 err = clk_enable(dev->gclk); in mchp_i2s_mcc_trigger()
783 dev_err_once(dev->dev, "failed to enable GCLK: %d\n", in mchp_i2s_mcc_trigger()
786 dev->gclk_running = 1; in mchp_i2s_mcc_trigger()
790 regmap_write(dev->regmap, MCHP_I2SMCC_IERA, iera); in mchp_i2s_mcc_trigger()
791 regmap_write(dev->regmap, MCHP_I2SMCC_CR, cr); in mchp_i2s_mcc_trigger()
803 return regmap_write(dev->regmap, MCHP_I2SMCC_CR, in mchp_i2s_mcc_startup()
825 init_waitqueue_head(&dev->wq_txrdy); in mchp_i2s_mcc_dai_probe()
826 init_waitqueue_head(&dev->wq_rxrdy); in mchp_i2s_mcc_dai_probe()
827 dev->tx_rdy = 1; in mchp_i2s_mcc_dai_probe()
828 dev->rx_rdy = 1; in mchp_i2s_mcc_dai_probe()
830 snd_soc_dai_init_dma_data(dai, &dev->playback, &dev->capture); in mchp_i2s_mcc_dai_probe()
848 .stream_name = "I2SMCC-Playback",
855 .stream_name = "I2SMCC-Capture",
868 .name = "mchp-i2s-mcc",
874 .compatible = "microchip,sam9x60-i2smcc",
891 dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); in mchp_i2s_mcc_probe()
893 return -ENOMEM; in mchp_i2s_mcc_probe()
896 base = devm_ioremap_resource(&pdev->dev, mem); in mchp_i2s_mcc_probe()
900 regmap = devm_regmap_init_mmio(&pdev->dev, base, in mchp_i2s_mcc_probe()
909 err = devm_request_irq(&pdev->dev, irq, mchp_i2s_mcc_interrupt, 0, in mchp_i2s_mcc_probe()
910 dev_name(&pdev->dev), dev); in mchp_i2s_mcc_probe()
914 dev->pclk = devm_clk_get(&pdev->dev, "pclk"); in mchp_i2s_mcc_probe()
915 if (IS_ERR(dev->pclk)) { in mchp_i2s_mcc_probe()
916 err = PTR_ERR(dev->pclk); in mchp_i2s_mcc_probe()
917 dev_err(&pdev->dev, in mchp_i2s_mcc_probe()
923 dev->gclk = devm_clk_get(&pdev->dev, "gclk"); in mchp_i2s_mcc_probe()
924 if (IS_ERR(dev->gclk)) { in mchp_i2s_mcc_probe()
925 if (PTR_ERR(dev->gclk) == -EPROBE_DEFER) in mchp_i2s_mcc_probe()
926 return -EPROBE_DEFER; in mchp_i2s_mcc_probe()
927 dev_warn(&pdev->dev, in mchp_i2s_mcc_probe()
929 dev->gclk = NULL; in mchp_i2s_mcc_probe()
932 dev->dev = &pdev->dev; in mchp_i2s_mcc_probe()
933 dev->regmap = regmap; in mchp_i2s_mcc_probe()
936 err = clk_prepare_enable(dev->pclk); in mchp_i2s_mcc_probe()
938 dev_err(&pdev->dev, in mchp_i2s_mcc_probe()
943 err = devm_snd_soc_register_component(&pdev->dev, in mchp_i2s_mcc_probe()
947 dev_err(&pdev->dev, "failed to register DAI: %d\n", err); in mchp_i2s_mcc_probe()
948 clk_disable_unprepare(dev->pclk); in mchp_i2s_mcc_probe()
952 dev->playback.addr = (dma_addr_t)mem->start + MCHP_I2SMCC_THR; in mchp_i2s_mcc_probe()
953 dev->capture.addr = (dma_addr_t)mem->start + MCHP_I2SMCC_RHR; in mchp_i2s_mcc_probe()
955 err = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); in mchp_i2s_mcc_probe()
957 dev_err(&pdev->dev, "failed to register PCM: %d\n", err); in mchp_i2s_mcc_probe()
958 clk_disable_unprepare(dev->pclk); in mchp_i2s_mcc_probe()
963 regmap_read(dev->regmap, MCHP_I2SMCC_VERSION, &version); in mchp_i2s_mcc_probe()
964 dev_info(&pdev->dev, "hw version: %#lx\n", in mchp_i2s_mcc_probe()
974 clk_disable_unprepare(dev->pclk); in mchp_i2s_mcc_remove()
989 MODULE_DESCRIPTION("Microchip I2S Multi-Channel Controller driver");