diff mbox series

[v2,4/4] clk: fsl-sai: Add MCLK generation support

Message ID 20241226162234.40141-4-marex@denx.de (mailing list archive)
State New
Headers show
Series [v2,1/4] dt-bindings: clock: fsl-sai: Document i.MX8M support | expand

Commit Message

Marek Vasut Dec. 26, 2024, 4:22 p.m. UTC
The driver currently supports generating BCLK. There are systems which
require generation of MCLK instead. Register new MCLK clock and handle
clock-cells = <1> to differentiate between BCLK and MCLK. In case of a
legacy system with clock-cells = <0>, the driver behaves as before, i.e.
always returns BCLK.

Signed-off-by: Marek Vasut <marex@denx.de>
---
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: Jaroslav Kysela <perex@perex.cz>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Liam Girdwood <lgirdwood@gmail.com>
Cc: Mark Brown <broonie@kernel.org>
Cc: Michael Turquette <mturquette@baylibre.com>
Cc: Michael Walle <michael@walle.cc>
Cc: Nicolin Chen <nicoleotsuka@gmail.com>
Cc: Rob Herring <robh@kernel.org>
Cc: Shengjiu Wang <shengjiu.wang@gmail.com>
Cc: Stephen Boyd <sboyd@kernel.org>
Cc: Takashi Iwai <tiwai@suse.com>
Cc: Xiubo Li <Xiubo.Lee@gmail.com>
Cc: devicetree@vger.kernel.org
Cc: linux-clk@vger.kernel.org
Cc: linux-sound@vger.kernel.org
---
V2: No change
---
 drivers/clk/clk-fsl-sai.c | 81 ++++++++++++++++++++++++++++++++-------
 1 file changed, 67 insertions(+), 14 deletions(-)

Comments

Marek Vasut Dec. 30, 2024, 12:47 a.m. UTC | #1
On 12/30/24 2:28 AM, Peng Fan wrote:

[...]

