1*c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2cc510c73SMaxime Ripard /*
3cc510c73SMaxime Ripard * Copyright 2015 Maxime Ripard
4cc510c73SMaxime Ripard *
5cc510c73SMaxime Ripard * Maxime Ripard <maxime.ripard@free-electrons.com>
6cc510c73SMaxime Ripard */
7cc510c73SMaxime Ripard
8cc510c73SMaxime Ripard #include <linux/clk-provider.h>
962e59c4eSStephen Boyd #include <linux/io.h>
10cc510c73SMaxime Ripard #include <linux/of.h>
11cc510c73SMaxime Ripard #include <linux/of_address.h>
12cc510c73SMaxime Ripard #include <linux/slab.h>
13cc510c73SMaxime Ripard #include <linux/spinlock.h>
14cc510c73SMaxime Ripard
15cc510c73SMaxime Ripard #define TCON_CH1_SCLK2_PARENTS 4
16cc510c73SMaxime Ripard
17cc510c73SMaxime Ripard #define TCON_CH1_SCLK2_GATE_BIT BIT(31)
18cc510c73SMaxime Ripard #define TCON_CH1_SCLK2_MUX_MASK 3
19cc510c73SMaxime Ripard #define TCON_CH1_SCLK2_MUX_SHIFT 24
20cc510c73SMaxime Ripard #define TCON_CH1_SCLK2_DIV_MASK 0xf
21cc510c73SMaxime Ripard #define TCON_CH1_SCLK2_DIV_SHIFT 0
22cc510c73SMaxime Ripard
23cc510c73SMaxime Ripard #define TCON_CH1_SCLK1_GATE_BIT BIT(15)
24cc510c73SMaxime Ripard #define TCON_CH1_SCLK1_HALF_BIT BIT(11)
25cc510c73SMaxime Ripard
26cc510c73SMaxime Ripard struct tcon_ch1_clk {
27cc510c73SMaxime Ripard struct clk_hw hw;
28cc510c73SMaxime Ripard spinlock_t lock;
29cc510c73SMaxime Ripard void __iomem *reg;
30cc510c73SMaxime Ripard };
31cc510c73SMaxime Ripard
32cc510c73SMaxime Ripard #define hw_to_tclk(hw) container_of(hw, struct tcon_ch1_clk, hw)
33cc510c73SMaxime Ripard
tcon_ch1_disable(struct clk_hw * hw)34cc510c73SMaxime Ripard static void tcon_ch1_disable(struct clk_hw *hw)
35cc510c73SMaxime Ripard {
36cc510c73SMaxime Ripard struct tcon_ch1_clk *tclk = hw_to_tclk(hw);
37cc510c73SMaxime Ripard unsigned long flags;
38cc510c73SMaxime Ripard u32 reg;
39cc510c73SMaxime Ripard
40cc510c73SMaxime Ripard spin_lock_irqsave(&tclk->lock, flags);
41cc510c73SMaxime Ripard reg = readl(tclk->reg);
42cc510c73SMaxime Ripard reg &= ~(TCON_CH1_SCLK2_GATE_BIT | TCON_CH1_SCLK1_GATE_BIT);
43cc510c73SMaxime Ripard writel(reg, tclk->reg);
44cc510c73SMaxime Ripard spin_unlock_irqrestore(&tclk->lock, flags);
45cc510c73SMaxime Ripard }
46cc510c73SMaxime Ripard
tcon_ch1_enable(struct clk_hw * hw)47cc510c73SMaxime Ripard static int tcon_ch1_enable(struct clk_hw *hw)
48cc510c73SMaxime Ripard {
49cc510c73SMaxime Ripard struct tcon_ch1_clk *tclk = hw_to_tclk(hw);
50cc510c73SMaxime Ripard unsigned long flags;
51cc510c73SMaxime Ripard u32 reg;
52cc510c73SMaxime Ripard
53cc510c73SMaxime Ripard spin_lock_irqsave(&tclk->lock, flags);
54cc510c73SMaxime Ripard reg = readl(tclk->reg);
55cc510c73SMaxime Ripard reg |= TCON_CH1_SCLK2_GATE_BIT | TCON_CH1_SCLK1_GATE_BIT;
56cc510c73SMaxime Ripard writel(reg, tclk->reg);
57cc510c73SMaxime Ripard spin_unlock_irqrestore(&tclk->lock, flags);
58cc510c73SMaxime Ripard
59cc510c73SMaxime Ripard return 0;
60cc510c73SMaxime Ripard }
61cc510c73SMaxime Ripard
tcon_ch1_is_enabled(struct clk_hw * hw)62cc510c73SMaxime Ripard static int tcon_ch1_is_enabled(struct clk_hw *hw)
63cc510c73SMaxime Ripard {
64cc510c73SMaxime Ripard struct tcon_ch1_clk *tclk = hw_to_tclk(hw);
65cc510c73SMaxime Ripard u32 reg;
66cc510c73SMaxime Ripard
67cc510c73SMaxime Ripard reg = readl(tclk->reg);
68cc510c73SMaxime Ripard return reg & (TCON_CH1_SCLK2_GATE_BIT | TCON_CH1_SCLK1_GATE_BIT);
69cc510c73SMaxime Ripard }
70cc510c73SMaxime Ripard
tcon_ch1_get_parent(struct clk_hw * hw)71cc510c73SMaxime Ripard static u8 tcon_ch1_get_parent(struct clk_hw *hw)
72cc510c73SMaxime Ripard {
73cc510c73SMaxime Ripard struct tcon_ch1_clk *tclk = hw_to_tclk(hw);
74cc510c73SMaxime Ripard u32 reg;
75cc510c73SMaxime Ripard
76cc510c73SMaxime Ripard reg = readl(tclk->reg) >> TCON_CH1_SCLK2_MUX_SHIFT;
77cc510c73SMaxime Ripard reg &= reg >> TCON_CH1_SCLK2_MUX_MASK;
78cc510c73SMaxime Ripard
79cc510c73SMaxime Ripard return reg;
80cc510c73SMaxime Ripard }
81cc510c73SMaxime Ripard
tcon_ch1_set_parent(struct clk_hw * hw,u8 index)82cc510c73SMaxime Ripard static int tcon_ch1_set_parent(struct clk_hw *hw, u8 index)
83cc510c73SMaxime Ripard {
84cc510c73SMaxime Ripard struct tcon_ch1_clk *tclk = hw_to_tclk(hw);
85cc510c73SMaxime Ripard unsigned long flags;
86cc510c73SMaxime Ripard u32 reg;
87cc510c73SMaxime Ripard
88cc510c73SMaxime Ripard spin_lock_irqsave(&tclk->lock, flags);
89cc510c73SMaxime Ripard reg = readl(tclk->reg);
90cc510c73SMaxime Ripard reg &= ~(TCON_CH1_SCLK2_MUX_MASK << TCON_CH1_SCLK2_MUX_SHIFT);
91cc510c73SMaxime Ripard reg |= index << TCON_CH1_SCLK2_MUX_SHIFT;
92cc510c73SMaxime Ripard writel(reg, tclk->reg);
93cc510c73SMaxime Ripard spin_unlock_irqrestore(&tclk->lock, flags);
94cc510c73SMaxime Ripard
95cc510c73SMaxime Ripard return 0;
96cc510c73SMaxime Ripard };
97cc510c73SMaxime Ripard
tcon_ch1_calc_divider(unsigned long rate,unsigned long parent_rate,u8 * div,bool * half)98cc510c73SMaxime Ripard static unsigned long tcon_ch1_calc_divider(unsigned long rate,
99cc510c73SMaxime Ripard unsigned long parent_rate,
100cc510c73SMaxime Ripard u8 *div,
101cc510c73SMaxime Ripard bool *half)
102cc510c73SMaxime Ripard {
103cc510c73SMaxime Ripard unsigned long best_rate = 0;
104cc510c73SMaxime Ripard u8 best_m = 0, m;
105cc510c73SMaxime Ripard bool is_double;
106cc510c73SMaxime Ripard
107cc510c73SMaxime Ripard for (m = 1; m < 16; m++) {
108cc510c73SMaxime Ripard u8 d;
109cc510c73SMaxime Ripard
110cc510c73SMaxime Ripard for (d = 1; d < 3; d++) {
111cc510c73SMaxime Ripard unsigned long tmp_rate;
112cc510c73SMaxime Ripard
113cc510c73SMaxime Ripard tmp_rate = parent_rate / m / d;
114cc510c73SMaxime Ripard
115cc510c73SMaxime Ripard if (tmp_rate > rate)
116cc510c73SMaxime Ripard continue;
117cc510c73SMaxime Ripard
118cc510c73SMaxime Ripard if (!best_rate ||
119cc510c73SMaxime Ripard (rate - tmp_rate) < (rate - best_rate)) {
120cc510c73SMaxime Ripard best_rate = tmp_rate;
121cc510c73SMaxime Ripard best_m = m;
122cc510c73SMaxime Ripard is_double = d;
123cc510c73SMaxime Ripard }
124cc510c73SMaxime Ripard }
125cc510c73SMaxime Ripard }
126cc510c73SMaxime Ripard
127cc510c73SMaxime Ripard if (div && half) {
128cc510c73SMaxime Ripard *div = best_m;
129cc510c73SMaxime Ripard *half = is_double;
130cc510c73SMaxime Ripard }
131cc510c73SMaxime Ripard
132cc510c73SMaxime Ripard return best_rate;
133cc510c73SMaxime Ripard }
134cc510c73SMaxime Ripard
tcon_ch1_determine_rate(struct clk_hw * hw,struct clk_rate_request * req)135cc510c73SMaxime Ripard static int tcon_ch1_determine_rate(struct clk_hw *hw,
136cc510c73SMaxime Ripard struct clk_rate_request *req)
137cc510c73SMaxime Ripard {
138cc510c73SMaxime Ripard long best_rate = -EINVAL;
139cc510c73SMaxime Ripard int i;
140cc510c73SMaxime Ripard
141cc510c73SMaxime Ripard for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
142cc510c73SMaxime Ripard unsigned long parent_rate;
143cc510c73SMaxime Ripard unsigned long tmp_rate;
144cc510c73SMaxime Ripard struct clk_hw *parent;
145cc510c73SMaxime Ripard
146cc510c73SMaxime Ripard parent = clk_hw_get_parent_by_index(hw, i);
147cc510c73SMaxime Ripard if (!parent)
148cc510c73SMaxime Ripard continue;
149cc510c73SMaxime Ripard
150cc510c73SMaxime Ripard parent_rate = clk_hw_get_rate(parent);
151cc510c73SMaxime Ripard
152cc510c73SMaxime Ripard tmp_rate = tcon_ch1_calc_divider(req->rate, parent_rate,
153cc510c73SMaxime Ripard NULL, NULL);
154cc510c73SMaxime Ripard
155cc510c73SMaxime Ripard if (best_rate < 0 ||
156cc510c73SMaxime Ripard (req->rate - tmp_rate) < (req->rate - best_rate)) {
157cc510c73SMaxime Ripard best_rate = tmp_rate;
158cc510c73SMaxime Ripard req->best_parent_rate = parent_rate;
159cc510c73SMaxime Ripard req->best_parent_hw = parent;
160cc510c73SMaxime Ripard }
161cc510c73SMaxime Ripard }
162cc510c73SMaxime Ripard
163cc510c73SMaxime Ripard if (best_rate < 0)
164cc510c73SMaxime Ripard return best_rate;
165cc510c73SMaxime Ripard
166cc510c73SMaxime Ripard req->rate = best_rate;
167cc510c73SMaxime Ripard return 0;
168cc510c73SMaxime Ripard }
169cc510c73SMaxime Ripard
tcon_ch1_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)170cc510c73SMaxime Ripard static unsigned long tcon_ch1_recalc_rate(struct clk_hw *hw,
171cc510c73SMaxime Ripard unsigned long parent_rate)
172cc510c73SMaxime Ripard {
173cc510c73SMaxime Ripard struct tcon_ch1_clk *tclk = hw_to_tclk(hw);
174cc510c73SMaxime Ripard u32 reg;
175cc510c73SMaxime Ripard
176cc510c73SMaxime Ripard reg = readl(tclk->reg);
177cc510c73SMaxime Ripard
178cc510c73SMaxime Ripard parent_rate /= (reg & TCON_CH1_SCLK2_DIV_MASK) + 1;
179cc510c73SMaxime Ripard
180cc510c73SMaxime Ripard if (reg & TCON_CH1_SCLK1_HALF_BIT)
181cc510c73SMaxime Ripard parent_rate /= 2;
182cc510c73SMaxime Ripard
183cc510c73SMaxime Ripard return parent_rate;
184cc510c73SMaxime Ripard }
185cc510c73SMaxime Ripard
tcon_ch1_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)186cc510c73SMaxime Ripard static int tcon_ch1_set_rate(struct clk_hw *hw, unsigned long rate,
187cc510c73SMaxime Ripard unsigned long parent_rate)
188cc510c73SMaxime Ripard {
189cc510c73SMaxime Ripard struct tcon_ch1_clk *tclk = hw_to_tclk(hw);
190cc510c73SMaxime Ripard unsigned long flags;
191cc510c73SMaxime Ripard bool half;
192cc510c73SMaxime Ripard u8 div_m;
193cc510c73SMaxime Ripard u32 reg;
194cc510c73SMaxime Ripard
195cc510c73SMaxime Ripard tcon_ch1_calc_divider(rate, parent_rate, &div_m, &half);
196cc510c73SMaxime Ripard
197cc510c73SMaxime Ripard spin_lock_irqsave(&tclk->lock, flags);
198cc510c73SMaxime Ripard reg = readl(tclk->reg);
199cc510c73SMaxime Ripard reg &= ~(TCON_CH1_SCLK2_DIV_MASK | TCON_CH1_SCLK1_HALF_BIT);
200cc510c73SMaxime Ripard reg |= (div_m - 1) & TCON_CH1_SCLK2_DIV_MASK;
201cc510c73SMaxime Ripard
202cc510c73SMaxime Ripard if (half)
203cc510c73SMaxime Ripard reg |= TCON_CH1_SCLK1_HALF_BIT;
204cc510c73SMaxime Ripard
205cc510c73SMaxime Ripard writel(reg, tclk->reg);
206cc510c73SMaxime Ripard spin_unlock_irqrestore(&tclk->lock, flags);
207cc510c73SMaxime Ripard
208cc510c73SMaxime Ripard return 0;
209cc510c73SMaxime Ripard }
210cc510c73SMaxime Ripard
211cc510c73SMaxime Ripard static const struct clk_ops tcon_ch1_ops = {
212cc510c73SMaxime Ripard .disable = tcon_ch1_disable,
213cc510c73SMaxime Ripard .enable = tcon_ch1_enable,
214cc510c73SMaxime Ripard .is_enabled = tcon_ch1_is_enabled,
215cc510c73SMaxime Ripard
216cc510c73SMaxime Ripard .get_parent = tcon_ch1_get_parent,
217cc510c73SMaxime Ripard .set_parent = tcon_ch1_set_parent,
218cc510c73SMaxime Ripard
219cc510c73SMaxime Ripard .determine_rate = tcon_ch1_determine_rate,
220cc510c73SMaxime Ripard .recalc_rate = tcon_ch1_recalc_rate,
221cc510c73SMaxime Ripard .set_rate = tcon_ch1_set_rate,
222cc510c73SMaxime Ripard };
223cc510c73SMaxime Ripard
tcon_ch1_setup(struct device_node * node)224cc510c73SMaxime Ripard static void __init tcon_ch1_setup(struct device_node *node)
225cc510c73SMaxime Ripard {
226cc510c73SMaxime Ripard const char *parents[TCON_CH1_SCLK2_PARENTS];
227cc510c73SMaxime Ripard const char *clk_name = node->name;
228cc510c73SMaxime Ripard struct clk_init_data init;
229cc510c73SMaxime Ripard struct tcon_ch1_clk *tclk;
230cc510c73SMaxime Ripard struct resource res;
231cc510c73SMaxime Ripard struct clk *clk;
232cc510c73SMaxime Ripard void __iomem *reg;
233cc510c73SMaxime Ripard int ret;
234cc510c73SMaxime Ripard
235cc510c73SMaxime Ripard of_property_read_string(node, "clock-output-names", &clk_name);
236cc510c73SMaxime Ripard
237cc510c73SMaxime Ripard reg = of_io_request_and_map(node, 0, of_node_full_name(node));
238cc510c73SMaxime Ripard if (IS_ERR(reg)) {
239cc510c73SMaxime Ripard pr_err("%s: Could not map the clock registers\n", clk_name);
240cc510c73SMaxime Ripard return;
241cc510c73SMaxime Ripard }
242cc510c73SMaxime Ripard
243cc510c73SMaxime Ripard ret = of_clk_parent_fill(node, parents, TCON_CH1_SCLK2_PARENTS);
244cc510c73SMaxime Ripard if (ret != TCON_CH1_SCLK2_PARENTS) {
245cc510c73SMaxime Ripard pr_err("%s Could not retrieve the parents\n", clk_name);
246cc510c73SMaxime Ripard goto err_unmap;
247cc510c73SMaxime Ripard }
248cc510c73SMaxime Ripard
249cc510c73SMaxime Ripard tclk = kzalloc(sizeof(*tclk), GFP_KERNEL);
250cc510c73SMaxime Ripard if (!tclk)
251cc510c73SMaxime Ripard goto err_unmap;
252cc510c73SMaxime Ripard
253cc510c73SMaxime Ripard init.name = clk_name;
254cc510c73SMaxime Ripard init.ops = &tcon_ch1_ops;
255cc510c73SMaxime Ripard init.parent_names = parents;
256cc510c73SMaxime Ripard init.num_parents = TCON_CH1_SCLK2_PARENTS;
257cc510c73SMaxime Ripard init.flags = CLK_SET_RATE_PARENT;
258cc510c73SMaxime Ripard
259cc510c73SMaxime Ripard tclk->reg = reg;
260cc510c73SMaxime Ripard tclk->hw.init = &init;
261cc510c73SMaxime Ripard spin_lock_init(&tclk->lock);
262cc510c73SMaxime Ripard
263cc510c73SMaxime Ripard clk = clk_register(NULL, &tclk->hw);
264cc510c73SMaxime Ripard if (IS_ERR(clk)) {
265cc510c73SMaxime Ripard pr_err("%s: Couldn't register the clock\n", clk_name);
266cc510c73SMaxime Ripard goto err_free_data;
267cc510c73SMaxime Ripard }
268cc510c73SMaxime Ripard
269cc510c73SMaxime Ripard ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
270cc510c73SMaxime Ripard if (ret) {
271cc510c73SMaxime Ripard pr_err("%s: Couldn't register our clock provider\n", clk_name);
272cc510c73SMaxime Ripard goto err_unregister_clk;
273cc510c73SMaxime Ripard }
274cc510c73SMaxime Ripard
275cc510c73SMaxime Ripard return;
276cc510c73SMaxime Ripard
277cc510c73SMaxime Ripard err_unregister_clk:
278cc510c73SMaxime Ripard clk_unregister(clk);
279cc510c73SMaxime Ripard err_free_data:
280cc510c73SMaxime Ripard kfree(tclk);
281cc510c73SMaxime Ripard err_unmap:
282cc510c73SMaxime Ripard iounmap(reg);
283cc510c73SMaxime Ripard of_address_to_resource(node, 0, &res);
284cc510c73SMaxime Ripard release_mem_region(res.start, resource_size(&res));
285cc510c73SMaxime Ripard }
286cc510c73SMaxime Ripard
287cc510c73SMaxime Ripard CLK_OF_DECLARE(tcon_ch1, "allwinner,sun4i-a10-tcon-ch1-clk",
288cc510c73SMaxime Ripard tcon_ch1_setup);
289