Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // Copyright (c) 2006 Simtec Electronics
0004 //  Ben Dooks <ben@simtec.co.uk>
0005 //
0006 // http://armlinux.simtec.co.uk/.
0007 
0008 #include <linux/kernel.h>
0009 #include <linux/types.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/list.h>
0012 #include <linux/timer.h>
0013 #include <linux/init.h>
0014 #include <linux/device.h>
0015 #include <linux/syscore_ops.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/io.h>
0018 
0019 #include <asm/cacheflush.h>
0020 #include <asm/irq.h>
0021 
0022 #include "irqs.h"
0023 #include "regs-gpio.h"
0024 
0025 #include "cpu.h"
0026 #include "pm.h"
0027 #include "wakeup-mask.h"
0028 
0029 #include "regs-dsc-s3c24xx.h"
0030 #include "s3c2412-power.h"
0031 
0032 extern void s3c2412_sleep_enter(void);
0033 
0034 static int s3c2412_cpu_suspend(unsigned long arg)
0035 {
0036     unsigned long tmp;
0037 
0038     /* set our standby method to sleep */
0039 
0040     tmp = __raw_readl(S3C2412_PWRCFG);
0041     tmp |= S3C2412_PWRCFG_STANDBYWFI_SLEEP;
0042     __raw_writel(tmp, S3C2412_PWRCFG);
0043 
0044     s3c2412_sleep_enter();
0045 
0046     pr_info("Failed to suspend the system\n");
0047     return 1; /* Aborting suspend */
0048 }
0049 
0050 /* mapping of interrupts to parts of the wakeup mask */
0051 static const struct samsung_wakeup_mask wake_irqs[] = {
0052     { .irq = IRQ_RTC,   .bit = S3C2412_PWRCFG_RTC_MASKIRQ, },
0053 };
0054 
0055 static void s3c2412_pm_prepare(void)
0056 {
0057     samsung_sync_wakemask(S3C2412_PWRCFG,
0058                   wake_irqs, ARRAY_SIZE(wake_irqs));
0059 }
0060 
0061 static int s3c2412_pm_add(struct device *dev, struct subsys_interface *sif)
0062 {
0063     pm_cpu_prep = s3c2412_pm_prepare;
0064     pm_cpu_sleep = s3c2412_cpu_suspend;
0065 
0066     return 0;
0067 }
0068 
0069 static struct sleep_save s3c2412_sleep[] = {
0070     SAVE_ITEM(S3C2412_DSC0),
0071     SAVE_ITEM(S3C2412_DSC1),
0072     SAVE_ITEM(S3C2413_GPJDAT),
0073     SAVE_ITEM(S3C2413_GPJCON),
0074     SAVE_ITEM(S3C2413_GPJUP),
0075 
0076     /* save the PWRCFG to get back to original sleep method */
0077 
0078     SAVE_ITEM(S3C2412_PWRCFG),
0079 
0080     /* save the sleep configuration anyway, just in case these
0081      * get damaged during wakeup */
0082 
0083     SAVE_ITEM(S3C2412_GPBSLPCON),
0084     SAVE_ITEM(S3C2412_GPCSLPCON),
0085     SAVE_ITEM(S3C2412_GPDSLPCON),
0086     SAVE_ITEM(S3C2412_GPFSLPCON),
0087     SAVE_ITEM(S3C2412_GPGSLPCON),
0088     SAVE_ITEM(S3C2412_GPHSLPCON),
0089     SAVE_ITEM(S3C2413_GPJSLPCON),
0090 };
0091 
0092 static struct subsys_interface s3c2412_pm_interface = {
0093     .name       = "s3c2412_pm",
0094     .subsys     = &s3c2412_subsys,
0095     .add_dev    = s3c2412_pm_add,
0096 };
0097 
0098 static __init int s3c2412_pm_init(void)
0099 {
0100     return subsys_interface_register(&s3c2412_pm_interface);
0101 }
0102 
0103 arch_initcall(s3c2412_pm_init);
0104 
0105 static int s3c2412_pm_suspend(void)
0106 {
0107     s3c_pm_do_save(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep));
0108     return 0;
0109 }
0110 
0111 static void s3c2412_pm_resume(void)
0112 {
0113     unsigned long tmp;
0114 
0115     tmp = __raw_readl(S3C2412_PWRCFG);
0116     tmp &= ~S3C2412_PWRCFG_STANDBYWFI_MASK;
0117     tmp |=  S3C2412_PWRCFG_STANDBYWFI_IDLE;
0118     __raw_writel(tmp, S3C2412_PWRCFG);
0119 
0120     s3c_pm_do_restore(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep));
0121 }
0122 
0123 struct syscore_ops s3c2412_pm_syscore_ops = {
0124     .suspend    = s3c2412_pm_suspend,
0125     .resume     = s3c2412_pm_resume,
0126 };