ASoC: SoundWire codecs: improve pm_runtime handling
authorMark Brown <broonie@kernel.org>
Mon, 7 Aug 2023 18:51:32 +0000 (19:51 +0100)
committerMark Brown <broonie@kernel.org>
Mon, 7 Aug 2023 18:51:32 +0000 (19:51 +0100)
Merge series from Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>:

This patchset improves the pm_runtime behavior in rare corner cases
identified by the Intel CI in the last 6 months.

a) in stress-tests, it's not uncommon to see the following type of
warnings when the codec reports as ATTACHED

    "rt711 sdw:0:025d:0711:00: runtime PM trying to activate child device
    sdw:0:025d:0711:00 but parent (sdw-master-0) is not active"

This warning was not correlated with any functional issue, but it
exposed a design issue on when to enable pm_runtime. The recommended
practice in the pm_runtime documentation is to keep the devices in
'suspended' mode and mark them as 'active' when they are really
functional.

b) enabling pm_runtime when the codec reports as ATTACHED also creates
a problematic case when the ASoC pm_runtime_get_sync() will silently
fail due to the -EACCESS error handling. This can happen when playback
starts before the codec is enumerated.

This patchset modifies the initial stages so that codecs are
pm_runtime enabled in the .probe() callback, but become pm_runtime
'active' only when they report present. This is better aligned with
the design of the pm_runtime helpers and improved CI results
significantly.

This patchset modifies all existing SoundWire codecs (except Qualcomm
ones), but the pattern of changes is exactly the same in all patches.

20 files changed:
sound/soc/codecs/max98363.c
sound/soc/codecs/max98373-sdw.c
sound/soc/codecs/rt1308-sdw.c
sound/soc/codecs/rt1316-sdw.c
sound/soc/codecs/rt1318-sdw.c
sound/soc/codecs/rt5682-sdw.c
sound/soc/codecs/rt5682.c
sound/soc/codecs/rt700-sdw.c
sound/soc/codecs/rt700.c
sound/soc/codecs/rt711-sdca-sdw.c
sound/soc/codecs/rt711-sdca.c
sound/soc/codecs/rt711-sdw.c
sound/soc/codecs/rt711.c
sound/soc/codecs/rt712-sdca-dmic.c
sound/soc/codecs/rt712-sdca-sdw.c
sound/soc/codecs/rt712-sdca.c
sound/soc/codecs/rt715-sdca-sdw.c
sound/soc/codecs/rt715-sdca.c
sound/soc/codecs/rt715-sdw.c
sound/soc/codecs/rt715.c

index b5c69bb..9e3873e 100644 (file)
@@ -160,28 +160,17 @@ static int max98363_io_init(struct sdw_slave *slave)
        struct max98363_priv *max98363 = dev_get_drvdata(dev);
        int ret, reg;
 
-       if (max98363->first_hw_init) {
-               regcache_cache_only(max98363->regmap, false);
+       regcache_cache_only(max98363->regmap, false);
+       if (max98363->first_hw_init)
                regcache_cache_bypass(max98363->regmap, true);
-       }
 
        /*
-        * PM runtime is only enabled when a Slave reports as Attached
+        * PM runtime status is marked as 'active' only when a Slave reports as Attached
         */
-       if (!max98363->first_hw_init) {
-               /* set autosuspend parameters */
-               pm_runtime_set_autosuspend_delay(dev, 3000);
-               pm_runtime_use_autosuspend(dev);
-
+       if (!max98363->first_hw_init)
                /* update count of parent 'active' children */
                pm_runtime_set_active(dev);
 
-               /* make sure the device does not suspend immediately */
-               pm_runtime_mark_last_busy(dev);
-
-               pm_runtime_enable(dev);
-       }
-
        pm_runtime_get_noresume(dev);
 
        ret = regmap_read(max98363->regmap, MAX98363_R21FF_REV_ID, &reg);
@@ -409,6 +398,8 @@ static int max98363_init(struct sdw_slave *slave, struct regmap *regmap)
        max98363->regmap = regmap;
        max98363->slave = slave;
 
+       regcache_cache_only(max98363->regmap, true);
+
        max98363->hw_init = false;
        max98363->first_hw_init = false;
 
@@ -416,10 +407,26 @@ static int max98363_init(struct sdw_slave *slave, struct regmap *regmap)
        ret = devm_snd_soc_register_component(dev, &soc_codec_dev_max98363,
                                              max98363_dai,
                                              ARRAY_SIZE(max98363_dai));
-       if (ret < 0)
+       if (ret < 0) {
                dev_err(dev, "Failed to register codec: %d\n", ret);
+               return ret;
+       }
 
