linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers
@ 2021-03-14 15:44 Dmitry Osipenko
  2021-03-14 15:44 ` [PATCH v5 01/17] ASoC: tegra20: ac97: Add reset control Dmitry Osipenko
                   ` (18 more replies)
  0 siblings, 19 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2021-03-14 15:44 UTC (permalink / raw)
  To: Thierry Reding, Jonathan Hunter, Mark Brown, Takashi Iwai,
	Jaroslav Kysela, Philipp Zabel, Paul Fertser
  Cc: alsa-devel, devicetree, linux-tegra, linux-kernel

Hi,

This series adds missing hardware reset controls to I2S and AC97 drivers,
corrects runtime PM usage and drivers probe/remove order. Currently drivers
happen to work properly because reset is implicitly deasserted by tegra-clk
driver, but clk driver shouldn't touch the resets and we need to fix it
because this breaks other Tegra drivers. Previously we fixed the resets of
the AHUB and HDMI codec drivers, but turned out that we missed the I2C and
AC97 drivers.

Thanks to Paul Fertser for testing the pending clk patches and finding
that audio got broken on Tegra20 AC100 netbook because of the missing I2S
reset.

Changelog:

v5: - After taking another look at the drivers I noticed couple more
      things that could be improved. These new patches correct runtime PM
      and probe/remove order of the drivers:

        ASoC: tegra20: spdif: Correct driver removal order
        ASoC: tegra20: spdif: Remove handing of disabled runtime PM
        ASoC: tegra20: i2s: Add system level suspend-resume callbacks
        ASoC: tegra20: i2s: Correct driver removal order
        ASoC: tegra20: i2s: Use devm_clk_get()
        ASoC: tegra20: i2s: Remove handing of disabled runtime PM
        ASoC: tegra30: i2s: Correct driver removal order
        ASoC: tegra30: i2s: Use devm_clk_get()
        ASoC: tegra30: i2s: Remove handing of disabled runtime PM
        ASoC: tegra30: ahub: Reset global variable
        ASoC: tegra30: ahub: Correct suspend-resume callbacks
        ASoC: tegra30: ahub: Remove handing of disabled runtime PM

v4: - Added missing prototype for reset_control_bulk_put().

v3: - Fixed reset stubs for !CONFIG_RESET_CONTROLLER.

v2: - After some more testing I found that I2S control logic doesn't require
      I2S clock to be enabled for resetting. Hence it's fine to have I2S to
      be reset by parent AHUB driver, so I dropped "tegra30: i2s: Add reset
      control" patch.

    - While I was double-checking resets on Tegra30, I found that that
      Tegra30 I2S driver has a broken runtime PM which doesn't restore
      hardware state on resume and it's lost after AHUB RPM-resume.
      Thus, added this new patch "tegra30: i2s: Restore hardware state
      on runtime PM resume".

    - Added new patches which switch AHUB driver to use reset-bulk API.
      I took the RFC patch from Philipp Zabel, fixed it and added
      devm_reset_control_bulk_optional_get_exclusive_released() that
      will be useful for further Tegra GPU patches. This is a minor
      improvement which makes code cleaner.

Dmitry Osipenko (16):
  ASoC: tegra20: ac97: Add reset control
  ASoC: tegra20: i2s: Add reset control
  ASoC: tegra30: i2s: Restore hardware state on runtime PM resume
  ASoC: tegra30: ahub: Switch to use reset-bulk API
  ASoC: tegra20: spdif: Correct driver removal order
  ASoC: tegra20: spdif: Remove handing of disabled runtime PM
  ASoC: tegra20: i2s: Add system level suspend-resume callbacks
  ASoC: tegra20: i2s: Correct driver removal order
  ASoC: tegra20: i2s: Use devm_clk_get()
  ASoC: tegra20: i2s: Remove handing of disabled runtime PM
  ASoC: tegra30: i2s: Correct driver removal order
  ASoC: tegra30: i2s: Use devm_clk_get()
  ASoC: tegra30: i2s: Remove handing of disabled runtime PM
  ASoC: tegra30: ahub: Reset global variable
  ASoC: tegra30: ahub: Correct suspend-resume callbacks
  ASoC: tegra30: ahub: Remove handing of disabled runtime PM

Philipp Zabel (1):
  reset: Add reset_control_bulk API

 drivers/reset/core.c            | 215 ++++++++++++++++++++++
 include/linux/reset.h           | 315 ++++++++++++++++++++++++++++++++
 sound/soc/tegra/tegra20_ac97.c  |  21 +++
 sound/soc/tegra/tegra20_ac97.h  |   1 +
 sound/soc/tegra/tegra20_i2s.c   |  60 +++---
 sound/soc/tegra/tegra20_i2s.h   |   1 +
 sound/soc/tegra/tegra20_spdif.c |  16 +-
 sound/soc/tegra/tegra30_ahub.c  | 168 ++++++-----------
 sound/soc/tegra/tegra30_ahub.h  |   5 +-
 sound/soc/tegra/tegra30_i2s.c   |  65 ++-----
 10 files changed, 667 insertions(+), 200 deletions(-)

-- 
2.30.2


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH v5 01/17] ASoC: tegra20: ac97: Add reset control
  2021-03-14 15:44 [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers Dmitry Osipenko
@ 2021-03-14 15:44 ` Dmitry Osipenko
  2021-03-14 15:44 ` [PATCH v5 02/17] ASoC: tegra20: i2s: " Dmitry Osipenko
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2021-03-14 15:44 UTC (permalink / raw)
  To: Thierry Reding, Jonathan Hunter, Mark Brown, Takashi Iwai,
	Jaroslav Kysela, Philipp Zabel, Paul Fertser
  Cc: alsa-devel, devicetree, linux-tegra, linux-kernel

Tegra20 AC97 driver doesn't manage the AC97 controller reset, relying on
implicit deassertion of the reset by tegra-clk driver, which needs to be
fixed since this behaviour is unacceptable by other Tegra drivers. Add
explicit reset control to the Tegra20 AC97 driver.

Note that AC97 reset was always specified in Tegra20 device-tree, hence
DTB ABI changes aren't required.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 sound/soc/tegra/tegra20_ac97.c | 21 +++++++++++++++++++++
 sound/soc/tegra/tegra20_ac97.h |  1 +
 2 files changed, 22 insertions(+)

diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c
index 06c728ae17ed..c454a34c15c4 100644
--- a/sound/soc/tegra/tegra20_ac97.c
+++ b/sound/soc/tegra/tegra20_ac97.c
@@ -21,6 +21,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
+#include <linux/reset.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -313,6 +314,12 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
 	}
 	dev_set_drvdata(&pdev->dev, ac97);
 
+	ac97->reset = devm_reset_control_get_exclusive(&pdev->dev, "ac97");
+	if (IS_ERR(ac97->reset)) {
+		dev_err(&pdev->dev, "Can't retrieve ac97 reset\n");
+		return PTR_ERR(ac97->reset);
+	}
+
 	ac97->clk_ac97 = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(ac97->clk_ac97)) {
 		dev_err(&pdev->dev, "Can't retrieve ac97 clock\n");
@@ -364,12 +371,26 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
 	ac97->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 	ac97->playback_dma_data.maxburst = 4;
 
+	ret = reset_control_assert(ac97->reset);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to assert AC'97 reset: %d\n", ret);
+		goto err_clk_put;
+	}
+
 	ret = clk_prepare_enable(ac97->clk_ac97);
 	if (ret) {
 		dev_err(&pdev->dev, "clk_enable failed: %d\n", ret);
 		goto err_clk_put;
 	}
 
+	usleep_range(10, 100);
+
+	ret = reset_control_deassert(ac97->reset);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to deassert AC'97 reset: %d\n", ret);
+		goto err_clk_disable_unprepare;
+	}
+
 	ret = snd_soc_set_ac97_ops(&tegra20_ac97_ops);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
