1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
3 * Copyright (c) 2018 BayLibre, SAS.
4 * Author: Jerome Brunet <jbrunet@baylibre.com>
7 #include <linux/clk-provider.h>
10 #define phase_step(_width) (360 / (1 << (_width)))
12 static inline struct meson_clk_phase_data
*
13 meson_clk_phase_data(struct clk_regmap
*clk
)
15 return (struct meson_clk_phase_data
*)clk
->data
;
18 int meson_clk_degrees_from_val(unsigned int val
, unsigned int width
)
20 return phase_step(width
) * val
;
22 EXPORT_SYMBOL_GPL(meson_clk_degrees_from_val
);
24 unsigned int meson_clk_degrees_to_val(int degrees
, unsigned int width
)
26 unsigned int val
= DIV_ROUND_CLOSEST(degrees
, phase_step(width
));
29 * This last calculation is here for cases when degrees is rounded
30 * to 360, in which case val == (1 << width).
32 return val
% (1 << width
);
34 EXPORT_SYMBOL_GPL(meson_clk_degrees_to_val
);
36 static int meson_clk_phase_get_phase(struct clk_hw
*hw
)
38 struct clk_regmap
*clk
= to_clk_regmap(hw
);
39 struct meson_clk_phase_data
*phase
= meson_clk_phase_data(clk
);
42 val
= meson_parm_read(clk
->map
, &phase
->ph
);
44 return meson_clk_degrees_from_val(val
, phase
->ph
.width
);
47 static int meson_clk_phase_set_phase(struct clk_hw
*hw
, int degrees
)
49 struct clk_regmap
*clk
= to_clk_regmap(hw
);
50 struct meson_clk_phase_data
*phase
= meson_clk_phase_data(clk
);
53 val
= meson_clk_degrees_to_val(degrees
, phase
->ph
.width
);
54 meson_parm_write(clk
->map
, &phase
->ph
, val
);
59 const struct clk_ops meson_clk_phase_ops
= {
60 .get_phase
= meson_clk_phase_get_phase
,
61 .set_phase
= meson_clk_phase_set_phase
,
63 EXPORT_SYMBOL_GPL(meson_clk_phase_ops
);