xref: /OK3568_Linux_fs/kernel/drivers/clk/rockchip/clk-pvtm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd
4  */
5 
6 #include <linux/clk.h>
7 #include <linux/delay.h>
8 #include <linux/err.h>
9 #include <linux/mfd/syscon.h>
10 #include <linux/module.h>
11 #include <linux/of.h>
12 #include <linux/of_platform.h>
13 #include <linux/platform_device.h>
14 #include <linux/regmap.h>
15 #include <linux/slab.h>
16 #include <linux/string.h>
17 #include <linux/clk-provider.h>
18 
19 #define CLK_SEL_EXTERNAL_32K		0
20 #define CLK_SEL_INTERNAL_PVTM		1
21 
22 #define wr_msk_bit(v, off, msk)  ((v) << (off) | (msk << (16 + (off))))
23 
24 struct rockchip_clock_pvtm;
25 
26 struct rockchip_clock_pvtm_info {
27 	u32 con;
28 	u32 sta;
29 	u32 sel_con;
30 	u32 sel_shift;
31 	u32 sel_value;
32 	u32 sel_mask;
33 	u32 div_shift;
34 	u32 div_mask;
35 
36 	u32 (*get_value)(struct rockchip_clock_pvtm *pvtm,
37 			 unsigned int time_us);
38 	int (*init_freq)(struct rockchip_clock_pvtm *pvtm);
39 	int (*sel_enable)(struct rockchip_clock_pvtm *pvtm);
40 };
41 
42 struct rockchip_clock_pvtm {
43 	const struct rockchip_clock_pvtm_info *info;
44 	struct regmap *grf;
45 	struct clk *pvtm_clk;
46 	struct clk *clk;
47 	unsigned long rate;
48 };
49 
xin32k_pvtm_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)50 static unsigned long xin32k_pvtm_recalc_rate(struct clk_hw *hw,
51 					     unsigned long parent_rate)
52 {
53 	return 32768;
54 }
55 
56 static const struct clk_ops xin32k_pvtm = {
57 	.recalc_rate = xin32k_pvtm_recalc_rate,
58 };
59 
rockchip_clock_pvtm_delay(unsigned int delay)60 static void rockchip_clock_pvtm_delay(unsigned int delay)
61 {
62 	unsigned int ms = delay / 1000;
63 	unsigned int us = delay % 1000;
64 
65 	if (ms > 0) {
66 		if (ms < 20)
67 			us += ms * 1000;
68 		else
69 			msleep(ms);
70 	}
71 
72 	if (us >= 10)
73 		usleep_range(us, us + 100);
74 	else
75 		udelay(us);
76 }
77 
rockchip_clock_sel_internal_pvtm(struct rockchip_clock_pvtm * pvtm)78 static int rockchip_clock_sel_internal_pvtm(struct rockchip_clock_pvtm *pvtm)
79 {
80 	int ret = 0;
81 
82 	ret = regmap_write(pvtm->grf, pvtm->info->sel_con,
83 			   wr_msk_bit(pvtm->info->sel_value,
84 				      pvtm->info->sel_shift,
85 				      pvtm->info->sel_mask));
86 	if (ret != 0)
87 		pr_err("%s: fail to write register\n", __func__);
88 
89 	return ret;
90 }
91 
92 /* get pmu pvtm value */
rockchip_clock_pvtm_get_value(struct rockchip_clock_pvtm * pvtm,u32 time_us)93 static u32 rockchip_clock_pvtm_get_value(struct rockchip_clock_pvtm *pvtm,
94 					 u32 time_us)
95 {
96 	const struct rockchip_clock_pvtm_info *info = pvtm->info;
97 	u32 val = 0, sta = 0;
98 	u32 clk_cnt, check_cnt;
99 
100 	/* 24m clk ,24cnt=1us */
101 	clk_cnt = time_us * 24;
102 
103 	regmap_write(pvtm->grf, info->con + 0x4, clk_cnt);
104 	regmap_write(pvtm->grf, info->con, wr_msk_bit(3, 0, 0x3));
105 
106 	rockchip_clock_pvtm_delay(time_us);
107 
108 	check_cnt = 100;
109 	while (check_cnt) {
110 		regmap_read(pvtm->grf, info->sta, &sta);
111 		if (sta & 0x1)
112 			break;
113 		udelay(4);
114 		check_cnt--;
115 	}
116 
117 	if (check_cnt) {
118 		regmap_read(pvtm->grf, info->sta + 0x4, &val);
119 	} else {
120 		pr_err("%s: wait pvtm_done timeout!\n", __func__);
121 		val = 0;
122 	}
123 
124 	regmap_write(pvtm->grf, info->con, wr_msk_bit(0, 0, 0x3));
125 
126 	return val;
127 }
128 
rockchip_clock_pvtm_init_freq(struct rockchip_clock_pvtm * pvtm)129 static int rockchip_clock_pvtm_init_freq(struct rockchip_clock_pvtm *pvtm)
130 {
131 	u32 pvtm_cnt = 0;
132 	u32 div, time_us;
133 	int ret = 0;
134 
135 	time_us = 1000;
136 	pvtm_cnt = pvtm->info->get_value(pvtm, time_us);
137 	pr_debug("get pvtm_cnt = %d\n", pvtm_cnt);
138 
139 	/* set pvtm_div to get rate */
140 	div = DIV_ROUND_UP(1000 * pvtm_cnt,  pvtm->rate);
141 	if (div > pvtm->info->div_mask) {
142 		pr_err("pvtm_div out of bounary! set max instead\n");
143 		div = pvtm->info->div_mask;
144 	}
145 
146 	pr_debug("set div %d, rate %luKHZ\n", div, pvtm->rate);
147 	ret = regmap_write(pvtm->grf, pvtm->info->con,
148 			   wr_msk_bit(div, pvtm->info->div_shift,
149 				      pvtm->info->div_mask));
150 	if (ret != 0)
151 		goto out;
152 
153 	/* pmu pvtm oscilator enable */
154 	ret = regmap_write(pvtm->grf, pvtm->info->con,
155 			   wr_msk_bit(1, 1, 0x1));
156 	if (ret != 0)
157 		goto out;
158 
159 	ret = pvtm->info->sel_enable(pvtm);
160 out:
161 	if (ret != 0)
162 		pr_err("%s: fail to write register\n", __func__);
163 
164 	return ret;
165 }
166 
clock_pvtm_regitstor(struct device * dev,struct rockchip_clock_pvtm * pvtm)167 static int clock_pvtm_regitstor(struct device *dev,
168 				struct rockchip_clock_pvtm *pvtm)
169 {
170 	struct clk_init_data init = {};
171 	struct clk_hw *clk_hw;
172 
173 	/* Init the xin32k_pvtm */
174 	pvtm->info->init_freq(pvtm);
175 
176 	init.parent_names = NULL;
177 	init.num_parents = 0;
178 	init.name = "xin32k_pvtm";
179 	init.ops = &xin32k_pvtm;
180 
181 	clk_hw = devm_kzalloc(dev, sizeof(*clk_hw), GFP_KERNEL);
182 	if (!clk_hw)
183 		return -ENOMEM;
184 	clk_hw->init = &init;
185 
186 	/* optional override of the clockname */
187 	of_property_read_string_index(dev->of_node, "clock-output-names",
188 				      0, &init.name);
189 	pvtm->clk = devm_clk_register(dev, clk_hw);
190 	if (IS_ERR(pvtm->clk))
191 		return PTR_ERR(pvtm->clk);
192 
193 	return of_clk_add_provider(dev->of_node, of_clk_src_simple_get,
194 				   pvtm->clk);
195 }
196 
197 static const struct rockchip_clock_pvtm_info rk3368_pvtm_data = {
198 	.con = 0x180,
199 	.sta = 0x190,
200 	.sel_con = 0x100,
201 	.sel_shift = 6,
202 	.sel_value = CLK_SEL_INTERNAL_PVTM,
203 	.sel_mask = 0x1,
204 	.div_shift = 2,
205 	.div_mask = 0x3f,
206 
207 	.sel_enable = rockchip_clock_sel_internal_pvtm,
208 	.get_value = rockchip_clock_pvtm_get_value,
209 	.init_freq = rockchip_clock_pvtm_init_freq,
210 };
211 
212 static const struct of_device_id rockchip_clock_pvtm_match[] = {
213 	{
214 		.compatible = "rockchip,rk3368-pvtm-clock",
215 		.data = (void *)&rk3368_pvtm_data,
216 	},
217 	{}
218 };
219 MODULE_DEVICE_TABLE(of, rockchip_clock_pvtm_match);
220 
rockchip_clock_pvtm_probe(struct platform_device * pdev)221 static int rockchip_clock_pvtm_probe(struct platform_device *pdev)
222 {
223 	struct device *dev = &pdev->dev;
224 	struct device_node *np = pdev->dev.of_node;
225 	const struct of_device_id *match;
226 	struct rockchip_clock_pvtm *pvtm;
227 	int error;
228 	u32 rate;
229 
230 	pvtm = devm_kzalloc(dev, sizeof(*pvtm), GFP_KERNEL);
231 	if (!pvtm)
232 		return -ENOMEM;
233 
234 	match = of_match_node(rockchip_clock_pvtm_match, np);
235 	if (!match)
236 		return -ENXIO;
237 
238 	pvtm->info = (const struct rockchip_clock_pvtm_info *)match->data;
239 	if (!pvtm->info)
240 		return -EINVAL;
241 
242 	if (!dev->parent || !dev->parent->of_node)
243 		return -EINVAL;
244 
245 	pvtm->grf = syscon_node_to_regmap(dev->parent->of_node);
246 	if (IS_ERR(pvtm->grf))
247 		return PTR_ERR(pvtm->grf);
248 
249 	if (!of_property_read_u32(np, "pvtm-rate", &rate))
250 		pvtm->rate  = rate;
251 	else
252 		pvtm->rate  = 32768;
253 
254 	pvtm->pvtm_clk = devm_clk_get(&pdev->dev, "pvtm_pmu_clk");
255 	if (IS_ERR(pvtm->pvtm_clk)) {
256 		error = PTR_ERR(pvtm->pvtm_clk);
257 		if (error != -EPROBE_DEFER)
258 			dev_err(&pdev->dev,
259 				"failed to get pvtm core clock: %d\n",
260 				error);
261 		goto out_probe;
262 	}
263 
264 	error = clk_prepare_enable(pvtm->pvtm_clk);
265 	if (error) {
266 		dev_err(&pdev->dev, "failed to enable the clock: %d\n",
267 			error);
268 		goto out_probe;
269 	}
270 
271 	platform_set_drvdata(pdev, pvtm);
272 
273 	error = clock_pvtm_regitstor(&pdev->dev, pvtm);
274 	if (error) {
275 		dev_err(&pdev->dev, "failed to registor clock: %d\n",
276 			error);
277 		goto out_clk_put;
278 	}
279 
280 	return error;
281 
282 out_clk_put:
283 	clk_disable_unprepare(pvtm->pvtm_clk);
284 out_probe:
285 	return error;
286 }
287 
rockchip_clock_pvtm_remove(struct platform_device * pdev)288 static int rockchip_clock_pvtm_remove(struct platform_device *pdev)
289 {
290 	struct rockchip_clock_pvtm *pvtm = platform_get_drvdata(pdev);
291 	struct device_node *np = pdev->dev.of_node;
292 
293 	of_clk_del_provider(np);
294 	clk_disable_unprepare(pvtm->pvtm_clk);
295 
296 	return 0;
297 }
298 
299 static struct platform_driver rockchip_clock_pvtm_driver = {
300 	.driver = {
301 		.name = "rockchip-clcok-pvtm",
302 		.of_match_table = rockchip_clock_pvtm_match,
303 	},
304 	.probe = rockchip_clock_pvtm_probe,
305 	.remove = rockchip_clock_pvtm_remove,
306 };
307 
308 module_platform_driver(rockchip_clock_pvtm_driver);
309 
310 MODULE_DESCRIPTION("Rockchip Clock Pvtm Driver");
311 MODULE_LICENSE("GPL v2");
312