@@ -24,6 +24,7 @@
#include <linux/slab.h>
#include <linux/soc/ti/ti-msgmgr.h>
#include <linux/soc/ti/ti_sci_protocol.h>
+#include <linux/suspend.h>
#include <linux/sys_soc.h>
#include <linux/reboot.h>
@@ -3608,6 +3609,84 @@ static int tisci_reboot_handler(struct sys_off_data *data)
return NOTIFY_BAD;
}
+#ifdef CONFIG_SUSPEND
+static int ti_sci_prepare_system_suspend(struct ti_sci_info *info)
+{
+ u8 mode;
+
+ /*
+ * Map and validate the target Linux suspend state to TISCI LPM.
+ * Default is to let Device Manager select the low power mode.
+ */
+ switch (pm_suspend_target_state) {
+ case PM_SUSPEND_MEM:
+ if (info->fw_caps & MSG_FLAG_CAPS_LPM_DM_MANAGED)
+ mode = TISCI_MSG_VALUE_SLEEP_MODE_DM_MANAGED;
+ else
+ /* DM Managed is not supported by the firmware. */
+ return -EOPNOTSUPP;
+ break;
+ default:
+ /*
+ * Do not fail if we don't have action to take for a
+ * specific suspend mode.
+ */
+ return 0;
+ }
+
+ return ti_sci_cmd_prepare_sleep(&info->handle, mode, 0, 0, 0);
+}
+
+static int ti_sci_suspend(struct device *dev)
+{
+ struct ti_sci_info *info = dev_get_drvdata(dev);
+ int ret;
+
+ ret = ti_sci_prepare_system_suspend(info);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int ti_sci_suspend_noirq(struct device *dev)
+{
+ struct ti_sci_info *info = dev_get_drvdata(dev);
+ int ret = 0;
+
+ ret = ti_sci_cmd_set_io_isolation(&info->handle, TISCI_MSG_VALUE_IO_ENABLE);
+ if (ret)
+ return ret;
+ dev_dbg(dev, "%s: set isolation: %d\n", __func__, ret);
+
+ return 0;
+}
+
+static int ti_sci_resume_noirq(struct device *dev)
+{
+ struct ti_sci_info *info = dev_get_drvdata(dev);
+ u32 source;
+ u64 time;
+ int ret = 0;
+
+ ret = ti_sci_cmd_set_io_isolation(&info->handle, TISCI_MSG_VALUE_IO_DISABLE);
+ if (ret)
+ return ret;
+ dev_dbg(dev, "%s: disable isolation: %d\n", __func__, ret);
+
+ ti_sci_msg_cmd_lpm_wake_reason(&info->handle, &source, &time);
+ dev_info(dev, "%s: wakeup source: 0x%X\n", __func__, source);
+
+ return 0;
+}
+
+static const struct dev_pm_ops ti_sci_pm_ops = {
+ .suspend = ti_sci_suspend,
+ .suspend_noirq = ti_sci_suspend_noirq,
+ .resume_noirq = ti_sci_resume_noirq,
+};
+#endif /* CONFIG_SUSPEND */
+
/* Description for K2G */
static const struct ti_sci_desc ti_sci_pmmc_k2g_desc = {
.default_host_id = 2,
@@ -3777,6 +3856,9 @@ static struct platform_driver ti_sci_driver = {
.name = "ti-sci",
.of_match_table = of_match_ptr(ti_sci_of_match),
.suppress_bind_attrs = true,
+#ifdef CONFIG_SUSPEND
+ .pm = &ti_sci_pm_ops,
+#endif
},
};
module_platform_driver(ti_sci_driver);