clk-impd1.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /*
  2. * Clock driver for the ARM Integrator/IM-PD1 board
  3. * Copyright (C) 2012-2013 Linus Walleij
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. */
  9. #include <linux/clk-provider.h>
  10. #include <linux/clkdev.h>
  11. #include <linux/err.h>
  12. #include <linux/io.h>
  13. #include <linux/platform_data/clk-integrator.h>
  14. #include "icst.h"
  15. #include "clk-icst.h"
  16. #define IMPD1_OSC1 0x00
  17. #define IMPD1_OSC2 0x04
  18. #define IMPD1_LOCK 0x08
  19. struct impd1_clk {
  20. char *pclkname;
  21. struct clk *pclk;
  22. char *vco1name;
  23. struct clk *vco1clk;
  24. char *vco2name;
  25. struct clk *vco2clk;
  26. struct clk *mmciclk;
  27. char *uartname;
  28. struct clk *uartclk;
  29. char *spiname;
  30. struct clk *spiclk;
  31. char *scname;
  32. struct clk *scclk;
  33. struct clk_lookup *clks[15];
  34. };
  35. /* One entry for each connected IM-PD1 LM */
  36. static struct impd1_clk impd1_clks[4];
  37. /*
  38. * There are two VCO's on the IM-PD1
  39. */
  40. static const struct icst_params impd1_vco1_params = {
  41. .ref = 24000000, /* 24 MHz */
  42. .vco_max = ICST525_VCO_MAX_3V,
  43. .vco_min = ICST525_VCO_MIN,
  44. .vd_min = 12,
  45. .vd_max = 519,
  46. .rd_min = 3,
  47. .rd_max = 120,
  48. .s2div = icst525_s2div,
  49. .idx2s = icst525_idx2s,
  50. };
  51. static const struct clk_icst_desc impd1_icst1_desc = {
  52. .params = &impd1_vco1_params,
  53. .vco_offset = IMPD1_OSC1,
  54. .lock_offset = IMPD1_LOCK,
  55. };
  56. static const struct icst_params impd1_vco2_params = {
  57. .ref = 24000000, /* 24 MHz */
  58. .vco_max = ICST525_VCO_MAX_3V,
  59. .vco_min = ICST525_VCO_MIN,
  60. .vd_min = 12,
  61. .vd_max = 519,
  62. .rd_min = 3,
  63. .rd_max = 120,
  64. .s2div = icst525_s2div,
  65. .idx2s = icst525_idx2s,
  66. };
  67. static const struct clk_icst_desc impd1_icst2_desc = {
  68. .params = &impd1_vco2_params,
  69. .vco_offset = IMPD1_OSC2,
  70. .lock_offset = IMPD1_LOCK,
  71. };
  72. /**
  73. * integrator_impd1_clk_init() - set up the integrator clock tree
  74. * @base: base address of the logic module (LM)
  75. * @id: the ID of this LM
  76. */
  77. void integrator_impd1_clk_init(void __iomem *base, unsigned int id)
  78. {
  79. struct impd1_clk *imc;
  80. struct clk *clk;
  81. struct clk *pclk;
  82. int i;
  83. if (id > 3) {
  84. pr_crit("no more than 4 LMs can be attached\n");
  85. return;
  86. }
  87. imc = &impd1_clks[id];
  88. /* Register the fixed rate PCLK */
  89. imc->pclkname = kasprintf(GFP_KERNEL, "lm%x-pclk", id);
  90. pclk = clk_register_fixed_rate(NULL, imc->pclkname, NULL, 0, 0);
  91. imc->pclk = pclk;
  92. imc->vco1name = kasprintf(GFP_KERNEL, "lm%x-vco1", id);
  93. clk = icst_clk_register(NULL, &impd1_icst1_desc, imc->vco1name, NULL,
  94. base);
  95. imc->vco1clk = clk;
  96. imc->clks[0] = clkdev_alloc(pclk, "apb_pclk", "lm%x:01000", id);
  97. imc->clks[1] = clkdev_alloc(clk, NULL, "lm%x:01000", id);
  98. /* VCO2 is also called "CLK2" */
  99. imc->vco2name = kasprintf(GFP_KERNEL, "lm%x-vco2", id);
  100. clk = icst_clk_register(NULL, &impd1_icst2_desc, imc->vco2name, NULL,
  101. base);
  102. imc->vco2clk = clk;
  103. /* MMCI uses CLK2 right off */
  104. imc->clks[2] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00700", id);
  105. imc->clks[3] = clkdev_alloc(clk, NULL, "lm%x:00700", id);
  106. /* UART reference clock divides CLK2 by a fixed factor 4 */
  107. imc->uartname = kasprintf(GFP_KERNEL, "lm%x-uartclk", id);
  108. clk = clk_register_fixed_factor(NULL, imc->uartname, imc->vco2name,
  109. CLK_IGNORE_UNUSED, 1, 4);
  110. imc->uartclk = clk;
  111. imc->clks[4] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00100", id);
  112. imc->clks[5] = clkdev_alloc(clk, NULL, "lm%x:00100", id);
  113. imc->clks[6] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00200", id);
  114. imc->clks[7] = clkdev_alloc(clk, NULL, "lm%x:00200", id);
  115. /* SPI PL022 clock divides CLK2 by a fixed factor 64 */
  116. imc->spiname = kasprintf(GFP_KERNEL, "lm%x-spiclk", id);
  117. clk = clk_register_fixed_factor(NULL, imc->spiname, imc->vco2name,
  118. CLK_IGNORE_UNUSED, 1, 64);
  119. imc->clks[8] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00300", id);
  120. imc->clks[9] = clkdev_alloc(clk, NULL, "lm%x:00300", id);
  121. /* The GPIO blocks and AACI have only PCLK */
  122. imc->clks[10] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00400", id);
  123. imc->clks[11] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00500", id);
  124. imc->clks[12] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00800", id);
  125. /* Smart Card clock divides CLK2 by a fixed factor 4 */
  126. imc->scname = kasprintf(GFP_KERNEL, "lm%x-scclk", id);
  127. clk = clk_register_fixed_factor(NULL, imc->scname, imc->vco2name,
  128. CLK_IGNORE_UNUSED, 1, 4);
  129. imc->scclk = clk;
  130. imc->clks[13] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00600", id);
  131. imc->clks[14] = clkdev_alloc(clk, NULL, "lm%x:00600", id);
  132. for (i = 0; i < ARRAY_SIZE(imc->clks); i++)
  133. clkdev_add(imc->clks[i]);
  134. }
  135. EXPORT_SYMBOL_GPL(integrator_impd1_clk_init);
  136. void integrator_impd1_clk_exit(unsigned int id)
  137. {
  138. int i;
  139. struct impd1_clk *imc;
  140. if (id > 3)
  141. return;
  142. imc = &impd1_clks[id];
  143. for (i = 0; i < ARRAY_SIZE(imc->clks); i++)
  144. clkdev_drop(imc->clks[i]);
  145. clk_unregister(imc->spiclk);
  146. clk_unregister(imc->uartclk);
  147. clk_unregister(imc->vco2clk);
  148. clk_unregister(imc->vco1clk);
  149. clk_unregister(imc->pclk);
  150. kfree(imc->scname);
  151. kfree(imc->spiname);
  152. kfree(imc->uartname);
  153. kfree(imc->vco2name);
  154. kfree(imc->vco1name);
  155. kfree(imc->pclkname);
  156. }
  157. EXPORT_SYMBOL_GPL(integrator_impd1_clk_exit);