1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * TI multiplexer clock support
4  *
5  * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
6  *
7  * Based on Linux kernel drivers/clk/ti/mux.c
8  */
9 
10 #include <common.h>
11 #include <dm.h>
12 #include <dm/device_compat.h>
13 #include <clk-uclass.h>
14 #include <asm/io.h>
15 #include <linux/clk-provider.h>
16 #include "clk.h"
17 
18 struct clk_ti_mux_priv {
19 	struct clk_bulk parents;
20 	fdt_addr_t reg;
21 	u32 flags;
22 	u32 mux_flags;
23 	u32 mask;
24 	u32 shift;
25 	s32 latch;
26 };
27 
clk_ti_mux_get_parent_by_index(struct clk_bulk * parents,int index)28 static struct clk *clk_ti_mux_get_parent_by_index(struct clk_bulk *parents,
29 						  int index)
30 {
31 	if (index < 0 || !parents)
32 		return ERR_PTR(-EINVAL);
33 
34 	if (index >= parents->count)
35 		return ERR_PTR(-ENODEV);
36 
37 	return &parents->clks[index];
38 }
39 
clk_ti_mux_get_parent_index(struct clk_bulk * parents,struct clk * parent)40 static int clk_ti_mux_get_parent_index(struct clk_bulk *parents,
41 				       struct clk *parent)
42 {
43 	int i;
44 
45 	if (!parents || !parent)
46 		return -EINVAL;
47 
48 	for (i = 0; i < parents->count; i++) {
49 		if (parents->clks[i].dev == parent->dev)
50 			return i;
51 	}
52 
53 	return -ENODEV;
54 }
55 
clk_ti_mux_get_index(struct clk * clk)56 static int clk_ti_mux_get_index(struct clk *clk)
57 {
58 	struct clk_ti_mux_priv *priv = dev_get_priv(clk->dev);
59 	u32 val;
60 
61 	val = readl(priv->reg);
62 	val >>= priv->shift;
63 	val &= priv->mask;
64 
65 	if (val && (priv->flags & CLK_MUX_INDEX_BIT))
66 		val = ffs(val) - 1;
67 
68 	if (val && (priv->flags & CLK_MUX_INDEX_ONE))
69 		val--;
70 
71 	if (val >= priv->parents.count)
72 		return -EINVAL;
73 
74 	return val;
75 }
76 
clk_ti_mux_set_parent(struct clk * clk,struct clk * parent)77 static int clk_ti_mux_set_parent(struct clk *clk, struct clk *parent)
78 {
79 	struct clk_ti_mux_priv *priv = dev_get_priv(clk->dev);
80 	int index;
81 	u32 val;
82 
83 	index = clk_ti_mux_get_parent_index(&priv->parents, parent);
84 	if (index < 0) {
85 		dev_err(clk->dev, "failed to get parent clock\n");
86 		return index;
87 	}
88 
89 	index = clk_mux_index_to_val(NULL, priv->flags, index);
90 
91 	if (priv->flags & CLK_MUX_HIWORD_MASK) {
92 		val = priv->mask << (priv->shift + 16);
93 	} else {
94 		val = readl(priv->reg);
95 		val &= ~(priv->mask << priv->shift);
96 	}
97 
98 	val |= index << priv->shift;
99 	writel(val, priv->reg);
100 	clk_ti_latch(priv->reg, priv->latch);
101 	return 0;
102 }
103 
clk_ti_mux_set_rate(struct clk * clk,ulong rate)104 static ulong clk_ti_mux_set_rate(struct clk *clk, ulong rate)
105 {
106 	struct clk_ti_mux_priv *priv = dev_get_priv(clk->dev);
107 	struct clk *parent;
108 	int index;
109 
110 	if ((clk->flags & CLK_SET_RATE_PARENT) == 0)
111 		return -ENOSYS;
112 
113 	index = clk_ti_mux_get_index(clk);
114 	parent = clk_ti_mux_get_parent_by_index(&priv->parents, index);
115 	if (IS_ERR(parent))
116 		return PTR_ERR(parent);
117 
118 	rate = clk_set_rate(parent, rate);
119 	dev_dbg(clk->dev, "rate=%ld\n", rate);
120 	return rate;
121 }
122 
clk_ti_mux_get_rate(struct clk * clk)123 static ulong clk_ti_mux_get_rate(struct clk *clk)
124 {
125 	struct clk_ti_mux_priv *priv = dev_get_priv(clk->dev);
126 	int index;
127 	struct clk *parent;
128 	ulong rate;
129 
130 	index = clk_ti_mux_get_index(clk);
131 	parent = clk_ti_mux_get_parent_by_index(&priv->parents, index);
132 	if (IS_ERR(parent))
133 		return PTR_ERR(parent);
134 
135 	rate = clk_get_rate(parent);
136 	dev_dbg(clk->dev, "rate=%ld\n", rate);
137 	return rate;
138 }
139 
clk_ti_mux_round_rate(struct clk * clk,ulong rate)140 static ulong clk_ti_mux_round_rate(struct clk *clk, ulong rate)
141 {
142 	struct clk_ti_mux_priv *priv = dev_get_priv(clk->dev);
143 	struct clk *parent;
144 	int index;
145 
146 	if ((clk->flags & CLK_SET_RATE_PARENT) == 0)
147 		return -ENOSYS;
148 
149 	index = clk_ti_mux_get_index(clk);
150 	parent = clk_ti_mux_get_parent_by_index(&priv->parents, index);
151 	if (IS_ERR(parent))
152 		return PTR_ERR(parent);
153 
154 	rate = clk_round_rate(parent, rate);
155 	dev_dbg(clk->dev, "rate=%ld\n", rate);
156 	return rate;
157 }
158 
clk_ti_mux_request(struct clk * clk)159 static int clk_ti_mux_request(struct clk *clk)
160 {
161 	struct clk_ti_mux_priv *priv = dev_get_priv(clk->dev);
162 	struct clk *parent;
163 	int index;
164 
165 	clk->flags = priv->flags;
166 
167 	index = clk_ti_mux_get_index(clk);
168 	parent = clk_ti_mux_get_parent_by_index(&priv->parents, index);
169 	if (IS_ERR(parent))
170 		return PTR_ERR(parent);
171 
172 	return clk_ti_mux_set_parent(clk, parent);
173 }
174 
175 static struct clk_ops clk_ti_mux_ops = {
176 	.request = clk_ti_mux_request,
177 	.round_rate = clk_ti_mux_round_rate,
178 	.get_rate = clk_ti_mux_get_rate,
179 	.set_rate = clk_ti_mux_set_rate,
180 	.set_parent = clk_ti_mux_set_parent,
181 };
182 
clk_ti_mux_remove(struct udevice * dev)183 static int clk_ti_mux_remove(struct udevice *dev)
184 {
185 	struct clk_ti_mux_priv *priv = dev_get_priv(dev);
186 	int err;
187 
188 	err = clk_release_all(priv->parents.clks, priv->parents.count);
189 	if (err)
190 		dev_dbg(dev, "could not release all parents' clocks\n");
191 
192 	return err;
193 }
194 
clk_ti_mux_probe(struct udevice * dev)195 static int clk_ti_mux_probe(struct udevice *dev)
196 {
197 	struct clk_ti_mux_priv *priv = dev_get_priv(dev);
198 	int err;
199 
200 	err = clk_get_bulk(dev, &priv->parents);
201 	if (err || priv->parents.count < 2) {
202 		dev_err(dev, "mux-clock must have parents\n");
203 		return err ? err : -EFAULT;
204 	}
205 
206 	/* Generate bit-mask based on parents info */
207 	priv->mask = priv->parents.count;
208 	if (!(priv->mux_flags & CLK_MUX_INDEX_ONE))
209 		priv->mask--;
210 
211 	priv->mask = (1 << fls(priv->mask)) - 1;
212 	return 0;
213 }
214 
clk_ti_mux_of_to_plat(struct udevice * dev)215 static int clk_ti_mux_of_to_plat(struct udevice *dev)
216 {
217 	struct clk_ti_mux_priv *priv = dev_get_priv(dev);
218 
219 	priv->reg = dev_read_addr(dev);
220 	if (priv->reg == FDT_ADDR_T_NONE) {
221 		dev_err(dev, "failed to get register\n");
222 		return -EINVAL;
223 	}
224 
225 	dev_dbg(dev, "reg=0x%08lx\n", priv->reg);
226 	priv->shift = dev_read_u32_default(dev, "ti,bit-shift", 0);
227 	priv->latch = dev_read_s32_default(dev, "ti,latch-bit", -EINVAL);
228 
229 	priv->flags = CLK_SET_RATE_NO_REPARENT;
230 	if (dev_read_bool(dev, "ti,set-rate-parent"))
231 		priv->flags |= CLK_SET_RATE_PARENT;
232 
233 	if (dev_read_bool(dev, "ti,index-starts-at-one"))
234 		priv->mux_flags |= CLK_MUX_INDEX_ONE;
235 
236 	return 0;
237 }
238 
239 static const struct udevice_id clk_ti_mux_of_match[] = {
240 	{.compatible = "ti,mux-clock"},
241 	{},
242 };
243 
244 U_BOOT_DRIVER(clk_ti_mux) = {
245 	.name = "ti_mux_clock",
246 	.id = UCLASS_CLK,
247 	.of_match = clk_ti_mux_of_match,
248 	.of_to_plat = clk_ti_mux_of_to_plat,
249 	.probe = clk_ti_mux_probe,
250 	.remove = clk_ti_mux_remove,
251 	.priv_auto = sizeof(struct clk_ti_mux_priv),
252 	.ops = &clk_ti_mux_ops,
253 };
254