1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2024 Neil Armstrong <neil.armstrong@linaro.org>
6 #include <linux/module.h>
9 /* The VCLK gate has a supplementary reset bit to pulse after ungating */
11 static inline struct meson_vclk_gate_data
*
12 clk_get_meson_vclk_gate_data(struct clk_regmap
*clk
)
14 return (struct meson_vclk_gate_data
*)clk
->data
;
17 static int meson_vclk_gate_enable(struct clk_hw
*hw
)
19 struct clk_regmap
*clk
= to_clk_regmap(hw
);
20 struct meson_vclk_gate_data
*vclk
= clk_get_meson_vclk_gate_data(clk
);
22 meson_parm_write(clk
->map
, &vclk
->enable
, 1);
24 /* Do a reset pulse */
25 meson_parm_write(clk
->map
, &vclk
->reset
, 1);
26 meson_parm_write(clk
->map
, &vclk
->reset
, 0);
31 static void meson_vclk_gate_disable(struct clk_hw
*hw
)
33 struct clk_regmap
*clk
= to_clk_regmap(hw
);
34 struct meson_vclk_gate_data
*vclk
= clk_get_meson_vclk_gate_data(clk
);
36 meson_parm_write(clk
->map
, &vclk
->enable
, 0);
39 static int meson_vclk_gate_is_enabled(struct clk_hw
*hw
)
41 struct clk_regmap
*clk
= to_clk_regmap(hw
);
42 struct meson_vclk_gate_data
*vclk
= clk_get_meson_vclk_gate_data(clk
);
44 return meson_parm_read(clk
->map
, &vclk
->enable
);
47 const struct clk_ops meson_vclk_gate_ops
= {
48 .enable
= meson_vclk_gate_enable
,
49 .disable
= meson_vclk_gate_disable
,
50 .is_enabled
= meson_vclk_gate_is_enabled
,
52 EXPORT_SYMBOL_NS_GPL(meson_vclk_gate_ops
, "CLK_MESON");
54 /* The VCLK Divider has supplementary reset & enable bits */
56 static inline struct meson_vclk_div_data
*
57 clk_get_meson_vclk_div_data(struct clk_regmap
*clk
)
59 return (struct meson_vclk_div_data
*)clk
->data
;
62 static unsigned long meson_vclk_div_recalc_rate(struct clk_hw
*hw
,
65 struct clk_regmap
*clk
= to_clk_regmap(hw
);
66 struct meson_vclk_div_data
*vclk
= clk_get_meson_vclk_div_data(clk
);
68 return divider_recalc_rate(hw
, prate
, meson_parm_read(clk
->map
, &vclk
->div
),
69 vclk
->table
, vclk
->flags
, vclk
->div
.width
);
72 static int meson_vclk_div_determine_rate(struct clk_hw
*hw
,
73 struct clk_rate_request
*req
)
75 struct clk_regmap
*clk
= to_clk_regmap(hw
);
76 struct meson_vclk_div_data
*vclk
= clk_get_meson_vclk_div_data(clk
);
78 return divider_determine_rate(hw
, req
, vclk
->table
, vclk
->div
.width
,
82 static int meson_vclk_div_set_rate(struct clk_hw
*hw
, unsigned long rate
,
83 unsigned long parent_rate
)
85 struct clk_regmap
*clk
= to_clk_regmap(hw
);
86 struct meson_vclk_div_data
*vclk
= clk_get_meson_vclk_div_data(clk
);
89 ret
= divider_get_val(rate
, parent_rate
, vclk
->table
, vclk
->div
.width
,
94 meson_parm_write(clk
->map
, &vclk
->div
, ret
);
99 static int meson_vclk_div_enable(struct clk_hw
*hw
)
101 struct clk_regmap
*clk
= to_clk_regmap(hw
);
102 struct meson_vclk_div_data
*vclk
= clk_get_meson_vclk_div_data(clk
);
104 /* Unreset the divider when ungating */
105 meson_parm_write(clk
->map
, &vclk
->reset
, 0);
106 meson_parm_write(clk
->map
, &vclk
->enable
, 1);
111 static void meson_vclk_div_disable(struct clk_hw
*hw
)
113 struct clk_regmap
*clk
= to_clk_regmap(hw
);
114 struct meson_vclk_div_data
*vclk
= clk_get_meson_vclk_div_data(clk
);
116 /* Reset the divider when gating */
117 meson_parm_write(clk
->map
, &vclk
->enable
, 0);
118 meson_parm_write(clk
->map
, &vclk
->reset
, 1);
121 static int meson_vclk_div_is_enabled(struct clk_hw
*hw
)
123 struct clk_regmap
*clk
= to_clk_regmap(hw
);
124 struct meson_vclk_div_data
*vclk
= clk_get_meson_vclk_div_data(clk
);
126 return meson_parm_read(clk
->map
, &vclk
->enable
);
129 const struct clk_ops meson_vclk_div_ops
= {
130 .recalc_rate
= meson_vclk_div_recalc_rate
,
131 .determine_rate
= meson_vclk_div_determine_rate
,
132 .set_rate
= meson_vclk_div_set_rate
,
133 .enable
= meson_vclk_div_enable
,
134 .disable
= meson_vclk_div_disable
,
135 .is_enabled
= meson_vclk_div_is_enabled
,
137 EXPORT_SYMBOL_NS_GPL(meson_vclk_div_ops
, "CLK_MESON");
139 MODULE_DESCRIPTION("Amlogic vclk clock driver");
140 MODULE_AUTHOR("Neil Armstrong <neil.armstrong@linaro.org>");
141 MODULE_LICENSE("GPL");
142 MODULE_IMPORT_NS("CLK_MESON");