^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) // Copyright (c) 2006 Simtec Electronics
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) // Ben Dooks <ben@simtec.co.uk>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) // http://armlinux.simtec.co.uk/.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/timer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/syscore_ops.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <asm/cacheflush.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <asm/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <mach/irqs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include "regs-gpio.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include "cpu.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include "pm.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include "wakeup-mask.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include "regs-dsc-s3c24xx.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include "s3c2412-power.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) extern void s3c2412_sleep_enter(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) static int s3c2412_cpu_suspend(unsigned long arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) unsigned long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) /* set our standby method to sleep */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) tmp = __raw_readl(S3C2412_PWRCFG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) tmp |= S3C2412_PWRCFG_STANDBYWFI_SLEEP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) __raw_writel(tmp, S3C2412_PWRCFG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) s3c2412_sleep_enter();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) pr_info("Failed to suspend the system\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) return 1; /* Aborting suspend */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) /* mapping of interrupts to parts of the wakeup mask */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) static const struct samsung_wakeup_mask wake_irqs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) { .irq = IRQ_RTC, .bit = S3C2412_PWRCFG_RTC_MASKIRQ, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) static void s3c2412_pm_prepare(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) samsung_sync_wakemask(S3C2412_PWRCFG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) wake_irqs, ARRAY_SIZE(wake_irqs));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) static int s3c2412_pm_add(struct device *dev, struct subsys_interface *sif)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) pm_cpu_prep = s3c2412_pm_prepare;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) pm_cpu_sleep = s3c2412_cpu_suspend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) static struct sleep_save s3c2412_sleep[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) SAVE_ITEM(S3C2412_DSC0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) SAVE_ITEM(S3C2412_DSC1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) SAVE_ITEM(S3C2413_GPJDAT),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) SAVE_ITEM(S3C2413_GPJCON),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) SAVE_ITEM(S3C2413_GPJUP),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) /* save the PWRCFG to get back to original sleep method */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) SAVE_ITEM(S3C2412_PWRCFG),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) /* save the sleep configuration anyway, just in case these
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) * get damaged during wakeup */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) SAVE_ITEM(S3C2412_GPBSLPCON),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) SAVE_ITEM(S3C2412_GPCSLPCON),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) SAVE_ITEM(S3C2412_GPDSLPCON),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) SAVE_ITEM(S3C2412_GPFSLPCON),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) SAVE_ITEM(S3C2412_GPGSLPCON),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) SAVE_ITEM(S3C2412_GPHSLPCON),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) SAVE_ITEM(S3C2413_GPJSLPCON),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) static struct subsys_interface s3c2412_pm_interface = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) .name = "s3c2412_pm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) .subsys = &s3c2412_subsys,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) .add_dev = s3c2412_pm_add,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) static __init int s3c2412_pm_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) return subsys_interface_register(&s3c2412_pm_interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) arch_initcall(s3c2412_pm_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) static int s3c2412_pm_suspend(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) s3c_pm_do_save(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) static void s3c2412_pm_resume(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) unsigned long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) tmp = __raw_readl(S3C2412_PWRCFG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) tmp &= ~S3C2412_PWRCFG_STANDBYWFI_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) tmp |= S3C2412_PWRCFG_STANDBYWFI_IDLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) __raw_writel(tmp, S3C2412_PWRCFG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) s3c_pm_do_restore(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) struct syscore_ops s3c2412_pm_syscore_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) .suspend = s3c2412_pm_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) .resume = s3c2412_pm_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) };