From cfb997a499232a9363d6d6a86c49a454f7af3138 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 6 Nov 2018 17:49:39 -0800 Subject: [PATCH 1/6] ASoC: SOF: move pci dev pm idle call to pci probe The patch does the following: 1. Move the runtime_put call for the pci dev to its probe routine 2. Use pm_runtime_put_noidle and pm_runtime_get_noresume in pci probe/remove Signed-off-by: Ranjani Sridharan --- sound/soc/sof/core.c | 4 ---- sound/soc/sof/sof-pci-dev.c | 11 +++++++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index edd5ea3e505fa8..a38a8fb19dd210 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -355,10 +355,6 @@ static int sof_probe(struct platform_device *pdev) pm_runtime_mark_last_busy(sdev->dev); pm_runtime_put_autosuspend(sdev->dev); - /* autosuspend pci/acpi/spi device */ - pm_runtime_mark_last_busy(plat_data->dev); - pm_runtime_put_autosuspend(plat_data->dev); - return 0; comp_err: diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 98f041247b3922..37eaa06047dcb9 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -259,8 +259,16 @@ static int sof_pci_probe(struct pci_dev *pci, /* allow runtime_pm */ pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY); pm_runtime_use_autosuspend(dev); + + /* + * runtime pm for pci device is "forbidden" by default. + * so call pm_runtime_allow() to enable it. + */ pm_runtime_allow(dev); + /* follow recommendation in pci-driver.c to decrement usage counter */ + pm_runtime_put_noidle(dev); + return ret; release_regions: @@ -291,6 +299,9 @@ static void sof_pci_remove(struct pci_dev *pci) /* release firmware */ release_firmware(sof_pdata->fw); + /* follow recommendation in pci-driver.c to increment usage counter */ + pm_runtime_get_noresume(&pci->dev); + /* release pci regions and disable device */ pci_release_regions(pci); pci_disable_device(pci); From a4c7e27d825cdf0525a5eb8fef8403a6ae2f52e9 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 6 Nov 2018 17:58:21 -0800 Subject: [PATCH 2/6] ASOC: SOF: hda: add/update PGCTL/CGCTL bits for clock gating and power gating Add CGCTL/PGCTL bits that will be used for enabling/disabling clock gating and power gating respectively. Also, LP SRAM retention mode is enabled/disabled by BIT(4) of PGCTL register. So, fix the error in its name from PCI_CGCTL_LSRMD_MASK to PCI_PGCTL_LSRMD_MASK. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-dsp.c | 4 ++-- sound/soc/sof/intel/hda.h | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index aeaa1af787dbae..6a2507bb571b09 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -298,8 +298,8 @@ static int hda_suspend(struct snd_sof_dev *sdev, int state) #endif /* disable LP retention mode */ - snd_sof_pci_update_bits(sdev, PCI_TCSEL, - PCI_CGCTL_LSRMD_MASK, PCI_CGCTL_LSRMD_MASK); + snd_sof_pci_update_bits(sdev, PCI_PGCTL, + PCI_PGCTL_LSRMD_MASK, PCI_PGCTL_LSRMD_MASK); return 0; } diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index c9c3e52508f00f..583f755fe73ec0 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -15,11 +15,16 @@ /* PCI registers */ #define PCI_TCSEL 0x44 +#define PCI_PGCTL PCI_TCSEL #define PCI_CGCTL 0x48 +/* PCI_PGCTL bits */ +#define PCI_PGCTL_ADSPPGD BIT(2) +#define PCI_PGCTL_LSRMD_MASK BIT(4) + /* PCI_CGCTL bits */ #define PCI_CGCTL_MISCBDCGE_MASK BIT(6) -#define PCI_CGCTL_LSRMD_MASK BIT(4) +#define PCI_CGCTL_ADSPDCGE BIT(1) /* Legacy HDA registers and bits used - widths are variable */ #define SOF_HDA_GCAP 0x0 From d69b39e74f5d49f24d221de2669f37cc5d63e9af Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 7 Nov 2018 20:29:09 -0800 Subject: [PATCH 3/6] ASoC: SOF: add pre/post fw run ops Add pre/post ops that will be called to perform actions before and after fw run routine. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/loader.c | 14 ++++++++++++++ sound/soc/sof/ops.h | 17 +++++++++++++++++ sound/soc/sof/sof-priv.h | 4 ++++ 3 files changed, 35 insertions(+) diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 6828d9e9b1a0d1..3bbbd3c0e0398b 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -296,6 +296,13 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) } } + /* perform pre fw run operations */ + ret = snd_sof_dsp_pre_fw_run(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed pre fw run op\n"); + return ret; + } + dev_dbg(sdev->dev, "booting DSP firmware\n"); /* boot the firmware on the DSP */ @@ -317,6 +324,13 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) dev_info(sdev->dev, "firmware boot complete\n"); + /* perform post fw run operations */ + ret = snd_sof_dsp_post_fw_run(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed post fw run op\n"); + return ret; + } + return 0; } EXPORT_SYMBOL(snd_sof_run_firmware); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 5bd6e3921b5510..78bca5ad419f2d 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -61,6 +61,23 @@ static inline int snd_sof_dsp_reset(struct snd_sof_dev *sdev) return 0; } +/* pre/post fw load */ +static inline int snd_sof_dsp_pre_fw_run(struct snd_sof_dev *sdev) +{ + if (sdev->ops->pre_fw_run) + return sdev->ops->pre_fw_run(sdev); + else + return 0; +} + +static inline int snd_sof_dsp_post_fw_run(struct snd_sof_dev *sdev) +{ + if (sdev->ops->post_fw_run) + return sdev->ops->post_fw_run(sdev); + else + return 0; +} + /* power management */ static inline int snd_sof_dsp_resume(struct snd_sof_dev *sdev) { diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 318762d1349fea..a4e6624d317088 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -78,6 +78,10 @@ struct snd_sof_dsp_ops { int (*stall)(struct snd_sof_dev *sof_dev); int (*reset)(struct snd_sof_dev *sof_dev); + /* pre/post firmware run */ + int (*pre_fw_run)(struct snd_sof_dev *sof_dev); + int (*post_fw_run)(struct snd_sof_dev *sof_dev); + /* DSP PM */ int (*suspend)(struct snd_sof_dev *sof_dev, int state); int (*resume)(struct snd_sof_dev *sof_dev); From f41dd306fd9902177c96eb5781e7f2e213dd9aa3 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 7 Nov 2018 20:33:52 -0800 Subject: [PATCH 4/6] ASoC: SOF: define pre/post fw run ops for SKL+ This patch defines pre/post fw run ops for SKL+ platforms. Disable clock gating, power gating and L1 support in pre_fw_run. Re-enable these in post_fw_run. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/apl.c | 4 ++++ sound/soc/sof/intel/cnl.c | 4 ++++ sound/soc/sof/intel/hda-ctrl.c | 28 ++++++++++++++++++++++++++++ sound/soc/sof/intel/hda-loader.c | 14 ++++++++++++++ sound/soc/sof/intel/hda.h | 6 ++++++ sound/soc/sof/intel/skl.c | 4 ++++ 6 files changed, 60 insertions(+) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 82edc77eeac1f7..19e98726060548 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -89,6 +89,10 @@ struct snd_sof_dsp_ops sof_apl_ops = { /* firmware run */ .run = hda_dsp_cl_boot_firmware, + /* pre/post fw run */ + .pre_fw_run = hda_dsp_pre_fw_run, + .post_fw_run = hda_dsp_post_fw_run, + /* trace callback */ .trace_init = hda_dsp_trace_init, .trace_release = hda_dsp_trace_release, diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 0fb531b08ea3af..e6f53afb1638c7 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -233,6 +233,10 @@ struct snd_sof_dsp_ops sof_cnl_ops = { /* firmware loading */ .load_firmware = hda_dsp_cl_load_fw, + /* pre/post fw run */ + .pre_fw_run = hda_dsp_pre_fw_run, + .post_fw_run = hda_dsp_post_fw_run, + /* firmware run */ .run = hda_dsp_cl_boot_firmware, diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index 867bc3c4c7d3e9..7fe431277b9533 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "../sof-priv.h" #include "../ops.h" @@ -148,6 +149,33 @@ void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable) snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_MISCBDCGE_MASK, val); } +/* + * enable/disable audio dsp clock gating and power gating bits. + * This allows the HW to opportunistically power and clock gate + * the audio dsp when it is idle + */ +int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + u32 val; + + /* enable/disable audio dsp clock gating */ + val = enable ? PCI_CGCTL_ADSPDCGE : 0; + snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_ADSPDCGE, val); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* enable/disable L1 support */ + val = enable ? SOF_HDA_VS_EM2_L1SEN : 0; + snd_hdac_chip_updatel(bus, VS_EM2, SOF_HDA_VS_EM2_L1SEN, val); +#endif + + /* enable/disable audio dsp power gating */ + val = enable ? 0 : PCI_PGCTL_ADSPPGD; + snd_sof_pci_update_bits(sdev, PCI_PGCTL, PCI_PGCTL_ADSPPGD, val); + + return 0; +} + #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* * While performing reset, controller may not come back properly and causing diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 76ac08d8d0883e..a02fe3873b3ece 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -372,3 +372,17 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) dev_err(sdev->dev, "error: load fw failed err: %d\n", ret); return ret; } + +/* pre fw run operations */ +int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev) +{ + /* disable clock gating and power gating */ + return hda_dsp_ctrl_clock_power_gating(sdev, false); +} + +/* post fw run operations */ +int hda_dsp_post_fw_run(struct snd_sof_dev *sdev) +{ + /* re-enable clock gating and power gating */ + return hda_dsp_ctrl_clock_power_gating(sdev, true); +} diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 583f755fe73ec0..a32ad316040680 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -37,6 +37,7 @@ #define SOF_HDA_WAKESTS 0x0E #define SOF_HDA_WAKESTS_INT_MASK ((1 << 8) - 1) #define SOF_HDA_RIRBSTS 0x5d +#define SOF_HDA_VS_EM2_L1SEN BIT(13) /* SOF_HDA_GCTL register bist */ #define SOF_HDA_GCTL_RESET BIT(0) @@ -489,12 +490,17 @@ int hda_dsp_cl_load_fw(struct snd_sof_dev *sdev, bool first_boot); int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev); int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev); +/* pre and post fw run ops */ +int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev); +int hda_dsp_post_fw_run(struct snd_sof_dev *sdev); + /* * HDA Controller Operations. */ int hda_dsp_ctrl_get_caps(struct snd_sof_dev *sdev); int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev); void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable); +int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable); int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset); /* diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index 43b0bc169438fe..b5cb56461e1f4c 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -85,6 +85,10 @@ struct snd_sof_dsp_ops sof_skl_ops = { /* firmware loading */ .load_firmware = hda_dsp_cl_load_fw, + /* pre/post fw run */ + .pre_fw_run = hda_dsp_pre_fw_run, + .post_fw_run = hda_dsp_post_fw_run, + /* firmware run */ .run = hda_dsp_cl_boot_firmware_skl, From 0ffb0676b6b17953f76332f33557cfaaafe4badb Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 6 Nov 2018 18:04:09 -0800 Subject: [PATCH 5/6] ASoC: SOF: reset HDA controller during suspend This patch does the following: 1. Reset HDA controller during suspend so that the PGD1 can be power gated. 2.Take controller out of reset during resume 3. This patch modifies the hda_dsp_ctrl_link_reset() method so it can be called to reset the controller during suspend. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-ctrl.c | 40 ++++++++++------------------------ sound/soc/sof/intel/hda-dsp.c | 24 ++++++++++++++++++++ sound/soc/sof/intel/hda.c | 9 +++++++- sound/soc/sof/intel/hda.h | 2 +- 4 files changed, 44 insertions(+), 31 deletions(-) diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index 7fe431277b9533..3414e50bf4fb7e 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -39,49 +39,31 @@ * HDA Operations. */ -int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev) +int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev, bool reset) { unsigned long timeout; u32 gctl = 0; + u32 val; - /* reset the HDA controller */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL, - SOF_HDA_GCTL_RESET, 0); - - /* wait for reset */ - timeout = jiffies + msecs_to_jiffies(HDA_DSP_CTRL_RESET_TIMEOUT); - while (time_before(jiffies, timeout)) { - usleep_range(500, 1000); - gctl = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL); - if ((gctl & SOF_HDA_GCTL_RESET) == 0) - goto clear; - } - - /* reset failed */ - dev_err(sdev->dev, "error: failed to reset HDA controller gctl 0x%x\n", - gctl); - return -EIO; - -clear: - /* wait for codec */ - usleep_range(500, 1000); + /* 0 to enter reset and 1 to exit reset */ + val = reset ? 0 : SOF_HDA_GCTL_RESET; - /* now take controller out of reset */ + /* enter/exit HDA controller reset */ snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL, - SOF_HDA_GCTL_RESET, SOF_HDA_GCTL_RESET); + SOF_HDA_GCTL_RESET, val); - /* wait for controller to be ready */ + /* wait to enter/exit reset */ timeout = jiffies + msecs_to_jiffies(HDA_DSP_CTRL_RESET_TIMEOUT); while (time_before(jiffies, timeout)) { gctl = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL); - if ((gctl & SOF_HDA_GCTL_RESET) == 1) + if ((gctl & SOF_HDA_GCTL_RESET) == val) return 0; usleep_range(500, 1000); } - /* reset failed */ - dev_err(sdev->dev, "error: failed to ready HDA controller gctl 0x%x\n", - gctl); + /* enter/exit reset failed */ + dev_err(sdev->dev, "error: failed to %s HDA controller gctl 0x%x\n", + reset ? "reset" : "ready", gctl); return -EIO; } diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 6a2507bb571b09..cd5ad87375c15d 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -301,6 +301,14 @@ static int hda_suspend(struct snd_sof_dev *sdev, int state) snd_sof_pci_update_bits(sdev, PCI_PGCTL, PCI_PGCTL_LSRMD_MASK, PCI_PGCTL_LSRMD_MASK); + /* reset controller */ + ret = hda_dsp_ctrl_link_reset(sdev, true); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to reset controller during suspend\n"); + return ret; + } + return 0; } @@ -339,6 +347,22 @@ static int hda_resume(struct snd_sof_dev *sdev) snd_hdac_ext_bus_ppcap_int_enable(bus, true); #endif + /* reset controller */ + ret = hda_dsp_ctrl_link_reset(sdev, true); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to reset controller during resume\n"); + return ret; + } + + /* take controller out of reset */ + ret = hda_dsp_ctrl_link_reset(sdev, false); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to ready controller during resume\n"); + return ret; + } + /* power up the DSP */ ret = hda_dsp_core_power_up(sdev, chip->cores_mask); if (ret < 0) { diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 89fbb3321b55ec..a31f9084446aac 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -617,12 +617,19 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) goto free_ipc_irq; /* reset HDA controller */ - ret = hda_dsp_ctrl_link_reset(sdev); + ret = hda_dsp_ctrl_link_reset(sdev, true); if (ret < 0) { dev_err(&pci->dev, "error: failed to reset HDA controller\n"); goto free_ipc_irq; } + /* exit HDA controller reset */ + ret = hda_dsp_ctrl_link_reset(sdev, false); + if (ret < 0) { + dev_err(&pci->dev, "error: failed to exit HDA controller reset\n"); + goto free_ipc_irq; + } + /* clear stream status */ list_for_each_entry(stream, &bus->stream_list, list) { sd_offset = SOF_STREAM_SD_OFFSET(stream); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index a32ad316040680..538ddbdac51f13 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -498,7 +498,7 @@ int hda_dsp_post_fw_run(struct snd_sof_dev *sdev); * HDA Controller Operations. */ int hda_dsp_ctrl_get_caps(struct snd_sof_dev *sdev); -int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev); +int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev, bool reset); void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable); int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable); int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset); From a7c6900479dc35326b0bbaec682563a2ac63e58b Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 8 Nov 2018 12:42:18 -0800 Subject: [PATCH 6/6] ASoC: SOF: remove duplicate runtime autosuspend call for sof device Runtime PM for sof device in enabled in pcm_probe() after the topology load has completed. So autosuspend should be called after pm_runtime_enable() here. Remove the call to autosuspend() in sof_probe as this should be done after topology load has been completed. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/core.c | 4 ---- sound/soc/sof/pcm.c | 4 +++- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index a38a8fb19dd210..2b275fb190cc00 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -351,10 +351,6 @@ static int sof_probe(struct platform_device *pdev) dev_dbg(sdev->dev, "created machine %s\n", dev_name(&plat_data->pdev_mach->dev)); - /* autosuspend sof device */ - pm_runtime_mark_last_busy(sdev->dev); - pm_runtime_put_autosuspend(sdev->dev); - return 0; comp_err: diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index f2e256d129bf50..f873c9bffac6b1 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -712,7 +712,9 @@ static int sof_pcm_probe(struct snd_soc_component *component) SND_SOF_SUSPEND_DELAY); pm_runtime_use_autosuspend(component->dev); pm_runtime_enable(component->dev); - err = pm_runtime_idle(component->dev); + + pm_runtime_mark_last_busy(component->dev); + err = pm_runtime_put_autosuspend(component->dev); if (err < 0) dev_err(sdev->dev, "error: failed to enter PM idle %d\n", err);