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