• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 	}
115 
116 	if (check_cnt) {
117 		regmap_read(pvtm->grf, info->sta + 0x4, &val);
118 	} else {
119 		pr_err("%s: wait pvtm_done timeout!\n", __func__);
120 		val = 0;
121 	}
122 
123 	regmap_write(pvtm->grf, info->con, wr_msk_bit(0, 0, 0x3));
124 
125 	return val;
126 }
127 
rockchip_clock_pvtm_init_freq(struct rockchip_clock_pvtm * pvtm)128 static int rockchip_clock_pvtm_init_freq(struct rockchip_clock_pvtm *pvtm)
129 {
130 	u32 pvtm_cnt = 0;
131 	u32 div, time_us;
132 	int ret = 0;
133 
134 	time_us = 1000;
135 	pvtm_cnt = pvtm->info->get_value(pvtm, time_us);
136 	pr_debug("get pvtm_cnt = %d\n", pvtm_cnt);
137 
138 	/* set pvtm_div to get rate */
139 	div = DIV_ROUND_UP(1000 * pvtm_cnt,  pvtm->rate);
140 	if (div > pvtm->info->div_mask) {
141 		pr_err("pvtm_div out of bounary! set max instead\n");
142 		div = pvtm->info->div_mask;
143 	}
144 
145 	pr_debug("set div %d, rate %luKHZ\n", div, pvtm->rate);
146 	ret = regmap_write(pvtm->grf, pvtm->info->con,
147 			   wr_msk_bit(div, pvtm->info->div_shift,
148 				      pvtm->info->div_mask));
149 	if (ret != 0)
150 		goto out;
151 
152 	/* pmu pvtm oscilator enable */
153 	ret = regmap_write(pvtm->grf, pvtm->info->con,
154 			   wr_msk_bit(1, 1, 0x1));
155 	if (ret != 0)
156 		goto out;
157 
158 	ret = pvtm->info->sel_enable(pvtm);
159 out:
160 	if (ret != 0)
161 		pr_err("%s: fail to write register\n", __func__);
162 
163 	return ret;
164 }
165 
clock_pvtm_regitstor(struct device * dev,struct rockchip_clock_pvtm * pvtm)166 static int clock_pvtm_regitstor(struct device *dev,
167 				struct rockchip_clock_pvtm *pvtm)
168 {
169 	struct clk_init_data init = {};
170 	struct clk_hw *clk_hw;
171 
172 	/* Init the xin32k_pvtm */
173 	pvtm->info->init_freq(pvtm);
174 
175 	init.parent_names = NULL;
176 	init.num_parents = 0;
177 	init.name = "xin32k_pvtm";
178 	init.ops = &xin32k_pvtm;
179 
180 	clk_hw = devm_kzalloc(dev, sizeof(*clk_hw), GFP_KERNEL);
181 	if (!clk_hw)
182 		return -ENOMEM;
183 	clk_hw->init = &init;
184 
185 	/* optional override of the clockname */
186 	of_property_read_string_index(dev->of_node, "clock-output-names",
187 				      0, &init.name);
188 	pvtm->clk = devm_clk_register(dev, clk_hw);
189 	if (IS_ERR(pvtm->clk))
190 		return PTR_ERR(pvtm->clk);
191 
192 	return of_clk_add_provider(dev->of_node, of_clk_src_simple_get,
193 				   pvtm->clk);
194 }
195 
196 static const struct rockchip_clock_pvtm_info rk3368_pvtm_data = {
197 	.con = 0x180,
198 	.sta = 0x190,
199 	.sel_con = 0x100,
200 	.sel_shift = 6,
201 	.sel_value = CLK_SEL_INTERNAL_PVTM,
202 	.sel_mask = 0x1,
203 	.div_shift = 2,
204 	.div_mask = 0x3f,
205 
206 	.sel_enable = rockchip_clock_sel_internal_pvtm,
207 	.get_value = rockchip_clock_pvtm_get_value,
208 	.init_freq = rockchip_clock_pvtm_init_freq,
209 };
210 
211 static const struct of_device_id rockchip_clock_pvtm_match[] = {
212 	{
213 		.compatible = "rockchip,rk3368-pvtm-clock",
214 		.data = (void *)&rk3368_pvtm_data,
215 	},
216 	{}
217 };
218 MODULE_DEVICE_TABLE(of, rockchip_clock_pvtm_match);
219 
rockchip_clock_pvtm_probe(struct platform_device * pdev)220 static int rockchip_clock_pvtm_probe(struct platform_device *pdev)
221 {
222 	struct device *dev = &pdev->dev;
223 	struct device_node *np = pdev->dev.of_node;
224 	const struct of_device_id *match;
225 	struct rockchip_clock_pvtm *pvtm;
226 	int error;
227 	u32 rate;
228 
229 	pvtm = devm_kzalloc(dev, sizeof(*pvtm), GFP_KERNEL);
230 	if (!pvtm)
231 		return -ENOMEM;
232 
233 	match = of_match_node(rockchip_clock_pvtm_match, np);
234 	if (!match)
235 		return -ENXIO;
236 
237 	pvtm->info = (const struct rockchip_clock_pvtm_info *)match->data;
238 	if (!pvtm->info)
239 		return -EINVAL;
240 
241 	if (!dev->parent || !dev->parent->of_node)
242 		return -EINVAL;
243 
244 	pvtm->grf = syscon_node_to_regmap(dev->parent->of_node);
245 	if (IS_ERR(pvtm->grf))
246 		return PTR_ERR(pvtm->grf);
247 
248 	if (!of_property_read_u32(np, "pvtm-rate", &rate))
249 		pvtm->rate  = rate;
250 	else
251 		pvtm->rate  = 32768;
252 
253 	pvtm->pvtm_clk = devm_clk_get(&pdev->dev, "pvtm_pmu_clk");
254 	if (IS_ERR(pvtm->pvtm_clk)) {
255 		error = PTR_ERR(pvtm->pvtm_clk);
256 		if (error != -EPROBE_DEFER)
257 			dev_err(&pdev->dev,
258 				"failed to get pvtm core clock: %d\n",
259 				error);
260 		goto out_probe;
261 	}
262 
263 	error = clk_prepare_enable(pvtm->pvtm_clk);
264 	if (error) {
265 		dev_err(&pdev->dev, "failed to enable the clock: %d\n",
266 			error);
267 		goto out_probe;
268 	}
269 
270 	platform_set_drvdata(pdev, pvtm);
271 
272 	error = clock_pvtm_regitstor(&pdev->dev, pvtm);
273 	if (error) {
274 		dev_err(&pdev->dev, "failed to registor clock: %d\n",
275 			error);
276 		goto out_clk_put;
277 	}
278 
279 	return error;
280 
281 out_clk_put:
282 	clk_disable_unprepare(pvtm->pvtm_clk);
283 out_probe:
284 	return error;
285 }
286 
rockchip_clock_pvtm_remove(struct platform_device * pdev)287 static int rockchip_clock_pvtm_remove(struct platform_device *pdev)
288 {
289 	struct rockchip_clock_pvtm *pvtm = platform_get_drvdata(pdev);
290 	struct device_node *np = pdev->dev.of_node;
291 
292 	of_clk_del_provider(np);
293 	clk_disable_unprepare(pvtm->pvtm_clk);
294 
295 	return 0;
296 }
297 
298 static struct platform_driver rockchip_clock_pvtm_driver = {
299 	.driver = {
300 		.name = "rockchip-clcok-pvtm",
301 		.of_match_table = rockchip_clock_pvtm_match,
302 	},
303 	.probe = rockchip_clock_pvtm_probe,
304 	.remove = rockchip_clock_pvtm_remove,
305 };
306 
307 module_platform_driver(rockchip_clock_pvtm_driver);
308 
309 MODULE_DESCRIPTION("Rockchip Clock Pvtm Driver");
310 MODULE_LICENSE("GPL v2");
311