Lines Matching +full:clk +full:- +full:gate

1 // SPDX-License-Identifier: GPL-2.0-only
6 #include <linux/clk-provider.h>
13 #include "clk-iproc.h"
23 struct iproc_asiu_gate gate; member
38 struct iproc_asiu_clk *clk = to_asiu_clk(hw); in iproc_asiu_clk_enable() local
39 struct iproc_asiu *asiu = clk->asiu; in iproc_asiu_clk_enable()
43 if (clk->gate.offset == IPROC_CLK_INVALID_OFFSET) in iproc_asiu_clk_enable()
46 val = readl(asiu->gate_base + clk->gate.offset); in iproc_asiu_clk_enable()
47 val |= (1 << clk->gate.en_shift); in iproc_asiu_clk_enable()
48 writel(val, asiu->gate_base + clk->gate.offset); in iproc_asiu_clk_enable()
55 struct iproc_asiu_clk *clk = to_asiu_clk(hw); in iproc_asiu_clk_disable() local
56 struct iproc_asiu *asiu = clk->asiu; in iproc_asiu_clk_disable()
60 if (clk->gate.offset == IPROC_CLK_INVALID_OFFSET) in iproc_asiu_clk_disable()
63 val = readl(asiu->gate_base + clk->gate.offset); in iproc_asiu_clk_disable()
64 val &= ~(1 << clk->gate.en_shift); in iproc_asiu_clk_disable()
65 writel(val, asiu->gate_base + clk->gate.offset); in iproc_asiu_clk_disable()
71 struct iproc_asiu_clk *clk = to_asiu_clk(hw); in iproc_asiu_clk_recalc_rate() local
72 struct iproc_asiu *asiu = clk->asiu; in iproc_asiu_clk_recalc_rate()
77 clk->rate = 0; in iproc_asiu_clk_recalc_rate()
82 val = readl(asiu->div_base + clk->div.offset); in iproc_asiu_clk_recalc_rate()
83 if ((val & (1 << clk->div.en_shift)) == 0) { in iproc_asiu_clk_recalc_rate()
84 clk->rate = parent_rate; in iproc_asiu_clk_recalc_rate()
89 div_h = (val >> clk->div.high_shift) & bit_mask(clk->div.high_width); in iproc_asiu_clk_recalc_rate()
91 div_l = (val >> clk->div.low_shift) & bit_mask(clk->div.low_width); in iproc_asiu_clk_recalc_rate()
94 clk->rate = parent_rate / (div_h + div_l); in iproc_asiu_clk_recalc_rate()
96 __func__, clk->rate, parent_rate, div_h, div_l); in iproc_asiu_clk_recalc_rate()
98 return clk->rate; in iproc_asiu_clk_recalc_rate()
106 if (req->rate == 0 || req->best_parent_rate == 0) in iproc_asiu_clk_determine_rate()
107 return -EINVAL; in iproc_asiu_clk_determine_rate()
109 if (req->rate == req->best_parent_rate) in iproc_asiu_clk_determine_rate()
112 div = DIV_ROUND_CLOSEST(req->best_parent_rate, req->rate); in iproc_asiu_clk_determine_rate()
114 req->rate = req->best_parent_rate; in iproc_asiu_clk_determine_rate()
119 req->rate = req->best_parent_rate / div; in iproc_asiu_clk_determine_rate()
127 struct iproc_asiu_clk *clk = to_asiu_clk(hw); in iproc_asiu_clk_set_rate() local
128 struct iproc_asiu *asiu = clk->asiu; in iproc_asiu_clk_set_rate()
133 return -EINVAL; in iproc_asiu_clk_set_rate()
137 val = readl(asiu->div_base + clk->div.offset); in iproc_asiu_clk_set_rate()
138 val &= ~(1 << clk->div.en_shift); in iproc_asiu_clk_set_rate()
139 writel(val, asiu->div_base + clk->div.offset); in iproc_asiu_clk_set_rate()
145 return -EINVAL; in iproc_asiu_clk_set_rate()
148 div_h--; in iproc_asiu_clk_set_rate()
149 div_l--; in iproc_asiu_clk_set_rate()
151 val = readl(asiu->div_base + clk->div.offset); in iproc_asiu_clk_set_rate()
152 val |= 1 << clk->div.en_shift; in iproc_asiu_clk_set_rate()
154 val &= ~(bit_mask(clk->div.high_width) in iproc_asiu_clk_set_rate()
155 << clk->div.high_shift); in iproc_asiu_clk_set_rate()
156 val |= div_h << clk->div.high_shift; in iproc_asiu_clk_set_rate()
158 val &= ~(bit_mask(clk->div.high_width) in iproc_asiu_clk_set_rate()
159 << clk->div.high_shift); in iproc_asiu_clk_set_rate()
162 val &= ~(bit_mask(clk->div.low_width) << clk->div.low_shift); in iproc_asiu_clk_set_rate()
163 val |= div_l << clk->div.low_shift; in iproc_asiu_clk_set_rate()
165 val &= ~(bit_mask(clk->div.low_width) << clk->div.low_shift); in iproc_asiu_clk_set_rate()
167 writel(val, asiu->div_base + clk->div.offset); in iproc_asiu_clk_set_rate()
182 const struct iproc_asiu_gate *gate, in iproc_asiu_setup() argument
188 if (WARN_ON(!gate || !div)) in iproc_asiu_setup()
195 asiu->clk_data = kzalloc(struct_size(asiu->clk_data, hws, num_clks), in iproc_asiu_setup()
197 if (WARN_ON(!asiu->clk_data)) in iproc_asiu_setup()
199 asiu->clk_data->num = num_clks; in iproc_asiu_setup()
201 asiu->clks = kcalloc(num_clks, sizeof(*asiu->clks), GFP_KERNEL); in iproc_asiu_setup()
202 if (WARN_ON(!asiu->clks)) in iproc_asiu_setup()
205 asiu->div_base = of_iomap(node, 0); in iproc_asiu_setup()
206 if (WARN_ON(!asiu->div_base)) in iproc_asiu_setup()
209 asiu->gate_base = of_iomap(node, 1); in iproc_asiu_setup()
210 if (WARN_ON(!asiu->gate_base)) in iproc_asiu_setup()
219 ret = of_property_read_string_index(node, "clock-output-names", in iproc_asiu_setup()
224 asiu_clk = &asiu->clks[i]; in iproc_asiu_setup()
225 asiu_clk->name = clk_name; in iproc_asiu_setup()
226 asiu_clk->asiu = asiu; in iproc_asiu_setup()
227 asiu_clk->div = div[i]; in iproc_asiu_setup()
228 asiu_clk->gate = gate[i]; in iproc_asiu_setup()
235 asiu_clk->hw.init = &init; in iproc_asiu_setup()
237 ret = clk_hw_register(NULL, &asiu_clk->hw); in iproc_asiu_setup()
240 asiu->clk_data->hws[i] = &asiu_clk->hw; in iproc_asiu_setup()
244 asiu->clk_data); in iproc_asiu_setup()
251 while (--i >= 0) in iproc_asiu_setup()
252 clk_hw_unregister(asiu->clk_data->hws[i]); in iproc_asiu_setup()
253 iounmap(asiu->gate_base); in iproc_asiu_setup()
256 iounmap(asiu->div_base); in iproc_asiu_setup()
259 kfree(asiu->clks); in iproc_asiu_setup()
262 kfree(asiu->clk_data); in iproc_asiu_setup()