clk_boston.c 2.1 KB

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