18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright 2012 Calxeda, Inc.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Based on arch/arm/plat-mxc/cpuidle.c: #v3.7
68c2ecf20Sopenharmony_ci * Copyright 2012 Freescale Semiconductor, Inc.
78c2ecf20Sopenharmony_ci * Copyright 2012 Linaro Ltd.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Maintainer: Rob Herring <rob.herring@calxeda.com>
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/cpuidle.h>
138c2ecf20Sopenharmony_ci#include <linux/cpu_pm.h>
148c2ecf20Sopenharmony_ci#include <linux/init.h>
158c2ecf20Sopenharmony_ci#include <linux/mm.h>
168c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
178c2ecf20Sopenharmony_ci#include <linux/psci.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <asm/cpuidle.h>
208c2ecf20Sopenharmony_ci#include <asm/suspend.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include <uapi/linux/psci.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define CALXEDA_IDLE_PARAM \
258c2ecf20Sopenharmony_ci	((0 << PSCI_0_2_POWER_STATE_ID_SHIFT) | \
268c2ecf20Sopenharmony_ci	 (0 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | \
278c2ecf20Sopenharmony_ci	 (PSCI_POWER_STATE_TYPE_POWER_DOWN << PSCI_0_2_POWER_STATE_TYPE_SHIFT))
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic int calxeda_idle_finish(unsigned long val)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	return psci_ops.cpu_suspend(CALXEDA_IDLE_PARAM, __pa(cpu_resume));
328c2ecf20Sopenharmony_ci}
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic int calxeda_pwrdown_idle(struct cpuidle_device *dev,
358c2ecf20Sopenharmony_ci				struct cpuidle_driver *drv,
368c2ecf20Sopenharmony_ci				int index)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	cpu_pm_enter();
398c2ecf20Sopenharmony_ci	cpu_suspend(0, calxeda_idle_finish);
408c2ecf20Sopenharmony_ci	cpu_pm_exit();
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	return index;
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic struct cpuidle_driver calxeda_idle_driver = {
468c2ecf20Sopenharmony_ci	.name = "calxeda_idle",
478c2ecf20Sopenharmony_ci	.states = {
488c2ecf20Sopenharmony_ci		ARM_CPUIDLE_WFI_STATE,
498c2ecf20Sopenharmony_ci		{
508c2ecf20Sopenharmony_ci			.name = "PG",
518c2ecf20Sopenharmony_ci			.desc = "Power Gate",
528c2ecf20Sopenharmony_ci			.exit_latency = 30,
538c2ecf20Sopenharmony_ci			.power_usage = 50,
548c2ecf20Sopenharmony_ci			.target_residency = 200,
558c2ecf20Sopenharmony_ci			.enter = calxeda_pwrdown_idle,
568c2ecf20Sopenharmony_ci		},
578c2ecf20Sopenharmony_ci	},
588c2ecf20Sopenharmony_ci	.state_count = 2,
598c2ecf20Sopenharmony_ci};
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic int calxeda_cpuidle_probe(struct platform_device *pdev)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	return cpuidle_register(&calxeda_idle_driver, NULL);
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic struct platform_driver calxeda_cpuidle_plat_driver = {
678c2ecf20Sopenharmony_ci        .driver = {
688c2ecf20Sopenharmony_ci                .name = "cpuidle-calxeda",
698c2ecf20Sopenharmony_ci        },
708c2ecf20Sopenharmony_ci        .probe = calxeda_cpuidle_probe,
718c2ecf20Sopenharmony_ci};
728c2ecf20Sopenharmony_cibuiltin_platform_driver(calxeda_cpuidle_plat_driver);
73