clkgen-mux.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * clkgen-mux.c: ST GEN-MUX Clock driver
  4. *
  5. * Copyright (C) 2014 STMicroelectronics (R&D) Limited
  6. *
  7. * Authors: Stephen Gallimore <[email protected]>
  8. * Pankaj Dev <[email protected]>
  9. */
  10. #include <linux/slab.h>
  11. #include <linux/io.h>
  12. #include <linux/of_address.h>
  13. #include <linux/clk.h>
  14. #include <linux/clk-provider.h>
  15. #include "clkgen.h"
  16. static const char ** __init clkgen_mux_get_parents(struct device_node *np,
  17. int *num_parents)
  18. {
  19. const char **parents;
  20. unsigned int nparents;
  21. nparents = of_clk_get_parent_count(np);
  22. if (WARN_ON(!nparents))
  23. return ERR_PTR(-EINVAL);
  24. parents = kcalloc(nparents, sizeof(const char *), GFP_KERNEL);
  25. if (!parents)
  26. return ERR_PTR(-ENOMEM);
  27. *num_parents = of_clk_parent_fill(np, parents, nparents);
  28. return parents;
  29. }
  30. struct clkgen_mux_data {
  31. u32 offset;
  32. u8 shift;
  33. u8 width;
  34. spinlock_t *lock;
  35. unsigned long clk_flags;
  36. u8 mux_flags;
  37. };
  38. static struct clkgen_mux_data stih407_a9_mux_data = {
  39. .offset = 0x1a4,
  40. .shift = 0,
  41. .width = 2,
  42. .lock = &clkgen_a9_lock,
  43. };
  44. static void __init st_of_clkgen_mux_setup(struct device_node *np,
  45. struct clkgen_mux_data *data)
  46. {
  47. struct clk *clk;
  48. void __iomem *reg;
  49. const char **parents;
  50. int num_parents = 0;
  51. struct device_node *parent_np;
  52. /*
  53. * First check for reg property within the node to keep backward
  54. * compatibility, then if reg doesn't exist look at the parent node
  55. */
  56. reg = of_iomap(np, 0);
  57. if (!reg) {
  58. parent_np = of_get_parent(np);
  59. reg = of_iomap(parent_np, 0);
  60. of_node_put(parent_np);
  61. if (!reg) {
  62. pr_err("%s: Failed to get base address\n", __func__);
  63. return;
  64. }
  65. }
  66. parents = clkgen_mux_get_parents(np, &num_parents);
  67. if (IS_ERR(parents)) {
  68. pr_err("%s: Failed to get parents (%ld)\n",
  69. __func__, PTR_ERR(parents));
  70. goto err_parents;
  71. }
  72. clk = clk_register_mux(NULL, np->name, parents, num_parents,
  73. data->clk_flags | CLK_SET_RATE_PARENT,
  74. reg + data->offset,
  75. data->shift, data->width, data->mux_flags,
  76. data->lock);
  77. if (IS_ERR(clk))
  78. goto err;
  79. pr_debug("%s: parent %s rate %u\n",
  80. __clk_get_name(clk),
  81. __clk_get_name(clk_get_parent(clk)),
  82. (unsigned int)clk_get_rate(clk));
  83. kfree(parents);
  84. of_clk_add_provider(np, of_clk_src_simple_get, clk);
  85. return;
  86. err:
  87. kfree(parents);
  88. err_parents:
  89. iounmap(reg);
  90. }
  91. static void __init st_of_clkgen_a9_mux_setup(struct device_node *np)
  92. {
  93. st_of_clkgen_mux_setup(np, &stih407_a9_mux_data);
  94. }
  95. CLK_OF_DECLARE(clkgen_a9mux, "st,stih407-clkgen-a9-mux",
  96. st_of_clkgen_a9_mux_setup);