Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: ti: davinci-i2s: Use external clock to drive sample rate generator

McBSP's internal sample rate generator can be programed to be driven by
its internal clock or by an external clock source located on CLKS pin.
The external clock source case is not handled by the driver.

Handle an optional clock related to this external clock source. If
present, the driver uses the clock located on CLKS pin as input for the
sample rate generator. Thus, the external clock rate is used to compute
divisors. If this optional clock is not present, the sample rate
generator is driven by the McBSP's functional clock.

Signed-off-by: Bastien Curutchet <bastien.curutchet@bootlin.com>
Acked-by: Peter Ujfalusi <peter.ujfalusi@gmail.com>
Link: https://msgid.link/r/20240402071213.11671-6-bastien.curutchet@bootlin.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Bastien Curutchet and committed by
Mark Brown
714ffb8d 6b1517b3

+49 -16
+49 -16
sound/soc/ti/davinci-i2s.c
··· 134 134 int mode; 135 135 u32 pcr; 136 136 struct clk *clk; 137 + struct clk *ext_clk; 137 138 /* 138 139 * Combining both channels into 1 element will at least double the 139 140 * amount of time between servicing the dma channel, increase ··· 365 364 struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); 366 365 struct snd_interval *i = NULL; 367 366 int mcbsp_word_length, master; 368 - unsigned int rcr, xcr, srgr, clk_div, freq, framesize; 367 + unsigned int rcr, xcr, clk_div, freq, framesize; 368 + unsigned int srgr = 0; 369 369 u32 spcr; 370 370 snd_pcm_format_t fmt; 371 371 unsigned element_cnt = 1; ··· 387 385 388 386 switch (master) { 389 387 case SND_SOC_DAIFMT_BP_FP: 390 - freq = clk_get_rate(dev->clk); 391 - srgr = DAVINCI_MCBSP_SRGR_FSGM | 392 - DAVINCI_MCBSP_SRGR_CLKSM; 388 + if (dev->ext_clk) { 389 + freq = clk_get_rate(dev->ext_clk); 390 + } else { 391 + freq = clk_get_rate(dev->clk); 392 + srgr = DAVINCI_MCBSP_SRGR_CLKSM; 393 + } 394 + srgr |= DAVINCI_MCBSP_SRGR_FSGM; 393 395 srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length * 394 396 8 - 1); 395 397 if (dev->i2s_accurate_sck) { ··· 697 691 return -ENODEV; 698 692 } 699 693 700 - dev->clk = clk_get(&pdev->dev, NULL); 694 + /* 695 + * The optional is there for backward compatibility. 696 + * If 'fck' is not present, the clk_get(dev, NULL) that follows may find something 697 + */ 698 + dev->clk = devm_clk_get_optional(&pdev->dev, "fck"); 701 699 if (IS_ERR(dev->clk)) 702 - return -ENODEV; 703 - ret = clk_enable(dev->clk); 700 + return dev_err_probe(&pdev->dev, PTR_ERR(dev->clk), "Invalid functional clock\n"); 701 + if (!dev->clk) { 702 + dev->clk = devm_clk_get(&pdev->dev, NULL); 703 + if (IS_ERR(dev->clk)) 704 + return dev_err_probe(&pdev->dev, PTR_ERR(dev->clk), 705 + "Missing functional clock\n"); 706 + } 707 + 708 + dev->ext_clk = devm_clk_get_optional(&pdev->dev, "clks"); 709 + if (IS_ERR(dev->ext_clk)) 710 + return dev_err_probe(&pdev->dev, PTR_ERR(dev->ext_clk), "Invalid external clock\n"); 711 + 712 + ret = clk_prepare_enable(dev->clk); 704 713 if (ret) 705 - goto err_put_clk; 714 + return ret; 715 + 716 + if (dev->ext_clk) { 717 + dev_dbg(&pdev->dev, "External clock used for sample rate generator\n"); 718 + ret = clk_prepare_enable(dev->ext_clk); 719 + if (ret) { 720 + dev_err_probe(&pdev->dev, ret, "Failed to enable external clock\n"); 721 + goto err_disable_clk; 722 + } 723 + } 706 724 707 725 dev->dev = &pdev->dev; 708 726 dev_set_drvdata(&pdev->dev, dev); ··· 734 704 ret = snd_soc_register_component(&pdev->dev, &davinci_i2s_component, 735 705 &davinci_i2s_dai, 1); 736 706 if (ret != 0) 737 - goto err_release_clk; 707 + goto err_disable_ext_clk; 738 708 739 709 ret = edma_pcm_platform_register(&pdev->dev); 740 710 if (ret) { ··· 746 716 747 717 err_unregister_component: 748 718 snd_soc_unregister_component(&pdev->dev); 749 - err_release_clk: 750 - clk_disable(dev->clk); 751 - err_put_clk: 752 - clk_put(dev->clk); 719 + err_disable_ext_clk: 720 + if (dev->ext_clk) 721 + clk_disable_unprepare(dev->ext_clk); 722 + err_disable_clk: 723 + clk_disable_unprepare(dev->clk); 724 + 753 725 return ret; 754 726 } 755 727 ··· 761 729 762 730 snd_soc_unregister_component(&pdev->dev); 763 731 764 - clk_disable(dev->clk); 765 - clk_put(dev->clk); 766 - dev->clk = NULL; 732 + clk_disable_unprepare(dev->clk); 733 + 734 + if (dev->ext_clk) 735 + clk_disable_unprepare(dev->ext_clk); 767 736 } 768 737 769 738 static const struct of_device_id davinci_i2s_match[] __maybe_unused = {