Lines Matching +full:sama7g5 +full:- +full:spdifrx

1 // SPDX-License-Identifier: GPL-2.0
21 * ---- S/PDIF Receiver Controller Register map ----
45 * ---- Control Register (Write-only) ----
50 * ---- Mode Register (Read/Write) ----
77 (((6 - (width) / 4) << 4) & SPDIFRX_MR_DATAWIDTH_MASK)
95 * ---- Interrupt Enable/Disable/Mask/Status Register (Write/Read-only) ----
113 * ---- Receiver Status Register (Read/Write) ----
125 * ---- Version Register (Read-only) ----
253 * struct mchp_spdifrx_ch_stat: MCHP SPDIFRX channel status
263 * struct mchp_spdifrx_user_data: MCHP SPDIFRX user data
273 * struct mchp_spdifrx_mixer_control: MCHP SPDIFRX mixer control data structure
289 * struct mchp_spdifrx_dev: MCHP SPDIFRX device data structure
313 struct mchp_spdifrx_mixer_control *ctrl = &dev->control; in mchp_spdifrx_channel_status_read()
314 u8 *ch_stat = &ctrl->ch_stat[channel].data[0]; in mchp_spdifrx_channel_status_read()
318 for (i = 0; i < ARRAY_SIZE(ctrl->ch_stat[channel].data) / 4; i++) { in mchp_spdifrx_channel_status_read()
319 regmap_read(dev->regmap, SPDIFRX_CHSR(channel, i), &val); in mchp_spdifrx_channel_status_read()
330 struct mchp_spdifrx_mixer_control *ctrl = &dev->control; in mchp_spdifrx_channel_user_data_read()
331 u8 *user_data = &ctrl->user_data[channel].data[0]; in mchp_spdifrx_channel_user_data_read()
335 for (i = 0; i < ARRAY_SIZE(ctrl->user_data[channel].data) / 4; i++) { in mchp_spdifrx_channel_user_data_read()
336 regmap_read(dev->regmap, SPDIFRX_CHUD(channel, i), &val); in mchp_spdifrx_channel_user_data_read()
347 struct mchp_spdifrx_mixer_control *ctrl = &dev->control; in mchp_spdif_interrupt()
352 regmap_read(dev->regmap, SPDIFRX_ISR, &sr); in mchp_spdif_interrupt()
353 regmap_read(dev->regmap, SPDIFRX_IMR, &imr); in mchp_spdif_interrupt()
355 dev_dbg(dev->dev, "ISR: %#x, IMR: %#x, pending: %#x\n", sr, imr, in mchp_spdif_interrupt()
364 complete(&ctrl->user_data[ch].done); in mchp_spdif_interrupt()
366 regmap_write(dev->regmap, SPDIFRX_IDR, SPDIFRX_IR_BLOCKEND); in mchp_spdif_interrupt()
373 complete(&ctrl->ch_stat[ch].done); in mchp_spdif_interrupt()
374 regmap_write(dev->regmap, SPDIFRX_IDR, SPDIFRX_IR_CSC(ch)); in mchp_spdif_interrupt()
380 dev_warn(dev->dev, "Overrun detected\n"); in mchp_spdif_interrupt()
397 mutex_lock(&dev->mlock); in mchp_spdifrx_trigger()
399 regmap_write(dev->regmap, SPDIFRX_IER, SPDIFRX_IR_OVERRUN); in mchp_spdifrx_trigger()
402 regmap_update_bits(dev->regmap, SPDIFRX_MR, SPDIFRX_MR_RXEN_MASK, in mchp_spdifrx_trigger()
404 dev->trigger_enabled = true; in mchp_spdifrx_trigger()
405 mutex_unlock(&dev->mlock); in mchp_spdifrx_trigger()
410 mutex_lock(&dev->mlock); in mchp_spdifrx_trigger()
412 regmap_write(dev->regmap, SPDIFRX_IDR, SPDIFRX_IR_OVERRUN); in mchp_spdifrx_trigger()
415 regmap_update_bits(dev->regmap, SPDIFRX_MR, SPDIFRX_MR_RXEN_MASK, in mchp_spdifrx_trigger()
417 dev->trigger_enabled = false; in mchp_spdifrx_trigger()
418 mutex_unlock(&dev->mlock); in mchp_spdifrx_trigger()
421 ret = -EINVAL; in mchp_spdifrx_trigger()
435 dev_dbg(dev->dev, "%s() rate=%u format=%#x width=%u channels=%u\n", in mchp_spdifrx_hw_params()
439 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { in mchp_spdifrx_hw_params()
440 dev_err(dev->dev, "Playback is not supported\n"); in mchp_spdifrx_hw_params()
441 return -EINVAL; in mchp_spdifrx_hw_params()
445 dev_err(dev->dev, "unsupported number of channels: %d\n", in mchp_spdifrx_hw_params()
447 return -EINVAL; in mchp_spdifrx_hw_params()
464 dev_err(dev->dev, "unsupported PCM format: %d\n", in mchp_spdifrx_hw_params()
466 return -EINVAL; in mchp_spdifrx_hw_params()
469 mutex_lock(&dev->mlock); in mchp_spdifrx_hw_params()
470 if (dev->trigger_enabled) { in mchp_spdifrx_hw_params()
471 dev_err(dev->dev, "PCM already running\n"); in mchp_spdifrx_hw_params()
472 ret = -EBUSY; in mchp_spdifrx_hw_params()
477 clk_disable_unprepare(dev->gclk); in mchp_spdifrx_hw_params()
479 ret = clk_set_min_rate(dev->gclk, params_rate(params) * in mchp_spdifrx_hw_params()
482 dev_err(dev->dev, in mchp_spdifrx_hw_params()
486 clk_prepare_enable(dev->gclk); in mchp_spdifrx_hw_params()
489 ret = clk_prepare_enable(dev->gclk); in mchp_spdifrx_hw_params()
491 dev_err(dev->dev, "unable to enable gclk: %d\n", ret); in mchp_spdifrx_hw_params()
495 dev_dbg(dev->dev, "GCLK range min set to %d\n", in mchp_spdifrx_hw_params()
498 ret = regmap_write(dev->regmap, SPDIFRX_MR, mr); in mchp_spdifrx_hw_params()
501 mutex_unlock(&dev->mlock); in mchp_spdifrx_hw_params()
521 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; in mchp_spdifrx_info()
522 uinfo->count = 1; in mchp_spdifrx_info()
531 struct mchp_spdifrx_mixer_control *ctrl = &dev->control; in mchp_spdifrx_cs_get()
532 struct mchp_spdifrx_ch_stat *ch_stat = &ctrl->ch_stat[channel]; in mchp_spdifrx_cs_get()
535 mutex_lock(&dev->mlock); in mchp_spdifrx_cs_get()
537 ret = pm_runtime_resume_and_get(dev->dev); in mchp_spdifrx_cs_get()
544 * timeout check the dev->trigger_enabled. in mchp_spdifrx_cs_get()
547 * - if the receiver is enabled CSC IRQ will update the data in software in mchp_spdifrx_cs_get()
548 * caches (ch_stat->data) in mchp_spdifrx_cs_get()
549 * - otherwise we just update it here the software caches with latest in mchp_spdifrx_cs_get()
555 if (dev->trigger_enabled) { in mchp_spdifrx_cs_get()
556 reinit_completion(&ch_stat->done); in mchp_spdifrx_cs_get()
557 regmap_write(dev->regmap, SPDIFRX_IER, SPDIFRX_IR_CSC(channel)); in mchp_spdifrx_cs_get()
559 ret = wait_for_completion_interruptible_timeout(&ch_stat->done, in mchp_spdifrx_cs_get()
563 dev_dbg(dev->dev, "channel status for channel %d timeout\n", in mchp_spdifrx_cs_get()
565 regmap_write(dev->regmap, SPDIFRX_IDR, SPDIFRX_IR_CSC(channel)); in mchp_spdifrx_cs_get()
566 ret = ret ? : -ETIMEDOUT; in mchp_spdifrx_cs_get()
576 memcpy(uvalue->value.iec958.status, ch_stat->data, in mchp_spdifrx_cs_get()
577 sizeof(ch_stat->data)); in mchp_spdifrx_cs_get()
580 pm_runtime_mark_last_busy(dev->dev); in mchp_spdifrx_cs_get()
581 pm_runtime_put_autosuspend(dev->dev); in mchp_spdifrx_cs_get()
583 mutex_unlock(&dev->mlock); in mchp_spdifrx_cs_get()
608 memset(uvalue->value.iec958.status, 0xff, in mchp_spdifrx_cs_mask()
609 sizeof(uvalue->value.iec958.status)); in mchp_spdifrx_cs_mask()
618 struct mchp_spdifrx_mixer_control *ctrl = &dev->control; in mchp_spdifrx_subcode_ch_get()
619 struct mchp_spdifrx_user_data *user_data = &ctrl->user_data[channel]; in mchp_spdifrx_subcode_ch_get()
622 mutex_lock(&dev->mlock); in mchp_spdifrx_subcode_ch_get()
624 ret = pm_runtime_resume_and_get(dev->dev); in mchp_spdifrx_subcode_ch_get()
631 * check here the dev->trigger_enabled flag. in mchp_spdifrx_subcode_ch_get()
634 * - if the receiver is enabled we need to wait for blockend IRQ to read in mchp_spdifrx_subcode_ch_get()
636 * - otherwise reading the SPDIFRX_CHUD() registers is enough. in mchp_spdifrx_subcode_ch_get()
639 if (dev->trigger_enabled) { in mchp_spdifrx_subcode_ch_get()
640 reinit_completion(&user_data->done); in mchp_spdifrx_subcode_ch_get()
641 regmap_write(dev->regmap, SPDIFRX_IER, SPDIFRX_IR_BLOCKEND); in mchp_spdifrx_subcode_ch_get()
642 ret = wait_for_completion_interruptible_timeout(&user_data->done, in mchp_spdifrx_subcode_ch_get()
646 dev_dbg(dev->dev, "user data for channel %d timeout\n", in mchp_spdifrx_subcode_ch_get()
648 regmap_write(dev->regmap, SPDIFRX_IDR, SPDIFRX_IR_BLOCKEND); in mchp_spdifrx_subcode_ch_get()
649 ret = ret ? : -ETIMEDOUT; in mchp_spdifrx_subcode_ch_get()
659 memcpy(uvalue->value.iec958.subcode, user_data->data, in mchp_spdifrx_subcode_ch_get()
660 sizeof(user_data->data)); in mchp_spdifrx_subcode_ch_get()
663 pm_runtime_mark_last_busy(dev->dev); in mchp_spdifrx_subcode_ch_get()
664 pm_runtime_put_autosuspend(dev->dev); in mchp_spdifrx_subcode_ch_get()
666 mutex_unlock(&dev->mlock); in mchp_spdifrx_subcode_ch_get()
691 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; in mchp_spdifrx_boolean_info()
692 uinfo->count = 1; in mchp_spdifrx_boolean_info()
693 uinfo->value.integer.min = 0; in mchp_spdifrx_boolean_info()
694 uinfo->value.integer.max = 1; in mchp_spdifrx_boolean_info()
704 struct mchp_spdifrx_mixer_control *ctrl = &dev->control; in mchp_spdifrx_ulock_get()
707 bool ulock_old = ctrl->ulock; in mchp_spdifrx_ulock_get()
709 mutex_lock(&dev->mlock); in mchp_spdifrx_ulock_get()
711 ret = pm_runtime_resume_and_get(dev->dev); in mchp_spdifrx_ulock_get()
718 * dev->trigger_enabled here to return a real status. in mchp_spdifrx_ulock_get()
720 if (dev->trigger_enabled) { in mchp_spdifrx_ulock_get()
721 regmap_read(dev->regmap, SPDIFRX_RSR, &val); in mchp_spdifrx_ulock_get()
722 ctrl->ulock = !(val & SPDIFRX_RSR_ULOCK); in mchp_spdifrx_ulock_get()
724 ctrl->ulock = 0; in mchp_spdifrx_ulock_get()
727 uvalue->value.integer.value[0] = ctrl->ulock; in mchp_spdifrx_ulock_get()
729 pm_runtime_mark_last_busy(dev->dev); in mchp_spdifrx_ulock_get()
730 pm_runtime_put_autosuspend(dev->dev); in mchp_spdifrx_ulock_get()
732 mutex_unlock(&dev->mlock); in mchp_spdifrx_ulock_get()
734 return ulock_old != ctrl->ulock; in mchp_spdifrx_ulock_get()
742 struct mchp_spdifrx_mixer_control *ctrl = &dev->control; in mchp_spdifrx_badf_get()
745 bool badf_old = ctrl->badf; in mchp_spdifrx_badf_get()
747 mutex_lock(&dev->mlock); in mchp_spdifrx_badf_get()
749 ret = pm_runtime_resume_and_get(dev->dev); in mchp_spdifrx_badf_get()
756 * dev->trigger_enabled here to return a real status. in mchp_spdifrx_badf_get()
758 if (dev->trigger_enabled) { in mchp_spdifrx_badf_get()
759 regmap_read(dev->regmap, SPDIFRX_RSR, &val); in mchp_spdifrx_badf_get()
760 ctrl->badf = !!(val & SPDIFRX_RSR_BADF); in mchp_spdifrx_badf_get()
762 ctrl->badf = 0; in mchp_spdifrx_badf_get()
765 pm_runtime_mark_last_busy(dev->dev); in mchp_spdifrx_badf_get()
766 pm_runtime_put_autosuspend(dev->dev); in mchp_spdifrx_badf_get()
768 mutex_unlock(&dev->mlock); in mchp_spdifrx_badf_get()
770 uvalue->value.integer.value[0] = ctrl->badf; in mchp_spdifrx_badf_get()
772 return badf_old != ctrl->badf; in mchp_spdifrx_badf_get()
780 struct mchp_spdifrx_mixer_control *ctrl = &dev->control; in mchp_spdifrx_signal_get()
783 bool signal_old = ctrl->signal; in mchp_spdifrx_signal_get()
785 mutex_lock(&dev->mlock); in mchp_spdifrx_signal_get()
787 ret = pm_runtime_resume_and_get(dev->dev); in mchp_spdifrx_signal_get()
796 if (!dev->trigger_enabled) { in mchp_spdifrx_signal_get()
797 regmap_update_bits(dev->regmap, SPDIFRX_MR, SPDIFRX_MR_RXEN_MASK, in mchp_spdifrx_signal_get()
801 while (--loops) { in mchp_spdifrx_signal_get()
802 regmap_read(dev->regmap, SPDIFRX_RSR, &val); in mchp_spdifrx_signal_get()
808 regmap_update_bits(dev->regmap, SPDIFRX_MR, SPDIFRX_MR_RXEN_MASK, in mchp_spdifrx_signal_get()
811 regmap_read(dev->regmap, SPDIFRX_RSR, &val); in mchp_spdifrx_signal_get()
814 pm_runtime_mark_last_busy(dev->dev); in mchp_spdifrx_signal_get()
815 pm_runtime_put_autosuspend(dev->dev); in mchp_spdifrx_signal_get()
818 mutex_unlock(&dev->mlock); in mchp_spdifrx_signal_get()
821 ctrl->signal = !(val & SPDIFRX_RSR_NOSIGNAL); in mchp_spdifrx_signal_get()
823 ctrl->signal = 0; in mchp_spdifrx_signal_get()
824 uvalue->value.integer.value[0] = ctrl->signal; in mchp_spdifrx_signal_get()
826 return signal_old != ctrl->signal; in mchp_spdifrx_signal_get()
832 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; in mchp_spdifrx_rate_info()
833 uinfo->count = 1; in mchp_spdifrx_rate_info()
834 uinfo->value.integer.min = 0; in mchp_spdifrx_rate_info()
835 uinfo->value.integer.max = 192000; in mchp_spdifrx_rate_info()
849 mutex_lock(&dev->mlock); in mchp_spdifrx_rate_get()
851 ret = pm_runtime_resume_and_get(dev->dev); in mchp_spdifrx_rate_get()
858 * dev->trigger_enabled here to return a real status. in mchp_spdifrx_rate_get()
860 if (dev->trigger_enabled) { in mchp_spdifrx_rate_get()
861 regmap_read(dev->regmap, SPDIFRX_RSR, &val); in mchp_spdifrx_rate_get()
864 ucontrol->value.integer.value[0] = 0; in mchp_spdifrx_rate_get()
869 ucontrol->value.integer.value[0] = 0; in mchp_spdifrx_rate_get()
873 rate = clk_get_rate(dev->gclk); in mchp_spdifrx_rate_get()
875 ucontrol->value.integer.value[0] = rate / (32 * SPDIFRX_RSR_IFS(val)); in mchp_spdifrx_rate_get()
878 pm_runtime_mark_last_busy(dev->dev); in mchp_spdifrx_rate_get()
879 pm_runtime_put_autosuspend(dev->dev); in mchp_spdifrx_rate_get()
881 mutex_unlock(&dev->mlock); in mchp_spdifrx_rate_get()
970 struct mchp_spdifrx_mixer_control *ctrl = &dev->control; in mchp_spdifrx_dai_probe()
973 snd_soc_dai_init_dma_data(dai, NULL, &dev->capture); in mchp_spdifrx_dai_probe()
976 regmap_write(dev->regmap, SPDIFRX_CR, SPDIFRX_CR_SWRST); in mchp_spdifrx_dai_probe()
979 regmap_write(dev->regmap, SPDIFRX_MR, in mchp_spdifrx_dai_probe()
986 init_completion(&ctrl->ch_stat[ch].done); in mchp_spdifrx_dai_probe()
987 init_completion(&ctrl->user_data[ch].done); in mchp_spdifrx_dai_probe()
1002 regmap_write(dev->regmap, SPDIFRX_IDR, GENMASK(14, 0)); in mchp_spdifrx_dai_remove()
1015 .name = "mchp-spdifrx",
1027 .name = "mchp-spdifrx",
1033 .compatible = "microchip,sama7g5-spdifrx",
1041 struct mchp_spdifrx_dev *spdifrx = dev_get_drvdata(dev); in mchp_spdifrx_runtime_suspend() local
1043 regcache_cache_only(spdifrx->regmap, true); in mchp_spdifrx_runtime_suspend()
1044 clk_disable_unprepare(spdifrx->gclk); in mchp_spdifrx_runtime_suspend()
1045 clk_disable_unprepare(spdifrx->pclk); in mchp_spdifrx_runtime_suspend()
1052 struct mchp_spdifrx_dev *spdifrx = dev_get_drvdata(dev); in mchp_spdifrx_runtime_resume() local
1055 ret = clk_prepare_enable(spdifrx->pclk); in mchp_spdifrx_runtime_resume()
1059 ret = clk_prepare_enable(spdifrx->gclk); in mchp_spdifrx_runtime_resume()
1063 regcache_cache_only(spdifrx->regmap, false); in mchp_spdifrx_runtime_resume()
1064 regcache_mark_dirty(spdifrx->regmap); in mchp_spdifrx_runtime_resume()
1065 ret = regcache_sync(spdifrx->regmap); in mchp_spdifrx_runtime_resume()
1067 regcache_cache_only(spdifrx->regmap, true); in mchp_spdifrx_runtime_resume()
1068 clk_disable_unprepare(spdifrx->gclk); in mchp_spdifrx_runtime_resume()
1070 clk_disable_unprepare(spdifrx->pclk); in mchp_spdifrx_runtime_resume()
1092 dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); in mchp_spdifrx_probe()
1094 return -ENOMEM; in mchp_spdifrx_probe()
1101 regmap = devm_regmap_init_mmio(&pdev->dev, base, in mchp_spdifrx_probe()
1111 err = devm_request_irq(&pdev->dev, irq, mchp_spdif_interrupt, 0, in mchp_spdifrx_probe()
1112 dev_name(&pdev->dev), dev); in mchp_spdifrx_probe()
1117 dev->pclk = devm_clk_get(&pdev->dev, "pclk"); in mchp_spdifrx_probe()
1118 if (IS_ERR(dev->pclk)) { in mchp_spdifrx_probe()
1119 err = PTR_ERR(dev->pclk); in mchp_spdifrx_probe()
1120 dev_err(&pdev->dev, "failed to get the peripheral clock: %d\n", in mchp_spdifrx_probe()
1126 dev->gclk = devm_clk_get(&pdev->dev, "gclk"); in mchp_spdifrx_probe()
1127 if (IS_ERR(dev->gclk)) { in mchp_spdifrx_probe()
1128 err = PTR_ERR(dev->gclk); in mchp_spdifrx_probe()
1129 dev_err(&pdev->dev, in mchp_spdifrx_probe()
1141 clk_set_min_rate(dev->gclk, 48000 * SPDIFRX_GCLK_RATIO_MIN + 1); in mchp_spdifrx_probe()
1143 mutex_init(&dev->mlock); in mchp_spdifrx_probe()
1145 dev->dev = &pdev->dev; in mchp_spdifrx_probe()
1146 dev->regmap = regmap; in mchp_spdifrx_probe()
1149 pm_runtime_enable(dev->dev); in mchp_spdifrx_probe()
1150 if (!pm_runtime_enabled(dev->dev)) { in mchp_spdifrx_probe()
1151 err = mchp_spdifrx_runtime_resume(dev->dev); in mchp_spdifrx_probe()
1156 dev->capture.addr = (dma_addr_t)mem->start + SPDIFRX_RHR; in mchp_spdifrx_probe()
1157 dev->capture.maxburst = 1; in mchp_spdifrx_probe()
1159 err = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); in mchp_spdifrx_probe()
1161 dev_err(&pdev->dev, "failed to register PCM: %d\n", err); in mchp_spdifrx_probe()
1165 err = devm_snd_soc_register_component(&pdev->dev, in mchp_spdifrx_probe()
1169 dev_err(&pdev->dev, "fail to register dai\n"); in mchp_spdifrx_probe()
1174 dev_info(&pdev->dev, "hw version: %#lx\n", vers & SPDIFRX_VERSION_MASK); in mchp_spdifrx_probe()
1179 if (!pm_runtime_status_suspended(dev->dev)) in mchp_spdifrx_probe()
1180 mchp_spdifrx_runtime_suspend(dev->dev); in mchp_spdifrx_probe()
1182 pm_runtime_disable(dev->dev); in mchp_spdifrx_probe()
1190 pm_runtime_disable(dev->dev); in mchp_spdifrx_remove()
1191 if (!pm_runtime_status_suspended(dev->dev)) in mchp_spdifrx_remove()
1192 mchp_spdifrx_runtime_suspend(dev->dev); in mchp_spdifrx_remove()