xref: /OK3568_Linux_fs/kernel/drivers/clk/rockchip/regmap/clk-rk618.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright (c) 2017 Rockchip Electronics Co. Ltd.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  */
14 
15 #include <linux/clk.h>
16 #include <linux/module.h>
17 #include <linux/platform_device.h>
18 #include <linux/clk-provider.h>
19 #include <linux/mfd/rk618.h>
20 
21 #include "clk-regmap.h"
22 
23 #define RK618_CRU_CLKSEL0		0x0058
24 #define RK618_CRU_CLKSEL1		0x005c
25 #define RK618_CRU_CLKSEL2		0x0060
26 #define RK618_CRU_CLKSEL3		0x0064
27 #define RK618_CRU_PLL0_CON0		0x0068
28 #define RK618_CRU_PLL0_CON1		0x006c
29 #define RK618_CRU_PLL0_CON2		0x0070
30 #define RK618_CRU_PLL1_CON0		0x0074
31 #define RK618_CRU_PLL1_CON1		0x0078
32 #define RK618_CRU_PLL1_CON2		0x007c
33 
34 enum {
35 	LCDC0_CLK = 1,
36 	LCDC1_CLK,
37 	VIF_PLLIN_CLK,
38 	SCALER_PLLIN_CLK,
39 	VIF_PLL_CLK,
40 	SCALER_PLL_CLK,
41 	VIF0_CLK,
42 	VIF1_CLK,
43 	SCALER_IN_CLK,
44 	SCALER_CLK,
45 	DITHER_CLK,
46 	HDMI_CLK,
47 	MIPI_CLK,
48 	LVDS_CLK,
49 	LVTTL_CLK,
50 	RGB_CLK,
51 	VIF0_PRE_CLK,
52 	VIF1_PRE_CLK,
53 	CODEC_CLK,
54 	NR_CLKS,
55 };
56 
57 struct rk618_cru {
58 	struct device *dev;
59 	struct rk618 *parent;
60 	struct regmap *regmap;
61 
62 	struct clk_onecell_data clk_data;
63 };
64 
65 static char clkin_name[32] = "dummy";
66 static char lcdc0_dclkp_name[32] = "dummy";
67 static char lcdc1_dclkp_name[32] = "dummy";
68 
69 #define PNAME(x) static const char *const x[]
70 
71 PNAME(mux_pll_in_p) = { "lcdc0_clk", "lcdc1_clk", clkin_name };
72 PNAME(mux_pll_src_p) = { "vif_pll_clk", "scaler_pll_clk", };
73 PNAME(mux_scaler_in_src_p) = { "vif0_clk", "vif1_clk" };
74 PNAME(mux_hdmi_src_p) = { "vif1_clk", "scaler_clk", "vif0_clk" };
75 PNAME(mux_dither_src_p) = { "vif0_clk", "scaler_clk" };
76 PNAME(mux_vif0_src_p) = { "vif0_pre_clk", lcdc0_dclkp_name };
77 PNAME(mux_vif1_src_p) = { "vif1_pre_clk", lcdc1_dclkp_name };
78 PNAME(mux_codec_src_p) = { "codec_pre_clk", clkin_name };
79 
80 /* Two PLL, one for dual datarate input logic, the other for scaler */
81 static const struct clk_pll_data rk618_clk_plls[] = {
82 	RK618_PLL(VIF_PLL_CLK, "vif_pll_clk", "vif_pllin_clk",
83 		  RK618_CRU_PLL0_CON0,
84 		  0),
85 	RK618_PLL(SCALER_PLL_CLK, "scaler_pll_clk", "scaler_pllin_clk",
86 		  RK618_CRU_PLL1_CON0,
87 		  0),
88 };
89 
90 static const struct clk_mux_data rk618_clk_muxes[] = {
91 	MUX(VIF_PLLIN_CLK, "vif_pllin_clk", mux_pll_in_p,
92 	    RK618_CRU_CLKSEL0, 6, 2,
93 	    0),
94 	MUX(SCALER_PLLIN_CLK, "scaler_pllin_clk", mux_pll_in_p,
95 	    RK618_CRU_CLKSEL0, 8, 2,
96 	    0),
97 	MUX(SCALER_IN_CLK, "scaler_in_clk", mux_scaler_in_src_p,
98 	    RK618_CRU_CLKSEL3, 15, 1,
99 	    0),
100 	MUX(DITHER_CLK, "dither_clk", mux_dither_src_p,
101 	    RK618_CRU_CLKSEL3, 14, 1,
102 	    0),
103 	MUX(VIF0_CLK, "vif0_clk", mux_vif0_src_p,
104 	    RK618_CRU_CLKSEL3, 1, 1,
105 	    CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT),
106 	MUX(VIF1_CLK, "vif1_clk", mux_vif1_src_p,
107 	    RK618_CRU_CLKSEL3, 7, 1,
108 	    CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT),
109 	MUX(CODEC_CLK, "codec_clk", mux_codec_src_p,
110 	    RK618_CRU_CLKSEL1, 1, 1,
111 	    CLK_SET_RATE_PARENT),
112 };
113 
114 static const struct clk_divider_data rk618_clk_dividers[] = {
115 	DIV(LCDC0_CLK, "lcdc0_clk", lcdc0_dclkp_name,
116 	    RK618_CRU_CLKSEL0, 0, 3,
117 	    0),
118 	DIV(LCDC1_CLK, "lcdc1_clk", lcdc1_dclkp_name,
119 	    RK618_CRU_CLKSEL0, 3, 3,
120 	    0),
121 };
122 
123 static const struct clk_gate_data rk618_clk_gates[] = {
124 	GATE(MIPI_CLK, "mipi_clk", "dither_clk",
125 	     RK618_CRU_CLKSEL1, 10,
126 	     CLK_IGNORE_UNUSED),
127 	GATE(LVDS_CLK, "lvds_clk", "dither_clk",
128 	     RK618_CRU_CLKSEL1, 9,
129 	     CLK_IGNORE_UNUSED),
130 	GATE(LVTTL_CLK, "lvttl_clk", "dither_clk",
131 	     RK618_CRU_CLKSEL1, 12,
132 	     0),
133 	GATE(RGB_CLK, "rgb_clk", "dither_clk",
134 	     RK618_CRU_CLKSEL1, 11,
135 	     0),
136 };
137 
138 static const struct clk_composite_data rk618_clk_composites[] = {
139 	COMPOSITE(SCALER_CLK, "scaler_clk", mux_pll_src_p,
140 		  RK618_CRU_CLKSEL1, 3, 1,
141 		  RK618_CRU_CLKSEL1, 5, 3,
142 		  RK618_CRU_CLKSEL1, 4,
143 		  CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT),
144 	COMPOSITE_NODIV(HDMI_CLK, "hdmi_clk", mux_hdmi_src_p,
145 			RK618_CRU_CLKSEL3, 12, 2,
146 			RK618_CRU_CLKSEL1, 8,
147 			0),
148 	COMPOSITE(VIF0_PRE_CLK, "vif0_pre_clk", mux_pll_src_p,
149 		  RK618_CRU_CLKSEL3, 0, 1,
150 		  RK618_CRU_CLKSEL3, 3, 3,
151 		  RK618_CRU_CLKSEL3, 2,
152 		  CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT),
153 	COMPOSITE(VIF1_PRE_CLK, "vif1_pre_clk", mux_pll_src_p,
154 		  RK618_CRU_CLKSEL3, 6, 1,
155 		  RK618_CRU_CLKSEL3, 9, 3,
156 		  RK618_CRU_CLKSEL3, 8,
157 		  CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT),
158 	COMPOSITE_FRAC_NOGATE(0, "codec_pre_clk", mux_pll_src_p,
159 			      RK618_CRU_CLKSEL1, 0, 1,
160 			      RK618_CRU_CLKSEL2,
161 			      0),
162 };
163 
rk618_clk_add_lookup(struct rk618_cru * cru,struct clk * clk,unsigned int id)164 static void rk618_clk_add_lookup(struct rk618_cru *cru, struct clk *clk,
165 				 unsigned int id)
166 {
167 	if (cru->clk_data.clks && id)
168 		cru->clk_data.clks[id] = clk;
169 }
170 
rk618_clk_register_muxes(struct rk618_cru * cru)171 static void rk618_clk_register_muxes(struct rk618_cru *cru)
172 {
173 	struct clk *clk;
174 	unsigned int i;
175 
176 	for (i = 0; i < ARRAY_SIZE(rk618_clk_muxes); i++) {
177 		const struct clk_mux_data *data = &rk618_clk_muxes[i];
178 
179 		clk = devm_clk_regmap_register_mux(cru->dev, data->name,
180 						   data->parent_names,
181 						   data->num_parents,
182 						   cru->regmap, data->reg,
183 						   data->shift, data->width,
184 						   data->flags);
185 		if (IS_ERR(clk)) {
186 			dev_err(cru->dev, "failed to register clock %s\n",
187 				data->name);
188 			continue;
189 		}
190 
191 		rk618_clk_add_lookup(cru, clk, data->id);
192 	}
193 }
194 
rk618_clk_register_dividers(struct rk618_cru * cru)195 static void rk618_clk_register_dividers(struct rk618_cru *cru)
196 {
197 	struct clk *clk;
198 	unsigned int i;
199 
200 	for (i = 0; i < ARRAY_SIZE(rk618_clk_dividers); i++) {
201 		const struct clk_divider_data *data = &rk618_clk_dividers[i];
202 
203 		clk = devm_clk_regmap_register_divider(cru->dev, data->name,
204 						       data->parent_name,
205 						       cru->regmap, data->reg,
206 						       data->shift, data->width,
207 						       data->flags);
208 		if (IS_ERR(clk)) {
209 			dev_err(cru->dev, "failed to register clock %s\n",
210 				data->name);
211 			continue;
212 		}
213 
214 		rk618_clk_add_lookup(cru, clk, data->id);
215 	}
216 }
217 
rk618_clk_register_gates(struct rk618_cru * cru)218 static void rk618_clk_register_gates(struct rk618_cru *cru)
219 {
220 	struct clk *clk;
221 	unsigned int i;
222 
223 	for (i = 0; i < ARRAY_SIZE(rk618_clk_gates); i++) {
224 		const struct clk_gate_data *data = &rk618_clk_gates[i];
225 
226 		clk = devm_clk_regmap_register_gate(cru->dev, data->name,
227 						    data->parent_name,
228 						    cru->regmap,
229 						    data->reg, data->shift,
230 						    data->flags);
231 		if (IS_ERR(clk)) {
232 			dev_err(cru->dev, "failed to register clock %s\n",
233 				data->name);
234 			continue;
235 		}
236 
237 		rk618_clk_add_lookup(cru, clk, data->id);
238 	}
239 }
240 
rk618_clk_register_composites(struct rk618_cru * cru)241 static void rk618_clk_register_composites(struct rk618_cru *cru)
242 {
243 	struct clk *clk;
244 	unsigned int i;
245 
246 	for (i = 0; i < ARRAY_SIZE(rk618_clk_composites); i++) {
247 		const struct clk_composite_data *data =
248 					&rk618_clk_composites[i];
249 
250 		clk = devm_clk_regmap_register_composite(cru->dev, data->name,
251 							 data->parent_names,
252 							 data->num_parents,
253 							 cru->regmap,
254 							 data->mux_reg,
255 							 data->mux_shift,
256 							 data->mux_width,
257 							 data->div_reg,
258 							 data->div_shift,
259 							 data->div_width,
260 							 data->div_flags,
261 							 data->gate_reg,
262 							 data->gate_shift,
263 							 data->flags);
264 		if (IS_ERR(clk)) {
265 			dev_err(cru->dev, "failed to register clock %s\n",
266 				data->name);
267 			continue;
268 		}
269 
270 		rk618_clk_add_lookup(cru, clk, data->id);
271 	}
272 }
273 
rk618_clk_register_plls(struct rk618_cru * cru)274 static void rk618_clk_register_plls(struct rk618_cru *cru)
275 {
276 	struct clk *clk;
277 	unsigned int i;
278 
279 	for (i = 0; i < ARRAY_SIZE(rk618_clk_plls); i++) {
280 		const struct clk_pll_data *data = &rk618_clk_plls[i];
281 
282 		clk = devm_clk_regmap_register_pll(cru->dev, data->name,
283 						   data->parent_name,
284 						   cru->regmap,
285 						   data->reg,
286 						   data->pd_shift,
287 						   data->dsmpd_shift,
288 						   data->lock_shift,
289 						   data->flags);
290 		if (IS_ERR(clk)) {
291 			dev_err(cru->dev, "failed to register clock %s\n",
292 				data->name);
293 			continue;
294 		}
295 
296 		rk618_clk_add_lookup(cru, clk, data->id);
297 	}
298 }
299 
rk618_cru_probe(struct platform_device * pdev)300 static int rk618_cru_probe(struct platform_device *pdev)
301 {
302 	struct rk618 *rk618 = dev_get_drvdata(pdev->dev.parent);
303 	struct device *dev = &pdev->dev;
304 	struct rk618_cru *cru;
305 	struct clk **clk_table;
306 	const char *parent_name;
307 	struct clk *clk;
308 	int ret, i;
309 
310 	if (!of_device_is_available(dev->of_node))
311 		return -ENODEV;
312 
313 	cru = devm_kzalloc(dev, sizeof(*cru), GFP_KERNEL);
314 	if (!cru)
315 		return -ENOMEM;
316 
317 	clk_table = devm_kcalloc(dev, NR_CLKS, sizeof(struct clk *),
318 				 GFP_KERNEL);
319 	if (!clk_table)
320 		return -ENOMEM;
321 
322 	for (i = 0; i < NR_CLKS; i++)
323 		clk_table[i] = ERR_PTR(-ENOENT);
324 
325 	cru->dev = dev;
326 	cru->parent = rk618;
327 	cru->regmap = rk618->regmap;
328 	cru->clk_data.clks = clk_table;
329 	cru->clk_data.clk_num = NR_CLKS;
330 	platform_set_drvdata(pdev, cru);
331 
332 	clk = devm_clk_get(dev, "clkin");
333 	if (IS_ERR(clk)) {
334 		ret = PTR_ERR(clk);
335 		dev_err(dev, "failed to get clkin: %d\n", ret);
336 		return ret;
337 	}
338 
339 	strlcpy(clkin_name, __clk_get_name(clk), sizeof(clkin_name));
340 
341 	clk = devm_clk_get(dev, "lcdc0_dclkp");
342 	if (IS_ERR(clk)) {
343 		if (PTR_ERR(clk) != -ENOENT) {
344 			ret = PTR_ERR(clk);
345 			dev_err(dev, "failed to get lcdc0_dclkp: %d\n", ret);
346 			return ret;
347 		}
348 
349 		clk = NULL;
350 	}
351 
352 	parent_name = __clk_get_name(clk);
353 	if (parent_name)
354 		strlcpy(lcdc0_dclkp_name, parent_name,
355 			sizeof(lcdc0_dclkp_name));
356 
357 	clk = devm_clk_get(dev, "lcdc1_dclkp");
358 	if (IS_ERR(clk)) {
359 		if (PTR_ERR(clk) != -ENOENT) {
360 			ret = PTR_ERR(clk);
361 			dev_err(dev, "failed to get lcdc1_dclkp: %d\n", ret);
362 			return ret;
363 		}
364 
365 		clk = NULL;
366 	}
367 
368 	parent_name = __clk_get_name(clk);
369 	if (parent_name)
370 		strlcpy(lcdc1_dclkp_name, parent_name,
371 			sizeof(lcdc1_dclkp_name));
372 
373 	rk618_clk_register_plls(cru);
374 	rk618_clk_register_muxes(cru);
375 	rk618_clk_register_dividers(cru);
376 	rk618_clk_register_gates(cru);
377 	rk618_clk_register_composites(cru);
378 
379 	return of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
380 				   &cru->clk_data);
381 }
382 
rk618_cru_remove(struct platform_device * pdev)383 static int rk618_cru_remove(struct platform_device *pdev)
384 {
385 	of_clk_del_provider(pdev->dev.of_node);
386 
387 	return 0;
388 }
389 
390 static const struct of_device_id rk618_cru_of_match[] = {
391 	{ .compatible = "rockchip,rk618-cru", },
392 	{},
393 };
394 MODULE_DEVICE_TABLE(of, rk618_cru_of_match);
395 
396 static struct platform_driver rk618_cru_driver = {
397 	.driver = {
398 		.name = "rk618-cru",
399 		.of_match_table = of_match_ptr(rk618_cru_of_match),
400 	},
401 	.probe	= rk618_cru_probe,
402 	.remove = rk618_cru_remove,
403 };
404 module_platform_driver(rk618_cru_driver);
405 
406 MODULE_AUTHOR("Wyon Bi <bivvy.bi@rock-chips.com>");
407 MODULE_DESCRIPTION("Rockchip rk618 CRU driver");
408 MODULE_LICENSE("GPL v2");
409