-       return ret;
+       /* set autosuspend parameters */
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
+
+       /* make sure the device does not suspend immediately */
+       pm_runtime_mark_last_busy(dev);
+
+       pm_runtime_enable(dev);
+
+       /* important note: the device is NOT tagged as 'active' and will remain
+        * 'suspended' until the hardware is enumerated/initialized. This is required
+        * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+        * fail with -EACCESS because of race conditions between card creation and enumeration
+        */
+       return 0;
 }
 
 static int max98363_sdw_probe(struct sdw_slave *slave,
index df92242..b5cb951 100644 (file)
@@ -361,28 +361,17 @@ static int max98373_io_init(struct sdw_slave *slave)
        struct device *dev = &slave->dev;
        struct max98373_priv *max98373 = dev_get_drvdata(dev);
 
-       if (max98373->first_hw_init) {
-               regcache_cache_only(max98373->regmap, false);
+       regcache_cache_only(max98373->regmap, false);
+       if (max98373->first_hw_init)
                regcache_cache_bypass(max98373->regmap, true);
-       }
 
        /*
-        * PM runtime is only enabled when a Slave reports as Attached
+        * PM runtime status is marked as 'active' only when a Slave reports as Attached
         */
-       if (!max98373->first_hw_init) {
-               /* set autosuspend parameters */
-               pm_runtime_set_autosuspend_delay(dev, 3000);
-               pm_runtime_use_autosuspend(dev);
-
+       if (!max98373->first_hw_init)
                /* update count of parent 'active' children */
                pm_runtime_set_active(dev);
 
-               /* make sure the device does not suspend immediately */
-               pm_runtime_mark_last_busy(dev);
-
-               pm_runtime_enable(dev);
-       }
-
        pm_runtime_get_noresume(dev);
 
        /* Software Reset */
@@ -753,6 +742,8 @@ static int max98373_init(struct sdw_slave *slave, struct regmap *regmap)
        max98373->regmap = regmap;
        max98373->slave = slave;
 
+       regcache_cache_only(max98373->regmap, true);
+
        max98373->cache_num = ARRAY_SIZE(max98373_sdw_cache_reg);
        max98373->cache = devm_kcalloc(dev, max98373->cache_num,
                                       sizeof(*max98373->cache),
@@ -773,10 +764,27 @@ static int max98373_init(struct sdw_slave *slave, struct regmap *regmap)
        ret = devm_snd_soc_register_component(dev, &soc_codec_dev_max98373_sdw,
                                              max98373_sdw_dai,
                                              ARRAY_SIZE(max98373_sdw_dai));
-       if (ret < 0)
+       if (ret < 0) {
                dev_err(dev, "Failed to register codec: %d\n", ret);
+               return ret;
+       }
 
-       return ret;
+       /* set autosuspend parameters */
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
+
+       /* make sure the device does not suspend immediately */
+       pm_runtime_mark_last_busy(dev);
+
+       pm_runtime_enable(dev);
+
+       /* important note: the device is NOT tagged as 'active' and will remain
+        * 'suspended' until the hardware is enumerated/initialized. This is required
+        * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+        * fail with -EACCESS because of race conditions between card creation and enumeration
+        */
+
+       return 0;
 }
 
 static int max98373_update_status(struct sdw_slave *slave,
@@ -834,10 +842,7 @@ static int max98373_sdw_probe(struct sdw_slave *slave,
 
 static int max98373_sdw_remove(struct sdw_slave *slave)
 {
-       struct max98373_priv *max98373 = dev_get_drvdata(&slave->dev);
-
-       if (max98373->first_hw_init)
-               pm_runtime_disable(&slave->dev);
+       pm_runtime_disable(&slave->dev);
 
        return 0;
 }
index f43520c..c98cd7a 100644 (file)
@@ -218,28 +218,17 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave)
        if (rt1308->hw_init)
                return 0;
 
-       if (rt1308->first_hw_init) {
-               regcache_cache_only(rt1308->regmap, false);
+       regcache_cache_only(rt1308->regmap, false);
+       if (rt1308->first_hw_init)
                regcache_cache_bypass(rt1308->regmap, true);
-       }
 
        /*
-        * PM runtime is only enabled when a Slave reports as Attached
+        * PM runtime status is marked as 'active' only when a Slave reports as Attached
         */
-       if (!rt1308->first_hw_init) {
-               /* set autosuspend parameters */
-               pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
-               pm_runtime_use_autosuspend(&slave->dev);
-
+       if (!rt1308->first_hw_init)
                /* update count of parent 'active' children */
                pm_runtime_set_active(&slave->dev);
 
-               /* make sure the device does not suspend immediately */
-               pm_runtime_mark_last_busy(&slave->dev);
-
-               pm_runtime_enable(&slave->dev);
-       }
-
        pm_runtime_get_noresume(&slave->dev);
 
        /* sw reset */
@@ -626,6 +615,9 @@ static int rt1308_sdw_component_probe(struct snd_soc_component *component)
        rt1308->component = component;
        rt1308_sdw_parse_dt(rt1308, &rt1308->sdw_slave->dev);
 
+       if (!rt1308->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume(component->dev);
        if (ret < 0 && ret != -EACCES)
                return ret;
@@ -688,6 +680,8 @@ static int rt1308_sdw_init(struct device *dev, struct regmap *regmap,
        rt1308->sdw_slave = slave;
        rt1308->regmap = regmap;
 
+       regcache_cache_only(rt1308->regmap, true);
+
        /*
         * Mark hw_init to false
         * HW init will be performed when device reports present
@@ -699,10 +693,27 @@ static int rt1308_sdw_init(struct device *dev, struct regmap *regmap,
                                &soc_component_sdw_rt1308,
                                rt1308_sdw_dai,
                                ARRAY_SIZE(rt1308_sdw_dai));
+       if (ret < 0)
+               return ret;
 
-       dev_dbg(&slave->dev, "%s\n", __func__);
+       /* set autosuspend parameters */
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
 
-       return ret;
+       /* make sure the device does not suspend immediately */
+       pm_runtime_mark_last_busy(dev);
+
+       pm_runtime_enable(dev);
+
+       /* important note: the device is NOT tagged as 'active' and will remain
+        * 'suspended' until the hardware is enumerated/initialized. This is required
+        * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+        * fail with -EACCESS because of race conditions between card creation and enumeration
+        */
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       return 0;
 }
 
 static int rt1308_sdw_probe(struct sdw_slave *slave,
@@ -715,17 +726,12 @@ static int rt1308_sdw_probe(struct sdw_slave *slave,
        if (IS_ERR(regmap))
                return PTR_ERR(regmap);
 
-       rt1308_sdw_init(&slave->dev, regmap, slave);
-
-       return 0;
+       return rt1308_sdw_init(&slave->dev, regmap, slave);
 }
 
 static int rt1308_sdw_remove(struct sdw_slave *slave)
 {
-       struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(&slave->dev);
-
-       if (rt1308->first_hw_init)
-               pm_runtime_disable(&slave->dev);
+       pm_runtime_disable(&slave->dev);
 
        return 0;
 }
index 10a53c8..47511f7 100644 (file)
@@ -272,25 +272,16 @@ static int rt1316_io_init(struct device *dev, struct sdw_slave *slave)
        if (rt1316->hw_init)
                return 0;
 
+       regcache_cache_only(rt1316->regmap, false);
        if (rt1316->first_hw_init) {
-               regcache_cache_only(rt1316->regmap, false);
                regcache_cache_bypass(rt1316->regmap, true);
        } else {
                /*
-                * PM runtime is only enabled when a Slave reports as Attached
+                *  PM runtime status is marked as 'active' only when a Slave reports as Attached
                 */
 
-               /* set autosuspend parameters */
-               pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
-               pm_runtime_use_autosuspend(&slave->dev);
-
                /* update count of parent 'active' children */
                pm_runtime_set_active(&slave->dev);
-
-               /* make sure the device does not suspend immediately */
-               pm_runtime_mark_last_busy(&slave->dev);
-
-               pm_runtime_enable(&slave->dev);
        }
 
        pm_runtime_get_noresume(&slave->dev);
@@ -607,6 +598,9 @@ static int rt1316_sdw_component_probe(struct snd_soc_component *component)
        rt1316->component = component;
        rt1316_sdw_parse_dt(rt1316, &rt1316->sdw_slave->dev);
 
+       if (!rt1316->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume(component->dev);
        if (ret < 0 && ret != -EACCES)
                return ret;
@@ -674,6 +668,8 @@ static int rt1316_sdw_init(struct device *dev, struct regmap *regmap,
        rt1316->sdw_slave = slave;
        rt1316->regmap = regmap;
 
+       regcache_cache_only(rt1316->regmap, true);
+
        /*
         * Mark hw_init to false
         * HW init will be performed when device reports present
@@ -685,10 +681,27 @@ static int rt1316_sdw_init(struct device *dev, struct regmap *regmap,
                                &soc_component_sdw_rt1316,
                                rt1316_sdw_dai,
                                ARRAY_SIZE(rt1316_sdw_dai));
+       if (ret < 0)
+               return ret;
 
-       dev_dbg(&slave->dev, "%s\n", __func__);
+       /* set autosuspend parameters */
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
 
-       return ret;
+       /* make sure the device does not suspend immediately */
+       pm_runtime_mark_last_busy(dev);
+
+       pm_runtime_enable(dev);
+
+       /* important note: the device is NOT tagged as 'active' and will remain
+        * 'suspended' until the hardware is enumerated/initialized. This is required
+        * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+        * fail with -EACCESS because of race conditions between card creation and enumeration
+        */
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       return 0;
 }
 
 static int rt1316_sdw_probe(struct sdw_slave *slave,
@@ -706,10 +719,7 @@ static int rt1316_sdw_probe(struct sdw_slave *slave,
 
 static int rt1316_sdw_remove(struct sdw_slave *slave)
 {
-       struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(&slave->dev);
-
-       if (rt1316->first_hw_init)
-               pm_runtime_disable(&slave->dev);
+       pm_runtime_disable(&slave->dev);
 
        return 0;
 }
index 16d7501..ff364bd 100644 (file)
@@ -408,25 +408,15 @@ static int rt1318_io_init(struct device *dev, struct sdw_slave *slave)
        if (rt1318->hw_init)
                return 0;
 
+       regcache_cache_only(rt1318->regmap, false);
        if (rt1318->first_hw_init) {
-               regcache_cache_only(rt1318->regmap, false);
                regcache_cache_bypass(rt1318->regmap, true);
        } else {
                /*
-                * PM runtime is only enabled when a Slave reports as Attached
+                * PM runtime status is marked as 'active' only when a Slave reports as Attached
                 */
-
-               /* set autosuspend parameters */
-               pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
-               pm_runtime_use_autosuspend(&slave->dev);
-
                /* update count of parent 'active' children */
                pm_runtime_set_active(&slave->dev);
-
-               /* make sure the device does not suspend immediately */
-               pm_runtime_mark_last_busy(&slave->dev);
-
-               pm_runtime_enable(&slave->dev);
        }
 
        pm_runtime_get_noresume(&slave->dev);
@@ -686,6 +676,9 @@ static int rt1318_sdw_component_probe(struct snd_soc_component *component)
 
        rt1318->component = component;
 
+       if (!rt1318->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume(component->dev);
        dev_dbg(&rt1318->sdw_slave->dev, "%s pm_runtime_resume, ret=%d", __func__, ret);
        if (ret < 0 && ret != -EACCES)
@@ -752,6 +745,8 @@ static int rt1318_sdw_init(struct device *dev, struct regmap *regmap,
        rt1318->sdw_slave = slave;
        rt1318->regmap = regmap;
 
+       regcache_cache_only(rt1318->regmap, true);
+
        /*
         * Mark hw_init to false
         * HW init will be performed when device reports present
@@ -763,8 +758,25 @@ static int rt1318_sdw_init(struct device *dev, struct regmap *regmap,
                                &soc_component_sdw_rt1318,
                                rt1318_sdw_dai,
                                ARRAY_SIZE(rt1318_sdw_dai));
+       if (ret < 0)
+               return ret;
+
+       /* set autosuspend parameters */
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
+
+       /* make sure the device does not suspend immediately */
+       pm_runtime_mark_last_busy(dev);
 
-       dev_dbg(&slave->dev, "%s\n", __func__);
+       pm_runtime_enable(dev);
+
+       /* important note: the device is NOT tagged as 'active' and will remain
+        * 'suspended' until the hardware is enumerated/initialized. This is required
+        * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+        * fail with -EACCESS because of race conditions between card creation and enumeration
+        */
+
+       dev_dbg(dev, "%s\n", __func__);
 
        return ret;
 }
@@ -784,10 +796,7 @@ static int rt1318_sdw_probe(struct sdw_slave *slave,
 
 static int rt1318_sdw_remove(struct sdw_slave *slave)
 {
-       struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(&slave->dev);
-
-       if (rt1318->first_hw_init)
-               pm_runtime_disable(&slave->dev);
+       pm_runtime_disable(&slave->dev);
 
        return 0;
 }
index 4968a8c..dfb702d 100644 (file)
@@ -322,6 +322,9 @@ static int rt5682_sdw_init(struct device *dev, struct regmap *regmap,
                return ret;
        }
 
+       regcache_cache_only(rt5682->sdw_regmap, true);
+       regcache_cache_only(rt5682->regmap, true);
+
        /*
         * Mark hw_init to false
         * HW init will be performed when device reports present
@@ -336,7 +339,25 @@ static int rt5682_sdw_init(struct device *dev, struct regmap *regmap,
        ret = devm_snd_soc_register_component(dev,
                                              &rt5682_soc_component_dev,
                                              rt5682_dai, ARRAY_SIZE(rt5682_dai));
-       dev_dbg(&slave->dev, "%s\n", __func__);
+       if (ret < 0)
+               return ret;
+
+       /* set autosuspend parameters */
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
+
+       /* make sure the device does not suspend immediately */
+       pm_runtime_mark_last_busy(dev);
+
+       pm_runtime_enable(dev);
+
+       /* important note: the device is NOT tagged as 'active' and will remain
+        * 'suspended' until the hardware is enumerated/initialized. This is required
+        * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+        * fail with -EACCESS because of race conditions between card creation and enumeration
+        */
+
+       dev_dbg(dev, "%s\n", __func__);
 
        return ret;
 }
@@ -352,30 +373,20 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave)
        if (rt5682->hw_init)
                return 0;
 
+       regcache_cache_only(rt5682->sdw_regmap, false);
+       regcache_cache_only(rt5682->regmap, false);
+       if (rt5682->first_hw_init)
+               regcache_cache_bypass(rt5682->regmap, true);
+
        /*
-        * PM runtime is only enabled when a Slave reports as Attached
+        * PM runtime status is marked as 'active' only when a Slave reports as Attached
         */
-       if (!rt5682->first_hw_init) {
-               /* set autosuspend parameters */
-               pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
-               pm_runtime_use_autosuspend(&slave->dev);
-
+       if (!rt5682->first_hw_init)
                /* update count of parent 'active' children */
                pm_runtime_set_active(&slave->dev);
 
-               /* make sure the device does not suspend immediately */
-               pm_runtime_mark_last_busy(&slave->dev);
-
-               pm_runtime_enable(&slave->dev);
-       }
-
        pm_runtime_get_noresume(&slave->dev);
 
-       if (rt5682->first_hw_init) {
-               regcache_cache_only(rt5682->regmap, false);
-               regcache_cache_bypass(rt5682->regmap, true);
-       }
-
        while (loop > 0) {
                regmap_read(rt5682->regmap, RT5682_DEVICE_ID, &val);
                if (val == DEVICE_ID)
@@ -674,9 +685,7 @@ static int rt5682_sdw_probe(struct sdw_slave *slave,
        if (IS_ERR(regmap))
                return -EINVAL;
 
-       rt5682_sdw_init(&slave->dev, regmap, slave);
-
-       return 0;
+       return rt5682_sdw_init(&slave->dev, regmap, slave);
 }
 
 static int rt5682_sdw_remove(struct sdw_slave *slave)
@@ -686,8 +695,7 @@ static int rt5682_sdw_remove(struct sdw_slave *slave)
        if (rt5682->hw_init)
                cancel_delayed_work_sync(&rt5682->jack_detect_work);
 
-       if (rt5682->first_hw_init)
-               pm_runtime_disable(&slave->dev);
+       pm_runtime_disable(&slave->dev);
 
        return 0;
 }
@@ -707,6 +715,7 @@ static int __maybe_unused rt5682_dev_suspend(struct device *dev)
 
        cancel_delayed_work_sync(&rt5682->jack_detect_work);
 
+       regcache_cache_only(rt5682->sdw_regmap, true);
        regcache_cache_only(rt5682->regmap, true);
        regcache_mark_dirty(rt5682->regmap);
 
@@ -771,6 +780,7 @@ static int __maybe_unused rt5682_dev_resume(struct device *dev)
 
 regmap_sync:
        slave->unattach_request = 0;
+       regcache_cache_only(rt5682->sdw_regmap, false);
        regcache_cache_only(rt5682->regmap, false);
        regcache_sync(rt5682->regmap);
 
index 5d99254..694c581 100644 (file)
@@ -1017,6 +1017,9 @@ static int rt5682_set_jack_detect(struct snd_soc_component *component,
 
        rt5682->hs_jack = hs_jack;
 
+       if (rt5682->is_sdw && !rt5682->first_hw_init)
+               return 0;
+
        if (!hs_jack) {
                regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2,
                        RT5682_JD1_EN_MASK, RT5682_JD1_DIS);
index 8b28e47..52c33d5 100644 (file)
@@ -452,9 +452,7 @@ static int rt700_sdw_probe(struct sdw_slave *slave,
        if (IS_ERR(regmap))
                return PTR_ERR(regmap);
 
-       rt700_init(&slave->dev, sdw_regmap, regmap, slave);
-
-       return 0;
+       return rt700_init(&slave->dev, sdw_regmap, regmap, slave);
 }
 
 static int rt700_sdw_remove(struct sdw_slave *slave)
@@ -466,8 +464,7 @@ static int rt700_sdw_remove(struct sdw_slave *slave)
                cancel_delayed_work_sync(&rt700->jack_btn_check_work);
        }
 
-       if (rt700->first_hw_init)
-               pm_runtime_disable(&slave->dev);
+       pm_runtime_disable(&slave->dev);
 
        return 0;
 }
index a04b924..0ebf344 100644 (file)
@@ -320,6 +320,10 @@ static int rt700_set_jack_detect(struct snd_soc_component *component,
 
        rt700->hs_jack = hs_jack;
 
+       /* we can only resume if the device was initialized at least once */
+       if (!rt700->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume_and_get(component->dev);
        if (ret < 0) {
                if (ret != -EACCES) {
@@ -823,6 +827,9 @@ static int rt700_probe(struct snd_soc_component *component)
 
        rt700->component = component;
 
+       if (!rt700->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume(component->dev);
        if (ret < 0 && ret != -EACCES)
                return ret;
@@ -1099,6 +1106,8 @@ int rt700_init(struct device *dev, struct regmap *sdw_regmap,
        rt700->sdw_regmap = sdw_regmap;
        rt700->regmap = regmap;
 
+       regcache_cache_only(rt700->regmap, true);
+
        mutex_init(&rt700->disable_irq_lock);
 
        INIT_DELAYED_WORK(&rt700->jack_detect_work,
@@ -1117,10 +1126,26 @@ int rt700_init(struct device *dev, struct regmap *sdw_regmap,
                                &soc_codec_dev_rt700,
                                rt700_dai,
                                ARRAY_SIZE(rt700_dai));
+       if (ret < 0)
+               return ret;
+
+       /* set autosuspend parameters */
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
+
+       /* make sure the device does not suspend immediately */
+       pm_runtime_mark_last_busy(dev);
+
+       pm_runtime_enable(dev);
 
+       /* important note: the device is NOT tagged as 'active' and will remain
+        * 'suspended' until the hardware is enumerated/initialized. This is required
+        * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+        * fail with -EACCESS because of race conditions between card creation and enumeration
+        */
        dev_dbg(&slave->dev, "%s\n", __func__);
 
-       return ret;
+       return 0;
 }
 
 int rt700_io_init(struct device *dev, struct sdw_slave *slave)
@@ -1132,28 +1157,17 @@ int rt700_io_init(struct device *dev, struct sdw_slave *slave)
        if (rt700->hw_init)
                return 0;
 
-       if (rt700->first_hw_init) {
-               regcache_cache_only(rt700->regmap, false);
+       regcache_cache_only(rt700->regmap, false);
+       if (rt700->first_hw_init)
                regcache_cache_bypass(rt700->regmap, true);
-       }
 
        /*
         * PM runtime is only enabled when a Slave reports as Attached
         */
-       if (!rt700->first_hw_init) {
-               /* set autosuspend parameters */
-               pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
-               pm_runtime_use_autosuspend(&slave->dev);
-
-               /* update count of parent 'active' children */
+       if (!rt700->first_hw_init)
+               /* PM runtime status is marked as 'active' only when a Slave reports as Attached */
                pm_runtime_set_active(&slave->dev);
 
-               /* make sure the device does not suspend immediately */
-               pm_runtime_mark_last_busy(&slave->dev);
-
-               pm_runtime_enable(&slave->dev);
-       }
-
        pm_runtime_get_noresume(&slave->dev);
 
        /* reset */
index 23f23f7..935e597 100644 (file)
@@ -366,8 +366,7 @@ static int rt711_sdca_sdw_remove(struct sdw_slave *slave)
                cancel_delayed_work_sync(&rt711->jack_btn_check_work);
        }
 
-       if (rt711->first_hw_init)
-               pm_runtime_disable(&slave->dev);
+       pm_runtime_disable(&slave->dev);
 
        mutex_destroy(&rt711->calibrate_mutex);
        mutex_destroy(&rt711->disable_irq_lock);
index 07640d2..447154c 100644 (file)
@@ -507,6 +507,10 @@ static int rt711_sdca_set_jack_detect(struct snd_soc_component *component,
 
        rt711->hs_jack = hs_jack;
 
+       /* we can only resume if the device was initialized at least once */
+       if (!rt711->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume_and_get(component->dev);
        if (ret < 0) {
                if (ret != -EACCES) {
@@ -1215,6 +1219,9 @@ static int rt711_sdca_probe(struct snd_soc_component *component)
        rt711_sdca_parse_dt(rt711, &rt711->slave->dev);
        rt711->component = component;
 
+       if (!rt711->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume(component->dev);
        if (ret < 0 && ret != -EACCES)
                return ret;
@@ -1406,6 +1413,9 @@ int rt711_sdca_init(struct device *dev, struct regmap *regmap,
        rt711->regmap = regmap;
        rt711->mbq_regmap = mbq_regmap;
 
+       regcache_cache_only(rt711->regmap, true);
+       regcache_cache_only(rt711->mbq_regmap, true);
+
        mutex_init(&rt711->calibrate_mutex);
        mutex_init(&rt711->disable_irq_lock);
 
@@ -1431,9 +1441,27 @@ int rt711_sdca_init(struct device *dev, struct regmap *regmap,
                        rt711_sdca_dai,
                        ARRAY_SIZE(rt711_sdca_dai));
 
-       dev_dbg(&slave->dev, "%s\n", __func__);
+       if (ret < 0)
+               return ret;
 
-       return ret;
+       /* set autosuspend parameters */
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
+
+       /* make sure the device does not suspend immediately */
+       pm_runtime_mark_last_busy(dev);
+
+       pm_runtime_enable(dev);
+
+       /* important note: the device is NOT tagged as 'active' and will remain
+        * 'suspended' until the hardware is enumerated/initialized. This is required
+        * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+        * fail with -EACCESS because of race conditions between card creation and enumeration
+        */
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       return 0;
 }
 
 static void rt711_sdca_vd0_io_init(struct rt711_sdca_priv *rt711)
@@ -1500,27 +1528,19 @@ int rt711_sdca_io_init(struct device *dev, struct sdw_slave *slave)
        if (rt711->hw_init)
                return 0;
 
+       regcache_cache_only(rt711->regmap, false);
+       regcache_cache_only(rt711->mbq_regmap, false);
+
        if (rt711->first_hw_init) {
-               regcache_cache_only(rt711->regmap, false);
                regcache_cache_bypass(rt711->regmap, true);
-               regcache_cache_only(rt711->mbq_regmap, false);
                regcache_cache_bypass(rt711->mbq_regmap, true);
        } else {
                /*
-                * PM runtime is only enabled when a Slave reports as Attached
+                * PM runtime status is marked as 'active' only when a Slave reports as Attached
                 */
 
-               /* set autosuspend parameters */
-               pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
-               pm_runtime_use_autosuspend(&slave->dev);
-
                /* update count of parent 'active' children */
                pm_runtime_set_active(&slave->dev);
-
-               /* make sure the device does not suspend immediately */
-               pm_runtime_mark_last_busy(&slave->dev);
-
-               pm_runtime_enable(&slave->dev);
        }
 
        pm_runtime_get_noresume(&slave->dev);
index 33dced3..3f57733 100644 (file)
@@ -453,9 +453,7 @@ static int rt711_sdw_probe(struct sdw_slave *slave,
        if (IS_ERR(regmap))
                return PTR_ERR(regmap);
 
-       rt711_init(&slave->dev, sdw_regmap, regmap, slave);
-
-       return 0;
+       return rt711_init(&slave->dev, sdw_regmap, regmap, slave);
 }
 
 static int rt711_sdw_remove(struct sdw_slave *slave)
@@ -468,8 +466,7 @@ static int rt711_sdw_remove(struct sdw_slave *slave)
                cancel_work_sync(&rt711->calibration_work);
        }
 
-       if (rt711->first_hw_init)
-               pm_runtime_disable(&slave->dev);
+       pm_runtime_disable(&slave->dev);
 
        mutex_destroy(&rt711->calibrate_mutex);
        mutex_destroy(&rt711->disable_irq_lock);
index af53cbc..66eaed1 100644 (file)
@@ -462,6 +462,10 @@ static int rt711_set_jack_detect(struct snd_soc_component *component,
 
        rt711->hs_jack = hs_jack;
 
+       /* we can only resume if the device was initialized at least once */
+       if (!rt711->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume_and_get(component->dev);
        if (ret < 0) {
                if (ret != -EACCES) {
@@ -941,6 +945,9 @@ static int rt711_probe(struct snd_soc_component *component)
        rt711_parse_dt(rt711, &rt711->slave->dev);
        rt711->component = component;
 
+       if (!rt711->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume(component->dev);
        if (ret < 0 && ret != -EACCES)
                return ret;
@@ -1183,6 +1190,8 @@ int rt711_init(struct device *dev, struct regmap *sdw_regmap,
        rt711->sdw_regmap = sdw_regmap;
        rt711->regmap = regmap;
 
+       regcache_cache_only(rt711->regmap, true);
+
        mutex_init(&rt711->calibrate_mutex);
        mutex_init(&rt711->disable_irq_lock);
 
@@ -1204,8 +1213,25 @@ int rt711_init(struct device *dev, struct regmap *sdw_regmap,
                                &soc_codec_dev_rt711,
                                rt711_dai,
                                ARRAY_SIZE(rt711_dai));
+       if (ret < 0)
+               return ret;
+
+       /* set autosuspend parameters */
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
 
-       dev_dbg(&slave->dev, "%s\n", __func__);
+       /* make sure the device does not suspend immediately */
+       pm_runtime_mark_last_busy(dev);
+
+       pm_runtime_enable(dev);
+
+       /* important note: the device is NOT tagged as 'active' and will remain
+        * 'suspended' until the hardware is enumerated/initialized. This is required
+        * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+        * fail with -EACCESS because of race conditions between card creation and enumeration
+        */
+
+       dev_dbg(dev, "%s\n", __func__);
 
        return ret;
 }
@@ -1219,28 +1245,17 @@ int rt711_io_init(struct device *dev, struct sdw_slave *slave)
        if (rt711->hw_init)
                return 0;
 
-       if (rt711->first_hw_init) {
-               regcache_cache_only(rt711->regmap, false);
+       regcache_cache_only(rt711->regmap, false);
+       if (rt711->first_hw_init)
                regcache_cache_bypass(rt711->regmap, true);
-       }
 
        /*
-        * PM runtime is only enabled when a Slave reports as Attached
+        * PM runtime status is marked as 'active' only when a Slave reports as Attached
         */
-       if (!rt711->first_hw_init) {
-               /* set autosuspend parameters */
-               pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
-               pm_runtime_use_autosuspend(&slave->dev);
-
+       if (!rt711->first_hw_init)
                /* update count of parent 'active' children */
                pm_runtime_set_active(&slave->dev);
 
-               /* make sure the device does not suspend immediately */
-               pm_runtime_mark_last_busy(&slave->dev);
-
-               pm_runtime_enable(&slave->dev);
-       }
-
        pm_runtime_get_noresume(&slave->dev);
 
        rt711_reset(rt711->regmap);
index 869cc7b..ba08d03 100644 (file)
@@ -182,27 +182,18 @@ static int rt712_sdca_dmic_io_init(struct device *dev, struct sdw_slave *slave)
        if (rt712->hw_init)
                return 0;
 
+       regcache_cache_only(rt712->regmap, false);
+       regcache_cache_only(rt712->mbq_regmap, false);
        if (rt712->first_hw_init) {
-               regcache_cache_only(rt712->regmap, false);
                regcache_cache_bypass(rt712->regmap, true);
-               regcache_cache_only(rt712->mbq_regmap, false);
                regcache_cache_bypass(rt712->mbq_regmap, true);
        } else {
                /*
-                * PM runtime is only enabled when a Slave reports as Attached
+                * PM runtime status is marked as 'active' only when a Slave reports as Attached
                 */
 
-               /* set autosuspend parameters */
-               pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
-               pm_runtime_use_autosuspend(&slave->dev);
-
                /* update count of parent 'active' children */
                pm_runtime_set_active(&slave->dev);
-
-               /* make sure the device does not suspend immediately */
-               pm_runtime_mark_last_busy(&slave->dev);
-
-               pm_runtime_enable(&slave->dev);
        }
 
        pm_runtime_get_noresume(&slave->dev);
@@ -608,6 +599,9 @@ static int rt712_sdca_dmic_probe(struct snd_soc_component *component)
 
        rt712->component = component;
 
+       if (!rt712->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume(component->dev);
        if (ret < 0 && ret != -EACCES)
                return ret;
@@ -777,6 +771,9 @@ static int rt712_sdca_dmic_init(struct device *dev, struct regmap *regmap,
        rt712->regmap = regmap;
        rt712->mbq_regmap = mbq_regmap;
 
+       regcache_cache_only(rt712->regmap, true);
+       regcache_cache_only(rt712->mbq_regmap, true);
+
        /*
         * Mark hw_init to false
         * HW init will be performed when device reports present
@@ -791,10 +788,27 @@ static int rt712_sdca_dmic_init(struct device *dev, struct regmap *regmap,
                        &soc_sdca_dev_rt712_dmic,
                        rt712_sdca_dmic_dai,
                        ARRAY_SIZE(rt712_sdca_dmic_dai));
+       if (ret < 0)
+               return ret;
 
-       dev_dbg(&slave->dev, "%s\n", __func__);
+       /* set autosuspend parameters */
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
 
-       return ret;
+       /* make sure the device does not suspend immediately */
+       pm_runtime_mark_last_busy(dev);
+
+       pm_runtime_enable(dev);
+
+       /* important note: the device is NOT tagged as 'active' and will remain
+        * 'suspended' until the hardware is enumerated/initialized. This is required
+        * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+        * fail with -EACCESS because of race conditions between card creation and enumeration
+        */
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       return 0;
 }
 
 
@@ -954,10 +968,7 @@ static int rt712_sdca_dmic_sdw_probe(struct sdw_slave *slave,
 
 static int rt712_sdca_dmic_sdw_remove(struct sdw_slave *slave)
 {
-       struct rt712_sdca_dmic_priv *rt712 = dev_get_drvdata(&slave->dev);
-
-       if (rt712->first_hw_init)
-               pm_runtime_disable(&slave->dev);
+       pm_runtime_disable(&slave->dev);
 
        return 0;
 }
index 6bc5039..6b644a8 100644 (file)
@@ -363,8 +363,7 @@ static int rt712_sdca_sdw_remove(struct sdw_slave *slave)
                cancel_delayed_work_sync(&rt712->jack_btn_check_work);
        }
 
-       if (rt712->first_hw_init)
-               pm_runtime_disable(&slave->dev);
+       pm_runtime_disable(&slave->dev);
 
        mutex_destroy(&rt712->calibrate_mutex);
        mutex_destroy(&rt712->disable_irq_lock);
index 89d2456..7077ff6 100644 (file)
@@ -453,6 +453,9 @@ static int rt712_sdca_set_jack_detect(struct snd_soc_component *component,
 
        rt712->hs_jack = hs_jack;
 
+       if (!rt712->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume_and_get(component->dev);
        if (ret < 0) {
                if (ret != -EACCES) {
@@ -960,6 +963,9 @@ static int rt712_sdca_probe(struct snd_soc_component *component)
        rt712_sdca_parse_dt(rt712, &rt712->slave->dev);
        rt712->component = component;
 
+       if (!rt712->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume(component->dev);
        if (ret < 0 && ret != -EACCES)
                return ret;
@@ -1183,6 +1189,9 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap,
        rt712->regmap = regmap;
        rt712->mbq_regmap = mbq_regmap;
 
+       regcache_cache_only(rt712->regmap, true);
+       regcache_cache_only(rt712->mbq_regmap, true);
+
        mutex_init(&rt712->calibrate_mutex);
        mutex_init(&rt712->disable_irq_lock);
 
@@ -1207,10 +1216,27 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap,
        else
                ret =  devm_snd_soc_register_component(dev,
                                &soc_sdca_dev_rt712, rt712_sdca_dai, 1);
+       if (ret < 0)
+               return ret;
 
-       dev_dbg(&slave->dev, "%s\n", __func__);
+       /* set autosuspend parameters */
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
 
-       return ret;
+       /* make sure the device does not suspend immediately */
+       pm_runtime_mark_last_busy(dev);
+
+       pm_runtime_enable(dev);
+
+       /* important note: the device is NOT tagged as 'active' and will remain
+        * 'suspended' until the hardware is enumerated/initialized. This is required
+        * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+        * fail with -EACCESS because of race conditions between card creation and enumeration
+        */
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       return 0;
 }
 
 int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
@@ -1224,27 +1250,18 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
        if (rt712->hw_init)
                return 0;
 
+       regcache_cache_only(rt712->regmap, false);
+       regcache_cache_only(rt712->mbq_regmap, false);
        if (rt712->first_hw_init) {
-               regcache_cache_only(rt712->regmap, false);
                regcache_cache_bypass(rt712->regmap, true);
-               regcache_cache_only(rt712->mbq_regmap, false);
                regcache_cache_bypass(rt712->mbq_regmap, true);
        } else {
                /*
-                * PM runtime is only enabled when a Slave reports as Attached
+                *  PM runtime status is marked as 'active' only when a Slave reports as Attached
                 */
 
-               /* set autosuspend parameters */
-               pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
-               pm_runtime_use_autosuspend(&slave->dev);
-
                /* update count of parent 'active' children */
                pm_runtime_set_active(&slave->dev);
-
-               /* make sure the device does not suspend immediately */
-               pm_runtime_mark_last_busy(&slave->dev);
-
-               pm_runtime_enable(&slave->dev);
        }
 
        pm_runtime_get_noresume(&slave->dev);
index df10916..ab54a67 100644 (file)
@@ -193,10 +193,7 @@ static int rt715_sdca_sdw_probe(struct sdw_slave *slave,
 
 static int rt715_sdca_sdw_remove(struct sdw_slave *slave)
 {
-       struct rt715_sdca_priv *rt715 = dev_get_drvdata(&slave->dev);
-
-       if (rt715->first_hw_init)
-               pm_runtime_disable(&slave->dev);
+       pm_runtime_disable(&slave->dev);
 
        return 0;
 }
index b989f90..9fa96fd 100644 (file)
@@ -761,8 +761,12 @@ static const struct snd_soc_dapm_route rt715_sdca_audio_map[] = {
 
 static int rt715_sdca_probe(struct snd_soc_component *component)
 {
+       struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
        int ret;
 
+       if (!rt715->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume(component->dev);
        if (ret < 0 && ret != -EACCES)
                return ret;
@@ -977,6 +981,10 @@ int rt715_sdca_init(struct device *dev, struct regmap *mbq_regmap,
        rt715->regmap = regmap;
        rt715->mbq_regmap = mbq_regmap;
        rt715->hw_sdw_ver = slave->id.sdw_version;
+
+       regcache_cache_only(rt715->regmap, true);
+       regcache_cache_only(rt715->mbq_regmap, true);
+
        /*
         * Mark hw_init to false
         * HW init will be performed when device reports present
@@ -988,6 +996,25 @@ int rt715_sdca_init(struct device *dev, struct regmap *mbq_regmap,
                        &soc_codec_dev_rt715_sdca,
                        rt715_sdca_dai,
                        ARRAY_SIZE(rt715_sdca_dai));
+       if (ret < 0)
+               return ret;
+
+       /* set autosuspend parameters */
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
+
+       /* make sure the device does not suspend immediately */
+       pm_runtime_mark_last_busy(dev);
+
+       pm_runtime_enable(dev);
+
+       /* important note: the device is NOT tagged as 'active' and will remain
+        * 'suspended' until the hardware is enumerated/initialized. This is required
+        * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+        * fail with -EACCESS because of race conditions between card creation and enumeration
+        */
+
+       dev_dbg(dev, "%s\n", __func__);
 
        return ret;
 }
@@ -1000,22 +1027,16 @@ int rt715_sdca_io_init(struct device *dev, struct sdw_slave *slave)
        if (rt715->hw_init)
                return 0;
 
+       regcache_cache_only(rt715->regmap, false);
+       regcache_cache_only(rt715->mbq_regmap, false);
+
        /*
-        * PM runtime is only enabled when a Slave reports as Attached
+        * PM runtime status is marked as 'active' only when a Slave reports as Attached
         */
        if (!rt715->first_hw_init) {
-               /* set autosuspend parameters */
-               pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
-               pm_runtime_use_autosuspend(&slave->dev);
-
                /* update count of parent 'active' children */
                pm_runtime_set_active(&slave->dev);
 
-               /* make sure the device does not suspend immediately */
-               pm_runtime_mark_last_busy(&slave->dev);
-
-               pm_runtime_enable(&slave->dev);
-
                rt715->first_hw_init = true;
        }
 
index 6db8744..21f37ba 100644 (file)
@@ -508,17 +508,12 @@ static int rt715_sdw_probe(struct sdw_slave *slave,
        if (IS_ERR(regmap))
                return PTR_ERR(regmap);
 
-       rt715_init(&slave->dev, sdw_regmap, regmap, slave);
-
-       return 0;
+       return rt715_init(&slave->dev, sdw_regmap, regmap, slave);
 }
 
 static int rt715_sdw_remove(struct sdw_slave *slave)
 {
-       struct rt715_priv *rt715 = dev_get_drvdata(&slave->dev);
-
-       if (rt715->first_hw_init)
-               pm_runtime_disable(&slave->dev);
+       pm_runtime_disable(&slave->dev);
 
        return 0;
 }
index 6c2e165..79416bb 100644 (file)
@@ -740,8 +740,12 @@ static int rt715_set_bias_level(struct snd_soc_component *component,
 
 static int rt715_probe(struct snd_soc_component *component)
 {
+       struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
        int ret;
 
+       if (!rt715->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume(component->dev);
        if (ret < 0 && ret != -EACCES)
                return ret;
@@ -984,6 +988,8 @@ int rt715_init(struct device *dev, struct regmap *sdw_regmap,
        rt715->regmap = regmap;
        rt715->sdw_regmap = sdw_regmap;
 
+       regcache_cache_only(rt715->regmap, true);
+
        /*
         * Mark hw_init to false
         * HW init will be performed when device reports present
@@ -995,8 +1001,25 @@ int rt715_init(struct device *dev, struct regmap *sdw_regmap,
                                                &soc_codec_dev_rt715,
                                                rt715_dai,
                                                ARRAY_SIZE(rt715_dai));
+       if (ret < 0)
+               return ret;
 
-       return ret;
+       /* set autosuspend parameters */
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
+
+       /* make sure the device does not suspend immediately */
+       pm_runtime_mark_last_busy(dev);
+
+       pm_runtime_enable(dev);
+
+       /* important note: the device is NOT tagged as 'active' and will remain
+        * 'suspended' until the hardware is enumerated/initialized. This is required
+        * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+        * fail with -EACCESS because of race conditions between card creation and enumeration
+        */
+
+       return 0;
 }
 
 int rt715_io_init(struct device *dev, struct sdw_slave *slave)
@@ -1006,23 +1029,15 @@ int rt715_io_init(struct device *dev, struct sdw_slave *slave)
        if (rt715->hw_init)
                return 0;
 
+       regcache_cache_only(rt715->regmap, false);
+
        /*
-        * PM runtime is only enabled when a Slave reports as Attached
+        *  PM runtime status is marked as 'active' only when a Slave reports as Attached
         */
-       if (!rt715->first_hw_init) {
-               /* set autosuspend parameters */
-               pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
-               pm_runtime_use_autosuspend(&slave->dev);
-
+       if (!rt715->first_hw_init)
                /* update count of parent 'active' children */
                pm_runtime_set_active(&slave->dev);
 
-               /* make sure the device does not suspend immediately */
-               pm_runtime_mark_last_busy(&slave->dev);
-
-               pm_runtime_enable(&slave->dev);
-       }
-
        pm_runtime_get_noresume(&slave->dev);
 
        /* Mute nid=08h/09h */