clk-uniphier-mux.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. /*
  2. * Copyright (C) 2016 Socionext Inc.
  3. * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. */
  15. #include <linux/clk-provider.h>
  16. #include <linux/device.h>
  17. #include <linux/regmap.h>
  18. #include "clk-uniphier.h"
  19. struct uniphier_clk_mux {
  20. struct clk_hw hw;
  21. struct regmap *regmap;
  22. unsigned int reg;
  23. const unsigned int *masks;
  24. const unsigned int *vals;
  25. };
  26. #define to_uniphier_clk_mux(_hw) container_of(_hw, struct uniphier_clk_mux, hw)
  27. static int uniphier_clk_mux_set_parent(struct clk_hw *hw, u8 index)
  28. {
  29. struct uniphier_clk_mux *mux = to_uniphier_clk_mux(hw);
  30. return regmap_write_bits(mux->regmap, mux->reg, mux->masks[index],
  31. mux->vals[index]);
  32. }
  33. static u8 uniphier_clk_mux_get_parent(struct clk_hw *hw)
  34. {
  35. struct uniphier_clk_mux *mux = to_uniphier_clk_mux(hw);
  36. int num_parents = clk_hw_get_num_parents(hw);
  37. int ret;
  38. unsigned int val;
  39. u8 i;
  40. ret = regmap_read(mux->regmap, mux->reg, &val);
  41. if (ret)
  42. return ret;
  43. for (i = 0; i < num_parents; i++)
  44. if ((mux->masks[i] & val) == mux->vals[i])
  45. return i;
  46. return -EINVAL;
  47. }
  48. static const struct clk_ops uniphier_clk_mux_ops = {
  49. .determine_rate = __clk_mux_determine_rate,
  50. .set_parent = uniphier_clk_mux_set_parent,
  51. .get_parent = uniphier_clk_mux_get_parent,
  52. };
  53. struct clk_hw *uniphier_clk_register_mux(struct device *dev,
  54. struct regmap *regmap,
  55. const char *name,
  56. const struct uniphier_clk_mux_data *data)
  57. {
  58. struct uniphier_clk_mux *mux;
  59. struct clk_init_data init;
  60. int ret;
  61. mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
  62. if (!mux)
  63. return ERR_PTR(-ENOMEM);
  64. init.name = name;
  65. init.ops = &uniphier_clk_mux_ops;
  66. init.flags = CLK_SET_RATE_PARENT;
  67. init.parent_names = data->parent_names;
  68. init.num_parents = data->num_parents,
  69. mux->regmap = regmap;
  70. mux->reg = data->reg;
  71. mux->masks = data->masks;
  72. mux->vals = data->vals;
  73. mux->hw.init = &init;
  74. ret = devm_clk_hw_register(dev, &mux->hw);
  75. if (ret)
  76. return ERR_PTR(ret);
  77. return &mux->hw;
  78. }