clk-smd.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /*
  2. * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. */
  10. #include <linux/clk-provider.h>
  11. #include <linux/clkdev.h>
  12. #include <linux/clk/at91_pmc.h>
  13. #include <linux/of.h>
  14. #include <linux/of_address.h>
  15. #include <linux/io.h>
  16. #include "pmc.h"
  17. #define SMD_SOURCE_MAX 2
  18. #define SMD_DIV_SHIFT 8
  19. #define SMD_MAX_DIV 0xf
  20. struct at91sam9x5_clk_smd {
  21. struct clk_hw hw;
  22. struct at91_pmc *pmc;
  23. };
  24. #define to_at91sam9x5_clk_smd(hw) \
  25. container_of(hw, struct at91sam9x5_clk_smd, hw)
  26. static unsigned long at91sam9x5_clk_smd_recalc_rate(struct clk_hw *hw,
  27. unsigned long parent_rate)
  28. {
  29. u32 tmp;
  30. u8 smddiv;
  31. struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
  32. struct at91_pmc *pmc = smd->pmc;
  33. tmp = pmc_read(pmc, AT91_PMC_SMD);
  34. smddiv = (tmp & AT91_PMC_SMD_DIV) >> SMD_DIV_SHIFT;
  35. return parent_rate / (smddiv + 1);
  36. }
  37. static long at91sam9x5_clk_smd_round_rate(struct clk_hw *hw, unsigned long rate,
  38. unsigned long *parent_rate)
  39. {
  40. unsigned long div;
  41. unsigned long bestrate;
  42. unsigned long tmp;
  43. if (rate >= *parent_rate)
  44. return *parent_rate;
  45. div = *parent_rate / rate;
  46. if (div > SMD_MAX_DIV)
  47. return *parent_rate / (SMD_MAX_DIV + 1);
  48. bestrate = *parent_rate / div;
  49. tmp = *parent_rate / (div + 1);
  50. if (bestrate - rate > rate - tmp)
  51. bestrate = tmp;
  52. return bestrate;
  53. }
  54. static int at91sam9x5_clk_smd_set_parent(struct clk_hw *hw, u8 index)
  55. {
  56. u32 tmp;
  57. struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
  58. struct at91_pmc *pmc = smd->pmc;
  59. if (index > 1)
  60. return -EINVAL;
  61. tmp = pmc_read(pmc, AT91_PMC_SMD) & ~AT91_PMC_SMDS;
  62. if (index)
  63. tmp |= AT91_PMC_SMDS;
  64. pmc_write(pmc, AT91_PMC_SMD, tmp);
  65. return 0;
  66. }
  67. static u8 at91sam9x5_clk_smd_get_parent(struct clk_hw *hw)
  68. {
  69. struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
  70. struct at91_pmc *pmc = smd->pmc;
  71. return pmc_read(pmc, AT91_PMC_SMD) & AT91_PMC_SMDS;
  72. }
  73. static int at91sam9x5_clk_smd_set_rate(struct clk_hw *hw, unsigned long rate,
  74. unsigned long parent_rate)
  75. {
  76. u32 tmp;
  77. struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
  78. struct at91_pmc *pmc = smd->pmc;
  79. unsigned long div = parent_rate / rate;
  80. if (parent_rate % rate || div < 1 || div > (SMD_MAX_DIV + 1))
  81. return -EINVAL;
  82. tmp = pmc_read(pmc, AT91_PMC_SMD) & ~AT91_PMC_SMD_DIV;
  83. tmp |= (div - 1) << SMD_DIV_SHIFT;
  84. pmc_write(pmc, AT91_PMC_SMD, tmp);
  85. return 0;
  86. }
  87. static const struct clk_ops at91sam9x5_smd_ops = {
  88. .recalc_rate = at91sam9x5_clk_smd_recalc_rate,
  89. .round_rate = at91sam9x5_clk_smd_round_rate,
  90. .get_parent = at91sam9x5_clk_smd_get_parent,
  91. .set_parent = at91sam9x5_clk_smd_set_parent,
  92. .set_rate = at91sam9x5_clk_smd_set_rate,
  93. };
  94. static struct clk * __init
  95. at91sam9x5_clk_register_smd(struct at91_pmc *pmc, const char *name,
  96. const char **parent_names, u8 num_parents)
  97. {
  98. struct at91sam9x5_clk_smd *smd;
  99. struct clk *clk = NULL;
  100. struct clk_init_data init;
  101. smd = kzalloc(sizeof(*smd), GFP_KERNEL);
  102. if (!smd)
  103. return ERR_PTR(-ENOMEM);
  104. init.name = name;
  105. init.ops = &at91sam9x5_smd_ops;
  106. init.parent_names = parent_names;
  107. init.num_parents = num_parents;
  108. init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
  109. smd->hw.init = &init;
  110. smd->pmc = pmc;
  111. clk = clk_register(NULL, &smd->hw);
  112. if (IS_ERR(clk))
  113. kfree(smd);
  114. return clk;
  115. }
  116. void __init of_at91sam9x5_clk_smd_setup(struct device_node *np,
  117. struct at91_pmc *pmc)
  118. {
  119. struct clk *clk;
  120. int num_parents;
  121. const char *parent_names[SMD_SOURCE_MAX];
  122. const char *name = np->name;
  123. num_parents = of_clk_get_parent_count(np);
  124. if (num_parents <= 0 || num_parents > SMD_SOURCE_MAX)
  125. return;
  126. of_clk_parent_fill(np, parent_names, num_parents);
  127. of_property_read_string(np, "clock-output-names", &name);
  128. clk = at91sam9x5_clk_register_smd(pmc, name, parent_names,
  129. num_parents);
  130. if (IS_ERR(clk))
  131. return;
  132. of_clk_add_provider(np, of_clk_src_simple_get, clk);
  133. }