clk.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /*
  2. * This file is subject to the terms and conditions of the GNU General Public
  3. * License. See the file "COPYING" in the main directory of this archive
  4. * for more details.
  5. *
  6. * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
  7. */
  8. #include <linux/module.h>
  9. #include <linux/mutex.h>
  10. #include <linux/err.h>
  11. #include <linux/clk.h>
  12. #include <bcm63xx_cpu.h>
  13. #include <bcm63xx_io.h>
  14. #include <bcm63xx_regs.h>
  15. #include <bcm63xx_clk.h>
  16. static DEFINE_MUTEX(clocks_mutex);
  17. static void clk_enable_unlocked(struct clk *clk)
  18. {
  19. if (clk->set && (clk->usage++) == 0)
  20. clk->set(clk, 1);
  21. }
  22. static void clk_disable_unlocked(struct clk *clk)
  23. {
  24. if (clk->set && (--clk->usage) == 0)
  25. clk->set(clk, 0);
  26. }
  27. static void bcm_hwclock_set(u32 mask, int enable)
  28. {
  29. u32 reg;
  30. reg = bcm_perf_readl(PERF_CKCTL_REG);
  31. if (enable)
  32. reg |= mask;
  33. else
  34. reg &= ~mask;
  35. bcm_perf_writel(reg, PERF_CKCTL_REG);
  36. }
  37. /*
  38. * Ethernet MAC "misc" clock: dma clocks and main clock on 6348
  39. */
  40. static void enet_misc_set(struct clk *clk, int enable)
  41. {
  42. u32 mask;
  43. if (BCMCPU_IS_6338())
  44. mask = CKCTL_6338_ENET_EN;
  45. else if (BCMCPU_IS_6345())
  46. mask = CKCTL_6345_ENET_EN;
  47. else if (BCMCPU_IS_6348())
  48. mask = CKCTL_6348_ENET_EN;
  49. else
  50. /* BCMCPU_IS_6358 */
  51. mask = CKCTL_6358_EMUSB_EN;
  52. bcm_hwclock_set(mask, enable);
  53. }
  54. static struct clk clk_enet_misc = {
  55. .set = enet_misc_set,
  56. };
  57. /*
  58. * Ethernet MAC clocks: only revelant on 6358, silently enable misc
  59. * clocks
  60. */
  61. static void enetx_set(struct clk *clk, int enable)
  62. {
  63. if (enable)
  64. clk_enable_unlocked(&clk_enet_misc);
  65. else
  66. clk_disable_unlocked(&clk_enet_misc);
  67. if (BCMCPU_IS_6358()) {
  68. u32 mask;
  69. if (clk->id == 0)
  70. mask = CKCTL_6358_ENET0_EN;
  71. else
  72. mask = CKCTL_6358_ENET1_EN;
  73. bcm_hwclock_set(mask, enable);
  74. }
  75. }
  76. static struct clk clk_enet0 = {
  77. .id = 0,
  78. .set = enetx_set,
  79. };
  80. static struct clk clk_enet1 = {
  81. .id = 1,
  82. .set = enetx_set,
  83. };
  84. /*
  85. * Ethernet PHY clock
  86. */
  87. static void ephy_set(struct clk *clk, int enable)
  88. {
  89. if (!BCMCPU_IS_6358())
  90. return;
  91. bcm_hwclock_set(CKCTL_6358_EPHY_EN, enable);
  92. }
  93. static struct clk clk_ephy = {
  94. .set = ephy_set,
  95. };
  96. /*
  97. * PCM clock
  98. */
  99. static void pcm_set(struct clk *clk, int enable)
  100. {
  101. if (!BCMCPU_IS_6358())
  102. return;
  103. bcm_hwclock_set(CKCTL_6358_PCM_EN, enable);
  104. }
  105. static struct clk clk_pcm = {
  106. .set = pcm_set,
  107. };
  108. /*
  109. * USB host clock
  110. */
  111. static void usbh_set(struct clk *clk, int enable)
  112. {
  113. if (!BCMCPU_IS_6348())
  114. return;
  115. bcm_hwclock_set(CKCTL_6348_USBH_EN, enable);
  116. }
  117. static struct clk clk_usbh = {
  118. .set = usbh_set,
  119. };
  120. /*
  121. * SPI clock
  122. */
  123. static void spi_set(struct clk *clk, int enable)
  124. {
  125. u32 mask;
  126. if (BCMCPU_IS_6338())
  127. mask = CKCTL_6338_SPI_EN;
  128. else if (BCMCPU_IS_6348())
  129. mask = CKCTL_6348_SPI_EN;
  130. else
  131. /* BCMCPU_IS_6358 */
  132. mask = CKCTL_6358_SPI_EN;
  133. bcm_hwclock_set(mask, enable);
  134. }
  135. static struct clk clk_spi = {
  136. .set = spi_set,
  137. };
  138. /*
  139. * Internal peripheral clock
  140. */
  141. static struct clk clk_periph = {
  142. .rate = (50 * 1000 * 1000),
  143. };
  144. /*
  145. * Linux clock API implementation
  146. */
  147. int clk_enable(struct clk *clk)
  148. {
  149. mutex_lock(&clocks_mutex);
  150. clk_enable_unlocked(clk);
  151. mutex_unlock(&clocks_mutex);
  152. return 0;
  153. }
  154. EXPORT_SYMBOL(clk_enable);
  155. void clk_disable(struct clk *clk)
  156. {
  157. mutex_lock(&clocks_mutex);
  158. clk_disable_unlocked(clk);
  159. mutex_unlock(&clocks_mutex);
  160. }
  161. EXPORT_SYMBOL(clk_disable);
  162. unsigned long clk_get_rate(struct clk *clk)
  163. {
  164. return clk->rate;
  165. }
  166. EXPORT_SYMBOL(clk_get_rate);
  167. struct clk *clk_get(struct device *dev, const char *id)
  168. {
  169. if (!strcmp(id, "enet0"))
  170. return &clk_enet0;
  171. if (!strcmp(id, "enet1"))
  172. return &clk_enet1;
  173. if (!strcmp(id, "ephy"))
  174. return &clk_ephy;
  175. if (!strcmp(id, "usbh"))
  176. return &clk_usbh;
  177. if (!strcmp(id, "spi"))
  178. return &clk_spi;
  179. if (!strcmp(id, "periph"))
  180. return &clk_periph;
  181. if (BCMCPU_IS_6358() && !strcmp(id, "pcm"))
  182. return &clk_pcm;
  183. return ERR_PTR(-ENOENT);
  184. }
  185. EXPORT_SYMBOL(clk_get);
  186. void clk_put(struct clk *clk)
  187. {
  188. }
  189. EXPORT_SYMBOL(clk_put);