EXPORT_SYMBOL(cros_ec_unregister);
 
 #ifdef CONFIG_PM_SLEEP
-/**
- * cros_ec_suspend() - Handle a suspend operation for the ChromeOS EC device.
- * @ec_dev: Device to suspend.
- *
- * This can be called by drivers to handle a suspend event.
- *
- * Return: 0 on success or negative error code.
- */
-int cros_ec_suspend(struct cros_ec_device *ec_dev)
+static void cros_ec_send_suspend_event(struct cros_ec_device *ec_dev)
 {
-       struct device *dev = ec_dev->dev;
        int ret;
        u8 sleep_event;
 
        if (ret < 0)
                dev_dbg(ec_dev->dev, "Error %d sending suspend event to ec\n",
                        ret);
+}
 
+/**
+ * cros_ec_suspend_prepare() - Handle a suspend prepare operation for the ChromeOS EC device.
+ * @ec_dev: Device to suspend.
+ *
+ * This can be called by drivers to handle a suspend prepare stage of suspend.
+ *
+ * Return: 0 always.
+ */
+int cros_ec_suspend_prepare(struct cros_ec_device *ec_dev)
+{
+       cros_ec_send_suspend_event(ec_dev);
+       return 0;
+}
+EXPORT_SYMBOL(cros_ec_suspend_prepare);
+
+static void cros_ec_disable_irq(struct cros_ec_device *ec_dev)
+{
+       struct device *dev = ec_dev->dev;
        if (device_may_wakeup(dev))
                ec_dev->wake_enabled = !enable_irq_wake(ec_dev->irq);
        else
 
        disable_irq(ec_dev->irq);
        ec_dev->suspended = true;
+}
 
+/**
+ * cros_ec_suspend_late() - Handle a suspend late operation for the ChromeOS EC device.
+ * @ec_dev: Device to suspend.
+ *
+ * This can be called by drivers to handle a suspend late stage of suspend.
+ *
+ * Return: 0 always.
+ */
+int cros_ec_suspend_late(struct cros_ec_device *ec_dev)
+{
+       cros_ec_disable_irq(ec_dev);
+       return 0;
+}
+EXPORT_SYMBOL(cros_ec_suspend_late);
+
+/**
+ * cros_ec_suspend() - Handle a suspend operation for the ChromeOS EC device.
+ * @ec_dev: Device to suspend.
+ *
+ * This can be called by drivers to handle a suspend event.
+ *
+ * Return: 0 always.
+ */
+int cros_ec_suspend(struct cros_ec_device *ec_dev)
+{
+       cros_ec_send_suspend_event(ec_dev);
+       cros_ec_disable_irq(ec_dev);
        return 0;
 }
 EXPORT_SYMBOL(cros_ec_suspend);
        }
 }
 
-/**
- * cros_ec_resume() - Handle a resume operation for the ChromeOS EC device.
- * @ec_dev: Device to resume.
- *
- * This can be called by drivers to handle a resume event.
- *
- * Return: 0 on success or negative error code.
- */
-int cros_ec_resume(struct cros_ec_device *ec_dev)
+static void cros_ec_send_resume_event(struct cros_ec_device *ec_dev)
 {
        int ret;
        u8 sleep_event;
 
-       ec_dev->suspended = false;
-       enable_irq(ec_dev->irq);
-
        sleep_event = (!IS_ENABLED(CONFIG_ACPI) || pm_suspend_via_firmware()) ?
                      HOST_SLEEP_EVENT_S3_RESUME :
                      HOST_SLEEP_EVENT_S0IX_RESUME;
        if (ret < 0)
                dev_dbg(ec_dev->dev, "Error %d sending resume event to ec\n",
                        ret);
+}
+
+/**
+ * cros_ec_resume_complete() - Handle a resume complete operation for the ChromeOS EC device.
+ * @ec_dev: Device to resume.
+ *
+ * This can be called by drivers to handle a resume complete stage of resume.
+ */
+void cros_ec_resume_complete(struct cros_ec_device *ec_dev)
+{
+       cros_ec_send_resume_event(ec_dev);
+}
+EXPORT_SYMBOL(cros_ec_resume_complete);
+
+static void cros_ec_enable_irq(struct cros_ec_device *ec_dev)
+{
+       ec_dev->suspended = false;
+       enable_irq(ec_dev->irq);
 
        if (ec_dev->wake_enabled)
                disable_irq_wake(ec_dev->irq);
         * suspend. This way the clients know what to do with them.
         */
        cros_ec_report_events_during_suspend(ec_dev);
+}
 
+/**
+ * cros_ec_resume_early() - Handle a resume early operation for the ChromeOS EC device.
+ * @ec_dev: Device to resume.
+ *
+ * This can be called by drivers to handle a resume early stage of resume.
+ *
+ * Return: 0 always.
+ */
+int cros_ec_resume_early(struct cros_ec_device *ec_dev)
+{
+       cros_ec_enable_irq(ec_dev);
+       return 0;
+}
+EXPORT_SYMBOL(cros_ec_resume_early);
 
+/**
+ * cros_ec_resume() - Handle a resume operation for the ChromeOS EC device.
+ * @ec_dev: Device to resume.
+ *
+ * This can be called by drivers to handle a resume event.
+ *
+ * Return: 0 always.
+ */
+int cros_ec_resume(struct cros_ec_device *ec_dev)
+{
+       cros_ec_enable_irq(ec_dev);
+       cros_ec_send_resume_event(ec_dev);
        return 0;
 }
 EXPORT_SYMBOL(cros_ec_resume);
 
 static int cros_ec_lpc_prepare(struct device *dev)
 {
        struct cros_ec_device *ec_dev = dev_get_drvdata(dev);
-
-       return cros_ec_suspend(ec_dev);
+       return cros_ec_suspend_prepare(ec_dev);
 }
 
 static void cros_ec_lpc_complete(struct device *dev)
 {
        struct cros_ec_device *ec_dev = dev_get_drvdata(dev);
-       cros_ec_resume(ec_dev);
+       cros_ec_resume_complete(ec_dev);
+}
+
+static int cros_ec_lpc_suspend_late(struct device *dev)
+{
+       struct cros_ec_device *ec_dev = dev_get_drvdata(dev);
+
+       return cros_ec_suspend_late(ec_dev);
+}
+
+static int cros_ec_lpc_resume_early(struct device *dev)
+{
+       struct cros_ec_device *ec_dev = dev_get_drvdata(dev);
+
+       return cros_ec_resume_early(ec_dev);
 }
 #endif
 
 static const struct dev_pm_ops cros_ec_lpc_pm_ops = {
 #ifdef CONFIG_PM_SLEEP
        .prepare = cros_ec_lpc_prepare,
-       .complete = cros_ec_lpc_complete
+       .complete = cros_ec_lpc_complete,
 #endif
+       SET_LATE_SYSTEM_SLEEP_PM_OPS(cros_ec_lpc_suspend_late, cros_ec_lpc_resume_early)
 };
 
 static struct platform_driver cros_ec_lpc_driver = {