linux/arch/arm/mach-omap2/pm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * pm.c - Common OMAP2+ power management-related code
   4 *
   5 * Copyright (C) 2010 Texas Instruments, Inc.
   6 * Copyright (C) 2010 Nokia Corporation
   7 */
   8
   9#include <linux/kernel.h>
  10#include <linux/init.h>
  11#include <linux/io.h>
  12#include <linux/err.h>
  13#include <linux/pm_opp.h>
  14#include <linux/export.h>
  15#include <linux/suspend.h>
  16#include <linux/clk.h>
  17#include <linux/cpu.h>
  18
  19#include <asm/system_misc.h>
  20
  21#include "omap_device.h"
  22#include "common.h"
  23
  24#include "soc.h"
  25#include "prcm-common.h"
  26#include "voltage.h"
  27#include "powerdomain.h"
  28#include "clockdomain.h"
  29#include "pm.h"
  30
  31u32 enable_off_mode;
  32
  33#ifdef CONFIG_SUSPEND
  34/*
  35 * omap_pm_suspend: points to a function that does the SoC-specific
  36 * suspend work
  37 */
  38static int (*omap_pm_suspend)(void);
  39#endif
  40
  41#ifdef CONFIG_PM
  42/**
  43 * struct omap2_oscillator - Describe the board main oscillator latencies
  44 * @startup_time: oscillator startup latency
  45 * @shutdown_time: oscillator shutdown latency
  46 */
  47struct omap2_oscillator {
  48        u32 startup_time;
  49        u32 shutdown_time;
  50};
  51
  52static struct omap2_oscillator oscillator = {
  53        .startup_time = ULONG_MAX,
  54        .shutdown_time = ULONG_MAX,
  55};
  56
  57void omap_pm_setup_oscillator(u32 tstart, u32 tshut)
  58{
  59        oscillator.startup_time = tstart;
  60        oscillator.shutdown_time = tshut;
  61}
  62
  63void omap_pm_get_oscillator(u32 *tstart, u32 *tshut)
  64{
  65        if (!tstart || !tshut)
  66                return;
  67
  68        *tstart = oscillator.startup_time;
  69        *tshut = oscillator.shutdown_time;
  70}
  71#endif
  72
  73int omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused)
  74{
  75        clkdm_allow_idle(clkdm);
  76        return 0;
  77}
  78
  79#ifdef CONFIG_SUSPEND
  80static int omap_pm_enter(suspend_state_t suspend_state)
  81{
  82        int ret = 0;
  83
  84        if (!omap_pm_suspend)
  85                return -ENOENT; /* XXX doublecheck */
  86
  87        switch (suspend_state) {
  88        case PM_SUSPEND_MEM:
  89                ret = omap_pm_suspend();
  90                break;
  91        default:
  92                ret = -EINVAL;
  93        }
  94
  95        return ret;
  96}
  97
  98static int omap_pm_begin(suspend_state_t state)
  99{
 100        cpu_idle_poll_ctrl(true);
 101        if (soc_is_omap34xx())
 102                omap_prcm_irq_prepare();
 103        return 0;
 104}
 105
 106static void omap_pm_end(void)
 107{
 108        cpu_idle_poll_ctrl(false);
 109}
 110
 111static void omap_pm_wake(void)
 112{
 113        if (soc_is_omap34xx())
 114                omap_prcm_irq_complete();
 115}
 116
 117static const struct platform_suspend_ops omap_pm_ops = {
 118        .begin          = omap_pm_begin,
 119        .end            = omap_pm_end,
 120        .enter          = omap_pm_enter,
 121        .wake           = omap_pm_wake,
 122        .valid          = suspend_valid_only_mem,
 123};
 124
 125/**
 126 * omap_common_suspend_init - Set common suspend routines for OMAP SoCs
 127 * @pm_suspend: function pointer to SoC specific suspend function
 128 */
 129void omap_common_suspend_init(void *pm_suspend)
 130{
 131        omap_pm_suspend = pm_suspend;
 132        suspend_set_ops(&omap_pm_ops);
 133}
 134#endif /* CONFIG_SUSPEND */
 135
 136int __maybe_unused omap_pm_nop_init(void)
 137{
 138        return 0;
 139}
 140
 141int (*omap_pm_soc_init)(void);
 142
 143int __init omap2_common_pm_late_init(void)
 144{
 145        int error;
 146
 147        if (!omap_pm_soc_init)
 148                return 0;
 149
 150        /* Init the voltage layer */
 151        omap3_twl_init();
 152        omap4_twl_init();
 153        omap4_cpcap_init();
 154        omap_voltage_late_init();
 155
 156        /* Smartreflex device init */
 157        omap_devinit_smartreflex();
 158
 159        error = omap_pm_soc_init();
 160        if (error)
 161                pr_warn("%s: pm soc init failed: %i\n", __func__, error);
 162
 163        omap2_clk_enable_autoidle_all();
 164
 165        return 0;
 166}
 167omap_late_initcall(omap2_common_pm_late_init);
 168