pm_runtime.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /*
  2. * arch/arm/mach-shmobile/pm_runtime.c
  3. *
  4. * Runtime PM support code for SuperH Mobile ARM
  5. *
  6. * Copyright (C) 2009-2010 Magnus Damm
  7. *
  8. * This file is subject to the terms and conditions of the GNU General Public
  9. * License. See the file "COPYING" in the main directory of this archive
  10. * for more details.
  11. */
  12. #include <linux/init.h>
  13. #include <linux/kernel.h>
  14. #include <linux/io.h>
  15. #include <linux/pm_runtime.h>
  16. #include <linux/platform_device.h>
  17. #include <linux/clk.h>
  18. #include <linux/sh_clk.h>
  19. #include <linux/bitmap.h>
  20. #ifdef CONFIG_PM_RUNTIME
  21. #define BIT_ONCE 0
  22. #define BIT_ACTIVE 1
  23. #define BIT_CLK_ENABLED 2
  24. struct pm_runtime_data {
  25. unsigned long flags;
  26. struct clk *clk;
  27. };
  28. static void __devres_release(struct device *dev, void *res)
  29. {
  30. struct pm_runtime_data *prd = res;
  31. dev_dbg(dev, "__devres_release()\n");
  32. if (test_bit(BIT_CLK_ENABLED, &prd->flags))
  33. clk_disable(prd->clk);
  34. if (test_bit(BIT_ACTIVE, &prd->flags))
  35. clk_put(prd->clk);
  36. }
  37. static struct pm_runtime_data *__to_prd(struct device *dev)
  38. {
  39. return devres_find(dev, __devres_release, NULL, NULL);
  40. }
  41. static void platform_pm_runtime_init(struct device *dev,
  42. struct pm_runtime_data *prd)
  43. {
  44. if (prd && !test_and_set_bit(BIT_ONCE, &prd->flags)) {
  45. prd->clk = clk_get(dev, NULL);
  46. if (!IS_ERR(prd->clk)) {
  47. set_bit(BIT_ACTIVE, &prd->flags);
  48. dev_info(dev, "clocks managed by runtime pm\n");
  49. }
  50. }
  51. }
  52. static void platform_pm_runtime_bug(struct device *dev,
  53. struct pm_runtime_data *prd)
  54. {
  55. if (prd && !test_and_set_bit(BIT_ONCE, &prd->flags))
  56. dev_err(dev, "runtime pm suspend before resume\n");
  57. }
  58. int platform_pm_runtime_suspend(struct device *dev)
  59. {
  60. struct pm_runtime_data *prd = __to_prd(dev);
  61. dev_dbg(dev, "platform_pm_runtime_suspend()\n");
  62. platform_pm_runtime_bug(dev, prd);
  63. if (prd && test_bit(BIT_ACTIVE, &prd->flags)) {
  64. clk_disable(prd->clk);
  65. clear_bit(BIT_CLK_ENABLED, &prd->flags);
  66. }
  67. return 0;
  68. }
  69. int platform_pm_runtime_resume(struct device *dev)
  70. {
  71. struct pm_runtime_data *prd = __to_prd(dev);
  72. dev_dbg(dev, "platform_pm_runtime_resume()\n");
  73. platform_pm_runtime_init(dev, prd);
  74. if (prd && test_bit(BIT_ACTIVE, &prd->flags)) {
  75. clk_enable(prd->clk);
  76. set_bit(BIT_CLK_ENABLED, &prd->flags);
  77. }
  78. return 0;
  79. }
  80. int platform_pm_runtime_idle(struct device *dev)
  81. {
  82. /* suspend synchronously to disable clocks immediately */
  83. return pm_runtime_suspend(dev);
  84. }
  85. static int platform_bus_notify(struct notifier_block *nb,
  86. unsigned long action, void *data)
  87. {
  88. struct device *dev = data;
  89. struct pm_runtime_data *prd;
  90. dev_dbg(dev, "platform_bus_notify() %ld !\n", action);
  91. if (action == BUS_NOTIFY_BIND_DRIVER) {
  92. prd = devres_alloc(__devres_release, sizeof(*prd), GFP_KERNEL);
  93. if (prd)
  94. devres_add(dev, prd);
  95. else
  96. dev_err(dev, "unable to alloc memory for runtime pm\n");
  97. }
  98. return 0;
  99. }
  100. #else /* CONFIG_PM_RUNTIME */
  101. static int platform_bus_notify(struct notifier_block *nb,
  102. unsigned long action, void *data)
  103. {
  104. struct device *dev = data;
  105. struct clk *clk;
  106. dev_dbg(dev, "platform_bus_notify() %ld !\n", action);
  107. switch (action) {
  108. case BUS_NOTIFY_BIND_DRIVER:
  109. clk = clk_get(dev, NULL);
  110. if (!IS_ERR(clk)) {
  111. clk_enable(clk);
  112. clk_put(clk);
  113. dev_info(dev, "runtime pm disabled, clock forced on\n");
  114. }
  115. break;
  116. case BUS_NOTIFY_UNBOUND_DRIVER:
  117. clk = clk_get(dev, NULL);
  118. if (!IS_ERR(clk)) {
  119. clk_disable(clk);
  120. clk_put(clk);
  121. dev_info(dev, "runtime pm disabled, clock forced off\n");
  122. }
  123. break;
  124. }
  125. return 0;
  126. }
  127. #endif /* CONFIG_PM_RUNTIME */
  128. static struct notifier_block platform_bus_notifier = {
  129. .notifier_call = platform_bus_notify
  130. };
  131. static int __init sh_pm_runtime_init(void)
  132. {
  133. bus_register_notifier(&platform_bus_type, &platform_bus_notifier);
  134. return 0;
  135. }
  136. core_initcall(sh_pm_runtime_init);