#include <linux/of_device.h>
 #include <linux/pinctrl/machine.h>
 #include <linux/platform_device.h>
+#include <linux/psci.h>
 #include <linux/slab.h>
 
 #include "core.h"
 };
 #endif
 
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM_PSCI_FW)
+static void sh_pfc_nop_reg(struct sh_pfc *pfc, u32 reg, unsigned int idx)
+{
+}
+
+static void sh_pfc_save_reg(struct sh_pfc *pfc, u32 reg, unsigned int idx)
+{
+       pfc->saved_regs[idx] = sh_pfc_read(pfc, reg);
+}
+
+static void sh_pfc_restore_reg(struct sh_pfc *pfc, u32 reg, unsigned int idx)
+{
+       sh_pfc_write(pfc, reg, pfc->saved_regs[idx]);
+}
+
+static unsigned int sh_pfc_walk_regs(struct sh_pfc *pfc,
+       void (*do_reg)(struct sh_pfc *pfc, u32 reg, unsigned int idx))
+{
+       unsigned int i, n = 0;
+
+       if (pfc->info->cfg_regs)
+               for (i = 0; pfc->info->cfg_regs[i].reg; i++)
+                       do_reg(pfc, pfc->info->cfg_regs[i].reg, n++);
+
+       if (pfc->info->drive_regs)
+               for (i = 0; pfc->info->drive_regs[i].reg; i++)
+                       do_reg(pfc, pfc->info->drive_regs[i].reg, n++);
+
+       if (pfc->info->bias_regs)
+               for (i = 0; pfc->info->bias_regs[i].puen; i++) {
+                       do_reg(pfc, pfc->info->bias_regs[i].puen, n++);
+                       if (pfc->info->bias_regs[i].pud)
+                               do_reg(pfc, pfc->info->bias_regs[i].pud, n++);
+               }
+
+       if (pfc->info->ioctrl_regs)
+               for (i = 0; pfc->info->ioctrl_regs[i].reg; i++)
+                       do_reg(pfc, pfc->info->ioctrl_regs[i].reg, n++);
+
+       return n;
+}
+
+static int sh_pfc_suspend_init(struct sh_pfc *pfc)
+{
+       unsigned int n;
+
+       /* This is the best we can do to check for the presence of PSCI */
+       if (!psci_ops.cpu_suspend)
+               return 0;
+
+       n = sh_pfc_walk_regs(pfc, sh_pfc_nop_reg);
+       if (!n)
+               return 0;
+
+       pfc->saved_regs = devm_kmalloc_array(pfc->dev, n,
+                                            sizeof(*pfc->saved_regs),
+                                            GFP_KERNEL);
+       if (!pfc->saved_regs)
+               return -ENOMEM;
+
+       dev_dbg(pfc->dev, "Allocated space to save %u regs\n", n);
+       return 0;
+}
+
+static int sh_pfc_suspend_noirq(struct device *dev)
+{
+       struct sh_pfc *pfc = dev_get_drvdata(dev);
+
+       if (pfc->saved_regs)
+               sh_pfc_walk_regs(pfc, sh_pfc_save_reg);
+       return 0;
+}
+
+static int sh_pfc_resume_noirq(struct device *dev)
+{
+       struct sh_pfc *pfc = dev_get_drvdata(dev);
+
+       if (pfc->saved_regs)
+               sh_pfc_walk_regs(pfc, sh_pfc_restore_reg);
+       return 0;
+}
+
+static const struct dev_pm_ops sh_pfc_pm  = {
+       SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(sh_pfc_suspend_noirq, sh_pfc_resume_noirq)
+};
+#define DEV_PM_OPS     &sh_pfc_pm
+#else
+static int sh_pfc_suspend_init(struct sh_pfc *pfc) { return 0; }
+#define DEV_PM_OPS     NULL
+#endif /* CONFIG_PM_SLEEP && CONFIG_ARM_PSCI_FW */
+
 static int sh_pfc_probe(struct platform_device *pdev)
 {
 #ifdef CONFIG_OF
                info = pfc->info;
        }
 
+       ret = sh_pfc_suspend_init(pfc);
+       if (ret)
+               return ret;
+
        /* Enable dummy states for those platforms without pinctrl support */
        if (!of_have_populated_dt())
                pinctrl_provide_dummies();
        .driver         = {
                .name   = DRV_NAME,
                .of_match_table = of_match_ptr(sh_pfc_of_table),
+               .pm     = DEV_PM_OPS,
        },
 };