Lines Matching +full:mclk +full:- +full:fs
1 // SPDX-License-Identifier: GPL-2.0-or-later
11 #include <linux/dma-mapping.h>
13 #include <linux/clk-provider.h>
22 #include "mxs-saif.h"
32 * For MXS, two SAIF modules are instantiated on-chip.
34 * mode simultaneously if they are connected to different off-chip codecs.
43 * The master id is provided in mach-specific layer according to different
54 saif->mclk = freq; in mxs_saif_set_dai_sysclk()
57 return -EINVAL; in mxs_saif_set_dai_sysclk()
70 return mxs_saif[saif->master_id]; in mxs_saif_get_master()
74 * Set SAIF clock and MCLK
77 unsigned int mclk, in mxs_saif_set_clk() argument
84 dev_dbg(saif->dev, "mclk %d rate %d\n", mclk, rate); in mxs_saif_set_clk()
89 return -EINVAL; in mxs_saif_set_clk()
91 dev_dbg(saif->dev, "master saif%d\n", master_saif->id); in mxs_saif_set_clk()
94 if (master_saif->ongoing && rate != master_saif->cur_rate) { in mxs_saif_set_clk()
95 dev_err(saif->dev, in mxs_saif_set_clk()
97 master_saif->id, master_saif->cur_rate); in mxs_saif_set_clk()
98 return -EINVAL; in mxs_saif_set_clk()
101 scr = __raw_readl(master_saif->base + SAIF_CTRL); in mxs_saif_set_clk()
108 * The SAIF clock should be either 384*fs or 512*fs. in mxs_saif_set_clk()
109 * If MCLK is used, the SAIF clk ratio needs to match mclk ratio. in mxs_saif_set_clk()
110 * For 256x, 128x, 64x, and 32x sub-rates, set saif clk as 512*fs. in mxs_saif_set_clk()
111 * For 192x, 96x, and 48x sub-rates, set saif clk as 384*fs. in mxs_saif_set_clk()
113 * If MCLK is not used, we just set saif clk to 512*fs. in mxs_saif_set_clk()
115 ret = clk_prepare_enable(master_saif->clk); in mxs_saif_set_clk()
119 if (master_saif->mclk_in_use) { in mxs_saif_set_clk()
120 switch (mclk / rate) { in mxs_saif_set_clk()
127 ret = clk_set_rate(master_saif->clk, 512 * rate); in mxs_saif_set_clk()
134 ret = clk_set_rate(master_saif->clk, 384 * rate); in mxs_saif_set_clk()
137 /* SAIF MCLK should be a sub-rate of 512x or 384x */ in mxs_saif_set_clk()
138 clk_disable_unprepare(master_saif->clk); in mxs_saif_set_clk()
139 return -EINVAL; in mxs_saif_set_clk()
142 ret = clk_set_rate(master_saif->clk, 512 * rate); in mxs_saif_set_clk()
146 clk_disable_unprepare(master_saif->clk); in mxs_saif_set_clk()
151 master_saif->cur_rate = rate; in mxs_saif_set_clk()
153 if (!master_saif->mclk_in_use) { in mxs_saif_set_clk()
154 __raw_writel(scr, master_saif->base + SAIF_CTRL); in mxs_saif_set_clk()
159 * Program the over-sample rate for MCLK output in mxs_saif_set_clk()
161 * The available MCLK range is 32x, 48x... 512x. The rate in mxs_saif_set_clk()
164 switch (mclk / rate) { in mxs_saif_set_clk()
193 return -EINVAL; in mxs_saif_set_clk()
196 __raw_writel(scr, master_saif->base + SAIF_CTRL); in mxs_saif_set_clk()
202 * Put and disable MCLK.
210 return -EINVAL; in mxs_saif_put_mclk()
212 stat = __raw_readl(saif->base + SAIF_STAT); in mxs_saif_put_mclk()
214 dev_err(saif->dev, "error: busy\n"); in mxs_saif_put_mclk()
215 return -EBUSY; in mxs_saif_put_mclk()
218 clk_disable_unprepare(saif->clk); in mxs_saif_put_mclk()
220 /* disable MCLK output */ in mxs_saif_put_mclk()
222 saif->base + SAIF_CTRL + MXS_SET_ADDR); in mxs_saif_put_mclk()
224 saif->base + SAIF_CTRL + MXS_CLR_ADDR); in mxs_saif_put_mclk()
226 saif->mclk_in_use = 0; in mxs_saif_put_mclk()
232 * Get MCLK and set clock rate, then enable it
234 * This interface is used for codecs who are using MCLK provided
237 int mxs_saif_get_mclk(unsigned int saif_id, unsigned int mclk, in mxs_saif_get_mclk() argument
246 return -EINVAL; in mxs_saif_get_mclk()
250 saif->base + SAIF_CTRL + MXS_CLR_ADDR); in mxs_saif_get_mclk()
254 saif->base + SAIF_CTRL + MXS_CLR_ADDR); in mxs_saif_get_mclk()
258 dev_err(saif->dev, "can not get mclk from a non-master saif\n"); in mxs_saif_get_mclk()
259 return -EINVAL; in mxs_saif_get_mclk()
262 stat = __raw_readl(saif->base + SAIF_STAT); in mxs_saif_get_mclk()
264 dev_err(saif->dev, "error: busy\n"); in mxs_saif_get_mclk()
265 return -EBUSY; in mxs_saif_get_mclk()
268 saif->mclk_in_use = 1; in mxs_saif_get_mclk()
269 ret = mxs_saif_set_clk(saif, mclk, rate); in mxs_saif_get_mclk()
273 ret = clk_prepare_enable(saif->clk); in mxs_saif_get_mclk()
277 /* enable MCLK output */ in mxs_saif_get_mclk()
279 saif->base + SAIF_CTRL + MXS_SET_ADDR); in mxs_saif_get_mclk()
295 stat = __raw_readl(saif->base + SAIF_STAT); in mxs_saif_set_dai_fmt()
297 dev_err(cpu_dai->dev, "error: busy\n"); in mxs_saif_set_dai_fmt()
298 return -EBUSY; in mxs_saif_set_dai_fmt()
304 if (saif->id != saif->master_id) { in mxs_saif_set_dai_fmt()
306 saif->base + SAIF_CTRL + MXS_CLR_ADDR); in mxs_saif_set_dai_fmt()
308 saif->base + SAIF_CTRL + MXS_CLR_ADDR); in mxs_saif_set_dai_fmt()
311 scr0 = __raw_readl(saif->base + SAIF_CTRL); in mxs_saif_set_dai_fmt()
330 return -EINVAL; in mxs_saif_set_dai_fmt()
362 if (saif->id == saif->master_id) in mxs_saif_set_dai_fmt()
367 __raw_writel(scr | scr0, saif->base + SAIF_CTRL); in mxs_saif_set_dai_fmt()
370 return -EINVAL; in mxs_saif_set_dai_fmt()
382 /* clear error status to 0 for each re-open */ in mxs_saif_startup()
383 saif->fifo_underrun = 0; in mxs_saif_startup()
384 saif->fifo_overrun = 0; in mxs_saif_startup()
388 saif->base + SAIF_CTRL + MXS_CLR_ADDR); in mxs_saif_startup()
392 saif->base + SAIF_CTRL + MXS_CLR_ADDR); in mxs_saif_startup()
394 ret = clk_prepare(saif->clk); in mxs_saif_startup()
406 clk_unprepare(saif->clk); in mxs_saif_shutdown()
424 return -EINVAL; in mxs_saif_hw_params()
426 /* mclk should already be set */ in mxs_saif_hw_params()
427 if (!saif->mclk && saif->mclk_in_use) { in mxs_saif_hw_params()
428 dev_err(cpu_dai->dev, "set mclk first\n"); in mxs_saif_hw_params()
429 return -EINVAL; in mxs_saif_hw_params()
432 stat = __raw_readl(saif->base + SAIF_STAT); in mxs_saif_hw_params()
433 if (!saif->mclk_in_use && (stat & BM_SAIF_STAT_BUSY)) { in mxs_saif_hw_params()
434 dev_err(cpu_dai->dev, "error: busy\n"); in mxs_saif_hw_params()
435 return -EBUSY; in mxs_saif_hw_params()
440 * If mclk is used, we also set mclk, if not, saif->mclk is in mxs_saif_hw_params()
443 ret = mxs_saif_set_clk(saif, saif->mclk, params_rate(params)); in mxs_saif_hw_params()
445 dev_err(cpu_dai->dev, "unable to get proper clk\n"); in mxs_saif_hw_params()
457 ret = clk_enable(saif->clk); in mxs_saif_hw_params()
461 ret = clk_set_rate(saif->clk, 24000000); in mxs_saif_hw_params()
462 clk_disable(saif->clk); in mxs_saif_hw_params()
466 ret = clk_prepare(master_saif->clk); in mxs_saif_hw_params()
471 scr = __raw_readl(saif->base + SAIF_CTRL); in mxs_saif_hw_params()
488 return -EINVAL; in mxs_saif_hw_params()
492 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { in mxs_saif_hw_params()
500 __raw_writel(scr, saif->base + SAIF_CTRL); in mxs_saif_hw_params()
511 saif->base + SAIF_CTRL + MXS_SET_ADDR); in mxs_saif_prepare()
526 return -EINVAL; in mxs_saif_trigger()
532 if (saif->state == MXS_SAIF_STATE_RUNNING) in mxs_saif_trigger()
535 dev_dbg(cpu_dai->dev, "start\n"); in mxs_saif_trigger()
537 ret = clk_enable(master_saif->clk); in mxs_saif_trigger()
539 dev_err(saif->dev, "Failed to enable master clock\n"); in mxs_saif_trigger()
548 ret = clk_enable(saif->clk); in mxs_saif_trigger()
550 dev_err(saif->dev, "Failed to enable master clock\n"); in mxs_saif_trigger()
551 clk_disable(master_saif->clk); in mxs_saif_trigger()
556 saif->base + SAIF_CTRL + MXS_SET_ADDR); in mxs_saif_trigger()
559 if (!master_saif->mclk_in_use) in mxs_saif_trigger()
561 master_saif->base + SAIF_CTRL + MXS_SET_ADDR); in mxs_saif_trigger()
563 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { in mxs_saif_trigger()
567 * For 24-bit format the 32-bit FIFO register stores in mxs_saif_trigger()
569 * This is also safe for the other non 24-bit formats. in mxs_saif_trigger()
571 __raw_writel(0, saif->base + SAIF_DATA); in mxs_saif_trigger()
572 __raw_writel(0, saif->base + SAIF_DATA); in mxs_saif_trigger()
577 * For 24-bit format the 32-bit FIFO register stores in mxs_saif_trigger()
579 * This is also safe for the other non 24-bit formats. in mxs_saif_trigger()
581 __raw_readl(saif->base + SAIF_DATA); in mxs_saif_trigger()
582 __raw_readl(saif->base + SAIF_DATA); in mxs_saif_trigger()
585 master_saif->ongoing = 1; in mxs_saif_trigger()
586 saif->state = MXS_SAIF_STATE_RUNNING; in mxs_saif_trigger()
588 dev_dbg(saif->dev, "CTRL 0x%x STAT 0x%x\n", in mxs_saif_trigger()
589 __raw_readl(saif->base + SAIF_CTRL), in mxs_saif_trigger()
590 __raw_readl(saif->base + SAIF_STAT)); in mxs_saif_trigger()
592 dev_dbg(master_saif->dev, "CTRL 0x%x STAT 0x%x\n", in mxs_saif_trigger()
593 __raw_readl(master_saif->base + SAIF_CTRL), in mxs_saif_trigger()
594 __raw_readl(master_saif->base + SAIF_STAT)); in mxs_saif_trigger()
599 if (saif->state == MXS_SAIF_STATE_STOPPED) in mxs_saif_trigger()
602 dev_dbg(cpu_dai->dev, "stop\n"); in mxs_saif_trigger()
605 delay = USEC_PER_SEC / master_saif->cur_rate; in mxs_saif_trigger()
607 if (!master_saif->mclk_in_use) { in mxs_saif_trigger()
609 master_saif->base + SAIF_CTRL + MXS_CLR_ADDR); in mxs_saif_trigger()
612 clk_disable(master_saif->clk); in mxs_saif_trigger()
616 saif->base + SAIF_CTRL + MXS_CLR_ADDR); in mxs_saif_trigger()
618 clk_disable(saif->clk); in mxs_saif_trigger()
621 master_saif->ongoing = 0; in mxs_saif_trigger()
622 saif->state = MXS_SAIF_STATE_STOPPED; in mxs_saif_trigger()
626 return -EINVAL; in mxs_saif_trigger()
648 .name = "mxs-saif",
665 .name = "mxs-saif",
674 stat = __raw_readl(saif->base + SAIF_STAT); in mxs_saif_irq()
680 dev_dbg(saif->dev, "underrun!!! %d\n", ++saif->fifo_underrun); in mxs_saif_irq()
682 saif->base + SAIF_STAT + MXS_CLR_ADDR); in mxs_saif_irq()
686 dev_dbg(saif->dev, "overrun!!! %d\n", ++saif->fifo_overrun); in mxs_saif_irq()
688 saif->base + SAIF_STAT + MXS_CLR_ADDR); in mxs_saif_irq()
691 dev_dbg(saif->dev, "SAIF_CTRL %x SAIF_STAT %x\n", in mxs_saif_irq()
692 __raw_readl(saif->base + SAIF_CTRL), in mxs_saif_irq()
693 __raw_readl(saif->base + SAIF_STAT)); in mxs_saif_irq()
701 struct device_node *np = pdev->dev.of_node; in mxs_saif_mclk_init()
705 clk = clk_register_divider(&pdev->dev, "mxs_saif_mclk", in mxs_saif_mclk_init()
706 __clk_get_name(saif->clk), 0, in mxs_saif_mclk_init()
707 saif->base + SAIF_CTRL, in mxs_saif_mclk_init()
712 if (ret == -EEXIST) in mxs_saif_mclk_init()
714 dev_err(&pdev->dev, "failed to register mclk: %d\n", ret); in mxs_saif_mclk_init()
727 struct device_node *np = pdev->dev.of_node; in mxs_saif_probe()
732 saif = devm_kzalloc(&pdev->dev, sizeof(*saif), GFP_KERNEL); in mxs_saif_probe()
734 return -ENOMEM; in mxs_saif_probe()
740 saif->id = ret; in mxs_saif_probe()
742 if (saif->id >= ARRAY_SIZE(mxs_saif)) { in mxs_saif_probe()
743 dev_err(&pdev->dev, "get wrong saif id\n"); in mxs_saif_probe()
744 return -EINVAL; in mxs_saif_probe()
748 * If there is no "fsl,saif-master" phandle, it's a saif in mxs_saif_probe()
752 master = of_parse_phandle(np, "fsl,saif-master", 0); in mxs_saif_probe()
754 saif->master_id = saif->id; in mxs_saif_probe()
761 saif->master_id = ret; in mxs_saif_probe()
763 if (saif->master_id >= ARRAY_SIZE(mxs_saif)) { in mxs_saif_probe()
764 dev_err(&pdev->dev, "get wrong master id\n"); in mxs_saif_probe()
765 return -EINVAL; in mxs_saif_probe()
769 mxs_saif[saif->id] = saif; in mxs_saif_probe()
771 saif->clk = devm_clk_get(&pdev->dev, NULL); in mxs_saif_probe()
772 if (IS_ERR(saif->clk)) { in mxs_saif_probe()
773 ret = PTR_ERR(saif->clk); in mxs_saif_probe()
774 dev_err(&pdev->dev, "Cannot get the clock: %d\n", in mxs_saif_probe()
779 saif->base = devm_platform_ioremap_resource(pdev, 0); in mxs_saif_probe()
780 if (IS_ERR(saif->base)) in mxs_saif_probe()
781 return PTR_ERR(saif->base); in mxs_saif_probe()
787 saif->dev = &pdev->dev; in mxs_saif_probe()
788 ret = devm_request_irq(&pdev->dev, irq, mxs_saif_irq, 0, in mxs_saif_probe()
789 dev_name(&pdev->dev), saif); in mxs_saif_probe()
791 dev_err(&pdev->dev, "failed to request irq\n"); in mxs_saif_probe()
798 if (saif->id == 0) { in mxs_saif_probe()
801 dev_warn(&pdev->dev, "failed to init clocks\n"); in mxs_saif_probe()
804 ret = devm_snd_soc_register_component(&pdev->dev, &mxs_saif_component, in mxs_saif_probe()
807 dev_err(&pdev->dev, "register DAI failed\n"); in mxs_saif_probe()
811 ret = mxs_pcm_platform_register(&pdev->dev); in mxs_saif_probe()
813 dev_err(&pdev->dev, "register PCM failed: %d\n", ret); in mxs_saif_probe()
821 { .compatible = "fsl,imx28-saif", },
830 .name = "mxs-saif",
840 MODULE_ALIAS("platform:mxs-saif");