xref: /linux/drivers/clk/clk-lan966x.c (revision ba65a4e7120a616d9c592750d9147f6dcafedffa)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Microchip LAN966x SoC Clock driver.
4  *
5  * Copyright (C) 2021 Microchip Technology, Inc. and its subsidiaries
6  *
7  * Author: Kavyasree Kotagiri <kavyasree.kotagiri@microchip.com>
8  */
9 
10 #include <linux/bitfield.h>
11 #include <linux/clk-provider.h>
12 #include <linux/io.h>
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 #include <linux/of.h>
16 #include <linux/platform_device.h>
17 #include <linux/slab.h>
18 
19 #define GCK_ENA         BIT(0)
20 #define GCK_SRC_SEL     GENMASK(9, 8)
21 #define GCK_PRESCALER   GENMASK(23, 16)
22 
23 #define DIV_MAX		255
24 
25 static const char * const lan966x_clk_names[] = {
26 	"qspi0", "qspi1", "qspi2", "sdmmc0",
27 	"pi", "mcan0", "mcan1", "flexcom0",
28 	"flexcom1", "flexcom2", "flexcom3",
29 	"flexcom4", "timer1", "usb_refclk",
30 };
31 
32 static const char * const lan969x_clk_names[] = {
33 	"qspi0", "qspi2", "sdmmc0", "sdmmc1",
34 	"mcan0", "mcan1", "flexcom0",
35 	"flexcom1", "flexcom2", "flexcom3",
36 	"timer1", "usb_refclk",
37 };
38 
39 struct lan966x_gck {
40 	struct clk_hw hw;
41 	void __iomem *reg;
42 };
43 #define to_lan966x_gck(hw) container_of(hw, struct lan966x_gck, hw)
44 
45 static const struct clk_parent_data lan966x_gck_pdata[] = {
46 	{ .fw_name = "cpu", },
47 	{ .fw_name = "ddr", },
48 	{ .fw_name = "sys", },
49 };
50 
51 static struct clk_init_data init = {
52 	.parent_data = lan966x_gck_pdata,
53 	.num_parents = ARRAY_SIZE(lan966x_gck_pdata),
54 };
55 
56 struct clk_gate_soc_desc {
57 	const char *name;
58 	int bit_idx;
59 };
60 
61 static const struct clk_gate_soc_desc lan966x_clk_gate_desc[] = {
62 	{ "uhphs", 11 },
63 	{ "udphs", 10 },
64 	{ "mcramc", 9 },
65 	{ "hmatrix", 8 },
66 	{ }
67 };
68 
69 static const struct clk_gate_soc_desc lan969x_clk_gate_desc[] = {
70 	{ "usb_drd", 10 },
71 	{ "mcramc", 9 },
72 	{ "hmatrix", 8 },
73 	{ }
74 };
75 
76 struct lan966x_match_data {
77 	char *name;
78 	const char * const *clk_name;
79 	const struct clk_gate_soc_desc *clk_gate_desc;
80 	u8 num_generic_clks;
81 	u8 num_total_clks;
82 };
83 
84 static struct lan966x_match_data lan966x_desc = {
85 	.name = "lan966x",
86 	.clk_name = lan966x_clk_names,
87 	.clk_gate_desc = lan966x_clk_gate_desc,
88 	.num_total_clks = 18,
89 	.num_generic_clks = 14,
90 };
91 
92 static struct lan966x_match_data lan969x_desc = {
93 	.name = "lan969x",
94 	.clk_name = lan969x_clk_names,
95 	.clk_gate_desc = lan969x_clk_gate_desc,
96 	.num_total_clks = 15,
97 	.num_generic_clks = 12,
98 };
99 
100 static DEFINE_SPINLOCK(clk_gate_lock);
101 static void __iomem *base;
102 
lan966x_gck_enable(struct clk_hw * hw)103 static int lan966x_gck_enable(struct clk_hw *hw)
104 {
105 	struct lan966x_gck *gck = to_lan966x_gck(hw);
106 	u32 val = readl(gck->reg);
107 
108 	val |= GCK_ENA;
109 	writel(val, gck->reg);
110 
111 	return 0;
112 }
113 
lan966x_gck_disable(struct clk_hw * hw)114 static void lan966x_gck_disable(struct clk_hw *hw)
115 {
116 	struct lan966x_gck *gck = to_lan966x_gck(hw);
117 	u32 val = readl(gck->reg);
118 
119 	val &= ~GCK_ENA;
120 	writel(val, gck->reg);
121 }
122 
lan966x_gck_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)123 static int lan966x_gck_set_rate(struct clk_hw *hw,
124 				unsigned long rate,
125 				unsigned long parent_rate)
126 {
127 	struct lan966x_gck *gck = to_lan966x_gck(hw);
128 	u32 div, val = readl(gck->reg);
129 
130 	if (rate == 0 || parent_rate == 0)
131 		return -EINVAL;
132 
133 	/* Set Prescalar */
134 	div = parent_rate / rate;
135 	val &= ~GCK_PRESCALER;
136 	val |= FIELD_PREP(GCK_PRESCALER, (div - 1));
137 	writel(val, gck->reg);
138 
139 	return 0;
140 }
141 
lan966x_gck_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)142 static unsigned long lan966x_gck_recalc_rate(struct clk_hw *hw,
143 					     unsigned long parent_rate)
144 {
145 	struct lan966x_gck *gck = to_lan966x_gck(hw);
146 	u32 div, val = readl(gck->reg);
147 
148 	div = FIELD_GET(GCK_PRESCALER, val);
149 
150 	return parent_rate / (div + 1);
151 }
152 
lan966x_gck_determine_rate(struct clk_hw * hw,struct clk_rate_request * req)153 static int lan966x_gck_determine_rate(struct clk_hw *hw,
154 				      struct clk_rate_request *req)
155 {
156 	struct clk_hw *parent;
157 	int i;
158 
159 	for (i = 0; i < clk_hw_get_num_parents(hw); ++i) {
160 		parent = clk_hw_get_parent_by_index(hw, i);
161 		if (!parent)
162 			continue;
163 
164 		/* Allowed prescaler divider range is 0-255 */
165 		if (clk_hw_get_rate(parent) / req->rate <= DIV_MAX) {
166 			req->best_parent_hw = parent;
167 			req->best_parent_rate = clk_hw_get_rate(parent);
168 
169 			return 0;
170 		}
171 	}
172 
173 	return -EINVAL;
174 }
175 
lan966x_gck_get_parent(struct clk_hw * hw)176 static u8 lan966x_gck_get_parent(struct clk_hw *hw)
177 {
178 	struct lan966x_gck *gck = to_lan966x_gck(hw);
179 	u32 val = readl(gck->reg);
180 
181 	return FIELD_GET(GCK_SRC_SEL, val);
182 }
183 
lan966x_gck_set_parent(struct clk_hw * hw,u8 index)184 static int lan966x_gck_set_parent(struct clk_hw *hw, u8 index)
185 {
186 	struct lan966x_gck *gck = to_lan966x_gck(hw);
187 	u32 val = readl(gck->reg);
188 
189 	val &= ~GCK_SRC_SEL;
190 	val |= FIELD_PREP(GCK_SRC_SEL, index);
191 	writel(val, gck->reg);
192 
193 	return 0;
194 }
195 
196 static const struct clk_ops lan966x_gck_ops = {
197 	.enable         = lan966x_gck_enable,
198 	.disable        = lan966x_gck_disable,
199 	.set_rate       = lan966x_gck_set_rate,
200 	.recalc_rate    = lan966x_gck_recalc_rate,
201 	.determine_rate = lan966x_gck_determine_rate,
202 	.set_parent     = lan966x_gck_set_parent,
203 	.get_parent     = lan966x_gck_get_parent,
204 };
205 
lan966x_gck_clk_register(struct device * dev,int i)206 static struct clk_hw *lan966x_gck_clk_register(struct device *dev, int i)
207 {
208 	struct lan966x_gck *priv;
209 	int ret;
210 
211 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
212 	if (!priv)
213 		return ERR_PTR(-ENOMEM);
214 
215 	priv->reg = base + (i * 4);
216 	priv->hw.init = &init;
217 	ret = devm_clk_hw_register(dev, &priv->hw);
218 	if (ret)
219 		return ERR_PTR(ret);
220 
221 	return &priv->hw;
222 };
223 
lan966x_gate_clk_register(struct device * dev,const struct lan966x_match_data * data,struct clk_hw_onecell_data * hw_data,void __iomem * gate_base)224 static int lan966x_gate_clk_register(struct device *dev,
225 				     const struct lan966x_match_data *data,
226 				     struct clk_hw_onecell_data *hw_data,
227 				     void __iomem *gate_base)
228 {
229 	for (int i = data->num_generic_clks; i < data->num_total_clks; ++i) {
230 		int idx = i - data->num_generic_clks;
231 		const struct clk_gate_soc_desc *desc;
232 
233 		desc = &data->clk_gate_desc[idx];
234 
235 		hw_data->hws[i] =
236 			devm_clk_hw_register_gate(dev, desc->name,
237 						  data->name, 0, gate_base,
238 						  desc->bit_idx,
239 						  0, &clk_gate_lock);
240 
241 		if (IS_ERR(hw_data->hws[i]))
242 			return dev_err_probe(dev, PTR_ERR(hw_data->hws[i]),
243 					     "failed to register %s clock\n",
244 					     desc->name);
245 	}
246 
247 	return 0;
248 }
249 
lan966x_clk_probe(struct platform_device * pdev)250 static int lan966x_clk_probe(struct platform_device *pdev)
251 {
252 	const struct lan966x_match_data *data;
253 	struct clk_hw_onecell_data *hw_data;
254 	struct device *dev = &pdev->dev;
255 	void __iomem *gate_base;
256 	struct resource *res;
257 	int i, ret;
258 
259 	data = device_get_match_data(dev);
260 	if (!data)
261 		return -EINVAL;
262 
263 	hw_data = devm_kzalloc(dev, struct_size(hw_data, hws, data->num_total_clks),
264 			       GFP_KERNEL);
265 	if (!hw_data)
266 		return -ENOMEM;
267 
268 	base = devm_platform_ioremap_resource(pdev, 0);
269 	if (IS_ERR(base))
270 		return PTR_ERR(base);
271 
272 	init.ops = &lan966x_gck_ops;
273 
274 	hw_data->num = data->num_generic_clks;
275 
276 	for (i = 0; i < data->num_generic_clks; i++) {
277 		init.name = data->clk_name[i];
278 		hw_data->hws[i] = lan966x_gck_clk_register(dev, i);
279 		if (IS_ERR(hw_data->hws[i])) {
280 			dev_err(dev, "failed to register %s clock\n",
281 				init.name);
282 			return PTR_ERR(hw_data->hws[i]);
283 		}
284 	}
285 
286 	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
287 	if (res) {
288 		gate_base = devm_ioremap_resource(&pdev->dev, res);
289 		if (IS_ERR(gate_base))
290 			return PTR_ERR(gate_base);
291 
292 		hw_data->num = data->num_total_clks;
293 
294 		ret = lan966x_gate_clk_register(dev, data, hw_data, gate_base);
295 		if (ret)
296 			return ret;
297 	}
298 
299 	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, hw_data);
300 }
301 
302 static const struct of_device_id lan966x_clk_dt_ids[] = {
303 	{ .compatible = "microchip,lan966x-gck", .data = &lan966x_desc },
304 	{ .compatible = "microchip,lan9691-gck", .data = &lan969x_desc },
305 	{ }
306 };
307 MODULE_DEVICE_TABLE(of, lan966x_clk_dt_ids);
308 
309 static struct platform_driver lan966x_clk_driver = {
310 	.probe  = lan966x_clk_probe,
311 	.driver = {
312 		.name = "lan966x-clk",
313 		.of_match_table = lan966x_clk_dt_ids,
314 	},
315 };
316 module_platform_driver(lan966x_clk_driver);
317 
318 MODULE_AUTHOR("Kavyasree Kotagiri <kavyasree.kotagiri@microchip.com>");
319 MODULE_DESCRIPTION("LAN966X clock driver");
320 MODULE_LICENSE("GPL v2");
321