clk_boston.c 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2016 Imagination Technologies
  4. */
  5. #include <common.h>
  6. #include <clk-uclass.h>
  7. #include <dm.h>
  8. #include <dt-bindings/clock/boston-clock.h>
  9. #include <regmap.h>
  10. #include <syscon.h>
  11. #include <linux/bitops.h>
  12. struct clk_boston {
  13. struct regmap *regmap;
  14. };
  15. #define BOSTON_PLAT_MMCMDIV 0x30
  16. # define BOSTON_PLAT_MMCMDIV_CLK0DIV (0xff << 0)
  17. # define BOSTON_PLAT_MMCMDIV_INPUT (0xff << 8)
  18. # define BOSTON_PLAT_MMCMDIV_MUL (0xff << 16)
  19. # define BOSTON_PLAT_MMCMDIV_CLK1DIV (0xff << 24)
  20. static uint32_t ext_field(uint32_t val, uint32_t mask)
  21. {
  22. return (val & mask) >> (ffs(mask) - 1);
  23. }
  24. static ulong clk_boston_get_rate(struct clk *clk)
  25. {
  26. struct clk_boston *state = dev_get_platdata(clk->dev);
  27. uint32_t in_rate, mul, div;
  28. uint mmcmdiv;
  29. int err;
  30. err = regmap_read(state->regmap, BOSTON_PLAT_MMCMDIV, &mmcmdiv);
  31. if (err)
  32. return 0;
  33. in_rate = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_INPUT);
  34. mul = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_MUL);
  35. switch (clk->id) {
  36. case BOSTON_CLK_SYS:
  37. div = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_CLK0DIV);
  38. break;
  39. case BOSTON_CLK_CPU:
  40. div = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_CLK1DIV);
  41. break;
  42. default:
  43. return 0;
  44. }
  45. return (in_rate * mul * 1000000) / div;
  46. }
  47. const struct clk_ops clk_boston_ops = {
  48. .get_rate = clk_boston_get_rate,
  49. };
  50. static int clk_boston_ofdata_to_platdata(struct udevice *dev)
  51. {
  52. struct clk_boston *state = dev_get_platdata(dev);
  53. struct udevice *syscon;
  54. int err;
  55. err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
  56. "regmap", &syscon);
  57. if (err) {
  58. pr_err("unable to find syscon device\n");
  59. return err;
  60. }
  61. state->regmap = syscon_get_regmap(syscon);
  62. if (!state->regmap) {
  63. pr_err("unable to find regmap\n");
  64. return -ENODEV;
  65. }
  66. return 0;
  67. }
  68. static const struct udevice_id clk_boston_match[] = {
  69. {
  70. .compatible = "img,boston-clock",
  71. },
  72. { /* sentinel */ }
  73. };
  74. U_BOOT_DRIVER(clk_boston) = {
  75. .name = "boston_clock",
  76. .id = UCLASS_CLK,
  77. .of_match = clk_boston_match,
  78. .ofdata_to_platdata = clk_boston_ofdata_to_platdata,
  79. .plat_auto = sizeof(struct clk_boston),
  80. .ops = &clk_boston_ops,
  81. };