hwblk.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. #include <linux/clk.h>
  2. #include <linux/compiler.h>
  3. #include <linux/slab.h>
  4. #include <linux/io.h>
  5. #include <linux/spinlock.h>
  6. #include <asm/suspend.h>
  7. #include <asm/hwblk.h>
  8. #include <asm/clock.h>
  9. static DEFINE_SPINLOCK(hwblk_lock);
  10. static void hwblk_area_mod_cnt(struct hwblk_info *info,
  11. int area, int counter, int value, int goal)
  12. {
  13. struct hwblk_area *hap = info->areas + area;
  14. hap->cnt[counter] += value;
  15. if (hap->cnt[counter] != goal)
  16. return;
  17. if (hap->flags & HWBLK_AREA_FLAG_PARENT)
  18. hwblk_area_mod_cnt(info, hap->parent, counter, value, goal);
  19. }
  20. static int __hwblk_mod_cnt(struct hwblk_info *info, int hwblk,
  21. int counter, int value, int goal)
  22. {
  23. struct hwblk *hp = info->hwblks + hwblk;
  24. hp->cnt[counter] += value;
  25. if (hp->cnt[counter] == goal)
  26. hwblk_area_mod_cnt(info, hp->area, counter, value, goal);
  27. return hp->cnt[counter];
  28. }
  29. static void hwblk_mod_cnt(struct hwblk_info *info, int hwblk,
  30. int counter, int value, int goal)
  31. {
  32. unsigned long flags;
  33. spin_lock_irqsave(&hwblk_lock, flags);
  34. __hwblk_mod_cnt(info, hwblk, counter, value, goal);
  35. spin_unlock_irqrestore(&hwblk_lock, flags);
  36. }
  37. void hwblk_cnt_inc(struct hwblk_info *info, int hwblk, int counter)
  38. {
  39. hwblk_mod_cnt(info, hwblk, counter, 1, 1);
  40. }
  41. void hwblk_cnt_dec(struct hwblk_info *info, int hwblk, int counter)
  42. {
  43. hwblk_mod_cnt(info, hwblk, counter, -1, 0);
  44. }
  45. void hwblk_enable(struct hwblk_info *info, int hwblk)
  46. {
  47. struct hwblk *hp = info->hwblks + hwblk;
  48. unsigned long tmp;
  49. unsigned long flags;
  50. int ret;
  51. spin_lock_irqsave(&hwblk_lock, flags);
  52. ret = __hwblk_mod_cnt(info, hwblk, HWBLK_CNT_USAGE, 1, 1);
  53. if (ret == 1) {
  54. tmp = __raw_readl(hp->mstp);
  55. tmp &= ~(1 << hp->bit);
  56. __raw_writel(tmp, hp->mstp);
  57. }
  58. spin_unlock_irqrestore(&hwblk_lock, flags);
  59. }
  60. void hwblk_disable(struct hwblk_info *info, int hwblk)
  61. {
  62. struct hwblk *hp = info->hwblks + hwblk;
  63. unsigned long tmp;
  64. unsigned long flags;
  65. int ret;
  66. spin_lock_irqsave(&hwblk_lock, flags);
  67. ret = __hwblk_mod_cnt(info, hwblk, HWBLK_CNT_USAGE, -1, 0);
  68. if (ret == 0) {
  69. tmp = __raw_readl(hp->mstp);
  70. tmp |= 1 << hp->bit;
  71. __raw_writel(tmp, hp->mstp);
  72. }
  73. spin_unlock_irqrestore(&hwblk_lock, flags);
  74. }
  75. struct hwblk_info *hwblk_info;
  76. int __init hwblk_register(struct hwblk_info *info)
  77. {
  78. hwblk_info = info;
  79. return 0;
  80. }
  81. int __init __weak arch_hwblk_init(void)
  82. {
  83. return 0;
  84. }
  85. int __weak arch_hwblk_sleep_mode(void)
  86. {
  87. return SUSP_SH_SLEEP;
  88. }
  89. int __init hwblk_init(void)
  90. {
  91. return arch_hwblk_init();
  92. }
  93. /* allow clocks to enable and disable hardware blocks */
  94. static int sh_hwblk_clk_enable(struct clk *clk)
  95. {
  96. if (!hwblk_info)
  97. return -ENOENT;
  98. hwblk_enable(hwblk_info, clk->arch_flags);
  99. return 0;
  100. }
  101. static void sh_hwblk_clk_disable(struct clk *clk)
  102. {
  103. if (hwblk_info)
  104. hwblk_disable(hwblk_info, clk->arch_flags);
  105. }
  106. static struct clk_ops sh_hwblk_clk_ops = {
  107. .enable = sh_hwblk_clk_enable,
  108. .disable = sh_hwblk_clk_disable,
  109. .recalc = followparent_recalc,
  110. };
  111. int __init sh_hwblk_clk_register(struct clk *clks, int nr)
  112. {
  113. struct clk *clkp;
  114. int ret = 0;
  115. int k;
  116. for (k = 0; !ret && (k < nr); k++) {
  117. clkp = clks + k;
  118. clkp->ops = &sh_hwblk_clk_ops;
  119. ret |= clk_register(clkp);
  120. }
  121. return ret;
  122. }