1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2018 BayLibre, SAS.
4 * Author: Jerome Brunet <jbrunet@baylibre.com>
7 #include <linux/module.h>
8 #include "clk-regmap.h"
10 static int clk_regmap_gate_endisable(struct clk_hw
*hw
, int enable
)
12 struct clk_regmap
*clk
= to_clk_regmap(hw
);
13 struct clk_regmap_gate_data
*gate
= clk_get_regmap_gate_data(clk
);
14 int set
= gate
->flags
& CLK_GATE_SET_TO_DISABLE
? 1 : 0;
18 return regmap_update_bits(clk
->map
, gate
->offset
, BIT(gate
->bit_idx
),
19 set
? BIT(gate
->bit_idx
) : 0);
22 static int clk_regmap_gate_enable(struct clk_hw
*hw
)
24 return clk_regmap_gate_endisable(hw
, 1);
27 static void clk_regmap_gate_disable(struct clk_hw
*hw
)
29 clk_regmap_gate_endisable(hw
, 0);
32 static int clk_regmap_gate_is_enabled(struct clk_hw
*hw
)
34 struct clk_regmap
*clk
= to_clk_regmap(hw
);
35 struct clk_regmap_gate_data
*gate
= clk_get_regmap_gate_data(clk
);
38 regmap_read(clk
->map
, gate
->offset
, &val
);
39 if (gate
->flags
& CLK_GATE_SET_TO_DISABLE
)
40 val
^= BIT(gate
->bit_idx
);
42 val
&= BIT(gate
->bit_idx
);
47 const struct clk_ops clk_regmap_gate_ops
= {
48 .enable
= clk_regmap_gate_enable
,
49 .disable
= clk_regmap_gate_disable
,
50 .is_enabled
= clk_regmap_gate_is_enabled
,
52 EXPORT_SYMBOL_NS_GPL(clk_regmap_gate_ops
, CLK_MESON
);
54 const struct clk_ops clk_regmap_gate_ro_ops
= {
55 .is_enabled
= clk_regmap_gate_is_enabled
,
57 EXPORT_SYMBOL_NS_GPL(clk_regmap_gate_ro_ops
, CLK_MESON
);
59 static unsigned long clk_regmap_div_recalc_rate(struct clk_hw
*hw
,
62 struct clk_regmap
*clk
= to_clk_regmap(hw
);
63 struct clk_regmap_div_data
*div
= clk_get_regmap_div_data(clk
);
67 ret
= regmap_read(clk
->map
, div
->offset
, &val
);
69 /* Gives a hint that something is wrong */
73 val
&= clk_div_mask(div
->width
);
74 return divider_recalc_rate(hw
, prate
, val
, div
->table
, div
->flags
,
78 static int clk_regmap_div_determine_rate(struct clk_hw
*hw
,
79 struct clk_rate_request
*req
)
81 struct clk_regmap
*clk
= to_clk_regmap(hw
);
82 struct clk_regmap_div_data
*div
= clk_get_regmap_div_data(clk
);
86 /* if read only, just return current value */
87 if (div
->flags
& CLK_DIVIDER_READ_ONLY
) {
88 ret
= regmap_read(clk
->map
, div
->offset
, &val
);
93 val
&= clk_div_mask(div
->width
);
95 return divider_ro_determine_rate(hw
, req
, div
->table
,
96 div
->width
, div
->flags
, val
);
99 return divider_determine_rate(hw
, req
, div
->table
, div
->width
,
103 static int clk_regmap_div_set_rate(struct clk_hw
*hw
, unsigned long rate
,
104 unsigned long parent_rate
)
106 struct clk_regmap
*clk
= to_clk_regmap(hw
);
107 struct clk_regmap_div_data
*div
= clk_get_regmap_div_data(clk
);
111 ret
= divider_get_val(rate
, parent_rate
, div
->table
, div
->width
,
116 val
= (unsigned int)ret
<< div
->shift
;
117 return regmap_update_bits(clk
->map
, div
->offset
,
118 clk_div_mask(div
->width
) << div
->shift
, val
);
121 /* Would prefer clk_regmap_div_ro_ops but clashes with qcom */
123 const struct clk_ops clk_regmap_divider_ops
= {
124 .recalc_rate
= clk_regmap_div_recalc_rate
,
125 .determine_rate
= clk_regmap_div_determine_rate
,
126 .set_rate
= clk_regmap_div_set_rate
,
128 EXPORT_SYMBOL_NS_GPL(clk_regmap_divider_ops
, CLK_MESON
);
130 const struct clk_ops clk_regmap_divider_ro_ops
= {
131 .recalc_rate
= clk_regmap_div_recalc_rate
,
132 .determine_rate
= clk_regmap_div_determine_rate
,
134 EXPORT_SYMBOL_NS_GPL(clk_regmap_divider_ro_ops
, CLK_MESON
);
136 static u8
clk_regmap_mux_get_parent(struct clk_hw
*hw
)
138 struct clk_regmap
*clk
= to_clk_regmap(hw
);
139 struct clk_regmap_mux_data
*mux
= clk_get_regmap_mux_data(clk
);
143 ret
= regmap_read(clk
->map
, mux
->offset
, &val
);
149 return clk_mux_val_to_index(hw
, mux
->table
, mux
->flags
, val
);
152 static int clk_regmap_mux_set_parent(struct clk_hw
*hw
, u8 index
)
154 struct clk_regmap
*clk
= to_clk_regmap(hw
);
155 struct clk_regmap_mux_data
*mux
= clk_get_regmap_mux_data(clk
);
156 unsigned int val
= clk_mux_index_to_val(mux
->table
, mux
->flags
, index
);
158 return regmap_update_bits(clk
->map
, mux
->offset
,
159 mux
->mask
<< mux
->shift
,
163 static int clk_regmap_mux_determine_rate(struct clk_hw
*hw
,
164 struct clk_rate_request
*req
)
166 struct clk_regmap
*clk
= to_clk_regmap(hw
);
167 struct clk_regmap_mux_data
*mux
= clk_get_regmap_mux_data(clk
);
169 return clk_mux_determine_rate_flags(hw
, req
, mux
->flags
);
172 const struct clk_ops clk_regmap_mux_ops
= {
173 .get_parent
= clk_regmap_mux_get_parent
,
174 .set_parent
= clk_regmap_mux_set_parent
,
175 .determine_rate
= clk_regmap_mux_determine_rate
,
177 EXPORT_SYMBOL_NS_GPL(clk_regmap_mux_ops
, CLK_MESON
);
179 const struct clk_ops clk_regmap_mux_ro_ops
= {
180 .get_parent
= clk_regmap_mux_get_parent
,
182 EXPORT_SYMBOL_NS_GPL(clk_regmap_mux_ro_ops
, CLK_MESON
);
184 MODULE_DESCRIPTION("Amlogic regmap backed clock driver");
185 MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
186 MODULE_LICENSE("GPL");
187 MODULE_IMPORT_NS(CLK_MESON
);