Revert "FROMLIST: PM / sleep: don't suspend parent when async child suspend_{noirq...
[firefly-linux-kernel-4.4.55.git] / drivers / firmware / psci.c
index d24f35d74b27079afeae5c08d601c3bcd899dee6..bc22d9fed1a70e1d6848b614ff1375584fcb87e9 100644 (file)
@@ -13,6 +13,7 @@
 
 #define pr_fmt(fmt) "psci: " fmt
 
+#include <linux/arm-smccc.h>
 #include <linux/errno.h>
 #include <linux/linkage.h>
 #include <linux/of.h>
@@ -21,6 +22,7 @@
 #include <linux/psci.h>
 #include <linux/reboot.h>
 #include <linux/suspend.h>
+#include <linux/regulator/machine.h>
 
 #include <uapi/linux/psci.h>
 
@@ -58,8 +60,6 @@ struct psci_operations psci_ops;
 
 typedef unsigned long (psci_fn)(unsigned long, unsigned long,
                                unsigned long, unsigned long);
-asmlinkage psci_fn __invoke_psci_fn_hvc;
-asmlinkage psci_fn __invoke_psci_fn_smc;
 static psci_fn *invoke_psci_fn;
 
 enum psci_function {
@@ -107,6 +107,26 @@ bool psci_power_state_is_valid(u32 state)
        return !(state & ~valid_mask);
 }
 
+static unsigned long __invoke_psci_fn_hvc(unsigned long function_id,
+                       unsigned long arg0, unsigned long arg1,
+                       unsigned long arg2)
+{
+       struct arm_smccc_res res;
+
+       arm_smccc_hvc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
+       return res.a0;
+}
+
+static unsigned long __invoke_psci_fn_smc(unsigned long function_id,
+                       unsigned long arg0, unsigned long arg1,
+                       unsigned long arg2)
+{
+       struct arm_smccc_res res;
+
+       arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
+       return res.a0;
+}
+
 static int psci_to_linux_errno(int errno)
 {
        switch (errno) {
@@ -236,9 +256,25 @@ static int psci_system_suspend_enter(suspend_state_t state)
        return cpu_suspend(0, psci_system_suspend);
 }
 
+static int psci_system_suspend_prepare(void)
+{
+       return regulator_suspend_prepare(PM_SUSPEND_MEM);
+}
+
+static void psci_system_suspend_finish(void)
+{
+       int ret;
+
+       ret = regulator_suspend_finish();
+       if (ret < 0)
+               pr_warn("regulator_suspend_finish failed (%d)\n", ret);
+}
+
 static const struct platform_suspend_ops psci_suspend_ops = {
        .valid          = suspend_valid_only_mem,
        .enter          = psci_system_suspend_enter,
+       .prepare        = psci_system_suspend_prepare,
+       .finish         = psci_system_suspend_finish,
 };
 
 static void __init psci_init_system_suspend(void)