common.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. // SPDX-License-Identifier: GPL-2.0
  2. //
  3. // Spreadtrum clock infrastructure
  4. //
  5. // Copyright (C) 2017 Spreadtrum, Inc.
  6. // Author: Chunyan Zhang <[email protected]>
  7. #include <linux/mfd/syscon.h>
  8. #include <linux/module.h>
  9. #include <linux/of_address.h>
  10. #include <linux/of_platform.h>
  11. #include <linux/regmap.h>
  12. #include "common.h"
  13. static const struct regmap_config sprdclk_regmap_config = {
  14. .reg_bits = 32,
  15. .reg_stride = 4,
  16. .val_bits = 32,
  17. .fast_io = true,
  18. };
  19. static void sprd_clk_set_regmap(const struct sprd_clk_desc *desc,
  20. struct regmap *regmap)
  21. {
  22. int i;
  23. struct sprd_clk_common *cclk;
  24. for (i = 0; i < desc->num_clk_clks; i++) {
  25. cclk = desc->clk_clks[i];
  26. if (!cclk)
  27. continue;
  28. cclk->regmap = regmap;
  29. }
  30. }
  31. int sprd_clk_regmap_init(struct platform_device *pdev,
  32. const struct sprd_clk_desc *desc)
  33. {
  34. void __iomem *base;
  35. struct device *dev = &pdev->dev;
  36. struct device_node *node = dev->of_node, *np;
  37. struct regmap *regmap;
  38. struct resource *res;
  39. struct regmap_config reg_config = sprdclk_regmap_config;
  40. if (of_find_property(node, "sprd,syscon", NULL)) {
  41. regmap = syscon_regmap_lookup_by_phandle(node, "sprd,syscon");
  42. if (IS_ERR(regmap)) {
  43. pr_err("%s: failed to get syscon regmap\n", __func__);
  44. return PTR_ERR(regmap);
  45. }
  46. } else if (of_device_is_compatible(np = of_get_parent(node), "syscon") ||
  47. (of_node_put(np), 0)) {
  48. regmap = device_node_to_regmap(np);
  49. of_node_put(np);
  50. if (IS_ERR(regmap)) {
  51. dev_err(dev, "failed to get regmap from its parent.\n");
  52. return PTR_ERR(regmap);
  53. }
  54. } else {
  55. base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
  56. if (IS_ERR(base))
  57. return PTR_ERR(base);
  58. reg_config.max_register = resource_size(res) - reg_config.reg_stride;
  59. regmap = devm_regmap_init_mmio(&pdev->dev, base,
  60. &reg_config);
  61. if (IS_ERR(regmap)) {
  62. pr_err("failed to init regmap\n");
  63. return PTR_ERR(regmap);
  64. }
  65. }
  66. sprd_clk_set_regmap(desc, regmap);
  67. return 0;
  68. }
  69. EXPORT_SYMBOL_GPL(sprd_clk_regmap_init);
  70. int sprd_clk_probe(struct device *dev, struct clk_hw_onecell_data *clkhw)
  71. {
  72. int i, ret;
  73. struct clk_hw *hw;
  74. for (i = 0; i < clkhw->num; i++) {
  75. const char *name;
  76. hw = clkhw->hws[i];
  77. if (!hw)
  78. continue;
  79. name = hw->init->name;
  80. ret = devm_clk_hw_register(dev, hw);
  81. if (ret) {
  82. dev_err(dev, "Couldn't register clock %d - %s\n",
  83. i, name);
  84. return ret;
  85. }
  86. }
  87. ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clkhw);
  88. if (ret)
  89. dev_err(dev, "Failed to add clock provider\n");
  90. return ret;
  91. }
  92. EXPORT_SYMBOL_GPL(sprd_clk_probe);
  93. MODULE_LICENSE("GPL v2");