1f50ee824SGregory CLEMENT /* 2c16788b4SThomas Petazzoni * Marvell Armada 370, 38x and XP SoC cpuidle driver 3f50ee824SGregory CLEMENT * 4f50ee824SGregory CLEMENT * Copyright (C) 2014 Marvell 5f50ee824SGregory CLEMENT * 6f50ee824SGregory CLEMENT * Nadav Haklai <nadavh@marvell.com> 7f50ee824SGregory CLEMENT * Gregory CLEMENT <gregory.clement@free-electrons.com> 8f50ee824SGregory CLEMENT * 9f50ee824SGregory CLEMENT * This file is licensed under the terms of the GNU General Public 10f50ee824SGregory CLEMENT * License version 2. This program is licensed "as is" without any 11f50ee824SGregory CLEMENT * warranty of any kind, whether express or implied. 12f50ee824SGregory CLEMENT * 13f50ee824SGregory CLEMENT * Maintainer: Gregory CLEMENT <gregory.clement@free-electrons.com> 14f50ee824SGregory CLEMENT */ 15f50ee824SGregory CLEMENT 16f50ee824SGregory CLEMENT #include <linux/cpu_pm.h> 17f50ee824SGregory CLEMENT #include <linux/cpuidle.h> 18f50ee824SGregory CLEMENT #include <linux/module.h> 19f50ee824SGregory CLEMENT #include <linux/of.h> 20f50ee824SGregory CLEMENT #include <linux/suspend.h> 21f50ee824SGregory CLEMENT #include <linux/platform_device.h> 22f50ee824SGregory CLEMENT #include <asm/cpuidle.h> 23f50ee824SGregory CLEMENT 24f50ee824SGregory CLEMENT #define MVEBU_V7_FLAG_DEEP_IDLE 0x10000 25f50ee824SGregory CLEMENT 26f50ee824SGregory CLEMENT static int (*mvebu_v7_cpu_suspend)(int); 27f50ee824SGregory CLEMENT 28f50ee824SGregory CLEMENT static int mvebu_v7_enter_idle(struct cpuidle_device *dev, 29f50ee824SGregory CLEMENT struct cpuidle_driver *drv, 30f50ee824SGregory CLEMENT int index) 31f50ee824SGregory CLEMENT { 32f50ee824SGregory CLEMENT int ret; 33f50ee824SGregory CLEMENT bool deepidle = false; 34f50ee824SGregory CLEMENT cpu_pm_enter(); 35f50ee824SGregory CLEMENT 36f50ee824SGregory CLEMENT if (drv->states[index].flags & MVEBU_V7_FLAG_DEEP_IDLE) 37f50ee824SGregory CLEMENT deepidle = true; 38f50ee824SGregory CLEMENT 39f50ee824SGregory CLEMENT ret = mvebu_v7_cpu_suspend(deepidle); 4043b68879SGregory CLEMENT cpu_pm_exit(); 4143b68879SGregory CLEMENT 42f50ee824SGregory CLEMENT if (ret) 43f50ee824SGregory CLEMENT return ret; 44f50ee824SGregory CLEMENT 45f50ee824SGregory CLEMENT return index; 46f50ee824SGregory CLEMENT } 47f50ee824SGregory CLEMENT 48f50ee824SGregory CLEMENT static struct cpuidle_driver armadaxp_idle_driver = { 49f50ee824SGregory CLEMENT .name = "armada_xp_idle", 50f50ee824SGregory CLEMENT .states[0] = ARM_CPUIDLE_WFI_STATE, 51f50ee824SGregory CLEMENT .states[1] = { 52f50ee824SGregory CLEMENT .enter = mvebu_v7_enter_idle, 53ce6031c8SSebastien Rannou .exit_latency = 100, 54f50ee824SGregory CLEMENT .power_usage = 50, 55ce6031c8SSebastien Rannou .target_residency = 1000, 56f50ee824SGregory CLEMENT .name = "MV CPU IDLE", 57f50ee824SGregory CLEMENT .desc = "CPU power down", 58f50ee824SGregory CLEMENT }, 59f50ee824SGregory CLEMENT .states[2] = { 60f50ee824SGregory CLEMENT .enter = mvebu_v7_enter_idle, 61ce6031c8SSebastien Rannou .exit_latency = 1000, 62f50ee824SGregory CLEMENT .power_usage = 5, 63ce6031c8SSebastien Rannou .target_residency = 10000, 64b82b6ccaSDaniel Lezcano .flags = MVEBU_V7_FLAG_DEEP_IDLE, 65f50ee824SGregory CLEMENT .name = "MV CPU DEEP IDLE", 66f50ee824SGregory CLEMENT .desc = "CPU and L2 Fabric power down", 67f50ee824SGregory CLEMENT }, 68f50ee824SGregory CLEMENT .state_count = 3, 69f50ee824SGregory CLEMENT }; 70f50ee824SGregory CLEMENT 71c3c7fe7cSThomas Petazzoni static struct cpuidle_driver armada370_idle_driver = { 72c3c7fe7cSThomas Petazzoni .name = "armada_370_idle", 73c3c7fe7cSThomas Petazzoni .states[0] = ARM_CPUIDLE_WFI_STATE, 74c3c7fe7cSThomas Petazzoni .states[1] = { 75c3c7fe7cSThomas Petazzoni .enter = mvebu_v7_enter_idle, 76c3c7fe7cSThomas Petazzoni .exit_latency = 100, 77c3c7fe7cSThomas Petazzoni .power_usage = 5, 78c3c7fe7cSThomas Petazzoni .target_residency = 1000, 79b82b6ccaSDaniel Lezcano .flags = MVEBU_V7_FLAG_DEEP_IDLE, 80c3c7fe7cSThomas Petazzoni .name = "Deep Idle", 81c3c7fe7cSThomas Petazzoni .desc = "CPU and L2 Fabric power down", 82c3c7fe7cSThomas Petazzoni }, 83c3c7fe7cSThomas Petazzoni .state_count = 2, 84c3c7fe7cSThomas Petazzoni }; 85c3c7fe7cSThomas Petazzoni 86c16788b4SThomas Petazzoni static struct cpuidle_driver armada38x_idle_driver = { 87c16788b4SThomas Petazzoni .name = "armada_38x_idle", 88c16788b4SThomas Petazzoni .states[0] = ARM_CPUIDLE_WFI_STATE, 89c16788b4SThomas Petazzoni .states[1] = { 90c16788b4SThomas Petazzoni .enter = mvebu_v7_enter_idle, 91c16788b4SThomas Petazzoni .exit_latency = 10, 92c16788b4SThomas Petazzoni .power_usage = 5, 93c16788b4SThomas Petazzoni .target_residency = 100, 94c16788b4SThomas Petazzoni .name = "Idle", 95c16788b4SThomas Petazzoni .desc = "CPU and SCU power down", 96c16788b4SThomas Petazzoni }, 97c16788b4SThomas Petazzoni .state_count = 2, 98c16788b4SThomas Petazzoni }; 99c16788b4SThomas Petazzoni 100f50ee824SGregory CLEMENT static int mvebu_v7_cpuidle_probe(struct platform_device *pdev) 101f50ee824SGregory CLEMENT { 102da1a64f8SRussell King const struct platform_device_id *id = pdev->id_entry; 103da1a64f8SRussell King 104da1a64f8SRussell King if (!id) 105da1a64f8SRussell King return -EINVAL; 106da1a64f8SRussell King 107f50ee824SGregory CLEMENT mvebu_v7_cpu_suspend = pdev->dev.platform_data; 108c3c7fe7cSThomas Petazzoni 109da1a64f8SRussell King return cpuidle_register((struct cpuidle_driver *)id->driver_data, NULL); 110f50ee824SGregory CLEMENT } 111f50ee824SGregory CLEMENT 112da1a64f8SRussell King static const struct platform_device_id mvebu_cpuidle_ids[] = { 113da1a64f8SRussell King { 114f50ee824SGregory CLEMENT .name = "cpuidle-armada-xp", 115da1a64f8SRussell King .driver_data = (unsigned long)&armadaxp_idle_driver, 116da1a64f8SRussell King }, { 117c3c7fe7cSThomas Petazzoni .name = "cpuidle-armada-370", 118da1a64f8SRussell King .driver_data = (unsigned long)&armada370_idle_driver, 119da1a64f8SRussell King }, { 120c16788b4SThomas Petazzoni .name = "cpuidle-armada-38x", 121da1a64f8SRussell King .driver_data = (unsigned long)&armada38x_idle_driver, 122c16788b4SThomas Petazzoni }, 123da1a64f8SRussell King {} 124c16788b4SThomas Petazzoni }; 125c16788b4SThomas Petazzoni 126da1a64f8SRussell King static struct platform_driver mvebu_cpuidle_driver = { 127da1a64f8SRussell King .probe = mvebu_v7_cpuidle_probe, 128da1a64f8SRussell King .driver = { 129da1a64f8SRussell King .name = "cpuidle-mbevu", 130*ab319939SRussell King .suppress_bind_attrs = true, 131da1a64f8SRussell King }, 132da1a64f8SRussell King .id_table = mvebu_cpuidle_ids, 133da1a64f8SRussell King }; 134da1a64f8SRussell King 135*ab319939SRussell King builtin_platform_driver(mvebu_cpuidle_driver); 136c16788b4SThomas Petazzoni 137f50ee824SGregory CLEMENT MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>"); 138f50ee824SGregory CLEMENT MODULE_DESCRIPTION("Marvell EBU v7 cpuidle driver"); 139f50ee824SGregory CLEMENT MODULE_LICENSE("GPL"); 140