Thread (13 messages) flat view 13 messages, 5 authors, 2021-08-24

Re: [PATCH v2 1/4] ASoC: rockchip: add support for i2s-tdm controller

From: Pierre-Louis Bossart <hidden>
Date: 2021-08-23 15:02:50
Also in: alsa-devel, linux-rockchip, lkml


On 8/21/21 3:45 PM, Nicolas Frattaroli wrote:
On Freitag, 20. August 2021 21:02:16 CEST Pierre-Louis Bossart wrote:
quoted
quoted
+	regmap_read(i2s_tdm->regmap, I2S_CLR, &val);
+	/* Wait on the clear operation to finish */
+	while (val) {
delay needed here?
The rockchip_i2s.c code doesn't have a delay here either, but I can
add one of 1 usec for good measure, it seems weird to retry the
read as fast as it can.
yep.
quoted
quoted
+static int rockchip_i2s_tdm_clk_set_rate(struct rk_i2s_tdm_dev *i2s_tdm,
+					 struct clk *clk, unsigned long rate,
+					 int ppm)
+{
+	unsigned long rate_target;
+	int delta, ret;
+
+	if (ppm == i2s_tdm->clk_ppm)
+		return 0;
+
+	delta = (ppm < 0) ? -1 : 1;
+	delta *= (int)div64_u64((u64)rate * (u64)abs(ppm) + 500000,
+				1000000);
formula looks odd? looks like you are implementing a round to nearest
operation, but that shouldn't require this multiplication?
I believe the multiplication is there to compensate for clock drift.
ppm is a value between -1000 and 1000 that specifies the clock drift
in presumably parts per million, going by the variable name.
I meant using a signed division with lsb round-to-nearest, something like:

delta = (int)div64_u64((u64)rate * (u64)(ppm) + 500000,
			1000000);
quoted
quoted
+	pm_runtime_enable(&pdev->dev);
+	if (!pm_runtime_enabled(&pdev->dev)) {
+		ret = i2s_tdm_runtime_resume(&pdev->dev);
that looks like dead code? you've just enabled pm_runtime, why would
this fail?
I've had a look at the upstream rockchip_i2s.c code which does the
same thing, and I believe the idea here is that we need to manually
prepare and enable the master clocks (mclk_rx/mclk_tx) if pm_runtime
is not available. Otherwise, pm_runtime will presumably call our
resume callback at some point.

If runtime power management is disabled in the kernel config then 
pm_runtime_enabled is always going to return false.
that seems very odd. why not enable the clocks by default and let them
stop in suspend.
quoted
quoted
+err_suspend:
+	if (!pm_runtime_status_suspended(&pdev->dev))
+		i2s_tdm_runtime_suspend(&pdev->dev);
why is this necessary?
I believe this is the same kind of situation as before, and the
other driver does this too: if pm_runtime is not available, we
need to stop our clocks manually on probe failure.
then use pm_runtime_disable() and manually stop the clocks...
quoted
quoted
+err_pm_disable:
+	pm_runtime_disable(&pdev->dev);>>> +
+	return ret;
+}
+
+static int rockchip_i2s_tdm_remove(struct platform_device *pdev)
+{
+	struct rk_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(&pdev->dev);
+
+	pm_runtime_disable(&pdev->dev);
+	if (!pm_runtime_status_suspended(&pdev->dev))
+		i2s_tdm_runtime_suspend(&pdev->dev);
this looks backwards, if you disable pm_runtime first what is the
expectation for the rest.
I'm not well versed in the PM code but if my theory of this being
related to unavailable PM is correct, then my best guess is that
pm_runtime_disable does suspend the device, so if it's not
suspended then we don't have pm_runtime and therefore need to call
it manually.
I think this is really doing things backwards. You want to
unconditionally enable all resources on probe, and let them go to idle
when no one needs them - or if pm_runtime is disabled.
quoted
quoted
+
+	if (!IS_ERR(i2s_tdm->mclk_tx))
+		clk_prepare_enable(i2s_tdm->mclk_tx);
+	if (!IS_ERR(i2s_tdm->mclk_rx))
+		clk_prepare_enable(i2s_tdm->mclk_rx);
+	if (!IS_ERR(i2s_tdm->hclk))
+		clk_disable_unprepare(i2s_tdm->hclk);
+
+	return 0;>>> +}
+
+#ifdef CONFIG_PM_SLEEP
use __maybe_unused
You mean instead of the ifdef stuff to just add this attribute to
the following functions like this?

static int rockchip_i2s_tdm_suspend(struct device *dev) __maybe_unused
yes
quoted
quoted
+static int rockchip_i2s_tdm_suspend(struct device *dev)
+{
+	struct rk_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(dev);
+
+	regcache_mark_dirty(i2s_tdm->regmap);
+
+	return 0;
+}
+
+static int rockchip_i2s_tdm_resume(struct device *dev)
+{
+	struct rk_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(dev);
+	int ret;
+
+	ret = pm_runtime_get_sync(dev);
+	if (ret < 0)
+		return ret;
+	ret = regcache_sync(i2s_tdm->regmap);
+	pm_runtime_put(dev);
+
+	return ret;
+}
+#endif
Thank you for your review!

Regards,
Nicolas Frattaroli

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help