Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Marvell Armada 370, 38x and XP SoC cpuidle driver
0003  *
0004  * Copyright (C) 2014 Marvell
0005  *
0006  * Nadav Haklai <nadavh@marvell.com>
0007  * Gregory CLEMENT <gregory.clement@free-electrons.com>
0008  *
0009  * This file is licensed under the terms of the GNU General Public
0010  * License version 2.  This program is licensed "as is" without any
0011  * warranty of any kind, whether express or implied.
0012  *
0013  * Maintainer: Gregory CLEMENT <gregory.clement@free-electrons.com>
0014  */
0015 
0016 #include <linux/cpu_pm.h>
0017 #include <linux/cpuidle.h>
0018 #include <linux/module.h>
0019 #include <linux/of.h>
0020 #include <linux/suspend.h>
0021 #include <linux/platform_device.h>
0022 #include <asm/cpuidle.h>
0023 
0024 #define MVEBU_V7_FLAG_DEEP_IDLE 0x10000
0025 
0026 static int (*mvebu_v7_cpu_suspend)(int);
0027 
0028 static int mvebu_v7_enter_idle(struct cpuidle_device *dev,
0029                 struct cpuidle_driver *drv,
0030                 int index)
0031 {
0032     int ret;
0033     bool deepidle = false;
0034     cpu_pm_enter();
0035 
0036     if (drv->states[index].flags & MVEBU_V7_FLAG_DEEP_IDLE)
0037         deepidle = true;
0038 
0039     ret = mvebu_v7_cpu_suspend(deepidle);
0040     cpu_pm_exit();
0041 
0042     if (ret)
0043         return ret;
0044 
0045     return index;
0046 }
0047 
0048 static struct cpuidle_driver armadaxp_idle_driver = {
0049     .name           = "armada_xp_idle",
0050     .states[0]      = ARM_CPUIDLE_WFI_STATE,
0051     .states[1]      = {
0052         .enter          = mvebu_v7_enter_idle,
0053         .exit_latency       = 100,
0054         .power_usage        = 50,
0055         .target_residency   = 1000,
0056         .name           = "MV CPU IDLE",
0057         .desc           = "CPU power down",
0058     },
0059     .states[2]      = {
0060         .enter          = mvebu_v7_enter_idle,
0061         .exit_latency       = 1000,
0062         .power_usage        = 5,
0063         .target_residency   = 10000,
0064         .flags          = MVEBU_V7_FLAG_DEEP_IDLE,
0065         .name           = "MV CPU DEEP IDLE",
0066         .desc           = "CPU and L2 Fabric power down",
0067     },
0068     .state_count = 3,
0069 };
0070 
0071 static struct cpuidle_driver armada370_idle_driver = {
0072     .name           = "armada_370_idle",
0073     .states[0]      = ARM_CPUIDLE_WFI_STATE,
0074     .states[1]      = {
0075         .enter          = mvebu_v7_enter_idle,
0076         .exit_latency       = 100,
0077         .power_usage        = 5,
0078         .target_residency   = 1000,
0079         .flags          = MVEBU_V7_FLAG_DEEP_IDLE,
0080         .name           = "Deep Idle",
0081         .desc           = "CPU and L2 Fabric power down",
0082     },
0083     .state_count = 2,
0084 };
0085 
0086 static struct cpuidle_driver armada38x_idle_driver = {
0087     .name           = "armada_38x_idle",
0088     .states[0]      = ARM_CPUIDLE_WFI_STATE,
0089     .states[1]      = {
0090         .enter          = mvebu_v7_enter_idle,
0091         .exit_latency       = 10,
0092         .power_usage        = 5,
0093         .target_residency   = 100,
0094         .name           = "Idle",
0095         .desc           = "CPU and SCU power down",
0096     },
0097     .state_count = 2,
0098 };
0099 
0100 static int mvebu_v7_cpuidle_probe(struct platform_device *pdev)
0101 {
0102     const struct platform_device_id *id = pdev->id_entry;
0103 
0104     if (!id)
0105         return -EINVAL;
0106 
0107     mvebu_v7_cpu_suspend = pdev->dev.platform_data;
0108 
0109     return cpuidle_register((struct cpuidle_driver *)id->driver_data, NULL);
0110 }
0111 
0112 static const struct platform_device_id mvebu_cpuidle_ids[] = {
0113     {
0114         .name = "cpuidle-armada-xp",
0115         .driver_data = (unsigned long)&armadaxp_idle_driver,
0116     }, {
0117         .name = "cpuidle-armada-370",
0118         .driver_data = (unsigned long)&armada370_idle_driver,
0119     }, {
0120         .name = "cpuidle-armada-38x",
0121         .driver_data = (unsigned long)&armada38x_idle_driver,
0122     },
0123     {}
0124 };
0125 
0126 static struct platform_driver mvebu_cpuidle_driver = {
0127     .probe = mvebu_v7_cpuidle_probe,
0128     .driver = {
0129         .name = "cpuidle-mbevu",
0130         .suppress_bind_attrs = true,
0131     },
0132     .id_table = mvebu_cpuidle_ids,
0133 };
0134 
0135 builtin_platform_driver(mvebu_cpuidle_driver);
0136 
0137 MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>");
0138 MODULE_DESCRIPTION("Marvell EBU v7 cpuidle driver");
0139 MODULE_LICENSE("GPL");