xref: /openbmc/linux/arch/arm/mach-omap2/pm.c (revision 6aeb51c1)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
26f88e9bcSKevin Hilman /*
36f88e9bcSKevin Hilman  * pm.c - Common OMAP2+ power management-related code
46f88e9bcSKevin Hilman  *
56f88e9bcSKevin Hilman  * Copyright (C) 2010 Texas Instruments, Inc.
66f88e9bcSKevin Hilman  * Copyright (C) 2010 Nokia Corporation
76f88e9bcSKevin Hilman  */
86f88e9bcSKevin Hilman 
96f88e9bcSKevin Hilman #include <linux/kernel.h>
106f88e9bcSKevin Hilman #include <linux/init.h>
116f88e9bcSKevin Hilman #include <linux/io.h>
126f88e9bcSKevin Hilman #include <linux/err.h>
13e4db1c74SNishanth Menon #include <linux/pm_opp.h>
14dc28094bSPaul Gortmaker #include <linux/export.h>
151416408dSPaul Walmsley #include <linux/suspend.h>
1644773ba1STony Lindgren #include <linux/clk.h>
1724d7b40aSKevin Hilman #include <linux/cpu.h>
186f88e9bcSKevin Hilman 
19335aece5SGovindraj.R #include <asm/system_misc.h>
20335aece5SGovindraj.R 
2125c7d49eSTony Lindgren #include "omap_device.h"
224e65331cSTony Lindgren #include "common.h"
236f88e9bcSKevin Hilman 
24e4c060dbSTony Lindgren #include "soc.h"
251416408dSPaul Walmsley #include "prcm-common.h"
26e1d6f472SPaul Walmsley #include "voltage.h"
2772e06d08SPaul Walmsley #include "powerdomain.h"
281540f214SPaul Walmsley #include "clockdomain.h"
290c0a5d61SThara Gopinath #include "pm.h"
30eb6a2c75SSantosh Shilimkar 
31fb2c599fSAndreas Kemnade u32 enable_off_mode;
32fb2c599fSAndreas Kemnade 
332e4b62dcSDave Gerlach #ifdef CONFIG_SUSPEND
341416408dSPaul Walmsley /*
351416408dSPaul Walmsley  * omap_pm_suspend: points to a function that does the SoC-specific
361416408dSPaul Walmsley  * suspend work
371416408dSPaul Walmsley  */
382e4b62dcSDave Gerlach static int (*omap_pm_suspend)(void);
392e4b62dcSDave Gerlach #endif
401416408dSPaul Walmsley 
4174d29168SKevin Hilman #ifdef CONFIG_PM
42908b75e8STero Kristo /**
43908b75e8STero Kristo  * struct omap2_oscillator - Describe the board main oscillator latencies
44908b75e8STero Kristo  * @startup_time: oscillator startup latency
45908b75e8STero Kristo  * @shutdown_time: oscillator shutdown latency
46908b75e8STero Kristo  */
47908b75e8STero Kristo struct omap2_oscillator {
48908b75e8STero Kristo 	u32 startup_time;
49908b75e8STero Kristo 	u32 shutdown_time;
50908b75e8STero Kristo };
51908b75e8STero Kristo 
52908b75e8STero Kristo static struct omap2_oscillator oscillator = {
53908b75e8STero Kristo 	.startup_time = ULONG_MAX,
54908b75e8STero Kristo 	.shutdown_time = ULONG_MAX,
55908b75e8STero Kristo };
56908b75e8STero Kristo 
omap_pm_get_oscillator(u32 * tstart,u32 * tshut)57908b75e8STero Kristo void omap_pm_get_oscillator(u32 *tstart, u32 *tshut)
58908b75e8STero Kristo {
59908b75e8STero Kristo 	if (!tstart || !tshut)
60908b75e8STero Kristo 		return;
61908b75e8STero Kristo 
62908b75e8STero Kristo 	*tstart = oscillator.startup_time;
63908b75e8STero Kristo 	*tshut = oscillator.shutdown_time;
64908b75e8STero Kristo }
6574d29168SKevin Hilman #endif
66908b75e8STero Kristo 
omap_pm_clkdms_setup(struct clockdomain * clkdm,void * unused)6733d3842dSDave Gerlach int omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused)
6892206fd2SPaul Walmsley {
6992206fd2SPaul Walmsley 	clkdm_allow_idle(clkdm);
7092206fd2SPaul Walmsley 	return 0;
7192206fd2SPaul Walmsley }
7292206fd2SPaul Walmsley 
731416408dSPaul Walmsley #ifdef CONFIG_SUSPEND
omap_pm_enter(suspend_state_t suspend_state)741416408dSPaul Walmsley static int omap_pm_enter(suspend_state_t suspend_state)
751416408dSPaul Walmsley {
761416408dSPaul Walmsley 	int ret = 0;
771416408dSPaul Walmsley 
781416408dSPaul Walmsley 	if (!omap_pm_suspend)
791416408dSPaul Walmsley 		return -ENOENT; /* XXX doublecheck */
801416408dSPaul Walmsley 
811416408dSPaul Walmsley 	switch (suspend_state) {
821416408dSPaul Walmsley 	case PM_SUSPEND_MEM:
831416408dSPaul Walmsley 		ret = omap_pm_suspend();
841416408dSPaul Walmsley 		break;
851416408dSPaul Walmsley 	default:
861416408dSPaul Walmsley 		ret = -EINVAL;
871416408dSPaul Walmsley 	}
881416408dSPaul Walmsley 
891416408dSPaul Walmsley 	return ret;
901416408dSPaul Walmsley }
911416408dSPaul Walmsley 
omap_pm_begin(suspend_state_t state)921416408dSPaul Walmsley static int omap_pm_begin(suspend_state_t state)
931416408dSPaul Walmsley {
94f7b861b7SThomas Gleixner 	cpu_idle_poll_ctrl(true);
95cb6675d6STony Lindgren 	if (soc_is_omap34xx())
961416408dSPaul Walmsley 		omap_prcm_irq_prepare();
971416408dSPaul Walmsley 	return 0;
981416408dSPaul Walmsley }
991416408dSPaul Walmsley 
omap_pm_end(void)1001416408dSPaul Walmsley static void omap_pm_end(void)
1011416408dSPaul Walmsley {
102f7b861b7SThomas Gleixner 	cpu_idle_poll_ctrl(false);
1031416408dSPaul Walmsley }
1041416408dSPaul Walmsley 
omap_pm_wake(void)105d3be6d2aSTony Lindgren static void omap_pm_wake(void)
1061416408dSPaul Walmsley {
107cb6675d6STony Lindgren 	if (soc_is_omap34xx())
1081416408dSPaul Walmsley 		omap_prcm_irq_complete();
1091416408dSPaul Walmsley }
1101416408dSPaul Walmsley 
1111416408dSPaul Walmsley static const struct platform_suspend_ops omap_pm_ops = {
1121416408dSPaul Walmsley 	.begin		= omap_pm_begin,
1131416408dSPaul Walmsley 	.end		= omap_pm_end,
1141416408dSPaul Walmsley 	.enter		= omap_pm_enter,
115d3be6d2aSTony Lindgren 	.wake		= omap_pm_wake,
1161416408dSPaul Walmsley 	.valid		= suspend_valid_only_mem,
1171416408dSPaul Walmsley };
1181416408dSPaul Walmsley 
1192e4b62dcSDave Gerlach /**
1202e4b62dcSDave Gerlach  * omap_common_suspend_init - Set common suspend routines for OMAP SoCs
1212e4b62dcSDave Gerlach  * @pm_suspend: function pointer to SoC specific suspend function
1222e4b62dcSDave Gerlach  */
omap_common_suspend_init(void * pm_suspend)1232e4b62dcSDave Gerlach void omap_common_suspend_init(void *pm_suspend)
1242e4b62dcSDave Gerlach {
1252e4b62dcSDave Gerlach 	omap_pm_suspend = pm_suspend;
1262e4b62dcSDave Gerlach 	suspend_set_ops(&omap_pm_ops);
1272e4b62dcSDave Gerlach }
1281416408dSPaul Walmsley #endif /* CONFIG_SUSPEND */
1291416408dSPaul Walmsley 
omap_pm_nop_init(void)13002b83dcbSTony Lindgren int __maybe_unused omap_pm_nop_init(void)
13102b83dcbSTony Lindgren {
13202b83dcbSTony Lindgren 	return 0;
13302b83dcbSTony Lindgren }
13402b83dcbSTony Lindgren 
13502b83dcbSTony Lindgren int (*omap_pm_soc_init)(void);
13602b83dcbSTony Lindgren 
omap2_common_pm_late_init(void)137*6aeb51c1SArnd Bergmann static int __init omap2_common_pm_late_init(void)
1382f34ce81SThara Gopinath {
13902b83dcbSTony Lindgren 	int error;
14002b83dcbSTony Lindgren 
14102b83dcbSTony Lindgren 	if (!omap_pm_soc_init)
14202b83dcbSTony Lindgren 		return 0;
14302b83dcbSTony Lindgren 
144cb6675d6STony Lindgren 	/* Init the voltage layer */
1452ee5f528STony Lindgren 	omap3_twl_init();
1462ee5f528STony Lindgren 	omap4_twl_init();
147d44fa156STony Lindgren 	omap4_cpcap_init();
1482f34ce81SThara Gopinath 	omap_voltage_late_init();
1491482d8beSThara Gopinath 
150fbc319f6SThara Gopinath 	/* Smartreflex device init */
1510c0a5d61SThara Gopinath 	omap_devinit_smartreflex();
15249ded525SNishanth Menon 
15302b83dcbSTony Lindgren 	error = omap_pm_soc_init();
15402b83dcbSTony Lindgren 	if (error)
15502b83dcbSTony Lindgren 		pr_warn("%s: pm soc init failed: %i\n", __func__, error);
15602b83dcbSTony Lindgren 
15702b83dcbSTony Lindgren 	omap2_clk_enable_autoidle_all();
15802b83dcbSTony Lindgren 
1592f34ce81SThara Gopinath 	return 0;
1602f34ce81SThara Gopinath }
16102b83dcbSTony Lindgren omap_late_initcall(omap2_common_pm_late_init);
162