linux/arch/arm/mach-exynos/suspend.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd.
   3 *              http://www.samsung.com
   4 *
   5 * EXYNOS - Suspend support
   6 *
   7 * Based on arch/arm/mach-s3c2410/pm.c
   8 * Copyright (c) 2006 Simtec Electronics
   9 *      Ben Dooks <ben@simtec.co.uk>
  10 *
  11 * This program is free software; you can redistribute it and/or modify
  12 * it under the terms of the GNU General Public License version 2 as
  13 * published by the Free Software Foundation.
  14 */
  15
  16#include <linux/init.h>
  17#include <linux/suspend.h>
  18#include <linux/syscore_ops.h>
  19#include <linux/cpu_pm.h>
  20#include <linux/io.h>
  21#include <linux/irq.h>
  22#include <linux/irqchip.h>
  23#include <linux/irqdomain.h>
  24#include <linux/of_address.h>
  25#include <linux/err.h>
  26#include <linux/regulator/machine.h>
  27#include <linux/soc/samsung/exynos-pmu.h>
  28#include <linux/soc/samsung/exynos-regs-pmu.h>
  29
  30#include <asm/cacheflush.h>
  31#include <asm/hardware/cache-l2x0.h>
  32#include <asm/firmware.h>
  33#include <asm/mcpm.h>
  34#include <asm/smp_scu.h>
  35#include <asm/suspend.h>
  36
  37#include <plat/pm-common.h>
  38
  39#include "common.h"
  40#include "regs-srom.h"
  41
  42#define REG_TABLE_END (-1U)
  43
  44#define EXYNOS5420_CPU_STATE    0x28
  45
  46/**
  47 * struct exynos_wkup_irq - PMU IRQ to mask mapping
  48 * @hwirq: Hardware IRQ signal of the PMU
  49 * @mask: Mask in PMU wake-up mask register
  50 */
  51struct exynos_wkup_irq {
  52        unsigned int hwirq;
  53        u32 mask;
  54};
  55
  56static struct sleep_save exynos_core_save[] = {
  57        /* SROM side */
  58        SAVE_ITEM(S5P_SROM_BW),
  59        SAVE_ITEM(S5P_SROM_BC0),
  60        SAVE_ITEM(S5P_SROM_BC1),
  61        SAVE_ITEM(S5P_SROM_BC2),
  62        SAVE_ITEM(S5P_SROM_BC3),
  63};
  64
  65struct exynos_pm_data {
  66        const struct exynos_wkup_irq *wkup_irq;
  67        unsigned int wake_disable_mask;
  68        unsigned int *release_ret_regs;
  69
  70        void (*pm_prepare)(void);
  71        void (*pm_resume_prepare)(void);
  72        void (*pm_resume)(void);
  73        int (*pm_suspend)(void);
  74        int (*cpu_suspend)(unsigned long);
  75};
  76
  77static const struct exynos_pm_data *pm_data;
  78
  79static int exynos5420_cpu_state;
  80static unsigned int exynos_pmu_spare3;
  81
  82/*
  83 * GIC wake-up support
  84 */
  85
  86static u32 exynos_irqwake_intmask = 0xffffffff;
  87
  88static const struct exynos_wkup_irq exynos3250_wkup_irq[] = {
  89        { 73, BIT(1) }, /* RTC alarm */
  90        { 74, BIT(2) }, /* RTC tick */
  91        { /* sentinel */ },
  92};
  93
  94static const struct exynos_wkup_irq exynos4_wkup_irq[] = {
  95        { 44, BIT(1) }, /* RTC alarm */
  96        { 45, BIT(2) }, /* RTC tick */
  97        { /* sentinel */ },
  98};
  99
 100static const struct exynos_wkup_irq exynos5250_wkup_irq[] = {
 101        { 43, BIT(1) }, /* RTC alarm */
 102        { 44, BIT(2) }, /* RTC tick */
 103        { /* sentinel */ },
 104};
 105
 106static unsigned int exynos_release_ret_regs[] = {
 107        S5P_PAD_RET_MAUDIO_OPTION,
 108        S5P_PAD_RET_GPIO_OPTION,
 109        S5P_PAD_RET_UART_OPTION,
 110        S5P_PAD_RET_MMCA_OPTION,
 111        S5P_PAD_RET_MMCB_OPTION,
 112        S5P_PAD_RET_EBIA_OPTION,
 113        S5P_PAD_RET_EBIB_OPTION,
 114        REG_TABLE_END,
 115};
 116
 117static unsigned int exynos3250_release_ret_regs[] = {
 118        S5P_PAD_RET_MAUDIO_OPTION,
 119        S5P_PAD_RET_GPIO_OPTION,
 120        S5P_PAD_RET_UART_OPTION,
 121        S5P_PAD_RET_MMCA_OPTION,
 122        S5P_PAD_RET_MMCB_OPTION,
 123        S5P_PAD_RET_EBIA_OPTION,
 124        S5P_PAD_RET_EBIB_OPTION,
 125        S5P_PAD_RET_MMC2_OPTION,
 126        S5P_PAD_RET_SPI_OPTION,
 127        REG_TABLE_END,
 128};
 129
 130static unsigned int exynos5420_release_ret_regs[] = {
 131        EXYNOS_PAD_RET_DRAM_OPTION,
 132        EXYNOS_PAD_RET_MAUDIO_OPTION,
 133        EXYNOS_PAD_RET_JTAG_OPTION,
 134        EXYNOS5420_PAD_RET_GPIO_OPTION,
 135        EXYNOS5420_PAD_RET_UART_OPTION,
 136        EXYNOS5420_PAD_RET_MMCA_OPTION,
 137        EXYNOS5420_PAD_RET_MMCB_OPTION,
 138        EXYNOS5420_PAD_RET_MMCC_OPTION,
 139        EXYNOS5420_PAD_RET_HSI_OPTION,
 140        EXYNOS_PAD_RET_EBIA_OPTION,
 141        EXYNOS_PAD_RET_EBIB_OPTION,
 142        EXYNOS5420_PAD_RET_SPI_OPTION,
 143        EXYNOS5420_PAD_RET_DRAM_COREBLK_OPTION,
 144        REG_TABLE_END,
 145};
 146
 147static int exynos_irq_set_wake(struct irq_data *data, unsigned int state)
 148{
 149        const struct exynos_wkup_irq *wkup_irq;
 150
 151        if (!pm_data->wkup_irq)
 152                return -ENOENT;
 153        wkup_irq = pm_data->wkup_irq;
 154
 155        while (wkup_irq->mask) {
 156                if (wkup_irq->hwirq == data->hwirq) {
 157                        if (!state)
 158                                exynos_irqwake_intmask |= wkup_irq->mask;
 159                        else
 160                                exynos_irqwake_intmask &= ~wkup_irq->mask;
 161                        return 0;
 162                }
 163                ++wkup_irq;
 164        }
 165
 166        return -ENOENT;
 167}
 168
 169static struct irq_chip exynos_pmu_chip = {
 170        .name                   = "PMU",
 171        .irq_eoi                = irq_chip_eoi_parent,
 172        .irq_mask               = irq_chip_mask_parent,
 173        .irq_unmask             = irq_chip_unmask_parent,
 174        .irq_retrigger          = irq_chip_retrigger_hierarchy,
 175        .irq_set_wake           = exynos_irq_set_wake,
 176#ifdef CONFIG_SMP
 177        .irq_set_affinity       = irq_chip_set_affinity_parent,
 178#endif
 179};
 180
 181static int exynos_pmu_domain_translate(struct irq_domain *d,
 182                                       struct irq_fwspec *fwspec,
 183                                       unsigned long *hwirq,
 184                                       unsigned int *type)
 185{
 186        if (is_of_node(fwspec->fwnode)) {
 187                if (fwspec->param_count != 3)
 188                        return -EINVAL;
 189
 190                /* No PPI should point to this domain */
 191                if (fwspec->param[0] != 0)
 192                        return -EINVAL;
 193
 194                *hwirq = fwspec->param[1];
 195                *type = fwspec->param[2];
 196                return 0;
 197        }
 198
 199        return -EINVAL;
 200}
 201
 202static int exynos_pmu_domain_alloc(struct irq_domain *domain,
 203                                   unsigned int virq,
 204                                   unsigned int nr_irqs, void *data)
 205{
 206        struct irq_fwspec *fwspec = data;
 207        struct irq_fwspec parent_fwspec;
 208        irq_hw_number_t hwirq;
 209        int i;
 210
 211        if (fwspec->param_count != 3)
 212                return -EINVAL; /* Not GIC compliant */
 213        if (fwspec->param[0] != 0)
 214                return -EINVAL; /* No PPI should point to this domain */
 215
 216        hwirq = fwspec->param[1];
 217
 218        for (i = 0; i < nr_irqs; i++)
 219                irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
 220                                              &exynos_pmu_chip, NULL);
 221
 222        parent_fwspec = *fwspec;
 223        parent_fwspec.fwnode = domain->parent->fwnode;
 224        return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
 225                                            &parent_fwspec);
 226}
 227
 228static const struct irq_domain_ops exynos_pmu_domain_ops = {
 229        .translate      = exynos_pmu_domain_translate,
 230        .alloc          = exynos_pmu_domain_alloc,
 231        .free           = irq_domain_free_irqs_common,
 232};
 233
 234static int __init exynos_pmu_irq_init(struct device_node *node,
 235                                      struct device_node *parent)
 236{
 237        struct irq_domain *parent_domain, *domain;
 238
 239        if (!parent) {
 240                pr_err("%s: no parent, giving up\n", node->full_name);
 241                return -ENODEV;
 242        }
 243
 244        parent_domain = irq_find_host(parent);
 245        if (!parent_domain) {
 246                pr_err("%s: unable to obtain parent domain\n", node->full_name);
 247                return -ENXIO;
 248        }
 249
 250        pmu_base_addr = of_iomap(node, 0);
 251
 252        if (!pmu_base_addr) {
 253                pr_err("%s: failed to find exynos pmu register\n",
 254                       node->full_name);
 255                return -ENOMEM;
 256        }
 257
 258        domain = irq_domain_add_hierarchy(parent_domain, 0, 0,
 259                                          node, &exynos_pmu_domain_ops,
 260                                          NULL);
 261        if (!domain) {
 262                iounmap(pmu_base_addr);
 263                return -ENOMEM;
 264        }
 265
 266        return 0;
 267}
 268
 269#define EXYNOS_PMU_IRQ(symbol, name)    IRQCHIP_DECLARE(symbol, name, exynos_pmu_irq_init)
 270
 271EXYNOS_PMU_IRQ(exynos3250_pmu_irq, "samsung,exynos3250-pmu");
 272EXYNOS_PMU_IRQ(exynos4210_pmu_irq, "samsung,exynos4210-pmu");
 273EXYNOS_PMU_IRQ(exynos4212_pmu_irq, "samsung,exynos4212-pmu");
 274EXYNOS_PMU_IRQ(exynos4412_pmu_irq, "samsung,exynos4412-pmu");
 275EXYNOS_PMU_IRQ(exynos4415_pmu_irq, "samsung,exynos4415-pmu");
 276EXYNOS_PMU_IRQ(exynos5250_pmu_irq, "samsung,exynos5250-pmu");
 277EXYNOS_PMU_IRQ(exynos5420_pmu_irq, "samsung,exynos5420-pmu");
 278
 279static int exynos_cpu_do_idle(void)
 280{
 281        /* issue the standby signal into the pm unit. */
 282        cpu_do_idle();
 283
 284        pr_info("Failed to suspend the system\n");
 285        return 1; /* Aborting suspend */
 286}
 287static void exynos_flush_cache_all(void)
 288{
 289        flush_cache_all();
 290        outer_flush_all();
 291}
 292
 293static int exynos_cpu_suspend(unsigned long arg)
 294{
 295        exynos_flush_cache_all();
 296        return exynos_cpu_do_idle();
 297}
 298
 299static int exynos3250_cpu_suspend(unsigned long arg)
 300{
 301        flush_cache_all();
 302        return exynos_cpu_do_idle();
 303}
 304
 305static int exynos5420_cpu_suspend(unsigned long arg)
 306{
 307        /* MCPM works with HW CPU identifiers */
 308        unsigned int mpidr = read_cpuid_mpidr();
 309        unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
 310        unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
 311
 312        __raw_writel(0x0, sysram_base_addr + EXYNOS5420_CPU_STATE);
 313
 314        if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM)) {
 315                mcpm_set_entry_vector(cpu, cluster, exynos_cpu_resume);
 316                mcpm_cpu_suspend();
 317        }
 318
 319        pr_info("Failed to suspend the system\n");
 320
 321        /* return value != 0 means failure */
 322        return 1;
 323}
 324
 325static void exynos_pm_set_wakeup_mask(void)
 326{
 327        /* Set wake-up mask registers */
 328        pmu_raw_writel(exynos_get_eint_wake_mask(), S5P_EINT_WAKEUP_MASK);
 329        pmu_raw_writel(exynos_irqwake_intmask & ~(1 << 31), S5P_WAKEUP_MASK);
 330}
 331
 332static void exynos_pm_enter_sleep_mode(void)
 333{
 334        /* Set value of power down register for sleep mode */
 335        exynos_sys_powerdown_conf(SYS_SLEEP);
 336        pmu_raw_writel(EXYNOS_SLEEP_MAGIC, S5P_INFORM1);
 337}
 338
 339static void exynos_pm_prepare(void)
 340{
 341        exynos_set_delayed_reset_assertion(false);
 342
 343        /* Set wake-up mask registers */
 344        exynos_pm_set_wakeup_mask();
 345
 346        s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save));
 347
 348        exynos_pm_enter_sleep_mode();
 349
 350        /* ensure at least INFORM0 has the resume address */
 351        pmu_raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0);
 352}
 353
 354static void exynos3250_pm_prepare(void)
 355{
 356        unsigned int tmp;
 357
 358        /* Set wake-up mask registers */
 359        exynos_pm_set_wakeup_mask();
 360
 361        tmp = pmu_raw_readl(EXYNOS3_ARM_L2_OPTION);
 362        tmp &= ~EXYNOS5_OPTION_USE_RETENTION;
 363        pmu_raw_writel(tmp, EXYNOS3_ARM_L2_OPTION);
 364
 365        exynos_pm_enter_sleep_mode();
 366
 367        /* ensure at least INFORM0 has the resume address */
 368        pmu_raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0);
 369}
 370
 371static void exynos5420_pm_prepare(void)
 372{
 373        unsigned int tmp;
 374
 375        /* Set wake-up mask registers */
 376        exynos_pm_set_wakeup_mask();
 377
 378        s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save));
 379
 380        exynos_pmu_spare3 = pmu_raw_readl(S5P_PMU_SPARE3);
 381        /*
 382         * The cpu state needs to be saved and restored so that the
 383         * secondary CPUs will enter low power start. Though the U-Boot
 384         * is setting the cpu state with low power flag, the kernel
 385         * needs to restore it back in case, the primary cpu fails to
 386         * suspend for any reason.
 387         */
 388        exynos5420_cpu_state = __raw_readl(sysram_base_addr +
 389                                                EXYNOS5420_CPU_STATE);
 390
 391        exynos_pm_enter_sleep_mode();
 392
 393        /* ensure at least INFORM0 has the resume address */
 394        if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM))
 395                pmu_raw_writel(virt_to_phys(mcpm_entry_point), S5P_INFORM0);
 396
 397        tmp = pmu_raw_readl(EXYNOS5_ARM_L2_OPTION);
 398        tmp &= ~EXYNOS5_USE_RETENTION;
 399        pmu_raw_writel(tmp, EXYNOS5_ARM_L2_OPTION);
 400
 401        tmp = pmu_raw_readl(EXYNOS5420_SFR_AXI_CGDIS1);
 402        tmp |= EXYNOS5420_UFS;
 403        pmu_raw_writel(tmp, EXYNOS5420_SFR_AXI_CGDIS1);
 404
 405        tmp = pmu_raw_readl(EXYNOS5420_ARM_COMMON_OPTION);
 406        tmp &= ~EXYNOS5420_L2RSTDISABLE_VALUE;
 407        pmu_raw_writel(tmp, EXYNOS5420_ARM_COMMON_OPTION);
 408
 409        tmp = pmu_raw_readl(EXYNOS5420_FSYS2_OPTION);
 410        tmp |= EXYNOS5420_EMULATION;
 411        pmu_raw_writel(tmp, EXYNOS5420_FSYS2_OPTION);
 412
 413        tmp = pmu_raw_readl(EXYNOS5420_PSGEN_OPTION);
 414        tmp |= EXYNOS5420_EMULATION;
 415        pmu_raw_writel(tmp, EXYNOS5420_PSGEN_OPTION);
 416}
 417
 418
 419static int exynos_pm_suspend(void)
 420{
 421        exynos_pm_central_suspend();
 422
 423        /* Setting SEQ_OPTION register */
 424        pmu_raw_writel(S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0,
 425                       S5P_CENTRAL_SEQ_OPTION);
 426
 427        if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9)
 428                exynos_cpu_save_register();
 429
 430        return 0;
 431}
 432
 433static int exynos5420_pm_suspend(void)
 434{
 435        u32 this_cluster;
 436
 437        exynos_pm_central_suspend();
 438
 439        /* Setting SEQ_OPTION register */
 440
 441        this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 1);
 442        if (!this_cluster)
 443                pmu_raw_writel(EXYNOS5420_ARM_USE_STANDBY_WFI0,
 444                                S5P_CENTRAL_SEQ_OPTION);
 445        else
 446                pmu_raw_writel(EXYNOS5420_KFC_USE_STANDBY_WFI0,
 447                                S5P_CENTRAL_SEQ_OPTION);
 448        return 0;
 449}
 450
 451static void exynos_pm_release_retention(void)
 452{
 453        unsigned int i;
 454
 455        for (i = 0; (pm_data->release_ret_regs[i] != REG_TABLE_END); i++)
 456                pmu_raw_writel(EXYNOS_WAKEUP_FROM_LOWPWR,
 457                                pm_data->release_ret_regs[i]);
 458}
 459
 460static void exynos_pm_resume(void)
 461{
 462        u32 cpuid = read_cpuid_part();
 463
 464        if (exynos_pm_central_resume())
 465                goto early_wakeup;
 466
 467        /* For release retention */
 468        exynos_pm_release_retention();
 469
 470        s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save));
 471
 472        if (cpuid == ARM_CPU_PART_CORTEX_A9)
 473                scu_enable(S5P_VA_SCU);
 474
 475        if (call_firmware_op(resume) == -ENOSYS
 476            && cpuid == ARM_CPU_PART_CORTEX_A9)
 477                exynos_cpu_restore_register();
 478
 479early_wakeup:
 480
 481        /* Clear SLEEP mode set in INFORM1 */
 482        pmu_raw_writel(0x0, S5P_INFORM1);
 483        exynos_set_delayed_reset_assertion(true);
 484}
 485
 486static void exynos3250_pm_resume(void)
 487{
 488        u32 cpuid = read_cpuid_part();
 489
 490        if (exynos_pm_central_resume())
 491                goto early_wakeup;
 492
 493        /* For release retention */
 494        exynos_pm_release_retention();
 495
 496        pmu_raw_writel(S5P_USE_STANDBY_WFI_ALL, S5P_CENTRAL_SEQ_OPTION);
 497
 498        if (call_firmware_op(resume) == -ENOSYS
 499            && cpuid == ARM_CPU_PART_CORTEX_A9)
 500                exynos_cpu_restore_register();
 501
 502early_wakeup:
 503
 504        /* Clear SLEEP mode set in INFORM1 */
 505        pmu_raw_writel(0x0, S5P_INFORM1);
 506}
 507
 508static void exynos5420_prepare_pm_resume(void)
 509{
 510        if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM))
 511                WARN_ON(mcpm_cpu_powered_up());
 512}
 513
 514static void exynos5420_pm_resume(void)
 515{
 516        unsigned long tmp;
 517
 518        /* Restore the CPU0 low power state register */
 519        tmp = pmu_raw_readl(EXYNOS5_ARM_CORE0_SYS_PWR_REG);
 520        pmu_raw_writel(tmp | S5P_CORE_LOCAL_PWR_EN,
 521                EXYNOS5_ARM_CORE0_SYS_PWR_REG);
 522
 523        /* Restore the sysram cpu state register */
 524        __raw_writel(exynos5420_cpu_state,
 525                sysram_base_addr + EXYNOS5420_CPU_STATE);
 526
 527        pmu_raw_writel(EXYNOS5420_USE_STANDBY_WFI_ALL,
 528                        S5P_CENTRAL_SEQ_OPTION);
 529
 530        if (exynos_pm_central_resume())
 531                goto early_wakeup;
 532
 533        /* For release retention */
 534        exynos_pm_release_retention();
 535
 536        pmu_raw_writel(exynos_pmu_spare3, S5P_PMU_SPARE3);
 537
 538        s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save));
 539
 540early_wakeup:
 541
 542        tmp = pmu_raw_readl(EXYNOS5420_SFR_AXI_CGDIS1);
 543        tmp &= ~EXYNOS5420_UFS;
 544        pmu_raw_writel(tmp, EXYNOS5420_SFR_AXI_CGDIS1);
 545
 546        tmp = pmu_raw_readl(EXYNOS5420_FSYS2_OPTION);
 547        tmp &= ~EXYNOS5420_EMULATION;
 548        pmu_raw_writel(tmp, EXYNOS5420_FSYS2_OPTION);
 549
 550        tmp = pmu_raw_readl(EXYNOS5420_PSGEN_OPTION);
 551        tmp &= ~EXYNOS5420_EMULATION;
 552        pmu_raw_writel(tmp, EXYNOS5420_PSGEN_OPTION);
 553
 554        /* Clear SLEEP mode set in INFORM1 */
 555        pmu_raw_writel(0x0, S5P_INFORM1);
 556}
 557
 558/*
 559 * Suspend Ops
 560 */
 561
 562static int exynos_suspend_enter(suspend_state_t state)
 563{
 564        int ret;
 565
 566        s3c_pm_debug_init();
 567
 568        S3C_PMDBG("%s: suspending the system...\n", __func__);
 569
 570        S3C_PMDBG("%s: wakeup masks: %08x,%08x\n", __func__,
 571                        exynos_irqwake_intmask, exynos_get_eint_wake_mask());
 572
 573        if (exynos_irqwake_intmask == -1U
 574            && exynos_get_eint_wake_mask() == -1U) {
 575                pr_err("%s: No wake-up sources!\n", __func__);
 576                pr_err("%s: Aborting sleep\n", __func__);
 577                return -EINVAL;
 578        }
 579
 580        s3c_pm_save_uarts();
 581        if (pm_data->pm_prepare)
 582                pm_data->pm_prepare();
 583        flush_cache_all();
 584        s3c_pm_check_store();
 585
 586        ret = call_firmware_op(suspend);
 587        if (ret == -ENOSYS)
 588                ret = cpu_suspend(0, pm_data->cpu_suspend);
 589        if (ret)
 590                return ret;
 591
 592        if (pm_data->pm_resume_prepare)
 593                pm_data->pm_resume_prepare();
 594        s3c_pm_restore_uarts();
 595
 596        S3C_PMDBG("%s: wakeup stat: %08x\n", __func__,
 597                        pmu_raw_readl(S5P_WAKEUP_STAT));
 598
 599        s3c_pm_check_restore();
 600
 601        S3C_PMDBG("%s: resuming the system...\n", __func__);
 602
 603        return 0;
 604}
 605
 606static int exynos_suspend_prepare(void)
 607{
 608        int ret;
 609
 610        /*
 611         * REVISIT: It would be better if struct platform_suspend_ops
 612         * .prepare handler get the suspend_state_t as a parameter to
 613         * avoid hard-coding the suspend to mem state. It's safe to do
 614         * it now only because the suspend_valid_only_mem function is
 615         * used as the .valid callback used to check if a given state
 616         * is supported by the platform anyways.
 617         */
 618        ret = regulator_suspend_prepare(PM_SUSPEND_MEM);
 619        if (ret) {
 620                pr_err("Failed to prepare regulators for suspend (%d)\n", ret);
 621                return ret;
 622        }
 623
 624        s3c_pm_check_prepare();
 625
 626        return 0;
 627}
 628
 629static void exynos_suspend_finish(void)
 630{
 631        int ret;
 632
 633        s3c_pm_check_cleanup();
 634
 635        ret = regulator_suspend_finish();
 636        if (ret)
 637                pr_warn("Failed to resume regulators from suspend (%d)\n", ret);
 638}
 639
 640static const struct platform_suspend_ops exynos_suspend_ops = {
 641        .enter          = exynos_suspend_enter,
 642        .prepare        = exynos_suspend_prepare,
 643        .finish         = exynos_suspend_finish,
 644        .valid          = suspend_valid_only_mem,
 645};
 646
 647static const struct exynos_pm_data exynos3250_pm_data = {
 648        .wkup_irq       = exynos3250_wkup_irq,
 649        .wake_disable_mask = ((0xFF << 8) | (0x1F << 1)),
 650        .release_ret_regs = exynos3250_release_ret_regs,
 651        .pm_suspend     = exynos_pm_suspend,
 652        .pm_resume      = exynos3250_pm_resume,
 653        .pm_prepare     = exynos3250_pm_prepare,
 654        .cpu_suspend    = exynos3250_cpu_suspend,
 655};
 656
 657static const struct exynos_pm_data exynos4_pm_data = {
 658        .wkup_irq       = exynos4_wkup_irq,
 659        .wake_disable_mask = ((0xFF << 8) | (0x1F << 1)),
 660        .release_ret_regs = exynos_release_ret_regs,
 661        .pm_suspend     = exynos_pm_suspend,
 662        .pm_resume      = exynos_pm_resume,
 663        .pm_prepare     = exynos_pm_prepare,
 664        .cpu_suspend    = exynos_cpu_suspend,
 665};
 666
 667static const struct exynos_pm_data exynos5250_pm_data = {
 668        .wkup_irq       = exynos5250_wkup_irq,
 669        .wake_disable_mask = ((0xFF << 8) | (0x1F << 1)),
 670        .release_ret_regs = exynos_release_ret_regs,
 671        .pm_suspend     = exynos_pm_suspend,
 672        .pm_resume      = exynos_pm_resume,
 673        .pm_prepare     = exynos_pm_prepare,
 674        .cpu_suspend    = exynos_cpu_suspend,
 675};
 676
 677static const struct exynos_pm_data exynos5420_pm_data = {
 678        .wkup_irq       = exynos5250_wkup_irq,
 679        .wake_disable_mask = (0x7F << 7) | (0x1F << 1),
 680        .release_ret_regs = exynos5420_release_ret_regs,
 681        .pm_resume_prepare = exynos5420_prepare_pm_resume,
 682        .pm_resume      = exynos5420_pm_resume,
 683        .pm_suspend     = exynos5420_pm_suspend,
 684        .pm_prepare     = exynos5420_pm_prepare,
 685        .cpu_suspend    = exynos5420_cpu_suspend,
 686};
 687
 688static const struct of_device_id exynos_pmu_of_device_ids[] __initconst = {
 689        {
 690                .compatible = "samsung,exynos3250-pmu",
 691                .data = &exynos3250_pm_data,
 692        }, {
 693                .compatible = "samsung,exynos4210-pmu",
 694                .data = &exynos4_pm_data,
 695        }, {
 696                .compatible = "samsung,exynos4212-pmu",
 697                .data = &exynos4_pm_data,
 698        }, {
 699                .compatible = "samsung,exynos4412-pmu",
 700                .data = &exynos4_pm_data,
 701        }, {
 702                .compatible = "samsung,exynos5250-pmu",
 703                .data = &exynos5250_pm_data,
 704        }, {
 705                .compatible = "samsung,exynos5420-pmu",
 706                .data = &exynos5420_pm_data,
 707        },
 708        { /*sentinel*/ },
 709};
 710
 711static struct syscore_ops exynos_pm_syscore_ops;
 712
 713void __init exynos_pm_init(void)
 714{
 715        const struct of_device_id *match;
 716        struct device_node *np;
 717        u32 tmp;
 718
 719        np = of_find_matching_node_and_match(NULL, exynos_pmu_of_device_ids, &match);
 720        if (!np) {
 721                pr_err("Failed to find PMU node\n");
 722                return;
 723        }
 724
 725        if (WARN_ON(!of_find_property(np, "interrupt-controller", NULL))) {
 726                pr_warn("Outdated DT detected, suspend/resume will NOT work\n");
 727                return;
 728        }
 729
 730        pm_data = (const struct exynos_pm_data *) match->data;
 731
 732        /* All wakeup disable */
 733        tmp = pmu_raw_readl(S5P_WAKEUP_MASK);
 734        tmp |= pm_data->wake_disable_mask;
 735        pmu_raw_writel(tmp, S5P_WAKEUP_MASK);
 736
 737        exynos_pm_syscore_ops.suspend   = pm_data->pm_suspend;
 738        exynos_pm_syscore_ops.resume    = pm_data->pm_resume;
 739
 740        register_syscore_ops(&exynos_pm_syscore_ops);
 741        suspend_set_ops(&exynos_suspend_ops);
 742}
 743