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, unsigned int time_us);
37     int (*init_freq)(struct rockchip_clock_pvtm *pvtm);
38     int (*sel_enable)(struct rockchip_clock_pvtm *pvtm);
39 };
40 
41 struct rockchip_clock_pvtm {
42     const struct rockchip_clock_pvtm_info *info;
43     struct regmap *grf;
44     struct clk *pvtm_clk;
45     struct clk *clk;
46     unsigned long rate;
47 };
48 
xin32k_pvtm_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)49 static unsigned long xin32k_pvtm_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
50 {
51     return 0x8000;
52 }
53 
54 static const struct clk_ops xin32k_pvtm = {
55     .recalc_rate = xin32k_pvtm_recalc_rate,
56 };
57 
rockchip_clock_pvtm_delay(unsigned int delay)58 static void rockchip_clock_pvtm_delay(unsigned int delay)
59 {
60     unsigned int ms = delay / 0x3e8;
61     unsigned int us = delay % 0x3e8;
62 
63     if (ms > 0) {
64         if (ms < 0x14) {
65             us += ms * 0x3e8;
66         } else {
67             msleep(ms);
68         }
69     }
70 
71     if (us >= 0xa) {
72         usleep_range(us, us + 0x64);
73     } else {
74         udelay(us);
75     }
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, pvtm->info->sel_shift, pvtm->info->sel_mask));
84     if (ret != 0) {
85         pr_err("%s: fail to write register\n", __func__);
86     }
87 
88     return ret;
89 }
90 
91 /* get pmu pvtm value */
rockchip_clock_pvtm_get_value(struct rockchip_clock_pvtm *pvtm, u32 time_us)92 static u32 rockchip_clock_pvtm_get_value(struct rockchip_clock_pvtm *pvtm, u32 time_us)
93 {
94     const struct rockchip_clock_pvtm_info *info = pvtm->info;
95     u32 val = 0, sta = 0;
96     u32 clk_cnt, check_cnt;
97 
98     /* 24m clk ,24cnt=1us */
99     clk_cnt = time_us * 0x18;
100 
101     regmap_write(pvtm->grf, info->con + 0x4, clk_cnt);
102     regmap_write(pvtm->grf, info->con, wr_msk_bit(0x3, 0, 0x3));
103 
104     rockchip_clock_pvtm_delay(time_us);
105 
106     check_cnt = 0x64;
107     while (check_cnt--) {
108         regmap_read(pvtm->grf, info->sta, &sta);
109         if (sta & 0x1) {
110             break;
111         }
112         udelay(0x4);
113     }
114 
115     if (check_cnt) {
116         regmap_read(pvtm->grf, info->sta + 0x4, &val);
117     } else {
118         pr_err("%s: wait pvtm_done timeout!\n", __func__);
119         val = 0;
120     }
121 
122     regmap_write(pvtm->grf, info->con, wr_msk_bit(0, 0, 0x3));
123 
124     return val;
125 }
126 
rockchip_clock_pvtm_init_freq(struct rockchip_clock_pvtm *pvtm)127 static int rockchip_clock_pvtm_init_freq(struct rockchip_clock_pvtm *pvtm)
128 {
129     u32 pvtm_cnt = 0;
130     u32 div, time_us;
131     int ret = 0;
132 
133     time_us = 0x3e8;
134     pvtm_cnt = pvtm->info->get_value(pvtm, time_us);
135     pr_debug("get pvtm_cnt = %d\n", pvtm_cnt);
136 
137     /* set pvtm_div to get rate */
138     div = DIV_ROUND_UP(0x3e8 * pvtm_cnt, pvtm->rate);
139     if (div > pvtm->info->div_mask) {
140         pr_err("pvtm_div out of bounary! set max instead\n");
141         div = pvtm->info->div_mask;
142     }
143 
144     pr_debug("set div %d, rate %luKHZ\n", div, pvtm->rate);
145     ret = regmap_write(pvtm->grf, pvtm->info->con, wr_msk_bit(div, pvtm->info->div_shift, pvtm->info->div_mask));
146     if (ret != 0) {
147         goto out;
148     }
149 
150     /* pmu pvtm oscilator enable */
151     ret = regmap_write(pvtm->grf, pvtm->info->con, wr_msk_bit(1, 1, 0x1));
152     if (ret != 0) {
153         goto out;
154     }
155 
156     ret = pvtm->info->sel_enable(pvtm);
157 out:
158     if (ret != 0) {
159         pr_err("%s: fail to write register\n", __func__);
160     }
161 
162     return ret;
163 }
164 
clock_pvtm_regitstor(struct device *dev, struct rockchip_clock_pvtm *pvtm)165 static int clock_pvtm_regitstor(struct device *dev, struct rockchip_clock_pvtm *pvtm)
166 {
167     struct clk_init_data init = {};
168     struct clk_hw *clk_hw;
169 
170     /* Init the xin32k_pvtm */
171     pvtm->info->init_freq(pvtm);
172 
173     init.parent_names = NULL;
174     init.num_parents = 0;
175     init.name = "xin32k_pvtm";
176     init.ops = &xin32k_pvtm;
177 
178     clk_hw = devm_kzalloc(dev, sizeof(*clk_hw), GFP_KERNEL);
179     if (!clk_hw) {
180         return -ENOMEM;
181     }
182     clk_hw->init = &init;
183 
184     /* optional override of the clockname */
185     of_property_read_string_index(dev->of_node, "clock-output-names", 0, &init.name);
186     pvtm->clk = devm_clk_register(dev, clk_hw);
187     if (IS_ERR(pvtm->clk)) {
188         return PTR_ERR(pvtm->clk);
189     }
190 
191     return of_clk_add_provider(dev->of_node, of_clk_src_simple_get, pvtm->clk);
192 }
193 
194 static const struct rockchip_clock_pvtm_info rk3368_pvtm_data = {
195     .con = 0x180,
196     .sta = 0x190,
197     .sel_con = 0x100,
198     .sel_shift = 6,
199     .sel_value = CLK_SEL_INTERNAL_PVTM,
200     .sel_mask = 0x1,
201     .div_shift = 2,
202     .div_mask = 0x3f,
203 
204     .sel_enable = rockchip_clock_sel_internal_pvtm,
205     .get_value = rockchip_clock_pvtm_get_value,
206     .init_freq = rockchip_clock_pvtm_init_freq,
207 };
208 
209 static const struct of_device_id rockchip_clock_pvtm_match[] = {{
210     .compatible = "rockchip,rk3368-pvtm-clock",
211     .data = (void *)&rk3368_pvtm_data,
212     },
213     {}};
214 MODULE_DEVICE_TABLE(of, rockchip_clock_pvtm_match);
215 
rockchip_clock_pvtm_probe(struct platform_device *pdev)216 static int rockchip_clock_pvtm_probe(struct platform_device *pdev)
217 {
218     struct device *dev = &pdev->dev;
219     struct device_node *np = pdev->dev.of_node;
220     const struct of_device_id *match;
221     struct rockchip_clock_pvtm *pvtm;
222     int error;
223     u32 rate;
224 
225     pvtm = devm_kzalloc(dev, sizeof(*pvtm), GFP_KERNEL);
226     if (!pvtm) {
227         return -ENOMEM;
228     }
229 
230     match = of_match_node(rockchip_clock_pvtm_match, np);
231     if (!match) {
232         return -ENXIO;
233     }
234 
235     pvtm->info = (const struct rockchip_clock_pvtm_info *)match->data;
236     if (!pvtm->info) {
237         return -EINVAL;
238     }
239 
240     if (!dev->parent || !dev->parent->of_node) {
241         return -EINVAL;
242     }
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 
249     if (!of_property_read_u32(np, "pvtm-rate", &rate)) {
250         pvtm->rate = rate;
251     } else {
252         pvtm->rate = 0x8000;
253     }
254 
255     pvtm->pvtm_clk = devm_clk_get(&pdev->dev, "pvtm_pmu_clk");
256     if (IS_ERR(pvtm->pvtm_clk)) {
257         error = PTR_ERR(pvtm->pvtm_clk);
258         if (error != -EPROBE_DEFER) {
259             dev_err(&pdev->dev, "failed to get pvtm core clock: %d\n", error);
260         }
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", 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", error);
275         goto out_clk_put;
276     }
277 
278     return error;
279 
280 out_clk_put:
281     clk_disable_unprepare(pvtm->pvtm_clk);
282 out_probe:
283     return error;
284 }
285 
rockchip_clock_pvtm_remove(struct platform_device *pdev)286 static int rockchip_clock_pvtm_remove(struct platform_device *pdev)
287 {
288     struct rockchip_clock_pvtm *pvtm = platform_get_drvdata(pdev);
289     struct device_node *np = pdev->dev.of_node;
290 
291     of_clk_del_provider(np);
292     clk_disable_unprepare(pvtm->pvtm_clk);
293 
294     return 0;
295 }
296 
297 static struct platform_driver rockchip_clock_pvtm_driver = {
298     .driver =
299         {
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