clk-system.c 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * System clock support for AT91 architectures.
  4. *
  5. * Copyright (C) Microchip Technology Inc. and its subsidiaries
  6. *
  7. * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
  8. *
  9. * Based on drivers/clk/at91/clk-system.c from Linux.
  10. */
  11. #include <asm/processor.h>
  12. #include <common.h>
  13. #include <clk-uclass.h>
  14. #include <dm.h>
  15. #include <linux/io.h>
  16. #include <linux/clk-provider.h>
  17. #include <linux/clk/at91_pmc.h>
  18. #include "pmc.h"
  19. #define UBOOT_DM_CLK_AT91_SYSTEM "at91-system-clk"
  20. #define SYSTEM_MAX_ID 31
  21. struct clk_system {
  22. void __iomem *base;
  23. struct clk clk;
  24. u8 id;
  25. };
  26. #define to_clk_system(_c) container_of(_c, struct clk_system, clk)
  27. static inline int is_pck(int id)
  28. {
  29. return (id >= 8) && (id <= 15);
  30. }
  31. static inline bool clk_system_ready(void __iomem *base, int id)
  32. {
  33. unsigned int status;
  34. pmc_read(base, AT91_PMC_SR, &status);
  35. return !!(status & (1 << id));
  36. }
  37. static int clk_system_enable(struct clk *clk)
  38. {
  39. struct clk_system *sys = to_clk_system(clk);
  40. pmc_write(sys->base, AT91_PMC_SCER, 1 << sys->id);
  41. if (!is_pck(sys->id))
  42. return 0;
  43. while (!clk_system_ready(sys->base, sys->id)) {
  44. debug("waiting for pck%u\n", sys->id);
  45. cpu_relax();
  46. }
  47. return 0;
  48. }
  49. static int clk_system_disable(struct clk *clk)
  50. {
  51. struct clk_system *sys = to_clk_system(clk);
  52. pmc_write(sys->base, AT91_PMC_SCDR, 1 << sys->id);
  53. return 0;
  54. }
  55. static const struct clk_ops system_ops = {
  56. .enable = clk_system_enable,
  57. .disable = clk_system_disable,
  58. .get_rate = clk_generic_get_rate,
  59. };
  60. struct clk *at91_clk_register_system(void __iomem *base, const char *name,
  61. const char *parent_name, u8 id)
  62. {
  63. struct clk_system *sys;
  64. struct clk *clk;
  65. int ret;
  66. if (!base || !name || !parent_name || id > SYSTEM_MAX_ID)
  67. return ERR_PTR(-EINVAL);
  68. sys = kzalloc(sizeof(*sys), GFP_KERNEL);
  69. if (!sys)
  70. return ERR_PTR(-ENOMEM);
  71. sys->id = id;
  72. sys->base = base;
  73. clk = &sys->clk;
  74. clk->flags = CLK_GET_RATE_NOCACHE;
  75. ret = clk_register(clk, UBOOT_DM_CLK_AT91_SYSTEM, name, parent_name);
  76. if (ret) {
  77. kfree(sys);
  78. clk = ERR_PTR(ret);
  79. }
  80. return clk;
  81. }
  82. U_BOOT_DRIVER(at91_system_clk) = {
  83. .name = UBOOT_DM_CLK_AT91_SYSTEM,
  84. .id = UCLASS_CLK,
  85. .ops = &system_ops,
  86. .flags = DM_FLAG_PRE_RELOC,
  87. };