Lines Matching +full:clock +full:- +full:master

1 // SPDX-License-Identifier: GPL-2.0-or-later
12 #include <linux/dma-mapping.h>
14 #include <linux/clk-provider.h>
23 #include "mxs-saif.h"
31 * SAIF is a little different with other normal SOC DAIs on clock using.
33 * For MXS, two SAIF modules are instantiated on-chip.
34 * Each SAIF has a set of clock pins and can be operating in master
35 * mode simultaneously if they are connected to different off-chip codecs.
36 * Also, one of the two SAIFs can master or drive the clock pins while the
37 * other SAIF, in slave mode, receives clocking from the master SAIF.
40 * We abstract this as each saif has a master, the master could be
42 * to know the different clkmux. Saif only needs to know who is its master
43 * and operating its master to generate the proper clock rate for it.
44 * The master id is provided in mach-specific layer according to different
55 saif->mclk = freq; in mxs_saif_set_dai_sysclk()
58 return -EINVAL; in mxs_saif_set_dai_sysclk()
65 * is provided by other SAIF, we provide a interface here to get its master
67 * Note that the master could be itself.
71 return mxs_saif[saif->master_id]; in mxs_saif_get_master()
75 * Set SAIF clock and MCLK
85 dev_dbg(saif->dev, "mclk %d rate %d\n", mclk, rate); in mxs_saif_set_clk()
87 /* Set master saif to generate proper clock */ in mxs_saif_set_clk()
90 return -EINVAL; in mxs_saif_set_clk()
92 dev_dbg(saif->dev, "master saif%d\n", master_saif->id); in mxs_saif_set_clk()
95 if (master_saif->ongoing && rate != master_saif->cur_rate) { in mxs_saif_set_clk()
96 dev_err(saif->dev, in mxs_saif_set_clk()
97 "can not change clock, master saif%d(rate %d) is ongoing\n", in mxs_saif_set_clk()
98 master_saif->id, master_saif->cur_rate); in mxs_saif_set_clk()
99 return -EINVAL; in mxs_saif_set_clk()
102 scr = __raw_readl(master_saif->base + SAIF_CTRL); in mxs_saif_set_clk()
107 * Set SAIF clock in mxs_saif_set_clk()
109 * The SAIF clock should be either 384*fs or 512*fs. in mxs_saif_set_clk()
111 * For 256x, 128x, 64x, and 32x sub-rates, set saif clk as 512*fs. in mxs_saif_set_clk()
112 * For 192x, 96x, and 48x sub-rates, set saif clk as 384*fs. in mxs_saif_set_clk()
116 ret = clk_prepare_enable(master_saif->clk); in mxs_saif_set_clk()
120 if (master_saif->mclk_in_use) { in mxs_saif_set_clk()
128 ret = clk_set_rate(master_saif->clk, 512 * rate); in mxs_saif_set_clk()
135 ret = clk_set_rate(master_saif->clk, 384 * rate); in mxs_saif_set_clk()
138 /* SAIF MCLK should be a sub-rate of 512x or 384x */ in mxs_saif_set_clk()
139 clk_disable_unprepare(master_saif->clk); in mxs_saif_set_clk()
140 return -EINVAL; in mxs_saif_set_clk()
143 ret = clk_set_rate(master_saif->clk, 512 * rate); in mxs_saif_set_clk()
147 clk_disable_unprepare(master_saif->clk); in mxs_saif_set_clk()
152 master_saif->cur_rate = rate; in mxs_saif_set_clk()
154 if (!master_saif->mclk_in_use) { in mxs_saif_set_clk()
155 __raw_writel(scr, master_saif->base + SAIF_CTRL); in mxs_saif_set_clk()
160 * Program the over-sample rate for MCLK output in mxs_saif_set_clk()
194 return -EINVAL; in mxs_saif_set_clk()
197 __raw_writel(scr, master_saif->base + SAIF_CTRL); in mxs_saif_set_clk()
211 return -EINVAL; in mxs_saif_put_mclk()
213 stat = __raw_readl(saif->base + SAIF_STAT); in mxs_saif_put_mclk()
215 dev_err(saif->dev, "error: busy\n"); in mxs_saif_put_mclk()
216 return -EBUSY; in mxs_saif_put_mclk()
219 clk_disable_unprepare(saif->clk); in mxs_saif_put_mclk()
223 saif->base + SAIF_CTRL + MXS_SET_ADDR); in mxs_saif_put_mclk()
225 saif->base + SAIF_CTRL + MXS_CLR_ADDR); in mxs_saif_put_mclk()
227 saif->mclk_in_use = 0; in mxs_saif_put_mclk()
233 * Get MCLK and set clock rate, then enable it
247 return -EINVAL; in mxs_saif_get_mclk()
251 saif->base + SAIF_CTRL + MXS_CLR_ADDR); in mxs_saif_get_mclk()
255 saif->base + SAIF_CTRL + MXS_CLR_ADDR); in mxs_saif_get_mclk()
259 dev_err(saif->dev, "can not get mclk from a non-master saif\n"); in mxs_saif_get_mclk()
260 return -EINVAL; in mxs_saif_get_mclk()
263 stat = __raw_readl(saif->base + SAIF_STAT); in mxs_saif_get_mclk()
265 dev_err(saif->dev, "error: busy\n"); in mxs_saif_get_mclk()
266 return -EBUSY; in mxs_saif_get_mclk()
269 saif->mclk_in_use = 1; in mxs_saif_get_mclk()
274 ret = clk_prepare_enable(saif->clk); in mxs_saif_get_mclk()
280 saif->base + SAIF_CTRL + MXS_SET_ADDR); in mxs_saif_get_mclk()
296 stat = __raw_readl(saif->base + SAIF_STAT); in mxs_saif_set_dai_fmt()
298 dev_err(cpu_dai->dev, "error: busy\n"); in mxs_saif_set_dai_fmt()
299 return -EBUSY; in mxs_saif_set_dai_fmt()
305 if (saif->id != saif->master_id) { in mxs_saif_set_dai_fmt()
307 saif->base + SAIF_CTRL + MXS_CLR_ADDR); in mxs_saif_set_dai_fmt()
309 saif->base + SAIF_CTRL + MXS_CLR_ADDR); in mxs_saif_set_dai_fmt()
312 scr0 = __raw_readl(saif->base + SAIF_CTRL); in mxs_saif_set_dai_fmt()
331 return -EINVAL; in mxs_saif_set_dai_fmt()
334 /* DAI clock inversion */ in mxs_saif_set_dai_fmt()
355 * Note: We simply just support master mode since SAIF TX can only in mxs_saif_set_dai_fmt()
356 * work as master. in mxs_saif_set_dai_fmt()
357 * Here the master is relative to codec side. in mxs_saif_set_dai_fmt()
363 if (saif->id == saif->master_id) in mxs_saif_set_dai_fmt()
368 __raw_writel(scr | scr0, saif->base + SAIF_CTRL); in mxs_saif_set_dai_fmt()
371 return -EINVAL; in mxs_saif_set_dai_fmt()
383 /* clear error status to 0 for each re-open */ in mxs_saif_startup()
384 saif->fifo_underrun = 0; in mxs_saif_startup()
385 saif->fifo_overrun = 0; in mxs_saif_startup()
389 saif->base + SAIF_CTRL + MXS_CLR_ADDR); in mxs_saif_startup()
391 /* clear clock gate */ in mxs_saif_startup()
393 saif->base + SAIF_CTRL + MXS_CLR_ADDR); in mxs_saif_startup()
395 ret = clk_prepare(saif->clk); in mxs_saif_startup()
407 clk_unprepare(saif->clk); in mxs_saif_shutdown()
425 return -EINVAL; in mxs_saif_hw_params()
428 if (!saif->mclk && saif->mclk_in_use) { in mxs_saif_hw_params()
429 dev_err(cpu_dai->dev, "set mclk first\n"); in mxs_saif_hw_params()
430 return -EINVAL; in mxs_saif_hw_params()
433 stat = __raw_readl(saif->base + SAIF_STAT); in mxs_saif_hw_params()
434 if (!saif->mclk_in_use && (stat & BM_SAIF_STAT_BUSY)) { in mxs_saif_hw_params()
435 dev_err(cpu_dai->dev, "error: busy\n"); in mxs_saif_hw_params()
436 return -EBUSY; in mxs_saif_hw_params()
441 * If mclk is used, we also set mclk, if not, saif->mclk is in mxs_saif_hw_params()
444 ret = mxs_saif_set_clk(saif, saif->mclk, params_rate(params)); in mxs_saif_hw_params()
446 dev_err(cpu_dai->dev, "unable to get proper clk\n"); in mxs_saif_hw_params()
452 * Set an initial clock rate for the saif internal logic to work in mxs_saif_hw_params()
455 * basic clock which should be fast enough for the internal in mxs_saif_hw_params()
458 ret = clk_enable(saif->clk); in mxs_saif_hw_params()
462 ret = clk_set_rate(saif->clk, 24000000); in mxs_saif_hw_params()
463 clk_disable(saif->clk); in mxs_saif_hw_params()
467 ret = clk_prepare(master_saif->clk); in mxs_saif_hw_params()
472 scr = __raw_readl(saif->base + SAIF_CTRL); in mxs_saif_hw_params()
489 return -EINVAL; in mxs_saif_hw_params()
493 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { in mxs_saif_hw_params()
501 __raw_writel(scr, saif->base + SAIF_CTRL); in mxs_saif_hw_params()
512 saif->base + SAIF_CTRL + MXS_SET_ADDR); in mxs_saif_prepare()
527 return -EINVAL; in mxs_saif_trigger()
533 if (saif->state == MXS_SAIF_STATE_RUNNING) in mxs_saif_trigger()
536 dev_dbg(cpu_dai->dev, "start\n"); in mxs_saif_trigger()
538 ret = clk_enable(master_saif->clk); in mxs_saif_trigger()
540 dev_err(saif->dev, "Failed to enable master clock\n"); in mxs_saif_trigger()
545 * If the saif's master is not itself, we also need to enable in mxs_saif_trigger()
549 ret = clk_enable(saif->clk); in mxs_saif_trigger()
551 dev_err(saif->dev, "Failed to enable master clock\n"); in mxs_saif_trigger()
552 clk_disable(master_saif->clk); in mxs_saif_trigger()
557 saif->base + SAIF_CTRL + MXS_SET_ADDR); in mxs_saif_trigger()
560 if (!master_saif->mclk_in_use) in mxs_saif_trigger()
562 master_saif->base + SAIF_CTRL + MXS_SET_ADDR); in mxs_saif_trigger()
564 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { in mxs_saif_trigger()
568 * For 24-bit format the 32-bit FIFO register stores in mxs_saif_trigger()
570 * This is also safe for the other non 24-bit formats. in mxs_saif_trigger()
572 __raw_writel(0, saif->base + SAIF_DATA); in mxs_saif_trigger()
573 __raw_writel(0, saif->base + SAIF_DATA); in mxs_saif_trigger()
578 * For 24-bit format the 32-bit FIFO register stores in mxs_saif_trigger()
580 * This is also safe for the other non 24-bit formats. in mxs_saif_trigger()
582 __raw_readl(saif->base + SAIF_DATA); in mxs_saif_trigger()
583 __raw_readl(saif->base + SAIF_DATA); in mxs_saif_trigger()
586 master_saif->ongoing = 1; in mxs_saif_trigger()
587 saif->state = MXS_SAIF_STATE_RUNNING; in mxs_saif_trigger()
589 dev_dbg(saif->dev, "CTRL 0x%x STAT 0x%x\n", in mxs_saif_trigger()
590 __raw_readl(saif->base + SAIF_CTRL), in mxs_saif_trigger()
591 __raw_readl(saif->base + SAIF_STAT)); in mxs_saif_trigger()
593 dev_dbg(master_saif->dev, "CTRL 0x%x STAT 0x%x\n", in mxs_saif_trigger()
594 __raw_readl(master_saif->base + SAIF_CTRL), in mxs_saif_trigger()
595 __raw_readl(master_saif->base + SAIF_STAT)); in mxs_saif_trigger()
600 if (saif->state == MXS_SAIF_STATE_STOPPED) in mxs_saif_trigger()
603 dev_dbg(cpu_dai->dev, "stop\n"); in mxs_saif_trigger()
606 delay = USEC_PER_SEC / master_saif->cur_rate; in mxs_saif_trigger()
608 if (!master_saif->mclk_in_use) { in mxs_saif_trigger()
610 master_saif->base + SAIF_CTRL + MXS_CLR_ADDR); in mxs_saif_trigger()
613 clk_disable(master_saif->clk); in mxs_saif_trigger()
617 saif->base + SAIF_CTRL + MXS_CLR_ADDR); in mxs_saif_trigger()
619 clk_disable(saif->clk); in mxs_saif_trigger()
622 master_saif->ongoing = 0; in mxs_saif_trigger()
623 saif->state = MXS_SAIF_STATE_STOPPED; in mxs_saif_trigger()
627 return -EINVAL; in mxs_saif_trigger()
649 .name = "mxs-saif",
666 .name = "mxs-saif",
675 stat = __raw_readl(saif->base + SAIF_STAT); in mxs_saif_irq()
681 dev_dbg(saif->dev, "underrun!!! %d\n", ++saif->fifo_underrun); in mxs_saif_irq()
683 saif->base + SAIF_STAT + MXS_CLR_ADDR); in mxs_saif_irq()
687 dev_dbg(saif->dev, "overrun!!! %d\n", ++saif->fifo_overrun); in mxs_saif_irq()
689 saif->base + SAIF_STAT + MXS_CLR_ADDR); in mxs_saif_irq()
692 dev_dbg(saif->dev, "SAIF_CTRL %x SAIF_STAT %x\n", in mxs_saif_irq()
693 __raw_readl(saif->base + SAIF_CTRL), in mxs_saif_irq()
694 __raw_readl(saif->base + SAIF_STAT)); in mxs_saif_irq()
702 struct device_node *np = pdev->dev.of_node; in mxs_saif_mclk_init()
706 clk = clk_register_divider(&pdev->dev, "mxs_saif_mclk", in mxs_saif_mclk_init()
707 __clk_get_name(saif->clk), 0, in mxs_saif_mclk_init()
708 saif->base + SAIF_CTRL, in mxs_saif_mclk_init()
713 if (ret == -EEXIST) in mxs_saif_mclk_init()
715 dev_err(&pdev->dev, "failed to register mclk: %d\n", ret); in mxs_saif_mclk_init()
728 struct device_node *np = pdev->dev.of_node; in mxs_saif_probe()
731 struct device_node *master; in mxs_saif_probe() local
733 saif = devm_kzalloc(&pdev->dev, sizeof(*saif), GFP_KERNEL); in mxs_saif_probe()
735 return -ENOMEM; in mxs_saif_probe()
741 saif->id = ret; in mxs_saif_probe()
743 if (saif->id >= ARRAY_SIZE(mxs_saif)) { in mxs_saif_probe()
744 dev_err(&pdev->dev, "get wrong saif id\n"); in mxs_saif_probe()
745 return -EINVAL; in mxs_saif_probe()
749 * If there is no "fsl,saif-master" phandle, it's a saif in mxs_saif_probe()
750 * master. Otherwise, it's a slave and its phandle points in mxs_saif_probe()
751 * to the master. in mxs_saif_probe()
753 master = of_parse_phandle(np, "fsl,saif-master", 0); in mxs_saif_probe()
754 if (!master) { in mxs_saif_probe()
755 saif->master_id = saif->id; in mxs_saif_probe()
757 ret = of_alias_get_id(master, "saif"); in mxs_saif_probe()
758 of_node_put(master); in mxs_saif_probe()
762 saif->master_id = ret; in mxs_saif_probe()
764 if (saif->master_id >= ARRAY_SIZE(mxs_saif)) { in mxs_saif_probe()
765 dev_err(&pdev->dev, "get wrong master id\n"); in mxs_saif_probe()
766 return -EINVAL; in mxs_saif_probe()
770 mxs_saif[saif->id] = saif; in mxs_saif_probe()
772 saif->clk = devm_clk_get(&pdev->dev, NULL); in mxs_saif_probe()
773 if (IS_ERR(saif->clk)) { in mxs_saif_probe()
774 ret = PTR_ERR(saif->clk); in mxs_saif_probe()
775 dev_err(&pdev->dev, "Cannot get the clock: %d\n", in mxs_saif_probe()
780 saif->base = devm_platform_ioremap_resource(pdev, 0); in mxs_saif_probe()
781 if (IS_ERR(saif->base)) in mxs_saif_probe()
782 return PTR_ERR(saif->base); in mxs_saif_probe()
788 saif->dev = &pdev->dev; in mxs_saif_probe()
789 ret = devm_request_irq(&pdev->dev, irq, mxs_saif_irq, 0, in mxs_saif_probe()
790 dev_name(&pdev->dev), saif); in mxs_saif_probe()
792 dev_err(&pdev->dev, "failed to request irq\n"); in mxs_saif_probe()
798 /* We only support saif0 being tx and clock master */ in mxs_saif_probe()
799 if (saif->id == 0) { in mxs_saif_probe()
802 dev_warn(&pdev->dev, "failed to init clocks\n"); in mxs_saif_probe()
805 ret = devm_snd_soc_register_component(&pdev->dev, &mxs_saif_component, in mxs_saif_probe()
808 dev_err(&pdev->dev, "register DAI failed\n"); in mxs_saif_probe()
812 ret = mxs_pcm_platform_register(&pdev->dev); in mxs_saif_probe()
814 dev_err(&pdev->dev, "register PCM failed: %d\n", ret); in mxs_saif_probe()
822 { .compatible = "fsl,imx28-saif", },
831 .name = "mxs-saif",
841 MODULE_ALIAS("platform:mxs-saif");