sckc.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Slow clock support for AT91 architectures.
  4. *
  5. * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
  6. *
  7. * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
  8. */
  9. #include <common.h>
  10. #include <clk-uclass.h>
  11. #include <dm.h>
  12. #include <dt-bindings/clk/at91.h>
  13. #include <linux/clk-provider.h>
  14. #include "pmc.h"
  15. #define UBOOT_DM_CLK_AT91_SAM9X60_TD_SLCK "at91-sam9x60-td-slck"
  16. #define UBOOT_DM_CLK_AT91_SCKC "at91-sckc"
  17. #define AT91_OSC_SEL BIT(24)
  18. #define AT91_OSC_SEL_SHIFT (24)
  19. struct sam9x60_sckc {
  20. void __iomem *reg;
  21. const char **parent_names;
  22. unsigned int num_parents;
  23. struct clk clk;
  24. };
  25. #define to_sam9x60_sckc(c) container_of(c, struct sam9x60_sckc, clk)
  26. static int sam9x60_sckc_of_xlate(struct clk *clk,
  27. struct ofnode_phandle_args *args)
  28. {
  29. if (args->args_count != 1) {
  30. debug("AT91: SCKC: Invalid args_count: %d\n", args->args_count);
  31. return -EINVAL;
  32. }
  33. clk->id = AT91_TO_CLK_ID(PMC_TYPE_SLOW, args->args[0]);
  34. return 0;
  35. }
  36. static const struct clk_ops sam9x60_sckc_ops = {
  37. .of_xlate = sam9x60_sckc_of_xlate,
  38. .get_rate = clk_generic_get_rate,
  39. };
  40. static int sam9x60_td_slck_set_parent(struct clk *clk, struct clk *parent)
  41. {
  42. struct sam9x60_sckc *sckc = to_sam9x60_sckc(clk);
  43. u32 i;
  44. for (i = 0; i < sckc->num_parents; i++) {
  45. if (!strcmp(parent->dev->name, sckc->parent_names[i]))
  46. break;
  47. }
  48. if (i == sckc->num_parents)
  49. return -EINVAL;
  50. pmc_update_bits(sckc->reg, 0, AT91_OSC_SEL, (i << AT91_OSC_SEL_SHIFT));
  51. return 0;
  52. }
  53. static const struct clk_ops sam9x60_td_slck_ops = {
  54. .get_rate = clk_generic_get_rate,
  55. .set_parent = sam9x60_td_slck_set_parent,
  56. };
  57. static struct clk *at91_sam9x60_clk_register_td_slck(struct sam9x60_sckc *sckc,
  58. const char *name, const char * const *parent_names,
  59. int num_parents)
  60. {
  61. struct clk *clk;
  62. int ret = -ENOMEM;
  63. u32 val, i;
  64. if (!sckc || !name || !parent_names || num_parents != 2)
  65. return ERR_PTR(-EINVAL);
  66. sckc->parent_names = kzalloc(sizeof(*sckc->parent_names) * num_parents,
  67. GFP_KERNEL);
  68. if (!sckc->parent_names)
  69. return ERR_PTR(ret);
  70. for (i = 0; i < num_parents; i++) {
  71. sckc->parent_names[i] = kmemdup(parent_names[i],
  72. strlen(parent_names[i]) + 1, GFP_KERNEL);
  73. if (!sckc->parent_names[i])
  74. goto free;
  75. }
  76. sckc->num_parents = num_parents;
  77. pmc_read(sckc->reg, 0, &val);
  78. val = (val & AT91_OSC_SEL) >> AT91_OSC_SEL_SHIFT;
  79. clk = &sckc->clk;
  80. ret = clk_register(clk, UBOOT_DM_CLK_AT91_SAM9X60_TD_SLCK, name,
  81. parent_names[val]);
  82. if (ret)
  83. goto free;
  84. return clk;
  85. free:
  86. for (; i >= 0; i--)
  87. kfree(sckc->parent_names[i]);
  88. kfree(sckc->parent_names);
  89. return ERR_PTR(ret);
  90. }
  91. U_BOOT_DRIVER(at91_sam9x60_td_slck) = {
  92. .name = UBOOT_DM_CLK_AT91_SAM9X60_TD_SLCK,
  93. .id = UCLASS_CLK,
  94. .ops = &sam9x60_td_slck_ops,
  95. .flags = DM_FLAG_PRE_RELOC,
  96. };
  97. static int at91_sam9x60_sckc_probe(struct udevice *dev)
  98. {
  99. struct sam9x60_sckc *sckc = dev_get_priv(dev);
  100. void __iomem *base = (void *)devfdt_get_addr(dev);
  101. const char *slow_rc_osc, *slow_osc;
  102. const char *parents[2];
  103. struct clk *clk, c;
  104. int ret;
  105. ret = clk_get_by_index(dev, 0, &c);
  106. if (ret)
  107. return ret;
  108. slow_rc_osc = clk_hw_get_name(&c);
  109. ret = clk_get_by_index(dev, 1, &c);
  110. if (ret)
  111. return ret;
  112. slow_osc = clk_hw_get_name(&c);
  113. clk = clk_register_fixed_factor(NULL, "md_slck", slow_rc_osc, 0, 1, 1);
  114. if (IS_ERR(clk))
  115. return PTR_ERR(clk);
  116. clk_dm(AT91_TO_CLK_ID(PMC_TYPE_SLOW, 0), clk);
  117. parents[0] = slow_rc_osc;
  118. parents[1] = slow_osc;
  119. sckc[1].reg = base;
  120. clk = at91_sam9x60_clk_register_td_slck(&sckc[1], "td_slck",
  121. parents, 2);
  122. if (IS_ERR(clk))
  123. return PTR_ERR(clk);
  124. clk_dm(AT91_TO_CLK_ID(PMC_TYPE_SLOW, 1), clk);
  125. return 0;
  126. }
  127. static const struct udevice_id sam9x60_sckc_ids[] = {
  128. { .compatible = "microchip,sam9x60-sckc" },
  129. { /* Sentinel. */ },
  130. };
  131. U_BOOT_DRIVER(at91_sckc) = {
  132. .name = UBOOT_DM_CLK_AT91_SCKC,
  133. .id = UCLASS_CLK,
  134. .of_match = sam9x60_sckc_ids,
  135. .priv_auto_alloc_size = sizeof(struct sam9x60_sckc) * 2,
  136. .ops = &sam9x60_sckc_ops,
  137. .probe = at91_sam9x60_sckc_probe,
  138. .flags = DM_FLAG_PRE_RELOC,
  139. };