diff --git a/sound/soc/tegra/tegra20_ac97.h b/sound/soc/tegra/tegra20_ac97.h
index e467cd1ff2ca..870ea09ff301 100644
--- a/sound/soc/tegra/tegra20_ac97.h
+++ b/sound/soc/tegra/tegra20_ac97.h
@@ -78,6 +78,7 @@ struct tegra20_ac97 {
 	struct clk *clk_ac97;
 	struct snd_dmaengine_dai_dma_data capture_dma_data;
 	struct snd_dmaengine_dai_dma_data playback_dma_data;
+	struct reset_control *reset;
 	struct regmap *regmap;
 	int reset_gpio;
 	int sync_gpio;
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v5 02/17] ASoC: tegra20: i2s: Add reset control
  2021-03-14 15:44 [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers Dmitry Osipenko
  2021-03-14 15:44 ` [PATCH v5 01/17] ASoC: tegra20: ac97: Add reset control Dmitry Osipenko
@ 2021-03-14 15:44 ` Dmitry Osipenko
  2021-03-14 15:44 ` [PATCH v5 03/17] ASoC: tegra30: i2s: Restore hardware state on runtime PM resume Dmitry Osipenko
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2021-03-14 15:44 UTC (permalink / raw)
  To: Thierry Reding, Jonathan Hunter, Mark Brown, Takashi Iwai,
	Jaroslav Kysela, Philipp Zabel, Paul Fertser
  Cc: alsa-devel, devicetree, linux-tegra, linux-kernel

The I2S reset may be asserted at a boot time, in particular this is the
case on Tegra20 AC100 netbook. Tegra20 I2S driver doesn't manage the
reset control and currently it happens to work because reset is implicitly
deasserted by the tegra-clk driver when I2S clock is enabled. The I2S
permanently stays in a reset once tegra-clk is fixed to not touch the
resets, which it shouldn't be doing. Add reset control to the Tegra20
I2S driver.

Note that I2S reset was always specified in Tegra20 device-tree, hence
DTB ABI changes aren't required.

Tested-by: Paul Fertser <fercerpav@gmail.com> # T20 AC100
Reported-by: Paul Fertser <fercerpav@gmail.com>
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 sound/soc/tegra/tegra20_i2s.c | 31 +++++++++++++++++++++++++++++++
 sound/soc/tegra/tegra20_i2s.h |  1 +
 2 files changed, 32 insertions(+)

diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c
index d7a3d046c8f8..c0af5352b483 100644
--- a/sound/soc/tegra/tegra20_i2s.c
+++ b/sound/soc/tegra/tegra20_i2s.c
@@ -22,6 +22,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
+#include <linux/reset.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -37,6 +38,8 @@ static int tegra20_i2s_runtime_suspend(struct device *dev)
 {
 	struct tegra20_i2s *i2s = dev_get_drvdata(dev);
 
+	regcache_cache_only(i2s->regmap, true);
+
 	clk_disable_unprepare(i2s->clk_i2s);
 
 	return 0;
@@ -47,13 +50,35 @@ static int tegra20_i2s_runtime_resume(struct device *dev)
 	struct tegra20_i2s *i2s = dev_get_drvdata(dev);
 	int ret;
 
+	ret = reset_control_assert(i2s->reset);
+	if (ret)
+		return ret;
+
 	ret = clk_prepare_enable(i2s->clk_i2s);
 	if (ret) {
 		dev_err(dev, "clk_enable failed: %d\n", ret);
 		return ret;
 	}
 
+	usleep_range(10, 100);
+
+	ret = reset_control_deassert(i2s->reset);
+	if (ret)
+		goto disable_clocks;
+
+	regcache_cache_only(i2s->regmap, false);
+	regcache_mark_dirty(i2s->regmap);
+
+	ret = regcache_sync(i2s->regmap);
+	if (ret)
+		goto disable_clocks;
+
 	return 0;
+
+disable_clocks:
+	clk_disable_unprepare(i2s->clk_i2s);
+
+	return ret;
 }
 
 static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai,
@@ -339,6 +364,12 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev)
 	i2s->dai = tegra20_i2s_dai_template;
 	i2s->dai.name = dev_name(&pdev->dev);
 
+	i2s->reset = devm_reset_control_get_exclusive(&pdev->dev, "i2s");
+	if (IS_ERR(i2s->reset)) {
+		dev_err(&pdev->dev, "Can't retrieve i2s reset\n");
+		return PTR_ERR(i2s->reset);
+	}
+
 	i2s->clk_i2s = clk_get(&pdev->dev, NULL);
 	if (IS_ERR(i2s->clk_i2s)) {
 		dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
diff --git a/sound/soc/tegra/tegra20_i2s.h b/sound/soc/tegra/tegra20_i2s.h
index 628d3ca09f42..8233e5fa2eff 100644
--- a/sound/soc/tegra/tegra20_i2s.h
+++ b/sound/soc/tegra/tegra20_i2s.h
@@ -144,6 +144,7 @@ struct tegra20_i2s {
 	struct snd_dmaengine_dai_dma_data capture_dma_data;
 	struct snd_dmaengine_dai_dma_data playback_dma_data;
 	struct regmap *regmap;
+	struct reset_control *reset;
 };
 
 #endif
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v5 03/17] ASoC: tegra30: i2s: Restore hardware state on runtime PM resume
  2021-03-14 15:44 [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers Dmitry Osipenko
  2021-03-14 15:44 ` [PATCH v5 01/17] ASoC: tegra20: ac97: Add reset control Dmitry Osipenko
  2021-03-14 15:44 ` [PATCH v5 02/17] ASoC: tegra20: i2s: " Dmitry Osipenko
@ 2021-03-14 15:44 ` Dmitry Osipenko
  2021-03-14 15:44 ` [PATCH v5 04/17] reset: Add reset_control_bulk API Dmitry Osipenko
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2021-03-14 15:44 UTC (permalink / raw)
  To: Thierry Reding, Jonathan Hunter, Mark Brown, Takashi Iwai,
	Jaroslav Kysela, Philipp Zabel, Paul Fertser
  Cc: alsa-devel, devicetree, linux-tegra, linux-kernel

Tegra30 I2S driver syncs regmap cache only on resume from system suspend,
but hardware is reset across the runtime suspend because RPM of the parent
AHUB driver resets the I2S hardware, hence h/w state is lost after each
RPM resume. The problem isn't visible because hardware happens to be fully
reprogrammed after each RPM resume. Move hardware syncing to RPM resume in
order to restore h/w state properly.

Fixes: ed9ce1ed2239 ("ASoC: tegra: ahub: Reset hardware properly")
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 sound/soc/tegra/tegra30_i2s.c | 40 +++++++++++------------------------
 1 file changed, 12 insertions(+), 28 deletions(-)

diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
index 6740df541508..3d22c1be6f3d 100644
--- a/sound/soc/tegra/tegra30_i2s.c
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -58,8 +58,18 @@ static int tegra30_i2s_runtime_resume(struct device *dev)
 	}
 
 	regcache_cache_only(i2s->regmap, false);
+	regcache_mark_dirty(i2s->regmap);
+
+	ret = regcache_sync(i2s->regmap);
+	if (ret)
+		goto disable_clocks;
 
 	return 0;
+
+disable_clocks:
+	clk_disable_unprepare(i2s->clk_i2s);
+
+	return ret;
 }
 
 static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai,
@@ -551,37 +561,11 @@ static int tegra30_i2s_platform_remove(struct platform_device *pdev)
 	return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int tegra30_i2s_suspend(struct device *dev)
-{
-	struct tegra30_i2s *i2s = dev_get_drvdata(dev);
-
-	regcache_mark_dirty(i2s->regmap);
-
-	return 0;
-}
-
-static int tegra30_i2s_resume(struct device *dev)
-{
-	struct tegra30_i2s *i2s = dev_get_drvdata(dev);
-	int ret;
-
-	ret = pm_runtime_get_sync(dev);
-	if (ret < 0) {
-		pm_runtime_put(dev);
-		return ret;
-	}
-	ret = regcache_sync(i2s->regmap);
-	pm_runtime_put(dev);
-
-	return ret;
-}
-#endif
-
 static const struct dev_pm_ops tegra30_i2s_pm_ops = {
 	SET_RUNTIME_PM_OPS(tegra30_i2s_runtime_suspend,
 			   tegra30_i2s_runtime_resume, NULL)
-	SET_SYSTEM_SLEEP_PM_OPS(tegra30_i2s_suspend, tegra30_i2s_resume)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
 };
 
 static struct platform_driver tegra30_i2s_driver = {
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v5 04/17] reset: Add reset_control_bulk API
  2021-03-14 15:44 [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers Dmitry Osipenko
                   ` (2 preceding siblings ...)
  2021-03-14 15:44 ` [PATCH v5 03/17] ASoC: tegra30: i2s: Restore hardware state on runtime PM resume Dmitry Osipenko
@ 2021-03-14 15:44 ` Dmitry Osipenko
  2021-03-14 15:44 ` [PATCH v5 05/17] ASoC: tegra30: ahub: Switch to use reset-bulk API Dmitry Osipenko
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2021-03-14 15:44 UTC (permalink / raw)
  To: Thierry Reding, Jonathan Hunter, Mark Brown, Takashi Iwai,
	Jaroslav Kysela, Philipp Zabel, Paul Fertser
  Cc: alsa-devel, devicetree, linux-tegra, linux-kernel

From: Philipp Zabel <p.zabel@pengutronix.de>

Follow the clock and regulator subsystems' lead and add a bulk API
for reset controls.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Tested-by: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/reset/core.c  | 215 ++++++++++++++++++++++++++++
 include/linux/reset.h | 315 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 530 insertions(+)

diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index dbf881b586d9..71c1c8264b2d 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -358,6 +358,30 @@ int reset_control_reset(struct reset_control *rstc)
 }
 EXPORT_SYMBOL_GPL(reset_control_reset);
 
+/**
+ * reset_control_bulk_reset - reset the controlled devices in order
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset controls set
+ *
+ * Issue a reset on all provided reset controls, in order.
+ *
+ * See also: reset_control_reset()
+ */
+int reset_control_bulk_reset(int num_rstcs,
+			     struct reset_control_bulk_data *rstcs)
+{
+	int ret, i;
+
+	for (i = 0; i < num_rstcs; i++) {
+		ret = reset_control_reset(rstcs[i].rstc);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(reset_control_bulk_reset);
+
 /**
  * reset_control_rearm - allow shared reset line to be re-triggered"
  * @rstc: reset controller
@@ -461,6 +485,36 @@ int reset_control_assert(struct reset_control *rstc)
 }
 EXPORT_SYMBOL_GPL(reset_control_assert);
 
+/**
+ * reset_control_bulk_assert - asserts the reset lines in order
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset controls set
+ *
+ * Assert the reset lines for all provided reset controls, in order.
+ * If an assertion fails, already asserted resets are deasserted again.
+ *
+ * See also: reset_control_assert()
+ */
+int reset_control_bulk_assert(int num_rstcs,
+			      struct reset_control_bulk_data *rstcs)
+{
+	int ret, i;
+
+	for (i = 0; i < num_rstcs; i++) {
+		ret = reset_control_assert(rstcs[i].rstc);
+		if (ret)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	while (i--)
+		reset_control_deassert(rstcs[i].rstc);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(reset_control_bulk_assert);
+
 /**
  * reset_control_deassert - deasserts the reset line
  * @rstc: reset controller
@@ -511,6 +565,36 @@ int reset_control_deassert(struct reset_control *rstc)
 }
 EXPORT_SYMBOL_GPL(reset_control_deassert);
 
+/**
+ * reset_control_bulk_deassert - deasserts the reset lines in reverse order
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset controls set
+ *
+ * Deassert the reset lines for all provided reset controls, in reverse order.
+ * If a deassertion fails, already deasserted resets are asserted again.
+ *
+ * See also: reset_control_deassert()
+ */
+int reset_control_bulk_deassert(int num_rstcs,
+				struct reset_control_bulk_data *rstcs)
+{
+	int ret, i;
+
+	for (i = num_rstcs - 1; i >= 0; i--) {
+		ret = reset_control_deassert(rstcs[i].rstc);
+		if (ret)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	while (i < num_rstcs)
+		reset_control_assert(rstcs[i++].rstc);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(reset_control_bulk_deassert);
+
 /**
  * reset_control_status - returns a negative errno if not supported, a
  * positive value if the reset line is asserted, or zero if the reset
@@ -588,6 +672,36 @@ int reset_control_acquire(struct reset_control *rstc)
 }
 EXPORT_SYMBOL_GPL(reset_control_acquire);
 
+/**
+ * reset_control_bulk_acquire - acquires reset controls for exclusive use
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset controls set
+ *
+ * This is used to explicitly acquire reset controls requested with
+ * reset_control_bulk_get_exclusive_release() for temporary exclusive use.
+ *
+ * See also: reset_control_acquire(), reset_control_bulk_release()
+ */
+int reset_control_bulk_acquire(int num_rstcs,
+			       struct reset_control_bulk_data *rstcs)
+{
+	int ret, i;
+
+	for (i = 0; i < num_rstcs; i++) {
+		ret = reset_control_acquire(rstcs[i].rstc);
+		if (ret)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	while (i--)
+		reset_control_release(rstcs[i].rstc);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(reset_control_bulk_acquire);
+
 /**
  * reset_control_release() - releases exclusive access to a reset control
  * @rstc: reset control
@@ -610,6 +724,26 @@ void reset_control_release(struct reset_control *rstc)
 }
 EXPORT_SYMBOL_GPL(reset_control_release);
 
+/**
+ * reset_control_bulk_release() - releases exclusive access to reset controls
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset controls set
+ *
+ * Releases exclusive access right to reset controls previously obtained by a
+ * call to reset_control_bulk_acquire().
+ *
+ * See also: reset_control_release(), reset_control_bulk_acquire()
+ */
+void reset_control_bulk_release(int num_rstcs,
+				struct reset_control_bulk_data *rstcs)
+{
+	int i;
+
+	for (i = 0; i < num_rstcs; i++)
+		reset_control_release(rstcs[i].rstc);
+}
+EXPORT_SYMBOL_GPL(reset_control_bulk_release);
+
 static struct reset_control *__reset_control_get_internal(
 				struct reset_controller_dev *rcdev,
 				unsigned int index, bool shared, bool acquired)
@@ -814,6 +948,32 @@ struct reset_control *__reset_control_get(struct device *dev, const char *id,
 }
 EXPORT_SYMBOL_GPL(__reset_control_get);
 
+int __reset_control_bulk_get(struct device *dev, int num_rstcs,
+			     struct reset_control_bulk_data *rstcs,
+			     bool shared, bool optional, bool acquired)
+{
+	int ret, i;
+
+	for (i = 0; i < num_rstcs; i++) {
+		rstcs[i].rstc = __reset_control_get(dev, rstcs[i].id, 0,
+						    shared, optional, acquired);
+		if (IS_ERR(rstcs[i].rstc)) {
+			ret = PTR_ERR(rstcs[i].rstc);
+			goto err;
+		}
+	}
+
+	return 0;
+
+err:
+	mutex_lock(&reset_list_mutex);
+	while (i--)
+		__reset_control_put_internal(rstcs[i].rstc);
+	mutex_unlock(&reset_list_mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(__reset_control_bulk_get);
+
 static void reset_control_array_put(struct reset_control_array *resets)
 {
 	int i;
@@ -845,6 +1005,23 @@ void reset_control_put(struct reset_control *rstc)
 }
 EXPORT_SYMBOL_GPL(reset_control_put);
 
+/**
+ * reset_control_bulk_put - free the reset controllers
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset controls set
+ */
+void reset_control_bulk_put(int num_rstcs, struct reset_control_bulk_data *rstcs)
+{
+	mutex_lock(&reset_list_mutex);
+	while (num_rstcs--) {
+		if (IS_ERR_OR_NULL(rstcs[num_rstcs].rstc))
+			continue;
+		__reset_control_put_internal(rstcs[num_rstcs].rstc);
+	}
+	mutex_unlock(&reset_list_mutex);
+}
+EXPORT_SYMBOL_GPL(reset_control_bulk_put);
+
 static void devm_reset_control_release(struct device *dev, void *res)
 {
 	reset_control_put(*(struct reset_control **)res);
@@ -874,6 +1051,44 @@ struct reset_control *__devm_reset_control_get(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(__devm_reset_control_get);
 
+struct reset_control_bulk_devres {
+	int num_rstcs;
+	struct reset_control_bulk_data *rstcs;
+};
+
+static void devm_reset_control_bulk_release(struct device *dev, void *res)
+{
+	struct reset_control_bulk_devres *devres = res;
+
+	reset_control_bulk_put(devres->num_rstcs, devres->rstcs);
+}
+
+int __devm_reset_control_bulk_get(struct device *dev, int num_rstcs,
+				  struct reset_control_bulk_data *rstcs,
+				  bool shared, bool optional, bool acquired)
+{
+	struct reset_control_bulk_devres *ptr;
+	int ret;
+
+	ptr = devres_alloc(devm_reset_control_bulk_release, sizeof(*ptr),
+			   GFP_KERNEL);
+	if (!ptr)
+		return -ENOMEM;
+
+	ret = __reset_control_bulk_get(dev, num_rstcs, rstcs, shared, optional, acquired);
+	if (ret < 0) {
+		devres_free(ptr);
+		return ret;
+	}
+
+	ptr->num_rstcs = num_rstcs;
+	ptr->rstcs = rstcs;
+	devres_add(dev, ptr);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(__devm_reset_control_bulk_get);
+
 /**
  * __device_reset - find reset controller associated with the device
  *                  and perform reset
diff --git a/include/linux/reset.h b/include/linux/reset.h
index b9109efa2a5c..46e6372cb431 100644
--- a/include/linux/reset.h
+++ b/include/linux/reset.h
@@ -10,6 +10,21 @@ struct device;
 struct device_node;
 struct reset_control;
 
+/**
+ * struct reset_control_bulk_data - Data used for bulk reset control operations.
+ *
+ * @id: reset control consumer ID
+ * @rstc: struct reset_control * to store the associated reset control
+ *
+ * The reset APIs provide a series of reset_control_bulk_*() API calls as
+ * a convenience to consumers which require multiple reset controls.
+ * This structure is used to manage data for these calls.
+ */
+struct reset_control_bulk_data {
+	const char			*id;
+	struct reset_control		*rstc;
+};
+
 #ifdef CONFIG_RESET_CONTROLLER
 
 int reset_control_reset(struct reset_control *rstc);
@@ -20,6 +35,12 @@ int reset_control_status(struct reset_control *rstc);
 int reset_control_acquire(struct reset_control *rstc);
 void reset_control_release(struct reset_control *rstc);
 
+int reset_control_bulk_reset(int num_rstcs, struct reset_control_bulk_data *rstcs);
+int reset_control_bulk_assert(int num_rstcs, struct reset_control_bulk_data *rstcs);
+int reset_control_bulk_deassert(int num_rstcs, struct reset_control_bulk_data *rstcs);
+int reset_control_bulk_acquire(int num_rstcs, struct reset_control_bulk_data *rstcs);
+void reset_control_bulk_release(int num_rstcs, struct reset_control_bulk_data *rstcs);
+
 struct reset_control *__of_reset_control_get(struct device_node *node,
 				     const char *id, int index, bool shared,
 				     bool optional, bool acquired);
@@ -27,10 +48,18 @@ struct reset_control *__reset_control_get(struct device *dev, const char *id,
 					  int index, bool shared,
 					  bool optional, bool acquired);
 void reset_control_put(struct reset_control *rstc);
+int __reset_control_bulk_get(struct device *dev, int num_rstcs,
+			     struct reset_control_bulk_data *rstcs,
+			     bool shared, bool optional, bool acquired);
+void reset_control_bulk_put(int num_rstcs, struct reset_control_bulk_data *rstcs);
+
 int __device_reset(struct device *dev, bool optional);
 struct reset_control *__devm_reset_control_get(struct device *dev,
 				     const char *id, int index, bool shared,
 				     bool optional, bool acquired);
+int __devm_reset_control_bulk_get(struct device *dev, int num_rstcs,
+				  struct reset_control_bulk_data *rstcs,
+				  bool shared, bool optional, bool acquired);
 
 struct reset_control *devm_reset_control_array_get(struct device *dev,
 						   bool shared, bool optional);
@@ -96,6 +125,48 @@ static inline struct reset_control *__reset_control_get(
 	return optional ? NULL : ERR_PTR(-ENOTSUPP);
 }
 
+static inline int
+reset_control_bulk_reset(int num_rstcs, struct reset_control_bulk_data *rstcs)
+{
+	return 0;
+}
+
+static inline int
+reset_control_bulk_assert(int num_rstcs, struct reset_control_bulk_data *rstcs)
+{
+	return 0;
+}
+
+static inline int
+reset_control_bulk_deassert(int num_rstcs, struct reset_control_bulk_data *rstcs)
+{
+	return 0;
+}
+
+static inline int
+reset_control_bulk_acquire(int num_rstcs, struct reset_control_bulk_data *rstcs)
+{
+	return 0;
+}
+
+static inline void
+reset_control_bulk_release(int num_rstcs, struct reset_control_bulk_data *rstcs)
+{
+}
+
+static inline int
+__reset_control_bulk_get(struct device *dev, int num_rstcs,
+			 struct reset_control_bulk_data *rstcs,
+			 bool shared, bool optional, bool acquired)
+{
+	return optional ? 0 : -EOPNOTSUPP;
+}
+
+static inline void
+reset_control_bulk_put(int num_rstcs, struct reset_control_bulk_data *rstcs)
+{
+}
+
 static inline struct reset_control *__devm_reset_control_get(
 					struct device *dev, const char *id,
 					int index, bool shared, bool optional,
@@ -104,6 +175,14 @@ static inline struct reset_control *__devm_reset_control_get(
 	return optional ? NULL : ERR_PTR(-ENOTSUPP);
 }
 
+static inline int
+__devm_reset_control_bulk_get(struct device *dev, int num_rstcs,
+			      struct reset_control_bulk_data *rstcs,
+			      bool shared, bool optional, bool acquired)
+{
+	return optional ? 0 : -EOPNOTSUPP;
+}
+
 static inline struct reset_control *
 devm_reset_control_array_get(struct device *dev, bool shared, bool optional)
 {
@@ -155,6 +234,23 @@ __must_check reset_control_get_exclusive(struct device *dev, const char *id)
 	return __reset_control_get(dev, id, 0, false, false, true);
 }
 
+/**
+ * reset_control_bulk_get_exclusive - Lookup and obtain exclusive references to
+ *                                    multiple reset controllers.
+ * @dev: device to be reset by the controller
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset line names set
+ *
+ * Fills the rstcs array with pointers to exclusive reset controls and
+ * returns 0, or an IS_ERR() condition containing errno.
+ */
+static inline int __must_check
+reset_control_bulk_get_exclusive(struct device *dev, int num_rstcs,
+				 struct reset_control_bulk_data *rstcs)
+{
+	return __reset_control_bulk_get(dev, num_rstcs, rstcs, false, false, true);
+}
+
 /**
  * reset_control_get_exclusive_released - Lookup and obtain a temoprarily
  *                                        exclusive reference to a reset
@@ -176,6 +272,48 @@ __must_check reset_control_get_exclusive_released(struct device *dev,
 	return __reset_control_get(dev, id, 0, false, false, false);
 }
 
+/**
+ * reset_control_bulk_get_exclusive_released - Lookup and obtain temporarily
+ *                                    exclusive references to multiple reset
+ *                                    controllers.
+ * @dev: device to be reset by the controller
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset line names set
+ *
+ * Fills the rstcs array with pointers to exclusive reset controls and
+ * returns 0, or an IS_ERR() condition containing errno.
+ * reset-controls returned by this function must be acquired via
+ * reset_control_bulk_acquire() before they can be used and should be released
+ * via reset_control_bulk_release() afterwards.
+ */
+static inline int __must_check
+reset_control_bulk_get_exclusive_released(struct device *dev, int num_rstcs,
+					  struct reset_control_bulk_data *rstcs)
+{
+	return __reset_control_bulk_get(dev, num_rstcs, rstcs, false, false, false);
+}
+
+/**
+ * reset_control_bulk_get_optional_exclusive_released - Lookup and obtain optional
+ *                                    temporarily exclusive references to multiple
+ *                                    reset controllers.
+ * @dev: device to be reset by the controller
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset line names set
+ *
+ * Optional variant of reset_control_bulk_get_exclusive_released(). If the
+ * requested reset is not specified in the device tree, this function returns 0
+ * instead of an error and missing rtsc is set to NULL.
+ *
+ * See reset_control_bulk_get_exclusive_released() for more information.
+ */
+static inline int __must_check
+reset_control_bulk_get_optional_exclusive_released(struct device *dev, int num_rstcs,
+						   struct reset_control_bulk_data *rstcs)
+{
+	return __reset_control_bulk_get(dev, num_rstcs, rstcs, false, true, false);
+}
+
 /**
  * reset_control_get_shared - Lookup and obtain a shared reference to a
  *                            reset controller.
@@ -204,6 +342,23 @@ static inline struct reset_control *reset_control_get_shared(
 	return __reset_control_get(dev, id, 0, true, false, false);
 }
 
+/**
+ * reset_control_bulk_get_shared - Lookup and obtain shared references to
+ *                                 multiple reset controllers.
+ * @dev: device to be reset by the controller
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset line names set
+ *
+ * Fills the rstcs array with pointers to shared reset controls and
+ * returns 0, or an IS_ERR() condition containing errno.
+ */
+static inline int __must_check
+reset_control_bulk_get_shared(struct device *dev, int num_rstcs,
+			      struct reset_control_bulk_data *rstcs)
+{
+	return __reset_control_bulk_get(dev, num_rstcs, rstcs, true, false, false);
+}
+
 /**
  * reset_control_get_optional_exclusive - optional reset_control_get_exclusive()
  * @dev: device to be reset by the controller
@@ -221,6 +376,26 @@ static inline struct reset_control *reset_control_get_optional_exclusive(
 	return __reset_control_get(dev, id, 0, false, true, true);
 }
 
+/**
+ * reset_control_bulk_get_optional_exclusive - optional
+ *                                             reset_control_bulk_get_exclusive()
+ * @dev: device to be reset by the controller
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset line names set
+ *
+ * Optional variant of reset_control_bulk_get_exclusive(). If any of the
+ * requested resets are not specified in the device tree, this function sets
+ * them to NULL instead of returning an error.
+ *
+ * See reset_control_bulk_get_exclusive() for more information.
+ */
+static inline int __must_check
+reset_control_bulk_get_optional_exclusive(struct device *dev, int num_rstcs,
+					  struct reset_control_bulk_data *rstcs)
+{
+	return __reset_control_bulk_get(dev, num_rstcs, rstcs, false, true, true);
+}
+
 /**
  * reset_control_get_optional_shared - optional reset_control_get_shared()
  * @dev: device to be reset by the controller
@@ -238,6 +413,26 @@ static inline struct reset_control *reset_control_get_optional_shared(
 	return __reset_control_get(dev, id, 0, true, true, false);
 }
 
+/**
+ * reset_control_bulk_get_optional_shared - optional
+ *                                             reset_control_bulk_get_shared()
+ * @dev: device to be reset by the controller
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset line names set
+ *
+ * Optional variant of reset_control_bulk_get_shared(). If the requested resets
+ * are not specified in the device tree, this function sets them to NULL
+ * instead of returning an error.
+ *
+ * See reset_control_bulk_get_shared() for more information.
+ */
+static inline int __must_check
+reset_control_bulk_get_optional_shared(struct device *dev, int num_rstcs,
+				       struct reset_control_bulk_data *rstcs)
+{
+	return __reset_control_bulk_get(dev, num_rstcs, rstcs, true, true, false);
+}
+
 /**
  * of_reset_control_get_exclusive - Lookup and obtain an exclusive reference
  *                                  to a reset controller.
@@ -343,6 +538,26 @@ __must_check devm_reset_control_get_exclusive(struct device *dev,
 	return __devm_reset_control_get(dev, id, 0, false, false, true);
 }
 
+/**
+ * devm_reset_control_bulk_get_exclusive - resource managed
+ *                                         reset_control_bulk_get_exclusive()
+ * @dev: device to be reset by the controller
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset line names set
+ *
+ * Managed reset_control_bulk_get_exclusive(). For reset controllers returned
+ * from this function, reset_control_put() is called automatically on driver
+ * detach.
+ *
+ * See reset_control_bulk_get_exclusive() for more information.
+ */
+static inline int __must_check
+devm_reset_control_bulk_get_exclusive(struct device *dev, int num_rstcs,
+				      struct reset_control_bulk_data *rstcs)
+{
+	return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, false, false, true);
+}
+
 /**
  * devm_reset_control_get_exclusive_released - resource managed
  *                                             reset_control_get_exclusive_released()
@@ -362,6 +577,26 @@ __must_check devm_reset_control_get_exclusive_released(struct device *dev,
 	return __devm_reset_control_get(dev, id, 0, false, false, false);
 }
 
+/**
+ * devm_reset_control_bulk_get_exclusive_released - resource managed
+ *                                                  reset_control_bulk_get_exclusive_released()
+ * @dev: device to be reset by the controller
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset line names set
+ *
+ * Managed reset_control_bulk_get_exclusive_released(). For reset controllers
+ * returned from this function, reset_control_put() is called automatically on
+ * driver detach.
+ *
+ * See reset_control_bulk_get_exclusive_released() for more information.
+ */
+static inline int __must_check
+devm_reset_control_bulk_get_exclusive_released(struct device *dev, int num_rstcs,
+					       struct reset_control_bulk_data *rstcs)
+{
+	return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, false, false, false);
+}
+
 /**
  * devm_reset_control_get_optional_exclusive_released - resource managed
  *                                                      reset_control_get_optional_exclusive_released()
@@ -381,6 +616,26 @@ __must_check devm_reset_control_get_optional_exclusive_released(struct device *d
 	return __devm_reset_control_get(dev, id, 0, false, true, false);
 }
 
+/**
+ * devm_reset_control_bulk_get_optional_exclusive_released - resource managed
+ *                                                           reset_control_bulk_optional_get_exclusive_released()
+ * @dev: device to be reset by the controller
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset line names set
+ *
+ * Managed reset_control_bulk_optional_get_exclusive_released(). For reset
+ * controllers returned from this function, reset_control_put() is called
+ * automatically on driver detach.
+ *
+ * See reset_control_bulk_optional_get_exclusive_released() for more information.
+ */
+static inline int __must_check
+devm_reset_control_bulk_get_optional_exclusive_released(struct device *dev, int num_rstcs,
+							struct reset_control_bulk_data *rstcs)
+{
+	return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, false, true, false);
+}
+
 /**
  * devm_reset_control_get_shared - resource managed reset_control_get_shared()
  * @dev: device to be reset by the controller
@@ -396,6 +651,26 @@ static inline struct reset_control *devm_reset_control_get_shared(
 	return __devm_reset_control_get(dev, id, 0, true, false, false);
 }
 
+/**
+ * devm_reset_control_bulk_get_shared - resource managed
+ *                                      reset_control_bulk_get_shared()
+ * @dev: device to be reset by the controller
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset line names set
+ *
+ * Managed reset_control_bulk_get_shared(). For reset controllers returned
+ * from this function, reset_control_put() is called automatically on driver
+ * detach.
+ *
+ * See reset_control_bulk_get_shared() for more information.
+ */
+static inline int __must_check
+devm_reset_control_bulk_get_shared(struct device *dev, int num_rstcs,
+				   struct reset_control_bulk_data *rstcs)
+{
+	return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, true, false, false);
+}
+
 /**
  * devm_reset_control_get_optional_exclusive - resource managed
  *                                             reset_control_get_optional_exclusive()
@@ -414,6 +689,26 @@ static inline struct reset_control *devm_reset_control_get_optional_exclusive(
 	return __devm_reset_control_get(dev, id, 0, false, true, true);
 }
 
+/**
+ * devm_reset_control_bulk_get_optional_exclusive - resource managed
+ *                                                  reset_control_bulk_get_optional_exclusive()
+ * @dev: device to be reset by the controller
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset line names set
+ *
+ * Managed reset_control_bulk_get_optional_exclusive(). For reset controllers
+ * returned from this function, reset_control_put() is called automatically on
+ * driver detach.
+ *
+ * See reset_control_bulk_get_optional_exclusive() for more information.
+ */
+static inline int __must_check
+devm_reset_control_bulk_get_optional_exclusive(struct device *dev, int num_rstcs,
+					       struct reset_control_bulk_data *rstcs)
+{
+	return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, true, false, true);
+}
+
 /**
  * devm_reset_control_get_optional_shared - resource managed
  *                                          reset_control_get_optional_shared()
@@ -432,6 +727,26 @@ static inline struct reset_control *devm_reset_control_get_optional_shared(
 	return __devm_reset_control_get(dev, id, 0, true, true, false);
 }
 
+/**
+ * devm_reset_control_bulk_get_optional_shared - resource managed
+ *                                               reset_control_bulk_get_optional_shared()
+ * @dev: device to be reset by the controller
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset line names set
+ *
+ * Managed reset_control_bulk_get_optional_shared(). For reset controllers
+ * returned from this function, reset_control_put() is called automatically on
+ * driver detach.
+ *
+ * See reset_control_bulk_get_optional_shared() for more information.
+ */
+static inline int __must_check
+devm_reset_control_bulk_get_optional_shared(struct device *dev, int num_rstcs,
+					    struct reset_control_bulk_data *rstcs)
+{
+	return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, true, true, false);
+}
+
 /**
  * devm_reset_control_get_exclusive_by_index - resource managed
  *                                             reset_control_get_exclusive()
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v5 05/17] ASoC: tegra30: ahub: Switch to use reset-bulk API
  2021-03-14 15:44 [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers Dmitry Osipenko
                   ` (3 preceding siblings ...)
  2021-03-14 15:44 ` [PATCH v5 04/17] reset: Add reset_control_bulk API Dmitry Osipenko
@ 2021-03-14 15:44 ` Dmitry Osipenko
  2021-03-14 15:44 ` [PATCH v5 06/17] ASoC: tegra20: spdif: Correct driver removal order Dmitry Osipenko
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2021-03-14 15:44 UTC (permalink / raw)
  To: Thierry Reding, Jonathan Hunter, Mark Brown, Takashi Iwai,
	Jaroslav Kysela, Philipp Zabel, Paul Fertser
  Cc: alsa-devel, devicetree, linux-tegra, linux-kernel

Switch to use reset-bulk API in order to make code cleaner.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 sound/soc/tegra/tegra30_ahub.c | 104 ++++++++++++---------------------
 sound/soc/tegra/tegra30_ahub.h |   5 +-
 sound/soc/tegra/tegra30_i2s.c  |   1 +
 3 files changed, 40 insertions(+), 70 deletions(-)

diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
index 9ef05ca4f6c4..d24c26f4960d 100644
--- a/sound/soc/tegra/tegra30_ahub.c
+++ b/sound/soc/tegra/tegra30_ahub.c
@@ -65,7 +65,7 @@ static int tegra30_ahub_runtime_resume(struct device *dev)
 {
 	int ret;
 
-	ret = reset_control_assert(ahub->reset);
+	ret = reset_control_bulk_assert(ahub->nresets, ahub->resets);
 	if (ret)
 		return ret;
 
@@ -75,7 +75,7 @@ static int tegra30_ahub_runtime_resume(struct device *dev)
 
 	usleep_range(10, 100);
 
-	ret = reset_control_deassert(ahub->reset);
+	ret = reset_control_bulk_deassert(ahub->nresets, ahub->resets);
 	if (ret)
 		goto disable_clocks;
 
@@ -339,41 +339,28 @@ int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif)
 }
 EXPORT_SYMBOL_GPL(tegra30_ahub_unset_rx_cif_source);
 
-#define MOD_LIST_MASK_TEGRA30	BIT(0)
-#define MOD_LIST_MASK_TEGRA114	BIT(1)
-#define MOD_LIST_MASK_TEGRA124	BIT(2)
-
-#define MOD_LIST_MASK_TEGRA30_OR_LATER \
-		(MOD_LIST_MASK_TEGRA30 | MOD_LIST_MASK_TEGRA114 | \
-			MOD_LIST_MASK_TEGRA124)
-#define MOD_LIST_MASK_TEGRA114_OR_LATER \
-		(MOD_LIST_MASK_TEGRA114 | MOD_LIST_MASK_TEGRA124)
-
-static const struct {
-	const char *rst_name;
-	u32 mod_list_mask;
-} configlink_mods[] = {
-	{ "d_audio", MOD_LIST_MASK_TEGRA30_OR_LATER },
-	{ "apbif", MOD_LIST_MASK_TEGRA30_OR_LATER },
-	{ "i2s0", MOD_LIST_MASK_TEGRA30_OR_LATER },
-	{ "i2s1", MOD_LIST_MASK_TEGRA30_OR_LATER },
-	{ "i2s2", MOD_LIST_MASK_TEGRA30_OR_LATER },
-	{ "i2s3", MOD_LIST_MASK_TEGRA30_OR_LATER },
-	{ "i2s4", MOD_LIST_MASK_TEGRA30_OR_LATER },
-	{ "dam0", MOD_LIST_MASK_TEGRA30_OR_LATER },
-	{ "dam1", MOD_LIST_MASK_TEGRA30_OR_LATER },
-	{ "dam2", MOD_LIST_MASK_TEGRA30_OR_LATER },
-	{ "spdif", MOD_LIST_MASK_TEGRA30_OR_LATER },
-	{ "amx", MOD_LIST_MASK_TEGRA114_OR_LATER },
-	{ "adx", MOD_LIST_MASK_TEGRA114_OR_LATER },
-	{ "amx1", MOD_LIST_MASK_TEGRA124 },
-	{ "adx1", MOD_LIST_MASK_TEGRA124 },
-	{ "afc0", MOD_LIST_MASK_TEGRA124 },
-	{ "afc1", MOD_LIST_MASK_TEGRA124 },
-	{ "afc2", MOD_LIST_MASK_TEGRA124 },
-	{ "afc3", MOD_LIST_MASK_TEGRA124 },
-	{ "afc4", MOD_LIST_MASK_TEGRA124 },
-	{ "afc5", MOD_LIST_MASK_TEGRA124 },
+static const struct reset_control_bulk_data tegra30_ahub_resets_data[] = {
+	{ "d_audio" },
+	{ "apbif" },
+	{ "i2s0" },
+	{ "i2s1" },
+	{ "i2s2" },
+	{ "i2s3" },
+	{ "i2s4" },
+	{ "dam0" },
+	{ "dam1" },
+	{ "dam2" },
+	{ "spdif" },
+	{ "amx" }, /* Tegra114+ */
+	{ "adx" }, /* Tegra114+ */
+	{ "amx1" }, /* Tegra124 */
+	{ "adx1" }, /* Tegra124 */
+	{ "afc0" }, /* Tegra124 */
+	{ "afc1" }, /* Tegra124 */
+	{ "afc2" }, /* Tegra124 */
+	{ "afc3" }, /* Tegra124 */
+	{ "afc4" }, /* Tegra124 */
+	{ "afc5" }, /* Tegra124 */
 };
 
 #define LAST_REG(name) \
@@ -502,17 +489,17 @@ static const struct regmap_config tegra30_ahub_ahub_regmap_config = {
 };
 
 static struct tegra30_ahub_soc_data soc_data_tegra30 = {
-	.mod_list_mask = MOD_LIST_MASK_TEGRA30,
+	.num_resets = 11,
 	.set_audio_cif = tegra30_ahub_set_cif,
 };
 
 static struct tegra30_ahub_soc_data soc_data_tegra114 = {
-	.mod_list_mask = MOD_LIST_MASK_TEGRA114,
+	.num_resets = 13,
 	.set_audio_cif = tegra30_ahub_set_cif,
 };
 
 static struct tegra30_ahub_soc_data soc_data_tegra124 = {
-	.mod_list_mask = MOD_LIST_MASK_TEGRA124,
+	.num_resets = 21,
 	.set_audio_cif = tegra124_ahub_set_cif,
 };
 
@@ -527,8 +514,6 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
 {
 	const struct of_device_id *match;
 	const struct tegra30_ahub_soc_data *soc_data;
-	struct reset_control *rst;
-	int i;
 	struct resource *res0;
 	void __iomem *regs_apbif, *regs_ahub;
 	int ret = 0;
@@ -541,34 +526,16 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
 		return -EINVAL;
 	soc_data = match->data;
 
-	/*
-	 * The AHUB hosts a register bus: the "configlink". For this to
-	 * operate correctly, all devices on this bus must be out of reset.
-	 */
-	for (i = 0; i < ARRAY_SIZE(configlink_mods); i++) {
-		if (!(configlink_mods[i].mod_list_mask &
-					soc_data->mod_list_mask))
-			continue;
-
-		rst = reset_control_get_exclusive(&pdev->dev,
-						  configlink_mods[i].rst_name);
-		if (IS_ERR(rst)) {
-			dev_err(&pdev->dev, "Can't get reset %s\n",
-				configlink_mods[i].rst_name);
-			ret = PTR_ERR(rst);
-			return ret;
-		}
-
-		/* just check presence of the reset control in DT */
-		reset_control_put(rst);
-	}
-
 	ahub = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_ahub),
 			    GFP_KERNEL);
 	if (!ahub)
 		return -ENOMEM;
 	dev_set_drvdata(&pdev->dev, ahub);
 
+	BUILD_BUG_ON(sizeof(ahub->resets) != sizeof(tegra30_ahub_resets_data));
+	memcpy(ahub->resets, tegra30_ahub_resets_data, sizeof(ahub->resets));
+
+	ahub->nresets = soc_data->num_resets;
 	ahub->soc_data = soc_data;
 	ahub->dev = &pdev->dev;
 
@@ -579,10 +546,11 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	ahub->reset = devm_reset_control_array_get_exclusive(&pdev->dev);
-	if (IS_ERR(ahub->reset)) {
-		dev_err(&pdev->dev, "Can't get resets: %pe\n", ahub->reset);
-		return PTR_ERR(ahub->reset);
+	ret = devm_reset_control_bulk_get_exclusive(&pdev->dev, ahub->nresets,
+						    ahub->resets);
+	if (ret) {
+		dev_err(&pdev->dev, "Can't get resets: %d\n", ret);
+		return ret;
 	}
 
 	res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h
index 3b85244f87f1..c9eaf4ec8f6e 100644
--- a/sound/soc/tegra/tegra30_ahub.h
+++ b/sound/soc/tegra/tegra30_ahub.h
@@ -491,7 +491,7 @@ void tegra124_ahub_set_cif(struct regmap *regmap, unsigned int reg,
 			   struct tegra30_ahub_cif_conf *conf);
 
 struct tegra30_ahub_soc_data {
-	u32 mod_list_mask;
+	unsigned int num_resets;
 	void (*set_audio_cif)(struct regmap *regmap,
 			      unsigned int reg,
 			      struct tegra30_ahub_cif_conf *conf);
@@ -511,7 +511,8 @@ struct tegra30_ahub_soc_data {
 struct tegra30_ahub {
 	const struct tegra30_ahub_soc_data *soc_data;
 	struct device *dev;
-	struct reset_control *reset;
+	struct reset_control_bulk_data resets[21];
+	unsigned int nresets;
 	struct clk_bulk_data clocks[2];
 	unsigned int nclocks;
 	resource_size_t apbif_addr;
diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
index 3d22c1be6f3d..614b67be1dd9 100644
--- a/sound/soc/tegra/tegra30_i2s.c
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -23,6 +23,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
+#include <linux/reset.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v5 06/17] ASoC: tegra20: spdif: Correct driver removal order
  2021-03-14 15:44 [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers Dmitry Osipenko
                   ` (4 preceding siblings ...)
  2021-03-14 15:44 ` [PATCH v5 05/17] ASoC: tegra30: ahub: Switch to use reset-bulk API Dmitry Osipenko
@ 2021-03-14 15:44 ` Dmitry Osipenko
  2021-03-14 15:44 ` [PATCH v5 07/17] ASoC: tegra20: spdif: Remove handing of disabled runtime PM Dmitry Osipenko
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2021-03-14 15:44 UTC (permalink / raw)
  To: Thierry Reding, Jonathan Hunter, Mark Brown, Takashi Iwai,
	Jaroslav Kysela, Philipp Zabel, Paul Fertser
  Cc: alsa-devel, devicetree, linux-tegra, linux-kernel

Tegra20 SPDIF driver has a wrong driver removal order, which should be
opposite to the registration order, but it's not. In particular the
runtime PM is disabled in a wrong order. Fix the order.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 sound/soc/tegra/tegra20_spdif.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c
index 5839833e23a0..e48d332506a0 100644
--- a/sound/soc/tegra/tegra20_spdif.c
+++ b/sound/soc/tegra/tegra20_spdif.c
@@ -329,13 +329,13 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev)
 
 static int tegra20_spdif_platform_remove(struct platform_device *pdev)
 {
+	tegra_pcm_platform_unregister(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
+
 	pm_runtime_disable(&pdev->dev);
 	if (!pm_runtime_status_suspended(&pdev->dev))
 		tegra20_spdif_runtime_suspend(&pdev->dev);
 
-	tegra_pcm_platform_unregister(&pdev->dev);
-	snd_soc_unregister_component(&pdev->dev);
-
 	return 0;
 }
 
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v5 07/17] ASoC: tegra20: spdif: Remove handing of disabled runtime PM
  2021-03-14 15:44 [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers Dmitry Osipenko
                   ` (5 preceding siblings ...)
  2021-03-14 15:44 ` [PATCH v5 06/17] ASoC: tegra20: spdif: Correct driver removal order Dmitry Osipenko
@ 2021-03-14 15:44 ` Dmitry Osipenko
  2021-03-14 15:44 ` [PATCH v5 08/17] ASoC: tegra20: i2s: Add system level suspend-resume callbacks Dmitry Osipenko
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2021-03-14 15:44 UTC (permalink / raw)
  To: Thierry Reding, Jonathan Hunter, Mark Brown, Takashi Iwai,
	Jaroslav Kysela, Philipp Zabel, Paul Fertser
  Cc: alsa-devel, devicetree, linux-tegra, linux-kernel

Runtime PM is always available on Tegra since commit 40b2bb1b132a
("ARM: tegra: enforce PM requirement"), hence there is no need to
handle the case of a disabled RPM by Tegra drivers. Remove handing
of a disabled runtime PM from Tegra20 SPDIF driver.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 sound/soc/tegra/tegra20_spdif.c | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c
index e48d332506a0..7b597ee63cb5 100644
--- a/sound/soc/tegra/tegra20_spdif.c
+++ b/sound/soc/tegra/tegra20_spdif.c
@@ -294,18 +294,13 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev)
 	spdif->playback_dma_data.slave_id = dmareq->start;
 
 	pm_runtime_enable(&pdev->dev);
-	if (!pm_runtime_enabled(&pdev->dev)) {
-		ret = tegra20_spdif_runtime_resume(&pdev->dev);
-		if (ret)
-			goto err_pm_disable;
-	}
 
 	ret = snd_soc_register_component(&pdev->dev, &tegra20_spdif_component,
 					 &tegra20_spdif_dai, 1);
 	if (ret) {
 		dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
 		ret = -ENOMEM;
-		goto err_suspend;
+		goto err_pm_disable;
 	}
 
 	ret = tegra_pcm_platform_register(&pdev->dev);
@@ -318,9 +313,6 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev)
 
 err_unregister_component:
 	snd_soc_unregister_component(&pdev->dev);
-err_suspend:
-	if (!pm_runtime_status_suspended(&pdev->dev))
-		tegra20_spdif_runtime_suspend(&pdev->dev);
 err_pm_disable:
 	pm_runtime_disable(&pdev->dev);
 
@@ -333,8 +325,6 @@ static int tegra20_spdif_platform_remove(struct platform_device *pdev)
 	snd_soc_unregister_component(&pdev->dev);
 
 	pm_runtime_disable(&pdev->dev);
-	if (!pm_runtime_status_suspended(&pdev->dev))
-		tegra20_spdif_runtime_suspend(&pdev->dev);
 
 	return 0;
 }
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v5 08/17] ASoC: tegra20: i2s: Add system level suspend-resume callbacks
  2021-03-14 15:44 [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers Dmitry Osipenko
                   ` (6 preceding siblings ...)
  2021-03-14 15:44 ` [PATCH v5 07/17] ASoC: tegra20: spdif: Remove handing of disabled runtime PM Dmitry Osipenko
@ 2021-03-14 15:44 ` Dmitry Osipenko
  2021-03-14 15:44 ` [PATCH v5 09/17] ASoC: tegra20: i2s: Correct driver removal order Dmitry Osipenko
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2021-03-14 15:44 UTC (permalink / raw)
  To: Thierry Reding, Jonathan Hunter, Mark Brown, Takashi Iwai,
	Jaroslav Kysela, Philipp Zabel, Paul Fertser
  Cc: alsa-devel, devicetree, linux-tegra, linux-kernel

Add system level suspend-resume callbacks in order to ensure that I2S
is gated before system is suspended. This puts Tegra20 I2S driver on
par with the Tegra30 I2S driver.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 sound/soc/tegra/tegra20_i2s.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c
index c0af5352b483..267517446d27 100644
--- a/sound/soc/tegra/tegra20_i2s.c
+++ b/sound/soc/tegra/tegra20_i2s.c
@@ -460,6 +460,8 @@ static const struct of_device_id tegra20_i2s_of_match[] = {
 static const struct dev_pm_ops tegra20_i2s_pm_ops = {
 	SET_RUNTIME_PM_OPS(tegra20_i2s_runtime_suspend,
 			   tegra20_i2s_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
 };
 
 static struct platform_driver tegra20_i2s_driver = {
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v5 09/17] ASoC: tegra20: i2s: Correct driver removal order
  2021-03-14 15:44 [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers Dmitry Osipenko
                   ` (7 preceding siblings ...)
  2021-03-14 15:44 ` [PATCH v5 08/17] ASoC: tegra20: i2s: Add system level suspend-resume callbacks Dmitry Osipenko
@ 2021-03-14 15:44 ` Dmitry Osipenko
  2021-03-14 15:44 ` [PATCH v5 10/17] ASoC: tegra20: i2s: Use devm_clk_get() Dmitry Osipenko
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2021-03-14 15:44 UTC (permalink / raw)
  To: Thierry Reding, Jonathan Hunter, Mark Brown, Takashi Iwai,
	Jaroslav Kysela, Philipp Zabel, Paul Fertser
  Cc: alsa-devel, devicetree, linux-tegra, linux-kernel

Tegra20 I2S driver has a wrong driver removal order, which should be
opposite to the registration order, but it's not. In particular the
runtime PM is disabled in a wrong order. Fix the order.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 sound/soc/tegra/tegra20_i2s.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c
index 267517446d27..0f2bdc2e8598 100644
--- a/sound/soc/tegra/tegra20_i2s.c
+++ b/sound/soc/tegra/tegra20_i2s.c
@@ -440,13 +440,13 @@ static int tegra20_i2s_platform_remove(struct platform_device *pdev)
 {
 	struct tegra20_i2s *i2s = dev_get_drvdata(&pdev->dev);
 
+	tegra_pcm_platform_unregister(&pdev->dev);
+	snd_soc_unregister_component(&pdev->dev);
+
 	pm_runtime_disable(&pdev->dev);
 	if (!pm_runtime_status_suspended(&pdev->dev))
 		tegra20_i2s_runtime_suspend(&pdev->dev);
 
-	tegra_pcm_platform_unregister(&pdev->dev);
-	snd_soc_unregister_component(&pdev->dev);
-
 	clk_put(i2s->clk_i2s);
 
 	return 0;
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v5 10/17] ASoC: tegra20: i2s: Use devm_clk_get()
  2021-03-14 15:44 [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers Dmitry Osipenko
                   ` (8 preceding siblings ...)
  2021-03-14 15:44 ` [PATCH v5 09/17] ASoC: tegra20: i2s: Correct driver removal order Dmitry Osipenko
@ 2021-03-14 15:44 ` Dmitry Osipenko
  2021-03-14 15:44 ` [PATCH v5 11/17] ASoC: tegra20: i2s: Remove handing of disabled runtime PM Dmitry Osipenko
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2021-03-14 15:44 UTC (permalink / raw)
  To: Thierry Reding, Jonathan Hunter, Mark Brown, Takashi Iwai,
	Jaroslav Kysela, Philipp Zabel, Paul Fertser
  Cc: alsa-devel, devicetree, linux-tegra, linux-kernel

Use resource-managed variant of clk_get() to simplify code.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 sound/soc/tegra/tegra20_i2s.c | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c
index 0f2bdc2e8598..fe569198b17a 100644
--- a/sound/soc/tegra/tegra20_i2s.c
+++ b/sound/soc/tegra/tegra20_i2s.c
@@ -370,7 +370,7 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev)
 		return PTR_ERR(i2s->reset);
 	}
 
-	i2s->clk_i2s = clk_get(&pdev->dev, NULL);
+	i2s->clk_i2s = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(i2s->clk_i2s)) {
 		dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
 		ret = PTR_ERR(i2s->clk_i2s);
@@ -381,7 +381,7 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev)
 	regs = devm_ioremap_resource(&pdev->dev, mem);
 	if (IS_ERR(regs)) {
 		ret = PTR_ERR(regs);
-		goto err_clk_put;
+		goto err;
 	}
 
 	i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
@@ -389,7 +389,7 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev)
 	if (IS_ERR(i2s->regmap)) {
 		dev_err(&pdev->dev, "regmap init failed\n");
 		ret = PTR_ERR(i2s->regmap);
-		goto err_clk_put;
+		goto err;
 	}
 
 	i2s->capture_dma_data.addr = mem->start + TEGRA20_I2S_FIFO2;
@@ -430,16 +430,12 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev)
 		tegra20_i2s_runtime_suspend(&pdev->dev);
 err_pm_disable:
 	pm_runtime_disable(&pdev->dev);
-err_clk_put:
-	clk_put(i2s->clk_i2s);
 err:
 	return ret;
 }
 
 static int tegra20_i2s_platform_remove(struct platform_device *pdev)
 {
-	struct tegra20_i2s *i2s = dev_get_drvdata(&pdev->dev);
-
 	tegra_pcm_platform_unregister(&pdev->dev);
 	snd_soc_unregister_component(&pdev->dev);
 
@@ -447,8 +443,6 @@ static int tegra20_i2s_platform_remove(struct platform_device *pdev)
 	if (!pm_runtime_status_suspended(&pdev->dev))
 		tegra20_i2s_runtime_suspend(&pdev->dev);
 
-	clk_put(i2s->clk_i2s);
-
 	return 0;
 }
 
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v5 11/17] ASoC: tegra20: i2s: Remove handing of disabled runtime PM
  2021-03-14 15:44 [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers Dmitry Osipenko
                   ` (9 preceding siblings ...)
  2021-03-14 15:44 ` [PATCH v5 10/17] ASoC: tegra20: i2s: Use devm_clk_get() Dmitry Osipenko
@ 2021-03-14 15:44 ` Dmitry Osipenko
  2021-03-14 15:44 ` [PATCH v5 12/17] ASoC: tegra30: i2s: Correct driver removal order Dmitry Osipenko
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2021-03-14 15:44 UTC (permalink / raw)
  To: Thierry Reding, Jonathan Hunter, Mark Brown, Takashi Iwai,
	Jaroslav Kysela, Philipp Zabel, Paul Fertser
  Cc: alsa-devel, devicetree, linux-tegra, linux-kernel

Runtime PM is always available on Tegra since commit 40b2bb1b132a
("ARM: tegra: enforce PM requirement"), hence there is no need to
handle the case of a disabled RPM by Tegra drivers. Remove handing
of a disabled runtime PM from Tegra20 I2S driver.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 sound/soc/tegra/tegra20_i2s.c | 13 +------------
 1 file changed, 1 insertion(+), 12 deletions(-)

diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c
index fe569198b17a..1b27f81c10fe 100644
--- a/sound/soc/tegra/tegra20_i2s.c
+++ b/sound/soc/tegra/tegra20_i2s.c
@@ -401,18 +401,13 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev)
 	i2s->playback_dma_data.maxburst = 4;
 
 	pm_runtime_enable(&pdev->dev);
-	if (!pm_runtime_enabled(&pdev->dev)) {
-		ret = tegra20_i2s_runtime_resume(&pdev->dev);
-		if (ret)
-			goto err_pm_disable;
-	}
 
 	ret = snd_soc_register_component(&pdev->dev, &tegra20_i2s_component,
 					 &i2s->dai, 1);
 	if (ret) {
 		dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
 		ret = -ENOMEM;
-		goto err_suspend;
+		goto err_pm_disable;
 	}
 
 	ret = tegra_pcm_platform_register(&pdev->dev);
@@ -425,9 +420,6 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev)
 
 err_unregister_component:
 	snd_soc_unregister_component(&pdev->dev);
-err_suspend:
-	if (!pm_runtime_status_suspended(&pdev->dev))
-		tegra20_i2s_runtime_suspend(&pdev->dev);
 err_pm_disable:
 	pm_runtime_disable(&pdev->dev);
 err:
@@ -438,10 +430,7 @@ static int tegra20_i2s_platform_remove(struct platform_device *pdev)
 {
 	tegra_pcm_platform_unregister(&pdev->dev);
 	snd_soc_unregister_component(&pdev->dev);
-
 	pm_runtime_disable(&pdev->dev);
-	if (!pm_runtime_status_suspended(&pdev->dev))
-		tegra20_i2s_runtime_suspend(&pdev->dev);
 
 	return 0;
 }
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v5 12/17] ASoC: tegra30: i2s: Correct driver removal order
  2021-03-14 15:44 [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers Dmitry Osipenko
                   ` (10 preceding siblings ...)
  2021-03-14 15:44 ` [PATCH v5 11/17] ASoC: tegra20: i2s: Remove handing of disabled runtime PM Dmitry Osipenko
@ 2021-03-14 15:44 ` Dmitry Osipenko
  2021-03-14 15:44 ` [PATCH v5 13/17] ASoC: tegra30: i2s: Use devm_clk_get() Dmitry Osipenko
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2021-03-14 15:44 UTC (permalink / raw)
  To: Thierry Reding, Jonathan Hunter, Mark Brown, Takashi Iwai,
	Jaroslav Kysela, Philipp Zabel, Paul Fertser
  Cc: alsa-devel, devicetree, linux-tegra, linux-kernel

Tegra30 I2S driver has a wrong driver removal order, which should be
opposite to the registration order, but it's not. In particular the
runtime PM is disabled in a wrong order. Fix the order.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 sound/soc/tegra/tegra30_i2s.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
index 614b67be1dd9..31e08c5c1405 100644
--- a/sound/soc/tegra/tegra30_i2s.c
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -544,10 +544,6 @@ static int tegra30_i2s_platform_remove(struct platform_device *pdev)
 {
 	struct tegra30_i2s *i2s = dev_get_drvdata(&pdev->dev);
 
-	pm_runtime_disable(&pdev->dev);
-	if (!pm_runtime_status_suspended(&pdev->dev))
-		tegra30_i2s_runtime_suspend(&pdev->dev);
-
 	tegra_pcm_platform_unregister(&pdev->dev);
 	snd_soc_unregister_component(&pdev->dev);
 
@@ -557,6 +553,10 @@ static int tegra30_i2s_platform_remove(struct platform_device *pdev)
 	tegra30_ahub_unset_rx_cif_source(i2s->playback_i2s_cif);
 	tegra30_ahub_free_tx_fifo(i2s->playback_fifo_cif);
 
+	pm_runtime_disable(&pdev->dev);
+	if (!pm_runtime_status_suspended(&pdev->dev))
+		tegra30_i2s_runtime_suspend(&pdev->dev);
+
 	clk_put(i2s->clk_i2s);
 
 	return 0;
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v5 13/17] ASoC: tegra30: i2s: Use devm_clk_get()
  2021-03-14 15:44 [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers Dmitry Osipenko
                   ` (11 preceding siblings ...)
  2021-03-14 15:44 ` [PATCH v5 12/17] ASoC: tegra30: i2s: Correct driver removal order Dmitry Osipenko
@ 2021-03-14 15:44 ` Dmitry Osipenko
  2021-03-14 15:44 ` [PATCH v5 14/17] ASoC: tegra30: i2s: Remove handing of disabled runtime PM Dmitry Osipenko
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2021-03-14 15:44 UTC (permalink / raw)
  To: Thierry Reding, Jonathan Hunter, Mark Brown, Takashi Iwai,
	Jaroslav Kysela, Philipp Zabel, Paul Fertser
  Cc: alsa-devel, devicetree, linux-tegra, linux-kernel

Use resource-managed variant of clk_get() to simplify code.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 sound/soc/tegra/tegra30_i2s.c | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
index 31e08c5c1405..0ed982548ce4 100644
--- a/sound/soc/tegra/tegra30_i2s.c
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -438,7 +438,7 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev)
 	i2s->playback_i2s_cif = cif_ids[0];
 	i2s->capture_i2s_cif = cif_ids[1];
 
-	i2s->clk_i2s = clk_get(&pdev->dev, NULL);
+	i2s->clk_i2s = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(i2s->clk_i2s)) {
 		dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
 		ret = PTR_ERR(i2s->clk_i2s);
@@ -448,7 +448,7 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev)
 	regs = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(regs)) {
 		ret = PTR_ERR(regs);
-		goto err_clk_put;
+		goto err;
 	}
 
 	i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
@@ -456,7 +456,7 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev)
 	if (IS_ERR(i2s->regmap)) {
 		dev_err(&pdev->dev, "regmap init failed\n");
 		ret = PTR_ERR(i2s->regmap);
-		goto err_clk_put;
+		goto err;
 	}
 	regcache_cache_only(i2s->regmap, true);
 
@@ -534,8 +534,6 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev)
 		tegra30_i2s_runtime_suspend(&pdev->dev);
 err_pm_disable:
 	pm_runtime_disable(&pdev->dev);
-err_clk_put:
-	clk_put(i2s->clk_i2s);
 err:
 	return ret;
 }
@@ -557,8 +555,6 @@ static int tegra30_i2s_platform_remove(struct platform_device *pdev)
 	if (!pm_runtime_status_suspended(&pdev->dev))
 		tegra30_i2s_runtime_suspend(&pdev->dev);
 
-	clk_put(i2s->clk_i2s);
-
 	return 0;
 }
 
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v5 14/17] ASoC: tegra30: i2s: Remove handing of disabled runtime PM
  2021-03-14 15:44 [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers Dmitry Osipenko
                   ` (12 preceding siblings ...)
  2021-03-14 15:44 ` [PATCH v5 13/17] ASoC: tegra30: i2s: Use devm_clk_get() Dmitry Osipenko
@ 2021-03-14 15:44 ` Dmitry Osipenko
  2021-03-14 15:44 ` [PATCH v5 15/17] ASoC: tegra30: ahub: Reset global variable Dmitry Osipenko
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2021-03-14 15:44 UTC (permalink / raw)
  To: Thierry Reding, Jonathan Hunter, Mark Brown, Takashi Iwai,
	Jaroslav Kysela, Philipp Zabel, Paul Fertser
  Cc: alsa-devel, devicetree, linux-tegra, linux-kernel

Runtime PM is always available on Tegra since commit 40b2bb1b132a
("ARM: tegra: enforce PM requirement"), hence there is no need to
handle the case of a disabled RPM by Tegra drivers. Remove handing
of a disabled runtime PM from Tegra30 I2S driver.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 sound/soc/tegra/tegra30_i2s.c | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
index 0ed982548ce4..8730ffa0f691 100644
--- a/sound/soc/tegra/tegra30_i2s.c
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -461,11 +461,6 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev)
 	regcache_cache_only(i2s->regmap, true);
 
 	pm_runtime_enable(&pdev->dev);
-	if (!pm_runtime_enabled(&pdev->dev)) {
-		ret = tegra30_i2s_runtime_resume(&pdev->dev);
-		if (ret)
-			goto err_pm_disable;
-	}
 
 	i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 	i2s->playback_dma_data.maxburst = 4;
@@ -475,7 +470,7 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev)
 					    &i2s->playback_dma_data.addr);
 	if (ret) {
 		dev_err(&pdev->dev, "Could not alloc TX FIFO: %d\n", ret);
-		goto err_suspend;
+		goto err_pm_disable;
 	}
 	ret = tegra30_ahub_set_rx_cif_source(i2s->playback_i2s_cif,
 					     i2s->playback_fifo_cif);
@@ -529,9 +524,6 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev)
 	tegra30_ahub_unset_rx_cif_source(i2s->playback_i2s_cif);
 err_free_tx_fifo:
 	tegra30_ahub_free_tx_fifo(i2s->playback_fifo_cif);
-err_suspend:
-	if (!pm_runtime_status_suspended(&pdev->dev))
-		tegra30_i2s_runtime_suspend(&pdev->dev);
 err_pm_disable:
 	pm_runtime_disable(&pdev->dev);
 err:
@@ -552,8 +544,6 @@ static int tegra30_i2s_platform_remove(struct platform_device *pdev)
 	tegra30_ahub_free_tx_fifo(i2s->playback_fifo_cif);
 
 	pm_runtime_disable(&pdev->dev);
-	if (!pm_runtime_status_suspended(&pdev->dev))
-		tegra30_i2s_runtime_suspend(&pdev->dev);
 
 	return 0;
 }
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v5 15/17] ASoC: tegra30: ahub: Reset global variable
  2021-03-14 15:44 [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers Dmitry Osipenko
                   ` (13 preceding siblings ...)
  2021-03-14 15:44 ` [PATCH v5 14/17] ASoC: tegra30: i2s: Remove handing of disabled runtime PM Dmitry Osipenko
@ 2021-03-14 15:44 ` Dmitry Osipenko
  2021-03-14 15:44 ` [PATCH v5 16/17] ASoC: tegra30: ahub: Correct suspend-resume callbacks Dmitry Osipenko
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2021-03-14 15:44 UTC (permalink / raw)
  To: Thierry Reding, Jonathan Hunter, Mark Brown, Takashi Iwai,
	Jaroslav Kysela, Philipp Zabel, Paul Fertser
  Cc: alsa-devel, devicetree, linux-tegra, linux-kernel

Tegra30 AHUB uses global variable that is never reset by the driver on
a probe failure and on driver removal, meaning that driver will never try
to re-probe and can't be unbound. Make driver to reset the variable.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 sound/soc/tegra/tegra30_ahub.c | 30 ++++++++++++++++--------------
 1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
index d24c26f4960d..409a259e6343 100644
--- a/sound/soc/tegra/tegra30_ahub.c
+++ b/sound/soc/tegra/tegra30_ahub.c
@@ -518,9 +518,6 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
 	void __iomem *regs_apbif, *regs_ahub;
 	int ret = 0;
 
-	if (ahub)
-		return -ENODEV;
-
 	match = of_match_device(tegra30_ahub_of_match, &pdev->dev);
 	if (!match)
 		return -EINVAL;
@@ -544,19 +541,21 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
 
 	ret = devm_clk_bulk_get(&pdev->dev, ahub->nclocks, ahub->clocks);
 	if (ret)
-		return ret;
+		goto err_unset_ahub;
 
 	ret = devm_reset_control_bulk_get_exclusive(&pdev->dev, ahub->nresets,
 						    ahub->resets);
 	if (ret) {
 		dev_err(&pdev->dev, "Can't get resets: %d\n", ret);
-		return ret;
+		goto err_unset_ahub;
 	}
 
 	res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	regs_apbif = devm_ioremap_resource(&pdev->dev, res0);
-	if (IS_ERR(regs_apbif))
-		return PTR_ERR(regs_apbif);
+	if (IS_ERR(regs_apbif)) {
+		ret = PTR_ERR(regs_apbif);
+		goto err_unset_ahub;
+	}
 
 	ahub->apbif_addr = res0->start;
 
@@ -565,20 +564,22 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
 	if (IS_ERR(ahub->regmap_apbif)) {
 		dev_err(&pdev->dev, "apbif regmap init failed\n");
 		ret = PTR_ERR(ahub->regmap_apbif);
-		return ret;
+		goto err_unset_ahub;
 	}
 	regcache_cache_only(ahub->regmap_apbif, true);
 
 	regs_ahub = devm_platform_ioremap_resource(pdev, 1);
-	if (IS_ERR(regs_ahub))
-		return PTR_ERR(regs_ahub);
+	if (IS_ERR(regs_ahub)) {
+		ret = PTR_ERR(regs_ahub);
+		goto err_unset_ahub;
+	}
 
 	ahub->regmap_ahub = devm_regmap_init_mmio(&pdev->dev, regs_ahub,
 					&tegra30_ahub_ahub_regmap_config);
 	if (IS_ERR(ahub->regmap_ahub)) {
 		dev_err(&pdev->dev, "ahub regmap init failed\n");
 		ret = PTR_ERR(ahub->regmap_ahub);
-		return ret;
+		goto err_unset_ahub;
 	}
 	regcache_cache_only(ahub->regmap_ahub, true);
 
@@ -595,19 +596,20 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
 
 err_pm_disable:
 	pm_runtime_disable(&pdev->dev);
+err_unset_ahub:
+	ahub = NULL;
 
 	return ret;
 }
 
 static int tegra30_ahub_remove(struct platform_device *pdev)
 {
-	if (!ahub)
-		return -ENODEV;
-
 	pm_runtime_disable(&pdev->dev);
 	if (!pm_runtime_status_suspended(&pdev->dev))
 		tegra30_ahub_runtime_suspend(&pdev->dev);
 
+	ahub = NULL;
+
 	return 0;
 }
 
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v5 16/17] ASoC: tegra30: ahub: Correct suspend-resume callbacks
  2021-03-14 15:44 [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers Dmitry Osipenko
                   ` (14 preceding siblings ...)
  2021-03-14 15:44 ` [PATCH v5 15/17] ASoC: tegra30: ahub: Reset global variable Dmitry Osipenko
@ 2021-03-14 15:44 ` Dmitry Osipenko
  2021-03-14 15:44 ` [PATCH v5 17/17] ASoC: tegra30: ahub: Remove handing of disabled runtime PM Dmitry Osipenko
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2021-03-14 15:44 UTC (permalink / raw)
  To: Thierry Reding, Jonathan Hunter, Mark Brown, Takashi Iwai,
	Jaroslav Kysela, Philipp Zabel, Paul Fertser
  Cc: alsa-devel, devicetree, linux-tegra, linux-kernel

Tegra30 AHUB driver always syncs hardware state on a runtime PM resume,
hence there is no needed to re-sync the state on system resume. Replace
the suspend-resume callbacks with a generic helpers which ensure that
AHUB is suspended using RPM callbacks across system suspend-resume.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 sound/soc/tegra/tegra30_ahub.c | 29 ++---------------------------
 1 file changed, 2 insertions(+), 27 deletions(-)

diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
index 409a259e6343..e64b41bc5fdf 100644
--- a/sound/soc/tegra/tegra30_ahub.c
+++ b/sound/soc/tegra/tegra30_ahub.c
@@ -613,36 +613,11 @@ static int tegra30_ahub_remove(struct platform_device *pdev)
 	return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int tegra30_ahub_suspend(struct device *dev)
-{
-	regcache_mark_dirty(ahub->regmap_ahub);
-	regcache_mark_dirty(ahub->regmap_apbif);
-
-	return 0;
-}
-
-static int tegra30_ahub_resume(struct device *dev)
-{
-	int ret;
-
-	ret = pm_runtime_get_sync(dev);
-	if (ret < 0) {
-		pm_runtime_put(dev);
-		return ret;
-	}
-	ret = regcache_sync(ahub->regmap_ahub);
-	ret |= regcache_sync(ahub->regmap_apbif);
-	pm_runtime_put(dev);
-
-	return ret;
-}
-#endif
-
 static const struct dev_pm_ops tegra30_ahub_pm_ops = {
 	SET_RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend,
 			   tegra30_ahub_runtime_resume, NULL)
-	SET_SYSTEM_SLEEP_PM_OPS(tegra30_ahub_suspend, tegra30_ahub_resume)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
 };
 
 static struct platform_driver tegra30_ahub_driver = {
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v5 17/17] ASoC: tegra30: ahub: Remove handing of disabled runtime PM
  2021-03-14 15:44 [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers Dmitry Osipenko
                   ` (15 preceding siblings ...)
  2021-03-14 15:44 ` [PATCH v5 16/17] ASoC: tegra30: ahub: Correct suspend-resume callbacks Dmitry Osipenko
@ 2021-03-14 15:44 ` Dmitry Osipenko
  2021-03-17 17:20 ` [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers Dmitry Osipenko
  2021-03-18 18:33 ` Mark Brown
  18 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2021-03-14 15:44 UTC (permalink / raw)
  To: Thierry Reding, Jonathan Hunter, Mark Brown, Takashi Iwai,
	Jaroslav Kysela, Philipp Zabel, Paul Fertser
  Cc: alsa-devel, devicetree, linux-tegra, linux-kernel

Runtime PM is always available on Tegra since commit 40b2bb1b132a
("ARM: tegra: enforce PM requirement"), hence there is no need to
handle the case of a disabled RPM by Tegra drivers. Remove handing
of a disabled runtime PM from Tegra30 AHUB driver.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 sound/soc/tegra/tegra30_ahub.c | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
index e64b41bc5fdf..d1718f3af3cd 100644
--- a/sound/soc/tegra/tegra30_ahub.c
+++ b/sound/soc/tegra/tegra30_ahub.c
@@ -584,18 +584,11 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
 	regcache_cache_only(ahub->regmap_ahub, true);
 
 	pm_runtime_enable(&pdev->dev);
-	if (!pm_runtime_enabled(&pdev->dev)) {
-		ret = tegra30_ahub_runtime_resume(&pdev->dev);
-		if (ret)
-			goto err_pm_disable;
-	}
 
 	of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
 
 	return 0;
 
-err_pm_disable:
-	pm_runtime_disable(&pdev->dev);
 err_unset_ahub:
 	ahub = NULL;
 
@@ -605,8 +598,6 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
 static int tegra30_ahub_remove(struct platform_device *pdev)
 {
 	pm_runtime_disable(&pdev->dev);
-	if (!pm_runtime_status_suspended(&pdev->dev))
-		tegra30_ahub_runtime_suspend(&pdev->dev);
 
 	ahub = NULL;
 
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers
  2021-03-14 15:44 [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers Dmitry Osipenko
                   ` (16 preceding siblings ...)
  2021-03-14 15:44 ` [PATCH v5 17/17] ASoC: tegra30: ahub: Remove handing of disabled runtime PM Dmitry Osipenko
@ 2021-03-17 17:20 ` Dmitry Osipenko
  2021-03-17 17:54   ` Mark Brown
  2021-03-18 18:33 ` Mark Brown
  18 siblings, 1 reply; 23+ messages in thread
From: Dmitry Osipenko @ 2021-03-17 17:20 UTC (permalink / raw)
  To: Thierry Reding, Jonathan Hunter, Mark Brown, Takashi Iwai,
	Jaroslav Kysela, Philipp Zabel, Paul Fertser
  Cc: alsa-devel, devicetree, linux-tegra, linux-kernel

14.03.2021 18:44, Dmitry Osipenko пишет:
> Hi,
> 
> This series adds missing hardware reset controls to I2S and AC97 drivers,
> corrects runtime PM usage and drivers probe/remove order. Currently drivers
> happen to work properly because reset is implicitly deasserted by tegra-clk
> driver, but clk driver shouldn't touch the resets and we need to fix it
> because this breaks other Tegra drivers. Previously we fixed the resets of
> the AHUB and HDMI codec drivers, but turned out that we missed the I2C and
> AC97 drivers.
> 
> Thanks to Paul Fertser for testing the pending clk patches and finding
> that audio got broken on Tegra20 AC100 netbook because of the missing I2S
> reset.
....
> Dmitry Osipenko (16):
>   ASoC: tegra20: ac97: Add reset control
>   ASoC: tegra20: i2s: Add reset control
>   ASoC: tegra30: i2s: Restore hardware state on runtime PM resume
>   ASoC: tegra30: ahub: Switch to use reset-bulk API
>   ASoC: tegra20: spdif: Correct driver removal order
>   ASoC: tegra20: spdif: Remove handing of disabled runtime PM
>   ASoC: tegra20: i2s: Add system level suspend-resume callbacks
>   ASoC: tegra20: i2s: Correct driver removal order
>   ASoC: tegra20: i2s: Use devm_clk_get()
>   ASoC: tegra20: i2s: Remove handing of disabled runtime PM
>   ASoC: tegra30: i2s: Correct driver removal order
>   ASoC: tegra30: i2s: Use devm_clk_get()
>   ASoC: tegra30: i2s: Remove handing of disabled runtime PM
>   ASoC: tegra30: ahub: Reset global variable
>   ASoC: tegra30: ahub: Correct suspend-resume callbacks
>   ASoC: tegra30: ahub: Remove handing of disabled runtime PM
> 
> Philipp Zabel (1):
>   reset: Add reset_control_bulk API

Mark / Takashi, I may try to split up this series into two or three
smaller patchsets and then the reset/ patch from Philipp Zabel could be
merged by Philipp himself. I primarily want to have the audio resets
fixed and the reset API extended with reset_control_bulk in 5.13 because
this will unblock other patches. Please let me know what you prefer more.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers
  2021-03-17 17:20 ` [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers Dmitry Osipenko
@ 2021-03-17 17:54   ` Mark Brown
  2021-03-17 18:12     ` Dmitry Osipenko
  0 siblings, 1 reply; 23+ messages in thread
From: Mark Brown @ 2021-03-17 17:54 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: Thierry Reding, Jonathan Hunter, Takashi Iwai, Jaroslav Kysela,
	Philipp Zabel, Paul Fertser, alsa-devel, devicetree, linux-tegra,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 582 bytes --]

On Wed, Mar 17, 2021 at 08:20:10PM +0300, Dmitry Osipenko wrote:

> Mark / Takashi, I may try to split up this series into two or three
> smaller patchsets and then the reset/ patch from Philipp Zabel could be
> merged by Philipp himself. I primarily want to have the audio resets
> fixed and the reset API extended with reset_control_bulk in 5.13 because
> this will unblock other patches. Please let me know what you prefer more.

I've actually already got this queued for application next time I apply
things, I'm guessing Phillip was intending that the reset patch go via
ASoC?

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers
  2021-03-17 17:54   ` Mark Brown
@ 2021-03-17 18:12     ` Dmitry Osipenko
  0 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2021-03-17 18:12 UTC (permalink / raw)
  To: Mark Brown, Philipp Zabel
  Cc: Thierry Reding, Jonathan Hunter, Takashi Iwai, Jaroslav Kysela,
	Paul Fertser, alsa-devel, devicetree, linux-tegra, linux-kernel

17.03.2021 20:54, Mark Brown пишет:
> On Wed, Mar 17, 2021 at 08:20:10PM +0300, Dmitry Osipenko wrote:
> 
>> Mark / Takashi, I may try to split up this series into two or three
>> smaller patchsets and then the reset/ patch from Philipp Zabel could be
>> merged by Philipp himself. I primarily want to have the audio resets
>> fixed and the reset API extended with reset_control_bulk in 5.13 because
>> this will unblock other patches. Please let me know what you prefer more.
> 
> I've actually already got this queued for application next time I apply
> things, I'm guessing Phillip was intending that the reset patch go via
> ASoC?
> 

I assume that Phillip is okay with applying the reset patch via ASoC
since he didn't say anything specifically about it. Thank you for taking
care of the patches!

Phillip, please let us know if you have objections in regards to
applying the reset_control_bulk via ASoC.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers
  2021-03-14 15:44 [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers Dmitry Osipenko
                   ` (17 preceding siblings ...)
  2021-03-17 17:20 ` [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers Dmitry Osipenko
@ 2021-03-18 18:33 ` Mark Brown
  2021-03-18 18:36   ` Mark Brown
  18 siblings, 1 reply; 23+ messages in thread
From: Mark Brown @ 2021-03-18 18:33 UTC (permalink / raw)
  To: Jaroslav Kysela, Thierry Reding, Paul Fertser, Dmitry Osipenko,
	Jonathan Hunter, Philipp Zabel, Takashi Iwai
  Cc: Mark Brown, linux-tegra, linux-kernel, alsa-devel, devicetree

On Sun, 14 Mar 2021 18:44:42 +0300, Dmitry Osipenko wrote:
> This series adds missing hardware reset controls to I2S and AC97 drivers,
> corrects runtime PM usage and drivers probe/remove order. Currently drivers
> happen to work properly because reset is implicitly deasserted by tegra-clk
> driver, but clk driver shouldn't touch the resets and we need to fix it
> because this breaks other Tegra drivers. Previously we fixed the resets of
> the AHUB and HDMI codec drivers, but turned out that we missed the I2C and
> AC97 drivers.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next

Thanks!

[01/17] ASoC: tegra20: ac97: Add reset control
        commit: a46b78247b852345ae4458711a4aec6744a7838c
[02/17] ASoC: tegra20: i2s: Add reset control
        commit: 9c648ef82d7d4696e80b286d37dae07b67a9a32d
[03/17] ASoC: tegra30: i2s: Restore hardware state on runtime PM resume
        commit: 0bbcecaaab15a74ba69f93df46c753f2a64eadca
[04/17] reset: Add reset_control_bulk API
        commit: 48d71395896d54eec989179dd265e569fcecb15a
[05/17] ASoC: tegra30: ahub: Switch to use reset-bulk API
        commit: 050086eb6dc945207b1db1d15cd81e9366dfd2f1
[06/17] ASoC: tegra20: spdif: Correct driver removal order
        commit: 0911f154a2ae264ee2a7c868c1267a102396d016
[07/17] ASoC: tegra20: spdif: Remove handing of disabled runtime PM
        commit: c53b396f0dd49a626ea2b1fc0a8b9e0a0bf95d4d
[08/17] ASoC: tegra20: i2s: Add system level suspend-resume callbacks
        commit: e33fdd9bee12be35d080bfd4acc9d1e3a0d04001
[09/17] ASoC: tegra20: i2s: Correct driver removal order
        commit: ca6e960ed6b10ba9236da8b3614574bb4524c65e
[10/17] ASoC: tegra20: i2s: Use devm_clk_get()
        commit: d3c6ef98dadd1e500445e4c5a9d684cbf3182c7d
[11/17] ASoC: tegra20: i2s: Remove handing of disabled runtime PM
        commit: 80ec4a4cb36d3f8bb56b5aa89faceb1145ef7aea
[12/17] ASoC: tegra30: i2s: Correct driver removal order
        commit: f852e1e4acf4ebde4c960bab6f89407fa18ca489
[13/17] ASoC: tegra30: i2s: Use devm_clk_get()
        commit: 52674aef9eb678f30d99f77fd53f6c564d5e2d92
[14/17] ASoC: tegra30: i2s: Remove handing of disabled runtime PM
        commit: b5f6f781fcb27b3ae5a2f04312a190115b5cbbd1
[15/17] ASoC: tegra30: ahub: Reset global variable
        commit: 5d956e3cb806870012c443bc265e6ac6188d3c36
[16/17] ASoC: tegra30: ahub: Correct suspend-resume callbacks
        commit: e2965c2ca139e780dc353cef1474103bb037136e
[17/17] ASoC: tegra30: ahub: Remove handing of disabled runtime PM
        commit: b5571449e6186bd37e8da16e7bce53f621c05e72

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers
  2021-03-18 18:33 ` Mark Brown
@ 2021-03-18 18:36   ` Mark Brown
  0 siblings, 0 replies; 23+ messages in thread
From: Mark Brown @ 2021-03-18 18:36 UTC (permalink / raw)
  To: Jaroslav Kysela, Thierry Reding, Paul Fertser, Dmitry Osipenko,
	Jonathan Hunter, Philipp Zabel, Takashi Iwai
  Cc: Mark Brown, linux-tegra, linux-kernel, alsa-devel, devicetree

On Sun, 14 Mar 2021 18:44:42 +0300, Dmitry Osipenko wrote:
> This series adds missing hardware reset controls to I2S and AC97 drivers,
> corrects runtime PM usage and drivers probe/remove order. Currently drivers
> happen to work properly because reset is implicitly deasserted by tegra-clk
> driver, but clk driver shouldn't touch the resets and we need to fix it
> because this breaks other Tegra drivers. Previously we fixed the resets of
> the AHUB and HDMI codec drivers, but turned out that we missed the I2C and
> AC97 drivers.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next

Thanks!

[01/17] ASoC: tegra20: ac97: Add reset control
        commit: a46b78247b852345ae4458711a4aec6744a7838c
[02/17] ASoC: tegra20: i2s: Add reset control
        commit: 9c648ef82d7d4696e80b286d37dae07b67a9a32d
[03/17] ASoC: tegra30: i2s: Restore hardware state on runtime PM resume
        commit: 0bbcecaaab15a74ba69f93df46c753f2a64eadca
[04/17] reset: Add reset_control_bulk API
        commit: 48d71395896d54eec989179dd265e569fcecb15a
[05/17] ASoC: tegra30: ahub: Switch to use reset-bulk API
        commit: 050086eb6dc945207b1db1d15cd81e9366dfd2f1
[06/17] ASoC: tegra20: spdif: Correct driver removal order
        commit: 0911f154a2ae264ee2a7c868c1267a102396d016
[07/17] ASoC: tegra20: spdif: Remove handing of disabled runtime PM
        commit: c53b396f0dd49a626ea2b1fc0a8b9e0a0bf95d4d
[08/17] ASoC: tegra20: i2s: Add system level suspend-resume callbacks
        commit: e33fdd9bee12be35d080bfd4acc9d1e3a0d04001
[09/17] ASoC: tegra20: i2s: Correct driver removal order
        commit: ca6e960ed6b10ba9236da8b3614574bb4524c65e
[10/17] ASoC: tegra20: i2s: Use devm_clk_get()
        commit: d3c6ef98dadd1e500445e4c5a9d684cbf3182c7d
[11/17] ASoC: tegra20: i2s: Remove handing of disabled runtime PM
        commit: 80ec4a4cb36d3f8bb56b5aa89faceb1145ef7aea
[12/17] ASoC: tegra30: i2s: Correct driver removal order
        commit: f852e1e4acf4ebde4c960bab6f89407fa18ca489
[13/17] ASoC: tegra30: i2s: Use devm_clk_get()
        commit: 52674aef9eb678f30d99f77fd53f6c564d5e2d92
[14/17] ASoC: tegra30: i2s: Remove handing of disabled runtime PM
        commit: b5f6f781fcb27b3ae5a2f04312a190115b5cbbd1
[15/17] ASoC: tegra30: ahub: Reset global variable
        commit: 5d956e3cb806870012c443bc265e6ac6188d3c36
[16/17] ASoC: tegra30: ahub: Correct suspend-resume callbacks
        commit: e2965c2ca139e780dc353cef1474103bb037136e
[17/17] ASoC: tegra30: ahub: Remove handing of disabled runtime PM
        commit: b5571449e6186bd37e8da16e7bce53f621c05e72

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2021-03-18 18:36 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-14 15:44 [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers Dmitry Osipenko
2021-03-14 15:44 ` [PATCH v5 01/17] ASoC: tegra20: ac97: Add reset control Dmitry Osipenko
2021-03-14 15:44 ` [PATCH v5 02/17] ASoC: tegra20: i2s: " Dmitry Osipenko
2021-03-14 15:44 ` [PATCH v5 03/17] ASoC: tegra30: i2s: Restore hardware state on runtime PM resume Dmitry Osipenko
2021-03-14 15:44 ` [PATCH v5 04/17] reset: Add reset_control_bulk API Dmitry Osipenko
2021-03-14 15:44 ` [PATCH v5 05/17] ASoC: tegra30: ahub: Switch to use reset-bulk API Dmitry Osipenko
2021-03-14 15:44 ` [PATCH v5 06/17] ASoC: tegra20: spdif: Correct driver removal order Dmitry Osipenko
2021-03-14 15:44 ` [PATCH v5 07/17] ASoC: tegra20: spdif: Remove handing of disabled runtime PM Dmitry Osipenko
2021-03-14 15:44 ` [PATCH v5 08/17] ASoC: tegra20: i2s: Add system level suspend-resume callbacks Dmitry Osipenko
2021-03-14 15:44 ` [PATCH v5 09/17] ASoC: tegra20: i2s: Correct driver removal order Dmitry Osipenko
2021-03-14 15:44 ` [PATCH v5 10/17] ASoC: tegra20: i2s: Use devm_clk_get() Dmitry Osipenko
2021-03-14 15:44 ` [PATCH v5 11/17] ASoC: tegra20: i2s: Remove handing of disabled runtime PM Dmitry Osipenko
2021-03-14 15:44 ` [PATCH v5 12/17] ASoC: tegra30: i2s: Correct driver removal order Dmitry Osipenko
2021-03-14 15:44 ` [PATCH v5 13/17] ASoC: tegra30: i2s: Use devm_clk_get() Dmitry Osipenko
2021-03-14 15:44 ` [PATCH v5 14/17] ASoC: tegra30: i2s: Remove handing of disabled runtime PM Dmitry Osipenko
2021-03-14 15:44 ` [PATCH v5 15/17] ASoC: tegra30: ahub: Reset global variable Dmitry Osipenko
2021-03-14 15:44 ` [PATCH v5 16/17] ASoC: tegra30: ahub: Correct suspend-resume callbacks Dmitry Osipenko
2021-03-14 15:44 ` [PATCH v5 17/17] ASoC: tegra30: ahub: Remove handing of disabled runtime PM Dmitry Osipenko
2021-03-17 17:20 ` [PATCH v5 00/17] Fix reset controls and RPM of NVIDIA Tegra ASoC drivers Dmitry Osipenko
2021-03-17 17:54   ` Mark Brown
2021-03-17 18:12     ` Dmitry Osipenko
2021-03-18 18:33 ` Mark Brown
2021-03-18 18:36   ` Mark Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).