clkgen-mux.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. /*
  2. * clkgen-mux.c: ST GEN-MUX Clock driver
  3. *
  4. * Copyright (C) 2014 STMicroelectronics (R&D) Limited
  5. *
  6. * Authors: Stephen Gallimore <stephen.gallimore@st.com>
  7. * Pankaj Dev <pankaj.dev@st.com>
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 2 of the License, or
  12. * (at your option) any later version.
  13. *
  14. */
  15. #include <linux/slab.h>
  16. #include <linux/of_address.h>
  17. #include <linux/clk.h>
  18. #include <linux/clk-provider.h>
  19. #include "clkgen.h"
  20. static const char ** __init clkgen_mux_get_parents(struct device_node *np,
  21. int *num_parents)
  22. {
  23. const char **parents;
  24. unsigned int nparents;
  25. nparents = of_clk_get_parent_count(np);
  26. if (WARN_ON(!nparents))
  27. return ERR_PTR(-EINVAL);
  28. parents = kcalloc(nparents, sizeof(const char *), GFP_KERNEL);
  29. if (!parents)
  30. return ERR_PTR(-ENOMEM);
  31. *num_parents = of_clk_parent_fill(np, parents, nparents);
  32. return parents;
  33. }
  34. struct clkgen_mux_data {
  35. u32 offset;
  36. u8 shift;
  37. u8 width;
  38. spinlock_t *lock;
  39. unsigned long clk_flags;
  40. u8 mux_flags;
  41. };
  42. static struct clkgen_mux_data stih407_a9_mux_data = {
  43. .offset = 0x1a4,
  44. .shift = 0,
  45. .width = 2,
  46. .lock = &clkgen_a9_lock,
  47. };
  48. static void __init st_of_clkgen_mux_setup(struct device_node *np,
  49. struct clkgen_mux_data *data)
  50. {
  51. struct clk *clk;
  52. void __iomem *reg;
  53. const char **parents;
  54. int num_parents = 0;
  55. reg = of_iomap(np, 0);
  56. if (!reg) {
  57. pr_err("%s: Failed to get base address\n", __func__);
  58. return;
  59. }
  60. parents = clkgen_mux_get_parents(np, &num_parents);
  61. if (IS_ERR(parents)) {
  62. pr_err("%s: Failed to get parents (%ld)\n",
  63. __func__, PTR_ERR(parents));
  64. goto err_parents;
  65. }
  66. clk = clk_register_mux(NULL, np->name, parents, num_parents,
  67. data->clk_flags | CLK_SET_RATE_PARENT,
  68. reg + data->offset,
  69. data->shift, data->width, data->mux_flags,
  70. data->lock);
  71. if (IS_ERR(clk))
  72. goto err;
  73. pr_debug("%s: parent %s rate %u\n",
  74. __clk_get_name(clk),
  75. __clk_get_name(clk_get_parent(clk)),
  76. (unsigned int)clk_get_rate(clk));
  77. kfree(parents);
  78. of_clk_add_provider(np, of_clk_src_simple_get, clk);
  79. return;
  80. err:
  81. kfree(parents);
  82. err_parents:
  83. iounmap(reg);
  84. }
  85. static void __init st_of_clkgen_a9_mux_setup(struct device_node *np)
  86. {
  87. st_of_clkgen_mux_setup(np, &stih407_a9_mux_data);
  88. }
  89. CLK_OF_DECLARE(clkgen_a9mux, "st,stih407-clkgen-a9-mux",
  90. st_of_clkgen_a9_mux_setup);