linux/arch/arm/mach-prima2/pm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * power management entry for CSR SiRFprimaII
   4 *
   5 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
   6 */
   7
   8#include <linux/kernel.h>
   9#include <linux/suspend.h>
  10#include <linux/slab.h>
  11#include <linux/export.h>
  12#include <linux/of.h>
  13#include <linux/of_address.h>
  14#include <linux/of_device.h>
  15#include <linux/of_platform.h>
  16#include <linux/io.h>
  17#include <linux/rtc/sirfsoc_rtciobrg.h>
  18#include <asm/outercache.h>
  19#include <asm/suspend.h>
  20#include <asm/hardware/cache-l2x0.h>
  21
  22#include "pm.h"
  23
  24/*
  25 * suspend asm codes will access these to make DRAM become self-refresh and
  26 * system sleep
  27 */
  28u32 sirfsoc_pwrc_base;
  29void __iomem *sirfsoc_memc_base;
  30
  31static void sirfsoc_set_wakeup_source(void)
  32{
  33        u32 pwr_trigger_en_reg;
  34        pwr_trigger_en_reg = sirfsoc_rtc_iobrg_readl(sirfsoc_pwrc_base +
  35                SIRFSOC_PWRC_TRIGGER_EN);
  36#define X_ON_KEY_B (1 << 0)
  37#define RTC_ALARM0_B (1 << 2)
  38#define RTC_ALARM1_B (1 << 3)
  39        sirfsoc_rtc_iobrg_writel(pwr_trigger_en_reg | X_ON_KEY_B |
  40                RTC_ALARM0_B | RTC_ALARM1_B,
  41                sirfsoc_pwrc_base + SIRFSOC_PWRC_TRIGGER_EN);
  42}
  43
  44static void sirfsoc_set_sleep_mode(u32 mode)
  45{
  46        u32 sleep_mode = sirfsoc_rtc_iobrg_readl(sirfsoc_pwrc_base +
  47                SIRFSOC_PWRC_PDN_CTRL);
  48        sleep_mode &= ~(SIRFSOC_SLEEP_MODE_MASK << 1);
  49        sleep_mode |= mode << 1;
  50        sirfsoc_rtc_iobrg_writel(sleep_mode, sirfsoc_pwrc_base +
  51                SIRFSOC_PWRC_PDN_CTRL);
  52}
  53
  54static int sirfsoc_pre_suspend_power_off(void)
  55{
  56        u32 wakeup_entry = __pa_symbol(cpu_resume);
  57
  58        sirfsoc_rtc_iobrg_writel(wakeup_entry, sirfsoc_pwrc_base +
  59                SIRFSOC_PWRC_SCRATCH_PAD1);
  60
  61        sirfsoc_set_wakeup_source();
  62
  63        sirfsoc_set_sleep_mode(SIRFSOC_DEEP_SLEEP_MODE);
  64
  65        return 0;
  66}
  67
  68static int sirfsoc_pm_enter(suspend_state_t state)
  69{
  70        switch (state) {
  71        case PM_SUSPEND_MEM:
  72                sirfsoc_pre_suspend_power_off();
  73
  74                outer_disable();
  75                /* go zzz */
  76                cpu_suspend(0, sirfsoc_finish_suspend);
  77                outer_resume();
  78                break;
  79        default:
  80                return -EINVAL;
  81        }
  82        return 0;
  83}
  84
  85static const struct platform_suspend_ops sirfsoc_pm_ops = {
  86        .enter = sirfsoc_pm_enter,
  87        .valid = suspend_valid_only_mem,
  88};
  89
  90static const struct of_device_id pwrc_ids[] = {
  91        { .compatible = "sirf,prima2-pwrc" },
  92        {}
  93};
  94
  95static int __init sirfsoc_of_pwrc_init(void)
  96{
  97        struct device_node *np;
  98
  99        np = of_find_matching_node(NULL, pwrc_ids);
 100        if (!np) {
 101                pr_err("unable to find compatible sirf pwrc node in dtb\n");
 102                return -ENOENT;
 103        }
 104
 105        /*
 106         * pwrc behind rtciobrg is not located in memory space
 107         * though the property is named reg. reg only means base
 108         * offset for pwrc. then of_iomap is not suitable here.
 109         */
 110        if (of_property_read_u32(np, "reg", &sirfsoc_pwrc_base))
 111                panic("unable to find base address of pwrc node in dtb\n");
 112
 113        of_node_put(np);
 114
 115        return 0;
 116}
 117
 118static const struct of_device_id memc_ids[] = {
 119        { .compatible = "sirf,prima2-memc" },
 120        {}
 121};
 122
 123static int sirfsoc_memc_probe(struct platform_device *op)
 124{
 125        struct device_node *np = op->dev.of_node;
 126
 127        sirfsoc_memc_base = of_iomap(np, 0);
 128        if (!sirfsoc_memc_base)
 129                panic("unable to map memc registers\n");
 130
 131        return 0;
 132}
 133
 134static struct platform_driver sirfsoc_memc_driver = {
 135        .probe          = sirfsoc_memc_probe,
 136        .driver = {
 137                .name = "sirfsoc-memc",
 138                .of_match_table = memc_ids,
 139        },
 140};
 141
 142static int __init sirfsoc_memc_init(void)
 143{
 144        return platform_driver_register(&sirfsoc_memc_driver);
 145}
 146
 147int __init sirfsoc_pm_init(void)
 148{
 149        sirfsoc_of_pwrc_init();
 150        sirfsoc_memc_init();
 151        suspend_set_ops(&sirfsoc_pm_ops);
 152        return 0;
 153}
 154