@@ -418,10 +418,12 @@ static int rt700_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(&rt700->disable_irq_lock);
+ if (status->control_port & 0x4 && !rt700->disable_irq) {
mod_delayed_work(system_power_efficient_wq,
&rt700->jack_detect_work, msecs_to_jiffies(250));
}
+ mutex_unlock(&rt700->disable_irq_lock);
return 0;
}
@@ -490,6 +492,34 @@ static int __maybe_unused rt700_dev_suspend(struct device *dev)
return 0;
}
+static int __maybe_unused rt700_dev_system_suspend(struct device *dev)
+{
+ struct sdw_slave *slave = dev_to_sdw_dev(dev);
+ struct rt700_priv *rt700 = dev_get_drvdata(dev);
+ int ret;
+
+ if (!rt700->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(&rt700->disable_irq_lock);
+ rt700->disable_irq = true;
+ ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1,
+ SDW_SCP_INT1_IMPL_DEF, 0);
+ mutex_unlock(&rt700->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 rt700_dev_suspend(dev);
+}
+
#define RT700_PROBE_TIMEOUT 5000
static int __maybe_unused rt700_dev_resume(struct device *dev)
@@ -521,7 +551,7 @@ static int __maybe_unused rt700_dev_resume(struct device *dev)
}
static const struct dev_pm_ops rt700_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(rt700_dev_suspend, rt700_dev_resume)
+ SET_SYSTEM_SLEEP_PM_OPS(rt700_dev_system_suspend, rt700_dev_resume)
SET_RUNTIME_PM_OPS(rt700_dev_suspend, rt700_dev_resume, NULL)
};
@@ -1112,6 +1112,8 @@ int rt700_init(struct device *dev, struct regmap *sdw_regmap,
rt700->sdw_regmap = sdw_regmap;
rt700->regmap = regmap;
+ mutex_init(&rt700->disable_irq_lock);
+
/*
* Mark hw_init to false
* HW init will be performed when device reports present
@@ -1133,6 +1135,8 @@ int rt700_io_init(struct device *dev, struct sdw_slave *slave)
{
struct rt700_priv *rt700 = dev_get_drvdata(dev);
+ rt700->disable_irq = false;
+
if (rt700->hw_init)
return 0;
@@ -23,6 +23,8 @@ struct rt700_priv {
struct delayed_work jack_detect_work;
struct delayed_work jack_btn_check_work;
int jack_type;
+ struct mutex disable_irq_lock; /* imp-def irq lock protection */
+ bool disable_irq;
};
struct sdw_stream_data {