0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/init.h>
0011 #include <linux/suspend.h>
0012 #include <linux/errno.h>
0013 #include <linux/delay.h>
0014 #include <linux/of.h>
0015 #include <linux/serial_s3c.h>
0016 #include <linux/io.h>
0017
0018 #include <asm/cacheflush.h>
0019 #include <asm/suspend.h>
0020
0021 #include "map.h"
0022 #include "regs-clock.h"
0023 #include "regs-irq.h"
0024 #include "irqs.h"
0025
0026 #include <asm/irq.h>
0027
0028 #include "cpu.h"
0029 #include "pm.h"
0030 #include "pm-core.h"
0031
0032
0033
0034 unsigned long s3c_pm_flags;
0035
0036
0037
0038
0039 unsigned long s3c_irqwake_intmask = 0xffffffffL;
0040 unsigned long s3c_irqwake_eintmask = 0xffffffffL;
0041
0042 int s3c_irqext_wake(struct irq_data *data, unsigned int state)
0043 {
0044 unsigned long bit = 1L << IRQ_EINT_BIT(data->irq);
0045
0046 if (!(s3c_irqwake_eintallow & bit))
0047 return -ENOENT;
0048
0049 printk(KERN_INFO "wake %s for irq %d\n",
0050 state ? "enabled" : "disabled", data->irq);
0051
0052 if (!state)
0053 s3c_irqwake_eintmask |= bit;
0054 else
0055 s3c_irqwake_eintmask &= ~bit;
0056
0057 return 0;
0058 }
0059
0060 void (*pm_cpu_prep)(void);
0061 int (*pm_cpu_sleep)(unsigned long);
0062
0063 #define any_allowed(mask, allow) (((mask) & (allow)) != (allow))
0064
0065
0066
0067
0068
0069
0070 static int s3c_pm_enter(suspend_state_t state)
0071 {
0072 int ret;
0073
0074 s3c_pm_debug_init_uart();
0075
0076 S3C_PMDBG("%s(%d)\n", __func__, state);
0077
0078 if (pm_cpu_prep == NULL || pm_cpu_sleep == NULL) {
0079 printk(KERN_ERR "%s: error: no cpu sleep function\n", __func__);
0080 return -EINVAL;
0081 }
0082
0083
0084
0085
0086
0087
0088 if (!of_have_populated_dt() &&
0089 !any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) &&
0090 !any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) {
0091 printk(KERN_ERR "%s: No wake-up sources!\n", __func__);
0092 printk(KERN_ERR "%s: Aborting sleep\n", __func__);
0093 return -EINVAL;
0094 }
0095
0096
0097
0098 if (!of_have_populated_dt()) {
0099 samsung_pm_save_gpios();
0100 samsung_pm_saved_gpios();
0101 }
0102
0103 s3c_pm_save_uarts(soc_is_s3c2410());
0104 s3c_pm_save_core();
0105
0106
0107
0108 s3c_pm_configure_extint();
0109
0110 S3C_PMDBG("sleep: irq wakeup masks: %08lx,%08lx\n",
0111 s3c_irqwake_intmask, s3c_irqwake_eintmask);
0112
0113 s3c_pm_arch_prepare_irqs();
0114
0115
0116
0117 pm_cpu_prep();
0118
0119
0120
0121 flush_cache_all();
0122
0123 s3c_pm_check_store();
0124
0125
0126
0127 s3c_pm_arch_stop_clocks();
0128
0129
0130
0131
0132
0133 ret = cpu_suspend(0, pm_cpu_sleep);
0134 if (ret)
0135 return ret;
0136
0137
0138
0139 s3c_pm_restore_core();
0140 s3c_pm_restore_uarts(soc_is_s3c2410());
0141
0142 if (!of_have_populated_dt()) {
0143 samsung_pm_restore_gpios();
0144 s3c_pm_restored_gpios();
0145 }
0146
0147 s3c_pm_debug_init_uart();
0148
0149
0150
0151 s3c_pm_arch_show_resume_irqs();
0152
0153 S3C_PMDBG("%s: post sleep, preparing to return\n", __func__);
0154
0155
0156 s3c_pm_debug_smdkled(1 << 1, 0);
0157
0158 s3c_pm_check_restore();
0159
0160
0161
0162 S3C_PMDBG("S3C PM Resume (post-restore)\n");
0163 return 0;
0164 }
0165
0166 static int s3c_pm_prepare(void)
0167 {
0168
0169
0170 s3c_pm_check_prepare();
0171 return 0;
0172 }
0173
0174 static void s3c_pm_finish(void)
0175 {
0176 s3c_pm_check_cleanup();
0177 }
0178
0179 static const struct platform_suspend_ops s3c_pm_ops = {
0180 .enter = s3c_pm_enter,
0181 .prepare = s3c_pm_prepare,
0182 .finish = s3c_pm_finish,
0183 .valid = suspend_valid_only_mem,
0184 };
0185
0186
0187
0188
0189
0190
0191
0192
0193 int __init s3c_pm_init(void)
0194 {
0195 printk("S3C Power Management, Copyright 2004 Simtec Electronics\n");
0196
0197 suspend_set_ops(&s3c_pm_ops);
0198 return 0;
0199 }