cpuidle-mvebu-v7.c 3.7 KB

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