clkgen-mux.c 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  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 <stephen.gallimore@st.com>
  8. * Pankaj Dev <pankaj.dev@st.com>
  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. reg = of_iomap(np, 0);
  52. if (!reg) {
  53. pr_err("%s: Failed to get base address\n", __func__);
  54. return;
  55. }
  56. parents = clkgen_mux_get_parents(np, &num_parents);
  57. if (IS_ERR(parents)) {
  58. pr_err("%s: Failed to get parents (%ld)\n",
  59. __func__, PTR_ERR(parents));
  60. goto err_parents;
  61. }
  62. clk = clk_register_mux(NULL, np->name, parents, num_parents,
  63. data->clk_flags | CLK_SET_RATE_PARENT,
  64. reg + data->offset,
  65. data->shift, data->width, data->mux_flags,
  66. data->lock);
  67. if (IS_ERR(clk))
  68. goto err;
  69. pr_debug("%s: parent %s rate %u\n",
  70. __clk_get_name(clk),
  71. __clk_get_name(clk_get_parent(clk)),
  72. (unsigned int)clk_get_rate(clk));
  73. kfree(parents);
  74. of_clk_add_provider(np, of_clk_src_simple_get, clk);
  75. return;
  76. err:
  77. kfree(parents);
  78. err_parents:
  79. iounmap(reg);
  80. }
  81. static void __init st_of_clkgen_a9_mux_setup(struct device_node *np)
  82. {
  83. st_of_clkgen_mux_setup(np, &stih407_a9_mux_data);
  84. }
  85. CLK_OF_DECLARE(clkgen_a9mux, "st,stih407-clkgen-a9-mux",
  86. st_of_clkgen_a9_mux_setup);