ALSA: hda/tegra: implement runtime suspend/resume

This change “ALSA: hda/tegra: implement runtime suspend/resume” in Linux kernel is authored by Sameer Pujar <spujar [at] nvidia.com> on Tue Jan 22 13:03:20 2019 +0530.

ALSA: hda/tegra: implement runtime suspend/resume

This patch moves clock enable/disable from system resume/suspend to
runtime resume/suspend respectively. Along with this hda controller
chip init or stop is also moved. System resume/suspend can invoke
runtime callbacks and do necessary setup.

chip->running can be used to check for probe completion and device
access during runtime_resume or runtime_suspend can be avoided if
probe is not yet finished. This helps to avoid kernel panic during
boot where runtime PM callbacks can happen from system PM.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
Reviewed-by: Ravindra Lokhande <rlokhande@nvidia.com>
Reviewed-by: Mohan Kumar D <mkumard@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>

This Linux change may have been applied to various maintained Linux releases and you can find Linux releases including commit 707e075.

There are 49 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 sound/pci/hda/hda_tegra.c | 49 +++++++++++++++++++++++++++++++----------------
 1 file changed, 33 insertions(+), 16 deletions(-)

diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c
index f068b1e..a7fd4c6 100644
--- a/sound/pci/hda/hda_tegra.c
+++ b/sound/pci/hda/hda_tegra.c
@@ -233,32 +233,24 @@ static void hda_tegra_disable_clocks(struct hda_tegra *data)
 static int hda_tegra_suspend(struct device *dev)
 {
 	struct snd_card *card = dev_get_drvdata(dev);
-	struct azx *chip = card->private_data;
-	struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
-	struct hdac_bus *bus = azx_bus(chip);
+	int rc;
 
+	rc = pm_runtime_force_suspend(dev);
+	if (rc < 0)
+		return rc;
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
 
-	azx_stop_chip(chip);
-	synchronize_irq(bus->irq);
-	azx_enter_link_reset(chip);
-	hda_tegra_disable_clocks(hda);
-
 	return 0;
 }
 
 static int hda_tegra_resume(struct device *dev)
 {
 	struct snd_card *card = dev_get_drvdata(dev);
-	struct azx *chip = card->private_data;
-	struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
-
-	hda_tegra_enable_clocks(hda);
-
-	hda_tegra_init(hda);
-
-	azx_init_chip(chip, 1);
+	int rc;
 
+	rc = pm_runtime_force_resume(dev);
+	if (rc < 0)
+		return rc;
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
 
 	return 0;
@@ -268,11 +260,36 @@ static int hda_tegra_resume(struct device *dev)
 #ifdef CONFIG_PM
 static int hda_tegra_runtime_suspend(struct device *dev)
 {
+	struct snd_card *card = dev_get_drvdata(dev);
+	struct azx *chip = card->private_data;
+	struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
+	struct hdac_bus *bus = azx_bus(chip);
+
+	if (chip && chip->running) {
+		azx_stop_chip(chip);
+		synchronize_irq(bus->irq);
+		azx_enter_link_reset(chip);
+	}
+	hda_tegra_disable_clocks(hda);
+
 	return 0;
 }
 
 static int hda_tegra_runtime_resume(struct device *dev)
 {
+	struct snd_card *card = dev_get_drvdata(dev);
+	struct azx *chip = card->private_data;
+	struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
+	int rc;
+
+	rc = hda_tegra_enable_clocks(hda);
+	if (rc != 0)
+		return rc;
+	if (chip && chip->running) {
+		hda_tegra_init(hda);
+		azx_init_chip(chip, 1);
+	}
+
 	return 0;
 }
 #endif /* CONFIG_PM */

The commit for this change in Linux stable tree is 707e075 (patch).

Leave a Reply

Your email address will not be published. Required fields are marked *