cpuidle-mvebu-v7.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  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 __cpuidle 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. ct_cpuidle_enter();
  34. ret = mvebu_v7_cpu_suspend(deepidle);
  35. ct_cpuidle_exit();
  36. cpu_pm_exit();
  37. if (ret)
  38. return ret;
  39. return index;
  40. }
  41. static struct cpuidle_driver armadaxp_idle_driver = {
  42. .name = "armada_xp_idle",
  43. .states[0] = ARM_CPUIDLE_WFI_STATE,
  44. .states[1] = {
  45. .enter = mvebu_v7_enter_idle,
  46. .exit_latency = 100,
  47. .power_usage = 50,
  48. .target_residency = 1000,
  49. .flags = CPUIDLE_FLAG_RCU_IDLE,
  50. .name = "MV CPU IDLE",
  51. .desc = "CPU power down",
  52. },
  53. .states[2] = {
  54. .enter = mvebu_v7_enter_idle,
  55. .exit_latency = 1000,
  56. .power_usage = 5,
  57. .target_residency = 10000,
  58. .flags = MVEBU_V7_FLAG_DEEP_IDLE | CPUIDLE_FLAG_RCU_IDLE,
  59. .name = "MV CPU DEEP IDLE",
  60. .desc = "CPU and L2 Fabric power down",
  61. },
  62. .state_count = 3,
  63. };
  64. static struct cpuidle_driver armada370_idle_driver = {
  65. .name = "armada_370_idle",
  66. .states[0] = ARM_CPUIDLE_WFI_STATE,
  67. .states[1] = {
  68. .enter = mvebu_v7_enter_idle,
  69. .exit_latency = 100,
  70. .power_usage = 5,
  71. .target_residency = 1000,
  72. .flags = MVEBU_V7_FLAG_DEEP_IDLE | CPUIDLE_FLAG_RCU_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_RCU_IDLE,
  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. const struct platform_device_id *id = pdev->id_entry;
  95. if (!id)
  96. return -EINVAL;
  97. mvebu_v7_cpu_suspend = pdev->dev.platform_data;
  98. return cpuidle_register((struct cpuidle_driver *)id->driver_data, NULL);
  99. }
  100. static const struct platform_device_id mvebu_cpuidle_ids[] = {
  101. {
  102. .name = "cpuidle-armada-xp",
  103. .driver_data = (unsigned long)&armadaxp_idle_driver,
  104. }, {
  105. .name = "cpuidle-armada-370",
  106. .driver_data = (unsigned long)&armada370_idle_driver,
  107. }, {
  108. .name = "cpuidle-armada-38x",
  109. .driver_data = (unsigned long)&armada38x_idle_driver,
  110. },
  111. {}
  112. };
  113. static struct platform_driver mvebu_cpuidle_driver = {
  114. .probe = mvebu_v7_cpuidle_probe,
  115. .driver = {
  116. .name = "cpuidle-mbevu",
  117. .suppress_bind_attrs = true,
  118. },
  119. .id_table = mvebu_cpuidle_ids,
  120. };
  121. builtin_platform_driver(mvebu_cpuidle_driver);
  122. MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>");
  123. MODULE_DESCRIPTION("Marvell EBU v7 cpuidle driver");
  124. MODULE_LICENSE("GPL");