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, 53f50ee824SGregory CLEMENT .exit_latency = 10, 54f50ee824SGregory CLEMENT .power_usage = 50, 55f50ee824SGregory CLEMENT .target_residency = 100, 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, 61f50ee824SGregory CLEMENT .exit_latency = 100, 62f50ee824SGregory CLEMENT .power_usage = 5, 63f50ee824SGregory CLEMENT .target_residency = 1000, 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 { 102f50ee824SGregory CLEMENT mvebu_v7_cpu_suspend = pdev->dev.platform_data; 103c3c7fe7cSThomas Petazzoni 104c3c7fe7cSThomas Petazzoni if (!strcmp(pdev->dev.driver->name, "cpuidle-armada-xp")) 105f50ee824SGregory CLEMENT return cpuidle_register(&armadaxp_idle_driver, NULL); 106c3c7fe7cSThomas Petazzoni else if (!strcmp(pdev->dev.driver->name, "cpuidle-armada-370")) 107c3c7fe7cSThomas Petazzoni return cpuidle_register(&armada370_idle_driver, NULL); 108c16788b4SThomas Petazzoni else if (!strcmp(pdev->dev.driver->name, "cpuidle-armada-38x")) 109c16788b4SThomas Petazzoni return cpuidle_register(&armada38x_idle_driver, NULL); 110c3c7fe7cSThomas Petazzoni else 111c3c7fe7cSThomas Petazzoni return -EINVAL; 112f50ee824SGregory CLEMENT } 113f50ee824SGregory CLEMENT 114f50ee824SGregory CLEMENT static struct platform_driver armadaxp_cpuidle_plat_driver = { 115f50ee824SGregory CLEMENT .driver = { 116f50ee824SGregory CLEMENT .name = "cpuidle-armada-xp", 117f50ee824SGregory CLEMENT }, 118f50ee824SGregory CLEMENT .probe = mvebu_v7_cpuidle_probe, 119f50ee824SGregory CLEMENT }; 120f50ee824SGregory CLEMENT 121f50ee824SGregory CLEMENT module_platform_driver(armadaxp_cpuidle_plat_driver); 122f50ee824SGregory CLEMENT 123c3c7fe7cSThomas Petazzoni static struct platform_driver armada370_cpuidle_plat_driver = { 124c3c7fe7cSThomas Petazzoni .driver = { 125c3c7fe7cSThomas Petazzoni .name = "cpuidle-armada-370", 126c3c7fe7cSThomas Petazzoni }, 127c3c7fe7cSThomas Petazzoni .probe = mvebu_v7_cpuidle_probe, 128c3c7fe7cSThomas Petazzoni }; 129c3c7fe7cSThomas Petazzoni 130c3c7fe7cSThomas Petazzoni module_platform_driver(armada370_cpuidle_plat_driver); 131c3c7fe7cSThomas Petazzoni 132c16788b4SThomas Petazzoni static struct platform_driver armada38x_cpuidle_plat_driver = { 133c16788b4SThomas Petazzoni .driver = { 134c16788b4SThomas Petazzoni .name = "cpuidle-armada-38x", 135c16788b4SThomas Petazzoni }, 136c16788b4SThomas Petazzoni .probe = mvebu_v7_cpuidle_probe, 137c16788b4SThomas Petazzoni }; 138c16788b4SThomas Petazzoni 139c16788b4SThomas Petazzoni module_platform_driver(armada38x_cpuidle_plat_driver); 140c16788b4SThomas Petazzoni 141f50ee824SGregory CLEMENT MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>"); 142f50ee824SGregory CLEMENT MODULE_DESCRIPTION("Marvell EBU v7 cpuidle driver"); 143f50ee824SGregory CLEMENT MODULE_LICENSE("GPL"); 144