diff options
Diffstat (limited to 'sound/soc/codecs/rt5682-sdw.c')
-rw-r--r-- | sound/soc/codecs/rt5682-sdw.c | 57 |
1 files changed, 47 insertions, 10 deletions
diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index e78ba3b064c4..31a4f286043e 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -344,6 +344,8 @@ static int rt5682_sdw_init(struct device *dev, struct regmap *regmap, rt5682->sdw_regmap = regmap; rt5682->is_sdw = true; + mutex_init(&rt5682->disable_irq_lock); + rt5682->regmap = devm_regmap_init(dev, NULL, dev, &rt5682_sdw_indirect_regmap); if (IS_ERR(rt5682->regmap)) { @@ -378,6 +380,8 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave) int ret = 0, loop = 10; unsigned int val; + rt5682->disable_irq = false; + if (rt5682->hw_init) return 0; @@ -400,6 +404,11 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave) 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) @@ -408,14 +417,11 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave) usleep_range(30000, 30005); loop--; } + if (val != DEVICE_ID) { dev_err(dev, "Device with ID register %x is not rt5682\n", val); - return -ENODEV; - } - - if (rt5682->first_hw_init) { - regcache_cache_only(rt5682->regmap, false); - regcache_cache_bypass(rt5682->regmap, true); + ret = -ENODEV; + goto err_nodev; } rt5682_calibrate(rt5682); @@ -486,10 +492,11 @@ reinit: rt5682->hw_init = true; rt5682->first_hw_init = true; +err_nodev: pm_runtime_mark_last_busy(&slave->dev); pm_runtime_put_autosuspend(&slave->dev); - dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); + dev_dbg(&slave->dev, "%s hw_init complete: %d\n", __func__, ret); return ret; } @@ -676,10 +683,12 @@ static int rt5682_interrupt_callback(struct sdw_slave *slave, dev_dbg(&slave->dev, "%s control_port_stat=%x", __func__, status->control_port); - if (status->control_port & 0x4) { + mutex_lock(&rt5682->disable_irq_lock); + if (status->control_port & 0x4 && !rt5682->disable_irq) { mod_delayed_work(system_power_efficient_wq, &rt5682->jack_detect_work, msecs_to_jiffies(rt5682->irq_work_delay_time)); } + mutex_unlock(&rt5682->disable_irq_lock); return 0; } @@ -737,13 +746,41 @@ static int __maybe_unused rt5682_dev_suspend(struct device *dev) return 0; } +static int __maybe_unused rt5682_dev_system_suspend(struct device *dev) +{ + struct rt5682_priv *rt5682 = dev_get_drvdata(dev); + struct sdw_slave *slave = dev_to_sdw_dev(dev); + int ret; + + if (!rt5682->hw_init) + return 0; + + /* + * prevent new interrupts from being handled after the + * deferred work completes and before the parent disables + * interrupts on the link + */ + mutex_lock(&rt5682->disable_irq_lock); + rt5682->disable_irq = true; + ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1, + SDW_SCP_INT1_IMPL_DEF, 0); + mutex_unlock(&rt5682->disable_irq_lock); + + if (ret < 0) { + /* log but don't prevent suspend from happening */ + dev_dbg(&slave->dev, "%s: could not disable imp-def interrupts\n:", __func__); + } + + return rt5682_dev_suspend(dev); +} + static int __maybe_unused rt5682_dev_resume(struct device *dev) { struct sdw_slave *slave = dev_to_sdw_dev(dev); struct rt5682_priv *rt5682 = dev_get_drvdata(dev); unsigned long time; - if (!rt5682->hw_init) + if (!rt5682->first_hw_init) return 0; if (!slave->unattach_request) @@ -765,7 +802,7 @@ regmap_sync: } static const struct dev_pm_ops rt5682_pm = { - SET_SYSTEM_SLEEP_PM_OPS(rt5682_dev_suspend, rt5682_dev_resume) + SET_SYSTEM_SLEEP_PM_OPS(rt5682_dev_system_suspend, rt5682_dev_resume) SET_RUNTIME_PM_OPS(rt5682_dev_suspend, rt5682_dev_resume, NULL) }; |