clk-triphase.c 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. // SPDX-License-Identifier: (GPL-2.0 OR MIT)
  2. /*
  3. * Copyright (c) 2018 BayLibre, SAS.
  4. * Author: Jerome Brunet <jbrunet@baylibre.com>
  5. */
  6. #include <linux/clk-provider.h>
  7. #include "clkc-audio.h"
  8. /*
  9. * This is a special clock for the audio controller.
  10. * The phase of mst_sclk clock output can be controlled independently
  11. * for the outside world (ph0), the tdmout (ph1) and tdmin (ph2).
  12. * Controlling these 3 phases as just one makes things simpler and
  13. * give the same clock view to all the element on the i2s bus.
  14. * If necessary, we can still control the phase in the tdm block
  15. * which makes these independent control redundant.
  16. */
  17. static inline struct meson_clk_triphase_data *
  18. meson_clk_triphase_data(struct clk_regmap *clk)
  19. {
  20. return (struct meson_clk_triphase_data *)clk->data;
  21. }
  22. static void meson_clk_triphase_sync(struct clk_hw *hw)
  23. {
  24. struct clk_regmap *clk = to_clk_regmap(hw);
  25. struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk);
  26. unsigned int val;
  27. /* Get phase 0 and sync it to phase 1 and 2 */
  28. val = meson_parm_read(clk->map, &tph->ph0);
  29. meson_parm_write(clk->map, &tph->ph1, val);
  30. meson_parm_write(clk->map, &tph->ph2, val);
  31. }
  32. static int meson_clk_triphase_get_phase(struct clk_hw *hw)
  33. {
  34. struct clk_regmap *clk = to_clk_regmap(hw);
  35. struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk);
  36. unsigned int val;
  37. /* Phase are in sync, reading phase 0 is enough */
  38. val = meson_parm_read(clk->map, &tph->ph0);
  39. return meson_clk_degrees_from_val(val, tph->ph0.width);
  40. }
  41. static int meson_clk_triphase_set_phase(struct clk_hw *hw, int degrees)
  42. {
  43. struct clk_regmap *clk = to_clk_regmap(hw);
  44. struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk);
  45. unsigned int val;
  46. val = meson_clk_degrees_to_val(degrees, tph->ph0.width);
  47. meson_parm_write(clk->map, &tph->ph0, val);
  48. meson_parm_write(clk->map, &tph->ph1, val);
  49. meson_parm_write(clk->map, &tph->ph2, val);
  50. return 0;
  51. }
  52. const struct clk_ops meson_clk_triphase_ops = {
  53. .init = meson_clk_triphase_sync,
  54. .get_phase = meson_clk_triphase_get_phase,
  55. .set_phase = meson_clk_triphase_set_phase,
  56. };
  57. EXPORT_SYMBOL_GPL(meson_clk_triphase_ops);