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_GPL(clk_regmap_gate_ops
);
54 const struct clk_ops clk_regmap_gate_ro_ops
= {
55 .is_enabled
= clk_regmap_gate_is_enabled
,
57 EXPORT_SYMBOL_GPL(clk_regmap_gate_ro_ops
);
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 long clk_regmap_div_round_rate(struct clk_hw
*hw
, unsigned long rate
,
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
);
90 /* Gives a hint that something is wrong */
94 val
&= clk_div_mask(div
->width
);
96 return divider_ro_round_rate(hw
, rate
, prate
, div
->table
,
97 div
->width
, div
->flags
, val
);
100 return divider_round_rate(hw
, rate
, prate
, div
->table
, div
->width
,
104 static int clk_regmap_div_set_rate(struct clk_hw
*hw
, unsigned long rate
,
105 unsigned long parent_rate
)
107 struct clk_regmap
*clk
= to_clk_regmap(hw
);
108 struct clk_regmap_div_data
*div
= clk_get_regmap_div_data(clk
);
112 ret
= divider_get_val(rate
, parent_rate
, div
->table
, div
->width
,
117 val
= (unsigned int)ret
<< div
->shift
;
118 return regmap_update_bits(clk
->map
, div
->offset
,
119 clk_div_mask(div
->width
) << div
->shift
, val
);
122 /* Would prefer clk_regmap_div_ro_ops but clashes with qcom */
124 const struct clk_ops clk_regmap_divider_ops
= {
125 .recalc_rate
= clk_regmap_div_recalc_rate
,
126 .round_rate
= clk_regmap_div_round_rate
,
127 .set_rate
= clk_regmap_div_set_rate
,
129 EXPORT_SYMBOL_GPL(clk_regmap_divider_ops
);
131 const struct clk_ops clk_regmap_divider_ro_ops
= {
132 .recalc_rate
= clk_regmap_div_recalc_rate
,
133 .round_rate
= clk_regmap_div_round_rate
,
135 EXPORT_SYMBOL_GPL(clk_regmap_divider_ro_ops
);
137 static u8
clk_regmap_mux_get_parent(struct clk_hw
*hw
)
139 struct clk_regmap
*clk
= to_clk_regmap(hw
);
140 struct clk_regmap_mux_data
*mux
= clk_get_regmap_mux_data(clk
);
144 ret
= regmap_read(clk
->map
, mux
->offset
, &val
);
150 return clk_mux_val_to_index(hw
, mux
->table
, mux
->flags
, val
);
153 static int clk_regmap_mux_set_parent(struct clk_hw
*hw
, u8 index
)
155 struct clk_regmap
*clk
= to_clk_regmap(hw
);
156 struct clk_regmap_mux_data
*mux
= clk_get_regmap_mux_data(clk
);
157 unsigned int val
= clk_mux_index_to_val(mux
->table
, mux
->flags
, index
);
159 return regmap_update_bits(clk
->map
, mux
->offset
,
160 mux
->mask
<< mux
->shift
,
164 static int clk_regmap_mux_determine_rate(struct clk_hw
*hw
,
165 struct clk_rate_request
*req
)
167 struct clk_regmap
*clk
= to_clk_regmap(hw
);
168 struct clk_regmap_mux_data
*mux
= clk_get_regmap_mux_data(clk
);
170 return clk_mux_determine_rate_flags(hw
, req
, mux
->flags
);
173 const struct clk_ops clk_regmap_mux_ops
= {
174 .get_parent
= clk_regmap_mux_get_parent
,
175 .set_parent
= clk_regmap_mux_set_parent
,
176 .determine_rate
= clk_regmap_mux_determine_rate
,
178 EXPORT_SYMBOL_GPL(clk_regmap_mux_ops
);
180 const struct clk_ops clk_regmap_mux_ro_ops
= {
181 .get_parent
= clk_regmap_mux_get_parent
,
183 EXPORT_SYMBOL_GPL(clk_regmap_mux_ro_ops
);
185 MODULE_DESCRIPTION("Amlogic regmap backed clock driver");
186 MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
187 MODULE_LICENSE("GPL v2");