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 | |
31 | u32 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 | */ |
38 | static 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 | */ |
47 | struct omap2_oscillator { |
48 | u32 startup_time; |
49 | u32 shutdown_time; |
50 | }; |
51 | |
52 | static struct omap2_oscillator oscillator = { |
53 | .startup_time = ULONG_MAX, |
54 | .shutdown_time = ULONG_MAX, |
55 | }; |
56 | |
57 | void omap_pm_get_oscillator(u32 *tstart, u32 *tshut) |
58 | { |
59 | if (!tstart || !tshut) |
60 | return; |
61 | |
62 | *tstart = oscillator.startup_time; |
63 | *tshut = oscillator.shutdown_time; |
64 | } |
65 | #endif |
66 | |
67 | int omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused) |
68 | { |
69 | clkdm_allow_idle(clkdm); |
70 | return 0; |
71 | } |
72 | |
73 | #ifdef CONFIG_SUSPEND |
74 | static int omap_pm_enter(suspend_state_t suspend_state) |
75 | { |
76 | int ret = 0; |
77 | |
78 | if (!omap_pm_suspend) |
79 | return -ENOENT; /* XXX doublecheck */ |
80 | |
81 | switch (suspend_state) { |
82 | case PM_SUSPEND_MEM: |
83 | ret = omap_pm_suspend(); |
84 | break; |
85 | default: |
86 | ret = -EINVAL; |
87 | } |
88 | |
89 | return ret; |
90 | } |
91 | |
92 | static int omap_pm_begin(suspend_state_t state) |
93 | { |
94 | cpu_idle_poll_ctrl(enable: true); |
95 | if (soc_is_omap34xx()) |
96 | omap_prcm_irq_prepare(); |
97 | return 0; |
98 | } |
99 | |
100 | static void omap_pm_end(void) |
101 | { |
102 | cpu_idle_poll_ctrl(enable: false); |
103 | } |
104 | |
105 | static void omap_pm_wake(void) |
106 | { |
107 | if (soc_is_omap34xx()) |
108 | omap_prcm_irq_complete(); |
109 | } |
110 | |
111 | static const struct platform_suspend_ops omap_pm_ops = { |
112 | .begin = omap_pm_begin, |
113 | .end = omap_pm_end, |
114 | .enter = omap_pm_enter, |
115 | .wake = omap_pm_wake, |
116 | .valid = suspend_valid_only_mem, |
117 | }; |
118 | |
119 | /** |
120 | * omap_common_suspend_init - Set common suspend routines for OMAP SoCs |
121 | * @pm_suspend: function pointer to SoC specific suspend function |
122 | */ |
123 | void omap_common_suspend_init(void *pm_suspend) |
124 | { |
125 | omap_pm_suspend = pm_suspend; |
126 | suspend_set_ops(ops: &omap_pm_ops); |
127 | } |
128 | #endif /* CONFIG_SUSPEND */ |
129 | |
130 | int __maybe_unused omap_pm_nop_init(void) |
131 | { |
132 | return 0; |
133 | } |
134 | |
135 | int (*omap_pm_soc_init)(void); |
136 | |
137 | static int __init omap2_common_pm_late_init(void) |
138 | { |
139 | int error; |
140 | |
141 | if (!omap_pm_soc_init) |
142 | return 0; |
143 | |
144 | /* Init the voltage layer */ |
145 | omap3_twl_init(); |
146 | omap4_twl_init(); |
147 | omap4_cpcap_init(); |
148 | omap_voltage_late_init(); |
149 | |
150 | /* Smartreflex device init */ |
151 | omap_devinit_smartreflex(); |
152 | |
153 | error = omap_pm_soc_init(); |
154 | if (error) |
155 | pr_warn("%s: pm soc init failed: %i\n" , __func__, error); |
156 | |
157 | omap2_clk_enable_autoidle_all(); |
158 | |
159 | return 0; |
160 | } |
161 | omap_late_initcall(omap2_common_pm_late_init); |
162 | |