clk-regmap-mux.c 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. /*
  2. * Copyright (c) 2014, The Linux Foundation. All rights reserved.
  3. *
  4. * This software is licensed under the terms of the GNU General Public
  5. * License version 2, as published by the Free Software Foundation, and
  6. * may be copied, distributed, and modified under those terms.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. */
  13. #include <linux/kernel.h>
  14. #include <linux/bitops.h>
  15. #include <linux/regmap.h>
  16. #include <linux/export.h>
  17. #include "clk-regmap-mux.h"
  18. static inline struct clk_regmap_mux *to_clk_regmap_mux(struct clk_hw *hw)
  19. {
  20. return container_of(to_clk_regmap(hw), struct clk_regmap_mux, clkr);
  21. }
  22. static u8 mux_get_parent(struct clk_hw *hw)
  23. {
  24. struct clk_regmap_mux *mux = to_clk_regmap_mux(hw);
  25. struct clk_regmap *clkr = to_clk_regmap(hw);
  26. unsigned int mask = GENMASK(mux->width - 1, 0);
  27. unsigned int val;
  28. regmap_read(clkr->regmap, mux->reg, &val);
  29. val >>= mux->shift;
  30. val &= mask;
  31. return val;
  32. }
  33. static int mux_set_parent(struct clk_hw *hw, u8 index)
  34. {
  35. struct clk_regmap_mux *mux = to_clk_regmap_mux(hw);
  36. struct clk_regmap *clkr = to_clk_regmap(hw);
  37. unsigned int mask = GENMASK(mux->width + mux->shift - 1, mux->shift);
  38. unsigned int val;
  39. val = index;
  40. val <<= mux->shift;
  41. return regmap_update_bits(clkr->regmap, mux->reg, mask, val);
  42. }
  43. const struct clk_ops clk_regmap_mux_closest_ops = {
  44. .get_parent = mux_get_parent,
  45. .set_parent = mux_set_parent,
  46. .determine_rate = __clk_mux_determine_rate_closest,
  47. };
  48. EXPORT_SYMBOL_GPL(clk_regmap_mux_closest_ops);