0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/kernel.h>
0010 #include <linux/init.h>
0011 #include <linux/io.h>
0012 #include <linux/err.h>
0013 #include <linux/pm_opp.h>
0014 #include <linux/export.h>
0015 #include <linux/suspend.h>
0016 #include <linux/clk.h>
0017 #include <linux/cpu.h>
0018
0019 #include <asm/system_misc.h>
0020
0021 #include "omap_device.h"
0022 #include "common.h"
0023
0024 #include "soc.h"
0025 #include "prcm-common.h"
0026 #include "voltage.h"
0027 #include "powerdomain.h"
0028 #include "clockdomain.h"
0029 #include "pm.h"
0030
0031 u32 enable_off_mode;
0032
0033 #ifdef CONFIG_SUSPEND
0034
0035
0036
0037
0038 static int (*omap_pm_suspend)(void);
0039 #endif
0040
0041 #ifdef CONFIG_PM
0042
0043
0044
0045
0046
0047 struct omap2_oscillator {
0048 u32 startup_time;
0049 u32 shutdown_time;
0050 };
0051
0052 static struct omap2_oscillator oscillator = {
0053 .startup_time = ULONG_MAX,
0054 .shutdown_time = ULONG_MAX,
0055 };
0056
0057 void omap_pm_setup_oscillator(u32 tstart, u32 tshut)
0058 {
0059 oscillator.startup_time = tstart;
0060 oscillator.shutdown_time = tshut;
0061 }
0062
0063 void omap_pm_get_oscillator(u32 *tstart, u32 *tshut)
0064 {
0065 if (!tstart || !tshut)
0066 return;
0067
0068 *tstart = oscillator.startup_time;
0069 *tshut = oscillator.shutdown_time;
0070 }
0071 #endif
0072
0073 int omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused)
0074 {
0075 clkdm_allow_idle(clkdm);
0076 return 0;
0077 }
0078
0079 #ifdef CONFIG_SUSPEND
0080 static int omap_pm_enter(suspend_state_t suspend_state)
0081 {
0082 int ret = 0;
0083
0084 if (!omap_pm_suspend)
0085 return -ENOENT;
0086
0087 switch (suspend_state) {
0088 case PM_SUSPEND_MEM:
0089 ret = omap_pm_suspend();
0090 break;
0091 default:
0092 ret = -EINVAL;
0093 }
0094
0095 return ret;
0096 }
0097
0098 static int omap_pm_begin(suspend_state_t state)
0099 {
0100 cpu_idle_poll_ctrl(true);
0101 if (soc_is_omap34xx())
0102 omap_prcm_irq_prepare();
0103 return 0;
0104 }
0105
0106 static void omap_pm_end(void)
0107 {
0108 cpu_idle_poll_ctrl(false);
0109 }
0110
0111 static void omap_pm_wake(void)
0112 {
0113 if (soc_is_omap34xx())
0114 omap_prcm_irq_complete();
0115 }
0116
0117 static const struct platform_suspend_ops omap_pm_ops = {
0118 .begin = omap_pm_begin,
0119 .end = omap_pm_end,
0120 .enter = omap_pm_enter,
0121 .wake = omap_pm_wake,
0122 .valid = suspend_valid_only_mem,
0123 };
0124
0125
0126
0127
0128
0129 void omap_common_suspend_init(void *pm_suspend)
0130 {
0131 omap_pm_suspend = pm_suspend;
0132 suspend_set_ops(&omap_pm_ops);
0133 }
0134 #endif
0135
0136 int __maybe_unused omap_pm_nop_init(void)
0137 {
0138 return 0;
0139 }
0140
0141 int (*omap_pm_soc_init)(void);
0142
0143 int __init omap2_common_pm_late_init(void)
0144 {
0145 int error;
0146
0147 if (!omap_pm_soc_init)
0148 return 0;
0149
0150
0151 omap3_twl_init();
0152 omap4_twl_init();
0153 omap4_cpcap_init();
0154 omap_voltage_late_init();
0155
0156
0157 omap_devinit_smartreflex();
0158
0159 error = omap_pm_soc_init();
0160 if (error)
0161 pr_warn("%s: pm soc init failed: %i\n", __func__, error);
0162
0163 omap2_clk_enable_autoidle_all();
0164
0165 return 0;
0166 }
0167 omap_late_initcall(omap2_common_pm_late_init);