clk-pfd.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2019 DENX Software Engineering
  4. * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
  5. *
  6. * Copyright 2012 Freescale Semiconductor, Inc.
  7. * Copyright 2012 Linaro Ltd.
  8. *
  9. * The code contained herein is licensed under the GNU General Public
  10. * License. You may obtain a copy of the GNU General Public License
  11. * Version 2 or later at the following locations:
  12. *
  13. * http://www.opensource.org/licenses/gpl-license.html
  14. * http://www.gnu.org/copyleft/gpl.html
  15. */
  16. #include <common.h>
  17. #include <asm/io.h>
  18. #include <malloc.h>
  19. #include <clk-uclass.h>
  20. #include <dm/device.h>
  21. #include <dm/devres.h>
  22. #include <linux/clk-provider.h>
  23. #include <div64.h>
  24. #include <clk.h>
  25. #include "clk.h"
  26. #include <linux/err.h>
  27. #define UBOOT_DM_CLK_IMX_PFD "imx_clk_pfd"
  28. struct clk_pfd {
  29. struct clk clk;
  30. void __iomem *reg;
  31. u8 idx;
  32. };
  33. #define to_clk_pfd(_clk) container_of(_clk, struct clk_pfd, clk)
  34. #define SET 0x4
  35. #define CLR 0x8
  36. #define OTG 0xc
  37. static unsigned long clk_pfd_recalc_rate(struct clk *clk)
  38. {
  39. struct clk_pfd *pfd =
  40. to_clk_pfd(dev_get_clk_ptr(clk->dev));
  41. unsigned long parent_rate = clk_get_parent_rate(clk);
  42. u64 tmp = parent_rate;
  43. u8 frac = (readl(pfd->reg) >> (pfd->idx * 8)) & 0x3f;
  44. tmp *= 18;
  45. do_div(tmp, frac);
  46. return tmp;
  47. }
  48. static unsigned long clk_pfd_set_rate(struct clk *clk, unsigned long rate)
  49. {
  50. struct clk_pfd *pfd = to_clk_pfd(clk);
  51. unsigned long parent_rate = clk_get_parent_rate(clk);
  52. u64 tmp = parent_rate;
  53. u8 frac;
  54. tmp = tmp * 18 + rate / 2;
  55. do_div(tmp, rate);
  56. frac = tmp;
  57. if (frac < 12)
  58. frac = 12;
  59. else if (frac > 35)
  60. frac = 35;
  61. writel(0x3f << (pfd->idx * 8), pfd->reg + CLR);
  62. writel(frac << (pfd->idx * 8), pfd->reg + SET);
  63. return 0;
  64. }
  65. static const struct clk_ops clk_pfd_ops = {
  66. .get_rate = clk_pfd_recalc_rate,
  67. .set_rate = clk_pfd_set_rate,
  68. };
  69. struct clk *imx_clk_pfd(const char *name, const char *parent_name,
  70. void __iomem *reg, u8 idx)
  71. {
  72. struct clk_pfd *pfd;
  73. struct clk *clk;
  74. int ret;
  75. pfd = kzalloc(sizeof(*pfd), GFP_KERNEL);
  76. if (!pfd)
  77. return ERR_PTR(-ENOMEM);
  78. pfd->reg = reg;
  79. pfd->idx = idx;
  80. /* register the clock */
  81. clk = &pfd->clk;
  82. ret = clk_register(clk, UBOOT_DM_CLK_IMX_PFD, name, parent_name);
  83. if (ret) {
  84. kfree(pfd);
  85. return ERR_PTR(ret);
  86. }
  87. return clk;
  88. }
  89. U_BOOT_DRIVER(clk_pfd) = {
  90. .name = UBOOT_DM_CLK_IMX_PFD,
  91. .id = UCLASS_CLK,
  92. .ops = &clk_pfd_ops,
  93. .flags = DM_FLAG_PRE_RELOC,
  94. };