clk-apbc.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. /*
  2. * mmp APB clock operation source file
  3. *
  4. * Copyright (C) 2012 Marvell
  5. * Chao Xie <xiechao.mail@gmail.com>
  6. *
  7. * This file is licensed under the terms of the GNU General Public
  8. * License version 2. This program is licensed "as is" without any
  9. * warranty of any kind, whether express or implied.
  10. */
  11. #include <linux/kernel.h>
  12. #include <linux/clk.h>
  13. #include <linux/io.h>
  14. #include <linux/err.h>
  15. #include <linux/delay.h>
  16. #include <linux/slab.h>
  17. #include "clk.h"
  18. /* Common APB clock register bit definitions */
  19. #define APBC_APBCLK (1 << 0) /* APB Bus Clock Enable */
  20. #define APBC_FNCLK (1 << 1) /* Functional Clock Enable */
  21. #define APBC_RST (1 << 2) /* Reset Generation */
  22. #define APBC_POWER (1 << 7) /* Reset Generation */
  23. #define to_clk_apbc(hw) container_of(hw, struct clk_apbc, hw)
  24. struct clk_apbc {
  25. struct clk_hw hw;
  26. void __iomem *base;
  27. unsigned int delay;
  28. unsigned int flags;
  29. spinlock_t *lock;
  30. };
  31. static int clk_apbc_prepare(struct clk_hw *hw)
  32. {
  33. struct clk_apbc *apbc = to_clk_apbc(hw);
  34. unsigned int data;
  35. unsigned long flags = 0;
  36. /*
  37. * It may share same register as MUX clock,
  38. * and it will impact FNCLK enable. Spinlock is needed
  39. */
  40. if (apbc->lock)
  41. spin_lock_irqsave(apbc->lock, flags);
  42. data = readl_relaxed(apbc->base);
  43. if (apbc->flags & APBC_POWER_CTRL)
  44. data |= APBC_POWER;
  45. data |= APBC_FNCLK;
  46. writel_relaxed(data, apbc->base);
  47. if (apbc->lock)
  48. spin_unlock_irqrestore(apbc->lock, flags);
  49. udelay(apbc->delay);
  50. if (apbc->lock)
  51. spin_lock_irqsave(apbc->lock, flags);
  52. data = readl_relaxed(apbc->base);
  53. data |= APBC_APBCLK;
  54. writel_relaxed(data, apbc->base);
  55. if (apbc->lock)
  56. spin_unlock_irqrestore(apbc->lock, flags);
  57. udelay(apbc->delay);
  58. if (!(apbc->flags & APBC_NO_BUS_CTRL)) {
  59. if (apbc->lock)
  60. spin_lock_irqsave(apbc->lock, flags);
  61. data = readl_relaxed(apbc->base);
  62. data &= ~APBC_RST;
  63. writel_relaxed(data, apbc->base);
  64. if (apbc->lock)
  65. spin_unlock_irqrestore(apbc->lock, flags);
  66. }
  67. return 0;
  68. }
  69. static void clk_apbc_unprepare(struct clk_hw *hw)
  70. {
  71. struct clk_apbc *apbc = to_clk_apbc(hw);
  72. unsigned long data;
  73. unsigned long flags = 0;
  74. if (apbc->lock)
  75. spin_lock_irqsave(apbc->lock, flags);
  76. data = readl_relaxed(apbc->base);
  77. if (apbc->flags & APBC_POWER_CTRL)
  78. data &= ~APBC_POWER;
  79. data &= ~APBC_FNCLK;
  80. writel_relaxed(data, apbc->base);
  81. if (apbc->lock)
  82. spin_unlock_irqrestore(apbc->lock, flags);
  83. udelay(10);
  84. if (apbc->lock)
  85. spin_lock_irqsave(apbc->lock, flags);
  86. data = readl_relaxed(apbc->base);
  87. data &= ~APBC_APBCLK;
  88. writel_relaxed(data, apbc->base);
  89. if (apbc->lock)
  90. spin_unlock_irqrestore(apbc->lock, flags);
  91. }
  92. struct clk_ops clk_apbc_ops = {
  93. .prepare = clk_apbc_prepare,
  94. .unprepare = clk_apbc_unprepare,
  95. };
  96. struct clk *mmp_clk_register_apbc(const char *name, const char *parent_name,
  97. void __iomem *base, unsigned int delay,
  98. unsigned int apbc_flags, spinlock_t *lock)
  99. {
  100. struct clk_apbc *apbc;
  101. struct clk *clk;
  102. struct clk_init_data init;
  103. apbc = kzalloc(sizeof(*apbc), GFP_KERNEL);
  104. if (!apbc)
  105. return NULL;
  106. init.name = name;
  107. init.ops = &clk_apbc_ops;
  108. init.flags = CLK_SET_RATE_PARENT;
  109. init.parent_names = (parent_name ? &parent_name : NULL);
  110. init.num_parents = (parent_name ? 1 : 0);
  111. apbc->base = base;
  112. apbc->delay = delay;
  113. apbc->flags = apbc_flags;
  114. apbc->lock = lock;
  115. apbc->hw.init = &init;
  116. clk = clk_register(NULL, &apbc->hw);
  117. if (IS_ERR(clk))
  118. kfree(apbc);
  119. return clk;
  120. }