1 /*
2  * Copyright (C) 2014 Free Electrons
3  *
4  * License Terms: GNU General Public License v2
5  * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
6  *
7  * Allwinner A31 AR100 clock driver
8  *
9  */
10 
11 #include <linux/clk-provider.h>
12 #include <linux/module.h>
13 #include <linux/of.h>
14 #include <linux/platform_device.h>
15 
16 #define SUN6I_AR100_MAX_PARENTS		4
17 #define SUN6I_AR100_SHIFT_MASK		0x3
18 #define SUN6I_AR100_SHIFT_MAX		SUN6I_AR100_SHIFT_MASK
19 #define SUN6I_AR100_SHIFT_SHIFT		4
20 #define SUN6I_AR100_DIV_MASK		0x1f
21 #define SUN6I_AR100_DIV_MAX		(SUN6I_AR100_DIV_MASK + 1)
22 #define SUN6I_AR100_DIV_SHIFT		8
23 #define SUN6I_AR100_MUX_MASK		0x3
24 #define SUN6I_AR100_MUX_SHIFT		16
25 
26 struct ar100_clk {
27 	struct clk_hw hw;
28 	void __iomem *reg;
29 };
30 
31 static inline struct ar100_clk *to_ar100_clk(struct clk_hw *hw)
32 {
33 	return container_of(hw, struct ar100_clk, hw);
34 }
35 
36 static unsigned long ar100_recalc_rate(struct clk_hw *hw,
37 				       unsigned long parent_rate)
38 {
39 	struct ar100_clk *clk = to_ar100_clk(hw);
40 	u32 val = readl(clk->reg);
41 	int shift = (val >> SUN6I_AR100_SHIFT_SHIFT) & SUN6I_AR100_SHIFT_MASK;
42 	int div = (val >> SUN6I_AR100_DIV_SHIFT) & SUN6I_AR100_DIV_MASK;
43 
44 	return (parent_rate >> shift) / (div + 1);
45 }
46 
47 static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate,
48 				 unsigned long min_rate,
49 				 unsigned long max_rate,
50 				 unsigned long *best_parent_rate,
51 				 struct clk_hw **best_parent_clk)
52 {
53 	int nparents = __clk_get_num_parents(hw->clk);
54 	long best_rate = -EINVAL;
55 	int i;
56 
57 	*best_parent_clk = NULL;
58 
59 	for (i = 0; i < nparents; i++) {
60 		unsigned long parent_rate;
61 		unsigned long tmp_rate;
62 		struct clk *parent;
63 		unsigned long div;
64 		int shift;
65 
66 		parent = clk_get_parent_by_index(hw->clk, i);
67 		parent_rate = __clk_get_rate(parent);
68 		div = DIV_ROUND_UP(parent_rate, rate);
69 
70 		/*
71 		 * The AR100 clk contains 2 divisors:
72 		 * - one power of 2 divisor
73 		 * - one regular divisor
74 		 *
75 		 * First check if we can safely shift (or divide by a power
76 		 * of 2) without losing precision on the requested rate.
77 		 */
78 		shift = ffs(div) - 1;
79 		if (shift > SUN6I_AR100_SHIFT_MAX)
80 			shift = SUN6I_AR100_SHIFT_MAX;
81 
82 		div >>= shift;
83 
84 		/*
85 		 * Then if the divisor is still bigger than what the HW
86 		 * actually supports, use a bigger shift (or power of 2
87 		 * divider) value and accept to lose some precision.
88 		 */
89 		while (div > SUN6I_AR100_DIV_MAX) {
90 			shift++;
91 			div >>= 1;
92 			if (shift > SUN6I_AR100_SHIFT_MAX)
93 				break;
94 		}
95 
96 		/*
97 		 * If the shift value (or power of 2 divider) is bigger
98 		 * than what the HW actually support, skip this parent.
99 		 */
100 		if (shift > SUN6I_AR100_SHIFT_MAX)
101 			continue;
102 
103 		tmp_rate = (parent_rate >> shift) / div;
104 		if (!*best_parent_clk || tmp_rate > best_rate) {
105 			*best_parent_clk = __clk_get_hw(parent);
106 			*best_parent_rate = parent_rate;
107 			best_rate = tmp_rate;
108 		}
109 	}
110 
111 	return best_rate;
112 }
113 
114 static int ar100_set_parent(struct clk_hw *hw, u8 index)
115 {
116 	struct ar100_clk *clk = to_ar100_clk(hw);
117 	u32 val = readl(clk->reg);
118 
119 	if (index >= SUN6I_AR100_MAX_PARENTS)
120 		return -EINVAL;
121 
122 	val &= ~(SUN6I_AR100_MUX_MASK << SUN6I_AR100_MUX_SHIFT);
123 	val |= (index << SUN6I_AR100_MUX_SHIFT);
124 	writel(val, clk->reg);
125 
126 	return 0;
127 }
128 
129 static u8 ar100_get_parent(struct clk_hw *hw)
130 {
131 	struct ar100_clk *clk = to_ar100_clk(hw);
132 	return (readl(clk->reg) >> SUN6I_AR100_MUX_SHIFT) &
133 	       SUN6I_AR100_MUX_MASK;
134 }
135 
136 static int ar100_set_rate(struct clk_hw *hw, unsigned long rate,
137 			  unsigned long parent_rate)
138 {
139 	unsigned long div = parent_rate / rate;
140 	struct ar100_clk *clk = to_ar100_clk(hw);
141 	u32 val = readl(clk->reg);
142 	int shift;
143 
144 	if (parent_rate % rate)
145 		return -EINVAL;
146 
147 	shift = ffs(div) - 1;
148 	if (shift > SUN6I_AR100_SHIFT_MAX)
149 		shift = SUN6I_AR100_SHIFT_MAX;
150 
151 	div >>= shift;
152 
153 	if (div > SUN6I_AR100_DIV_MAX)
154 		return -EINVAL;
155 
156 	val &= ~((SUN6I_AR100_SHIFT_MASK << SUN6I_AR100_SHIFT_SHIFT) |
157 		 (SUN6I_AR100_DIV_MASK << SUN6I_AR100_DIV_SHIFT));
158 	val |= (shift << SUN6I_AR100_SHIFT_SHIFT) |
159 	       (div << SUN6I_AR100_DIV_SHIFT);
160 	writel(val, clk->reg);
161 
162 	return 0;
163 }
164 
165 static struct clk_ops ar100_ops = {
166 	.recalc_rate = ar100_recalc_rate,
167 	.determine_rate = ar100_determine_rate,
168 	.set_parent = ar100_set_parent,
169 	.get_parent = ar100_get_parent,
170 	.set_rate = ar100_set_rate,
171 };
172 
173 static int sun6i_a31_ar100_clk_probe(struct platform_device *pdev)
174 {
175 	const char *parents[SUN6I_AR100_MAX_PARENTS];
176 	struct device_node *np = pdev->dev.of_node;
177 	const char *clk_name = np->name;
178 	struct clk_init_data init;
179 	struct ar100_clk *ar100;
180 	struct resource *r;
181 	struct clk *clk;
182 	int nparents;
183 	int i;
184 
185 	ar100 = devm_kzalloc(&pdev->dev, sizeof(*ar100), GFP_KERNEL);
186 	if (!ar100)
187 		return -ENOMEM;
188 
189 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
190 	ar100->reg = devm_ioremap_resource(&pdev->dev, r);
191 	if (IS_ERR(ar100->reg))
192 		return PTR_ERR(ar100->reg);
193 
194 	nparents = of_clk_get_parent_count(np);
195 	if (nparents > SUN6I_AR100_MAX_PARENTS)
196 		nparents = SUN6I_AR100_MAX_PARENTS;
197 
198 	for (i = 0; i < nparents; i++)
199 		parents[i] = of_clk_get_parent_name(np, i);
200 
201 	of_property_read_string(np, "clock-output-names", &clk_name);
202 
203 	init.name = clk_name;
204 	init.ops = &ar100_ops;
205 	init.parent_names = parents;
206 	init.num_parents = nparents;
207 	init.flags = 0;
208 
209 	ar100->hw.init = &init;
210 
211 	clk = clk_register(&pdev->dev, &ar100->hw);
212 	if (IS_ERR(clk))
213 		return PTR_ERR(clk);
214 
215 	return of_clk_add_provider(np, of_clk_src_simple_get, clk);
216 }
217 
218 static const struct of_device_id sun6i_a31_ar100_clk_dt_ids[] = {
219 	{ .compatible = "allwinner,sun6i-a31-ar100-clk" },
220 	{ /* sentinel */ }
221 };
222 
223 static struct platform_driver sun6i_a31_ar100_clk_driver = {
224 	.driver = {
225 		.name = "sun6i-a31-ar100-clk",
226 		.of_match_table = sun6i_a31_ar100_clk_dt_ids,
227 	},
228 	.probe = sun6i_a31_ar100_clk_probe,
229 };
230 module_platform_driver(sun6i_a31_ar100_clk_driver);
231 
232 MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>");
233 MODULE_DESCRIPTION("Allwinner A31 AR100 clock Driver");
234 MODULE_LICENSE("GPL v2");
235