>> static int fsl_sai_clk_probe(struct platform_device *pdev)
>> {
>> 	struct device *dev = &pdev->dev;
>> 	const struct fsl_sai_data *data = device_get_match_data(dev);
>> -	struct fsl_sai_clk *sai_clk;
>> 	struct clk_parent_data pdata = { .index = 0 };
>> +	struct fsl_sai_clk *sai_clk;
>> +	struct clk *clk_bus;
>> 	void __iomem *base;
>> 	struct clk_hw *hw;
>>
>> @@ -47,39 +65,74 @@ static int fsl_sai_clk_probe(struct platform_device *pdev)
>> 	if (IS_ERR(base))
>> 		return PTR_ERR(base);
>>
>> +	clk_bus = devm_clk_get_enabled(dev, "bus");
>> +	if (IS_ERR(clk_bus))
>> +		return PTR_ERR(clk_bus);
>> +
> 
> This only applies to i.MX?
I think so ... what am I missing , some Vybrid / Layerscape detail ?
Peng Fan (OSS) Dec. 30, 2024, 1:28 a.m. UTC | #2
On Thu, Dec 26, 2024 at 05:22:24PM +0100, Marek Vasut wrote:
>The driver currently supports generating BCLK. There are systems which
>require generation of MCLK instead. Register new MCLK clock and handle
>clock-cells = <1> to differentiate between BCLK and MCLK. In case of a
>legacy system with clock-cells = <0>, the driver behaves as before, i.e.
>always returns BCLK.
>
>Signed-off-by: Marek Vasut <marex@denx.de>
>---
>Cc: Conor Dooley <conor+dt@kernel.org>
>Cc: Fabio Estevam <festevam@gmail.com>
>Cc: Jaroslav Kysela <perex@perex.cz>
>Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
>Cc: Liam Girdwood <lgirdwood@gmail.com>
>Cc: Mark Brown <broonie@kernel.org>
>Cc: Michael Turquette <mturquette@baylibre.com>
>Cc: Michael Walle <michael@walle.cc>
>Cc: Nicolin Chen <nicoleotsuka@gmail.com>
>Cc: Rob Herring <robh@kernel.org>
>Cc: Shengjiu Wang <shengjiu.wang@gmail.com>
>Cc: Stephen Boyd <sboyd@kernel.org>
>Cc: Takashi Iwai <tiwai@suse.com>
>Cc: Xiubo Li <Xiubo.Lee@gmail.com>
>Cc: devicetree@vger.kernel.org
>Cc: linux-clk@vger.kernel.org
>Cc: linux-sound@vger.kernel.org
>---
>V2: No change
>---
> drivers/clk/clk-fsl-sai.c | 81 ++++++++++++++++++++++++++++++++-------
> 1 file changed, 67 insertions(+), 14 deletions(-)
>
>diff --git a/drivers/clk/clk-fsl-sai.c b/drivers/clk/clk-fsl-sai.c
>index 628e53a3a26fa..0f8e2f2662d87 100644
>--- a/drivers/clk/clk-fsl-sai.c
>+++ b/drivers/clk/clk-fsl-sai.c
>@@ -7,6 +7,7 @@
> 
> #include <linux/module.h>
> #include <linux/platform_device.h>
>+#include <linux/clk.h>
> #include <linux/clk-provider.h>
> #include <linux/err.h>
> #include <linux/of.h>
>@@ -15,27 +16,44 @@
> 
> #define I2S_CSR		0x00
> #define I2S_CR2		0x08
>+#define I2S_MCR		0x100
> #define CSR_BCE_BIT	28
>+#define CSR_TE_BIT	31
> #define CR2_BCD		BIT(24)
> #define CR2_DIV_SHIFT	0
> #define CR2_DIV_WIDTH	8
>+#define MCR_MOE		BIT(30)
> 
> struct fsl_sai_clk {
>-	struct clk_divider div;
>-	struct clk_gate gate;
>+	struct clk_divider bclk_div;
>+	struct clk_divider mclk_div;
>+	struct clk_gate bclk_gate;
>+	struct clk_gate mclk_gate;
>+	struct clk_hw *bclk_hw;
>+	struct clk_hw *mclk_hw;
> 	spinlock_t lock;
> };
> 
> struct fsl_sai_data {
> 	unsigned int	offset;	/* Register offset */
>+	bool		have_mclk; /* Have MCLK control */
> };
> 
>+static struct clk_hw *
>+fsl_sai_of_clk_get(struct of_phandle_args *clkspec, void *data)
>+{
>+	struct fsl_sai_clk *sai_clk = data;
>+
>+	return clkspec->args[0] ? sai_clk->mclk_hw : sai_clk->bclk_hw;
>+}
>+
> static int fsl_sai_clk_probe(struct platform_device *pdev)
> {
> 	struct device *dev = &pdev->dev;
> 	const struct fsl_sai_data *data = device_get_match_data(dev);
>-	struct fsl_sai_clk *sai_clk;
> 	struct clk_parent_data pdata = { .index = 0 };
>+	struct fsl_sai_clk *sai_clk;
>+	struct clk *clk_bus;
> 	void __iomem *base;
> 	struct clk_hw *hw;
> 
>@@ -47,39 +65,74 @@ static int fsl_sai_clk_probe(struct platform_device *pdev)
> 	if (IS_ERR(base))
> 		return PTR_ERR(base);
> 
>+	clk_bus = devm_clk_get_enabled(dev, "bus");
>+	if (IS_ERR(clk_bus))
>+		return PTR_ERR(clk_bus);
>+

This only applies to i.MX? 

> 	spin_lock_init(&sai_clk->lock);
> 

Regards,
Peng
Michael Walle Dec. 30, 2024, 7:51 a.m. UTC | #3
Hi Marek,

On Thu Dec 26, 2024 at 5:22 PM CET, Marek Vasut wrote:
> The driver currently supports generating BCLK.

I'd say the driver supports generating *any* clock on the BCLK pin.
It's not necessarily the BCLK clock. I.e. on the board where this is
used, this is the clock with a given frequency sourcing the PLL in
the audio codec.

> There are systems which require generation of MCLK instead.

You mean systems that use the MCLK pin instead? ..Which is the
normal use case for this pin. This driver was created because the
LS1028A doesn't have a MCLK pin, so we've "misused" the BCLK pin,
with the restriction that only integer dividers are possible. I
haven't looked at the datasheet, but doesn't the MCLK has a PLL
which could generate any frequency? Also I'd expect that the imx
SoCs already supports the MCLK for audio applications. Isn't that
the case?

> Register new MCLK clock and handle
> clock-cells = <1> to differentiate between BCLK and MCLK. In case of a
> legacy system with clock-cells = <0>, the driver behaves as before, i.e.
> always returns BCLK.

-michael
Marek Vasut Dec. 30, 2024, 10:18 p.m. UTC | #4
On 12/30/24 8:51 AM, Michael Walle wrote:
> Hi Marek,

Hi,

> On Thu Dec 26, 2024 at 5:22 PM CET, Marek Vasut wrote:
>> The driver currently supports generating BCLK.
> 
> I'd say the driver supports generating *any* clock on the BCLK pin.

The clock are coming out of the SAI 'BCLK' output and are controlled by 
the SAI BCLK control bits. Of course, it is possible to feed arbitrary 
upstream clock into the SAI and have those exposed on the BCLK pin. I'll 
try to reword the commit message to make that clearer.

> It's not necessarily the BCLK clock. I.e. on the board where this is
> used, this is the clock with a given frequency sourcing the PLL in
> the audio codec.

Right

>> There are systems which require generation of MCLK instead.
> 
> You mean systems that use the MCLK pin instead?

Yes

> ..Which is the
> normal use case for this pin. This driver was created because the
> LS1028A doesn't have a MCLK pin, so we've "misused" the BCLK pin,
> with the restriction that only integer dividers are possible.

I have a system that is wired a bit unfortunately, I need to source 
codec clock, where the codec is the clock consumer and needs to be able 
to control the clock (SGTL5000). SAI MCLK is the only way I can get them 
out of the pin I need, hence this patch.

> I
> haven't looked at the datasheet, but doesn't the MCLK has a PLL
> which could generate any frequency?

Audio PLL , sure.

> Also I'd expect that the imx
> SoCs already supports the MCLK for audio applications. Isn't that
> the case?

That does not work if the MCLK has to be enabled/disabled by the MCLK 
clock consumer .

[...]
Michael Walle Jan. 2, 2025, 9:58 a.m. UTC | #5
Hi,

> > ..Which is the
> > normal use case for this pin. This driver was created because the
> > LS1028A doesn't have a MCLK pin, so we've "misused" the BCLK pin,
> > with the restriction that only integer dividers are possible.
>
> I have a system that is wired a bit unfortunately, I need to source 
> codec clock, where the codec is the clock consumer and needs to be able 
> to control the clock (SGTL5000). SAI MCLK is the only way I can get them 
> out of the pin I need, hence this patch.

Which is also the default case, no?

> > Also I'd expect that the imx
> > SoCs already supports the MCLK for audio applications. Isn't that
> > the case?
>
> That does not work if the MCLK has to be enabled/disabled by the MCLK 
> clock consumer .

Why's that?

Don't get me wrong. I don't have anything against this patch, I'm
just confused, why that isn't already working with the current MCLK
driver as this seems to be the usual requirements.

-michael
Marek Vasut Jan. 2, 2025, 1:34 p.m. UTC | #6
On 1/2/25 10:58 AM, Michael Walle wrote:
> Hi,

Hi,

>>> ..Which is the
>>> normal use case for this pin. This driver was created because the
>>> LS1028A doesn't have a MCLK pin, so we've "misused" the BCLK pin,
>>> with the restriction that only integer dividers are possible.
>>
>> I have a system that is wired a bit unfortunately, I need to source
>> codec clock, where the codec is the clock consumer and needs to be able
>> to control the clock (SGTL5000). SAI MCLK is the only way I can get them
>> out of the pin I need, hence this patch.
> 
> Which is also the default case, no?

Not quite, there is a difference.

If SAI (audio driver) is used to control the MCLK enablement, then MCLK 
clock is not always enabled, and it is not necessarily enabled when the 
codec may need the clock to be enabled. There is also no way for the 
codec node to specify phandle to clock provider in DT, because the SAI 
(audio driver) is not clock provider.

If SAI (clock driver) is used to control the MCLK enablement, then MCLK 
clock is enabled when the codec needs the clock enabled, because the 
codec is the clock consumer and the SAI (clock driver) is the clock 
provider, and the codec driver can request the clock to be enabled when 
needed. There is also the usual phandle to clock provider in DT, because 
the SAI (clock driver) is clock provider.

>>> Also I'd expect that the imx
>>> SoCs already supports the MCLK for audio applications. Isn't that
>>> the case?
>>
>> That does not work if the MCLK has to be enabled/disabled by the MCLK
>> clock consumer .
> 
> Why's that?
> 
> Don't get me wrong. I don't have anything against this patch, I'm
> just confused, why that isn't already working with the current MCLK
> driver as this seems to be the usual requirements.
Which current MCLK driver, the SAI in audio driver role ?

Does the paragraph in the middle of this email possibly answer this 
question ?
Michael Walle Jan. 7, 2025, 8:52 a.m. UTC | #7
On Thu Jan 2, 2025 at 2:34 PM CET, Marek Vasut wrote:
> On 1/2/25 10:58 AM, Michael Walle wrote:
> > Hi,
>
> Hi,
>
> >>> ..Which is the
> >>> normal use case for this pin. This driver was created because the
> >>> LS1028A doesn't have a MCLK pin, so we've "misused" the BCLK pin,
> >>> with the restriction that only integer dividers are possible.
> >>
> >> I have a system that is wired a bit unfortunately, I need to source
> >> codec clock, where the codec is the clock consumer and needs to be able
> >> to control the clock (SGTL5000). SAI MCLK is the only way I can get them
> >> out of the pin I need, hence this patch.
> > 
> > Which is also the default case, no?
>
> Not quite, there is a difference.
>
> If SAI (audio driver) is used to control the MCLK enablement, then MCLK 
> clock is not always enabled, and it is not necessarily enabled when the 
> codec may need the clock to be enabled. There is also no way for the 
> codec node to specify phandle to clock provider in DT, because the SAI 
> (audio driver) is not clock provider.
>
> If SAI (clock driver) is used to control the MCLK enablement, then MCLK 
> clock is enabled when the codec needs the clock enabled, because the 
> codec is the clock consumer and the SAI (clock driver) is the clock 
> provider, and the codec driver can request the clock to be enabled when 
> needed. There is also the usual phandle to clock provider in DT, because 
> the SAI (clock driver) is clock provider.
>
> >>> Also I'd expect that the imx
> >>> SoCs already supports the MCLK for audio applications. Isn't that
> >>> the case?
> >>
> >> That does not work if the MCLK has to be enabled/disabled by the MCLK
> >> clock consumer .
> > 
> > Why's that?
> > 
> > Don't get me wrong. I don't have anything against this patch, I'm
> > just confused, why that isn't already working with the current MCLK
> > driver as this seems to be the usual requirements.
> Which current MCLK driver, the SAI in audio driver role ?

Yes.

> Does the paragraph in the middle of this email possibly answer this 
> question ?

Yes thanks!

For reference, IMHO the correct way to do it would be to add clock
provider support to the original SAI, esp. because both drivers are
mutually exclusive. But I'm fine to add MCLK support for this driver
for hardware which has a spare SAI and to just use that as a MCLK
source.

Acked-by: Michael Walle <mwalle@kernel.org>

-michael
diff mbox series

Patch

diff --git a/drivers/clk/clk-fsl-sai.c b/drivers/clk/clk-fsl-sai.c
index 628e53a3a26fa..0f8e2f2662d87 100644
--- a/drivers/clk/clk-fsl-sai.c
+++ b/drivers/clk/clk-fsl-sai.c
@@ -7,6 +7,7 @@ 
 
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/err.h>
 #include <linux/of.h>
@@ -15,27 +16,44 @@ 
 
 #define I2S_CSR		0x00
 #define I2S_CR2		0x08
+#define I2S_MCR		0x100
 #define CSR_BCE_BIT	28
+#define CSR_TE_BIT	31
 #define CR2_BCD		BIT(24)
 #define CR2_DIV_SHIFT	0
 #define CR2_DIV_WIDTH	8
+#define MCR_MOE		BIT(30)
 
 struct fsl_sai_clk {
-	struct clk_divider div;
-	struct clk_gate gate;
+	struct clk_divider bclk_div;
+	struct clk_divider mclk_div;
+	struct clk_gate bclk_gate;
+	struct clk_gate mclk_gate;
+	struct clk_hw *bclk_hw;
+	struct clk_hw *mclk_hw;
 	spinlock_t lock;
 };
 
 struct fsl_sai_data {
 	unsigned int	offset;	/* Register offset */
+	bool		have_mclk; /* Have MCLK control */
 };
 
+static struct clk_hw *
+fsl_sai_of_clk_get(struct of_phandle_args *clkspec, void *data)
+{
+	struct fsl_sai_clk *sai_clk = data;
+
+	return clkspec->args[0] ? sai_clk->mclk_hw : sai_clk->bclk_hw;
+}
+
 static int fsl_sai_clk_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	const struct fsl_sai_data *data = device_get_match_data(dev);
-	struct fsl_sai_clk *sai_clk;
 	struct clk_parent_data pdata = { .index = 0 };
+	struct fsl_sai_clk *sai_clk;
+	struct clk *clk_bus;
 	void __iomem *base;
 	struct clk_hw *hw;
 
@@ -47,39 +65,74 @@  static int fsl_sai_clk_probe(struct platform_device *pdev)
 	if (IS_ERR(base))
 		return PTR_ERR(base);
 
+	clk_bus = devm_clk_get_enabled(dev, "bus");
+	if (IS_ERR(clk_bus))
+		return PTR_ERR(clk_bus);
+
 	spin_lock_init(&sai_clk->lock);
 
-	sai_clk->gate.reg = base + data->offset + I2S_CSR;
-	sai_clk->gate.bit_idx = CSR_BCE_BIT;
-	sai_clk->gate.lock = &sai_clk->lock;
+	sai_clk->bclk_gate.reg = base + data->offset + I2S_CSR;
+	sai_clk->bclk_gate.bit_idx = CSR_BCE_BIT;
+	sai_clk->bclk_gate.lock = &sai_clk->lock;
 
-	sai_clk->div.reg = base + data->offset + I2S_CR2;
-	sai_clk->div.shift = CR2_DIV_SHIFT;
-	sai_clk->div.width = CR2_DIV_WIDTH;
-	sai_clk->div.lock = &sai_clk->lock;
+	sai_clk->bclk_div.reg = base + data->offset + I2S_CR2;
+	sai_clk->bclk_div.shift = CR2_DIV_SHIFT;
+	sai_clk->bclk_div.width = CR2_DIV_WIDTH;
+	sai_clk->bclk_div.lock = &sai_clk->lock;
 
 	/* set clock direction, we are the BCLK master */
 	writel(CR2_BCD, base + data->offset + I2S_CR2);
 
-	hw = devm_clk_hw_register_composite_pdata(dev, dev->of_node->name,
+	hw = devm_clk_hw_register_composite_pdata(dev, "BCLK",
 						  &pdata, 1, NULL, NULL,
-						  &sai_clk->div.hw,
+						  &sai_clk->bclk_div.hw,
 						  &clk_divider_ops,
-						  &sai_clk->gate.hw,
+						  &sai_clk->bclk_gate.hw,
 						  &clk_gate_ops,
 						  CLK_SET_RATE_GATE);
 	if (IS_ERR(hw))
 		return PTR_ERR(hw);
 
-	return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw);
+	sai_clk->bclk_hw = hw;
+
+	if (data->have_mclk) {
+		sai_clk->mclk_gate.reg = base + data->offset + I2S_CSR;
+		sai_clk->mclk_gate.bit_idx = CSR_TE_BIT;
+		sai_clk->mclk_gate.lock = &sai_clk->lock;
+
+		sai_clk->mclk_div.reg = base + I2S_MCR;
+		sai_clk->mclk_div.shift = CR2_DIV_SHIFT;
+		sai_clk->mclk_div.width = CR2_DIV_WIDTH;
+		sai_clk->mclk_div.lock = &sai_clk->lock;
+
+		pdata.index = 1; /* MCLK1 */
+		hw = devm_clk_hw_register_composite_pdata(dev, "MCLK",
+							  &pdata, 1, NULL, NULL,
+							  &sai_clk->mclk_div.hw,
+							  &clk_divider_ops,
+							  &sai_clk->mclk_gate.hw,
+							  &clk_gate_ops,
+							  CLK_SET_RATE_GATE);
+		if (IS_ERR(hw))
+			return PTR_ERR(hw);
+
+		sai_clk->mclk_hw = hw;
+
+		/* set clock direction, we are the MCLK output */
+		writel(MCR_MOE, base + I2S_MCR);
+	}
+
+	return devm_of_clk_add_hw_provider(dev, fsl_sai_of_clk_get, sai_clk);
 }
 
 static const struct fsl_sai_data fsl_sai_vf610_data = {
 	.offset	= 0,
+	.have_mclk = false,
 };
 
 static const struct fsl_sai_data fsl_sai_imx8mq_data = {
 	.offset	= 8,
+	.have_mclk = true,
 };
 
 static const struct of_device_id of_fsl_sai_clk_ids[] = {