generic/4.4: remove ISSI SI25CD512 SPI flash support patch
[openwrt.git] / target / linux / mediatek / patches / 0033-cpufreq-mediatek-Add-MT8173-cpufreq-driver.patch
1 From 2028cb37c941014f6a817d27a867ee1d37ccf2b6 Mon Sep 17 00:00:00 2001
2 From: "pi-cheng.chen" <pi-cheng.chen@linaro.org>
3 Date: Mon, 8 Jun 2015 20:29:21 +0800
4 Subject: [PATCH 33/76] cpufreq: mediatek: Add MT8173 cpufreq driver
5
6 This patch implements MT8173 cpufreq driver.
7
8 Signed-off-by: Pi-Cheng Chen <pi-cheng.chen@linaro.org>
9 ---
10  drivers/cpufreq/Kconfig.arm      |    7 +
11  drivers/cpufreq/Makefile         |    1 +
12  drivers/cpufreq/mt8173-cpufreq.c |  550 ++++++++++++++++++++++++++++++++++++++
13  3 files changed, 558 insertions(+)
14  create mode 100644 drivers/cpufreq/mt8173-cpufreq.c
15
16 --- a/drivers/cpufreq/Kconfig.arm
17 +++ b/drivers/cpufreq/Kconfig.arm
18 @@ -141,6 +141,13 @@ config ARM_KIRKWOOD_CPUFREQ
19           This adds the CPUFreq driver for Marvell Kirkwood
20           SoCs.
21  
22 +config ARM_MT8173_CPUFREQ
23 +       bool "Mediatek MT8173 CPUFreq support"
24 +       depends on ARCH_MEDIATEK && REGULATOR
25 +       select PM_OPP
26 +       help
27 +         This adds the CPUFreq driver support for Mediatek MT8173 SoC.
28 +
29  config ARM_OMAP2PLUS_CPUFREQ
30         bool "TI OMAP2+"
31         depends on ARCH_OMAP2PLUS
32 --- a/drivers/cpufreq/Makefile
33 +++ b/drivers/cpufreq/Makefile
34 @@ -63,6 +63,7 @@ obj-$(CONFIG_ARM_HISI_ACPU_CPUFREQ)   += h
35  obj-$(CONFIG_ARM_IMX6Q_CPUFREQ)                += imx6q-cpufreq.o
36  obj-$(CONFIG_ARM_INTEGRATOR)           += integrator-cpufreq.o
37  obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ)     += kirkwood-cpufreq.o
38 +obj-$(CONFIG_ARM_MT8173_CPUFREQ)       += mt8173-cpufreq.o
39  obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)    += omap-cpufreq.o
40  obj-$(CONFIG_ARM_PXA2xx_CPUFREQ)       += pxa2xx-cpufreq.o
41  obj-$(CONFIG_PXA3xx)                   += pxa3xx-cpufreq.o
42 --- /dev/null
43 +++ b/drivers/cpufreq/mt8173-cpufreq.c
44 @@ -0,0 +1,550 @@
45 +/*
46 + * Copyright (c) 2015 Linaro Ltd.
47 + * Author: Pi-Cheng Chen <pi-cheng.chen@linaro.org>
48 + *
49 + * This program is free software; you can redistribute it and/or modify
50 + * it under the terms of the GNU General Public License version 2 as
51 + * published by the Free Software Foundation.
52 + *
53 + * This program is distributed in the hope that it will be useful,
54 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
55 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
56 + * GNU General Public License for more details.
57 + */
58 +
59 +#include <linux/clk.h>
60 +#include <linux/cpu.h>
61 +#include <linux/cpufreq.h>
62 +#include <linux/cpumask.h>
63 +#include <linux/module.h>
64 +#include <linux/of.h>
65 +#include <linux/platform_device.h>
66 +#include <linux/pm_opp.h>
67 +#include <linux/regulator/consumer.h>
68 +#include <linux/slab.h>
69 +
70 +#define MIN_VOLT_SHIFT         (100000)
71 +#define MAX_VOLT_SHIFT         (200000)
72 +#define MAX_VOLT_LIMIT         (1150000)
73 +#define VOLT_TOL               (10000)
74 +
75 +/*
76 + * The struct mtk_cpu_dvfs_info holds necessary information for doing CPU DVFS
77 + * on each CPU power/clock domain of Mediatek SoCs. Each CPU cluster in
78 + * Mediatek SoCs has two voltage inputs, Vproc and Vsram. In some cases the two
79 + * voltage inputs need to be controlled under a hardware limitation:
80 + * 100mV < Vsram - Vproc < 200mV
81 + *
82 + * When scaling the clock frequency of a CPU clock domain, the clock source
83 + * needs to be switched to another stable PLL clock temporarily until
84 + * the original PLL becomes stable at target frequency.
85 + */
86 +struct mtk_cpu_dvfs_info {
87 +       struct list_head node;
88 +       cpumask_var_t cpus;
89 +       struct cpufreq_frequency_table *freq_table;
90 +       struct device *cpu_dev;
91 +       struct regulator *proc_reg;
92 +       struct regulator *sram_reg;
93 +       struct clk *cpu_clk;
94 +       struct clk *inter_clk;
95 +       int intermediate_voltage;
96 +       bool need_voltage_trace;
97 +};
98 +
99 +static LIST_HEAD(cpu_dvfs_info_list);
100 +
101 +static inline struct mtk_cpu_dvfs_info *to_mtk_cpu_dvfs_info(
102 +                       struct list_head *list)
103 +{
104 +       return list_entry(list, struct mtk_cpu_dvfs_info, node);
105 +}
106 +
107 +static inline void mtk_cpu_dvfs_info_add(struct mtk_cpu_dvfs_info *info)
108 +{
109 +       list_add(&info->node, &cpu_dvfs_info_list);
110 +}
111 +
112 +static struct mtk_cpu_dvfs_info *mtk_cpu_dvfs_info_get(int cpu)
113 +{
114 +       struct mtk_cpu_dvfs_info *info;
115 +       struct list_head *list;
116 +
117 +       list_for_each(list, &cpu_dvfs_info_list) {
118 +               info = to_mtk_cpu_dvfs_info(list);
119 +
120 +               if (cpumask_test_cpu(cpu, info->cpus))
121 +                       return info;
122 +       }
123 +
124 +       return NULL;
125 +}
126 +
127 +static void mtk_cpu_dvfs_info_release(void)
128 +{
129 +       struct list_head *list, *tmp;
130 +       struct mtk_cpu_dvfs_info *info;
131 +
132 +       list_for_each_safe(list, tmp, &cpu_dvfs_info_list) {
133 +               info = to_mtk_cpu_dvfs_info(list);
134 +
135 +               dev_pm_opp_free_cpufreq_table(info->cpu_dev,
136 +                                             &info->freq_table);
137 +
138 +               if (!IS_ERR(info->proc_reg))
139 +                       regulator_put(info->proc_reg);
140 +               if (!IS_ERR(info->sram_reg))
141 +                       regulator_put(info->sram_reg);
142 +               if (!IS_ERR(info->cpu_clk))
143 +                       clk_put(info->cpu_clk);
144 +               if (!IS_ERR(info->inter_clk))
145 +                       clk_put(info->inter_clk);
146 +
147 +               of_free_opp_table(info->cpu_dev);
148 +
149 +               list_del(list);
150 +               kfree(info);
151 +       }
152 +}
153 +
154 +#define MIN(a, b) ((a) < (b) ? (a) : (b))
155 +#define MAX(a, b) ((a) > (b) ? (a) : (b))
156 +
157 +static int mtk_cpufreq_voltage_trace(struct mtk_cpu_dvfs_info *info,
158 +                                    int new_vproc)
159 +{
160 +       struct regulator *proc_reg = info->proc_reg;
161 +       struct regulator *sram_reg = info->sram_reg;
162 +       int old_vproc, old_vsram, new_vsram, vsram, vproc, ret;
163 +
164 +       old_vproc = regulator_get_voltage(proc_reg);
165 +       old_vsram = regulator_get_voltage(sram_reg);
166 +       /* Vsram should not exceed the maximum allowed voltage of SoC. */
167 +       new_vsram = min(new_vproc + MIN_VOLT_SHIFT, MAX_VOLT_LIMIT);
168 +
169 +       if (old_vproc < new_vproc) {
170 +               /*
171 +                * When scaling up voltages, Vsram and Vproc scale up step
172 +                * by step. At each step, set Vsram to (Vproc + 200mV) first,
173 +                * then set Vproc to (Vsram - 100mV).
174 +                * Keep doing it until Vsram and Vproc hit target voltages.
175 +                */
176 +               do {
177 +                       old_vsram = regulator_get_voltage(sram_reg);
178 +                       old_vproc = regulator_get_voltage(proc_reg);
179 +
180 +                       vsram = MIN(new_vsram, old_vproc + MAX_VOLT_SHIFT);
181 +
182 +                       if (vsram + VOLT_TOL >= MAX_VOLT_LIMIT) {
183 +                               vsram = MAX_VOLT_LIMIT;
184 +
185 +                               /*
186 +                                * If the target Vsram hits the maximum voltage,
187 +                                * try to set the exact voltage value first.
188 +                                */
189 +                               ret = regulator_set_voltage(sram_reg, vsram,
190 +                                                           vsram);
191 +                               if (ret)
192 +                                       ret = regulator_set_voltage(sram_reg,
193 +                                                       vsram - VOLT_TOL,
194 +                                                       vsram);
195 +
196 +                               vproc = new_vproc;
197 +                       } else {
198 +                               ret = regulator_set_voltage(sram_reg, vsram,
199 +                                                           vsram + VOLT_TOL);
200 +
201 +                               vproc = vsram - MIN_VOLT_SHIFT;
202 +                       }
203 +                       if (ret)
204 +                               return ret;
205 +
206 +                       ret = regulator_set_voltage(proc_reg, vproc,
207 +                                                   vproc + VOLT_TOL);
208 +                       if (ret) {
209 +                               regulator_set_voltage(sram_reg, old_vsram,
210 +                                                     old_vsram);
211 +                               return ret;
212 +                       }
213 +               } while (vproc < new_vproc || vsram < new_vsram);
214 +       } else if (old_vproc > new_vproc) {
215 +               /*
216 +                * When scaling down voltages, Vsram and Vproc scale down step
217 +                * by step. At each step, set Vproc to (Vsram - 200mV) first,
218 +                * then set Vproc to (Vproc + 100mV).
219 +                * Keep doing it until Vsram and Vproc hit target voltages.
220 +                */
221 +               do {
222 +                       old_vproc = regulator_get_voltage(proc_reg);
223 +                       old_vsram = regulator_get_voltage(sram_reg);
224 +
225 +                       vproc = MAX(new_vproc, old_vsram - MAX_VOLT_SHIFT);
226 +                       ret = regulator_set_voltage(proc_reg, vproc,
227 +                                                   vproc + VOLT_TOL);
228 +                       if (ret)
229 +                               return ret;
230 +
231 +                       if (vproc == new_vproc)
232 +                               vsram = new_vsram;
233 +                       else
234 +                               vsram = MAX(new_vsram, vproc + MIN_VOLT_SHIFT);
235 +
236 +                       if (vsram + VOLT_TOL >= MAX_VOLT_LIMIT) {
237 +                               vsram = MAX_VOLT_LIMIT;
238 +
239 +                               /*
240 +                                * If the target Vsram hits the maximum voltage,
241 +                                * try to set the exact voltage value first.
242 +                                */
243 +                               ret = regulator_set_voltage(sram_reg, vsram,
244 +                                                           vsram);
245 +                               if (ret)
246 +                                       ret = regulator_set_voltage(sram_reg,
247 +                                                       vsram - VOLT_TOL,
248 +                                                       vsram);
249 +                       } else {
250 +                               ret = regulator_set_voltage(sram_reg, vsram,
251 +                                                           vsram + VOLT_TOL);
252 +                       }
253 +
254 +                       if (ret) {
255 +                               regulator_set_voltage(proc_reg, old_vproc,
256 +                                                     old_vproc);
257 +                               return ret;
258 +                       }
259 +               } while (vproc > new_vproc + VOLT_TOL ||
260 +                        vsram > new_vsram + VOLT_TOL);
261 +       }
262 +
263 +       return 0;
264 +}
265 +
266 +static int mtk_cpufreq_set_voltage(struct mtk_cpu_dvfs_info *info, int vproc)
267 +{
268 +       if (info->need_voltage_trace)
269 +               return mtk_cpufreq_voltage_trace(info, vproc);
270 +       else
271 +               return regulator_set_voltage(info->proc_reg, vproc,
272 +                                            vproc + VOLT_TOL);
273 +}
274 +
275 +static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
276 +                                 unsigned int index)
277 +{
278 +       struct cpufreq_frequency_table *freq_table = policy->freq_table;
279 +       struct clk *cpu_clk = policy->clk;
280 +       struct clk *armpll = clk_get_parent(cpu_clk);
281 +       struct mtk_cpu_dvfs_info *info = policy->driver_data;
282 +       struct device *cpu_dev = info->cpu_dev;
283 +       struct dev_pm_opp *opp;
284 +       long freq_hz, old_freq_hz;
285 +       int vproc, old_vproc, inter_vproc, target_vproc, ret;
286 +
287 +       inter_vproc = info->intermediate_voltage;
288 +
289 +       old_freq_hz = clk_get_rate(cpu_clk);
290 +       old_vproc = regulator_get_voltage(info->proc_reg);
291 +
292 +       freq_hz = freq_table[index].frequency * 1000;
293 +       rcu_read_lock();
294 +       opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
295 +       if (IS_ERR(opp)) {
296 +               rcu_read_unlock();
297 +               pr_err("cpu%d: failed to find OPP for %ld\n",
298 +                      policy->cpu, freq_hz);
299 +               return PTR_ERR(opp);
300 +       }
301 +       vproc = dev_pm_opp_get_voltage(opp);
302 +       rcu_read_unlock();
303 +
304 +       /*
305 +        * If the new voltage or the intermediate voltage is higher than the
306 +        * current voltage, scale up voltage first.
307 +        */
308 +       target_vproc = (inter_vproc > vproc) ? inter_vproc : vproc;
309 +       if (old_vproc < target_vproc) {
310 +               ret = mtk_cpufreq_set_voltage(info, target_vproc);
311 +               if (ret) {
312 +                       pr_err("cpu%d: failed to scale up voltage!\n",
313 +                              policy->cpu);
314 +                       mtk_cpufreq_set_voltage(info, old_vproc);
315 +                       return ret;
316 +               }
317 +       }
318 +
319 +       /* Reparent the CPU clock to intermediate clock. */
320 +       ret = clk_set_parent(cpu_clk, info->inter_clk);
321 +       if (ret) {
322 +               pr_err("cpu%d: failed to re-parent cpu clock!\n",
323 +                      policy->cpu);
324 +               mtk_cpufreq_set_voltage(info, old_vproc);
325 +               WARN_ON(1);
326 +               return ret;
327 +       }
328 +
329 +       /* Set the original PLL to target rate. */
330 +       ret = clk_set_rate(armpll, freq_hz);
331 +       if (ret) {
332 +               pr_err("cpu%d: failed to scale cpu clock rate!\n",
333 +                      policy->cpu);
334 +               clk_set_parent(cpu_clk, armpll);
335 +               mtk_cpufreq_set_voltage(info, old_vproc);
336 +               return ret;
337 +       }
338 +
339 +       /* Set parent of CPU clock back to the original PLL. */
340 +       ret = clk_set_parent(cpu_clk, armpll);
341 +       if (ret) {
342 +               pr_err("cpu%d: failed to re-parent cpu clock!\n",
343 +                      policy->cpu);
344 +               mtk_cpufreq_set_voltage(info, inter_vproc);
345 +               WARN_ON(1);
346 +               return ret;
347 +       }
348 +
349 +       /*
350 +        * If the new voltage is lower than the intermediate voltage or the
351 +        * original voltage, scale down to the new voltage.
352 +        */
353 +       if (vproc < inter_vproc || vproc < old_vproc) {
354 +               ret = mtk_cpufreq_set_voltage(info, vproc);
355 +               if (ret) {
356 +                       pr_err("cpu%d: failed to scale down voltage!\n",
357 +                              policy->cpu);
358 +                       clk_set_parent(cpu_clk, info->inter_clk);
359 +                       clk_set_rate(armpll, old_freq_hz);
360 +                       clk_set_parent(cpu_clk, armpll);
361 +                       return ret;
362 +               }
363 +       }
364 +
365 +       return 0;
366 +}
367 +
368 +static int mtk_cpufreq_init(struct cpufreq_policy *policy)
369 +{
370 +       struct mtk_cpu_dvfs_info *info;
371 +       int ret;
372 +
373 +       info = mtk_cpu_dvfs_info_get(policy->cpu);
374 +       if (!info) {
375 +               pr_err("%s: mtk cpu dvfs info for cpu%d is not initialized\n",
376 +                      __func__, policy->cpu);
377 +               return -ENODEV;
378 +       }
379 +
380 +       ret = cpufreq_table_validate_and_show(policy, info->freq_table);
381 +       if (ret) {
382 +               pr_err("%s: invalid frequency table: %d\n", __func__, ret);
383 +               return ret;
384 +       }
385 +
386 +       cpumask_copy(policy->cpus, info->cpus);
387 +       policy->driver_data = info;
388 +       policy->clk = info->cpu_clk;
389 +
390 +       return 0;
391 +}
392 +
393 +static struct cpufreq_driver mt8173_cpufreq_driver = {
394 +       .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
395 +       .verify = cpufreq_generic_frequency_table_verify,
396 +       .target_index = mtk_cpufreq_set_target,
397 +       .get = cpufreq_generic_get,
398 +       .init = mtk_cpufreq_init,
399 +       .name = "mtk-cpufreq",
400 +       .attr = cpufreq_generic_attr,
401 +};
402 +
403 +static int mtk_cpu_dvfs_info_init(int cpu)
404 +{
405 +       struct device *cpu_dev;
406 +       struct regulator *proc_reg = ERR_PTR(-ENODEV);
407 +       struct regulator *sram_reg = ERR_PTR(-ENODEV);
408 +       struct clk *cpu_clk = ERR_PTR(-ENODEV);
409 +       struct clk *inter_clk = ERR_PTR(-ENODEV);
410 +       struct mtk_cpu_dvfs_info *info;
411 +       struct cpufreq_frequency_table *freq_table;
412 +       struct dev_pm_opp *opp;
413 +       unsigned long rate;
414 +       int ret;
415 +
416 +       cpu_dev = get_cpu_device(cpu);
417 +       if (!cpu_dev) {
418 +               pr_err("failed to get cpu%d device\n", cpu);
419 +               return -ENODEV;
420 +       }
421 +
422 +       ret = of_init_opp_table(cpu_dev);
423 +       if (ret) {
424 +               pr_warn("no OPP table for cpu%d\n", cpu);
425 +               return ret;
426 +       }
427 +
428 +       cpu_clk = clk_get(cpu_dev, "cpu");
429 +       if (IS_ERR(cpu_clk)) {
430 +               if (PTR_ERR(cpu_clk) == -EPROBE_DEFER)
431 +                       pr_warn("cpu clk for cpu%d not ready, retry.\n", cpu);
432 +               else
433 +                       pr_err("failed to get cpu clk for cpu%d\n", cpu);
434 +
435 +               ret = PTR_ERR(cpu_clk);
436 +               goto out_free_opp_table;
437 +       }
438 +
439 +       inter_clk = clk_get(cpu_dev, "intermediate");
440 +       if (IS_ERR(inter_clk)) {
441 +               if (PTR_ERR(inter_clk) == -EPROBE_DEFER)
442 +                       pr_warn("intermediate clk for cpu%d not ready, retry.\n",
443 +                               cpu);
444 +               else
445 +                       pr_err("failed to get intermediate clk for cpu%d\n",
446 +                              cpu);
447 +
448 +               ret = PTR_ERR(cpu_clk);
449 +               goto out_free_resources;
450 +       }
451 +
452 +       proc_reg = regulator_get_exclusive(cpu_dev, "proc");
453 +       if (IS_ERR(proc_reg)) {
454 +               if (PTR_ERR(proc_reg) == -EPROBE_DEFER)
455 +                       pr_warn("proc regulator for cpu%d not ready, retry.\n",
456 +                               cpu);
457 +               else
458 +                       pr_err("failed to get proc regulator for cpu%d\n",
459 +                              cpu);
460 +
461 +               ret = PTR_ERR(proc_reg);
462 +               goto out_free_resources;
463 +       }
464 +
465 +       /* Both presence and absence of sram regulator are valid cases. */
466 +       sram_reg = regulator_get_exclusive(cpu_dev, "sram");
467 +
468 +       info = kzalloc(sizeof(*info), GFP_KERNEL);
469 +       if (!info) {
470 +               ret = -ENOMEM;
471 +               goto out_free_resources;
472 +       }
473 +
474 +       ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
475 +       if (ret) {
476 +               pr_err("failed to init cpufreq table for cpu%d: %d\n",
477 +                      cpu, ret);
478 +               goto out_free_mtk_cpu_dvfs_info;
479 +       }
480 +
481 +       if (!alloc_cpumask_var(&info->cpus, GFP_KERNEL))
482 +               goto out_free_cpufreq_table;
483 +
484 +       /* Search a safe voltage for intermediate frequency. */
485 +       rate = clk_get_rate(inter_clk);
486 +       rcu_read_lock();
487 +       opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate);
488 +       if (IS_ERR(opp)) {
489 +               pr_err("failed to get intermediate opp for cpu%d\n", cpu);
490 +               ret = PTR_ERR(opp);
491 +               goto out_free_cpumask;
492 +       }
493 +       info->intermediate_voltage = dev_pm_opp_get_voltage(opp);
494 +       rcu_read_unlock();
495 +
496 +       /* CPUs in the same cluster share a clock and power domain. */
497 +       cpumask_copy(info->cpus, &cpu_topology[cpu].core_sibling);
498 +
499 +       info->cpu_dev = cpu_dev;
500 +       info->proc_reg = proc_reg;
501 +       info->sram_reg = IS_ERR(sram_reg) ? NULL : sram_reg;
502 +       info->cpu_clk = cpu_clk;
503 +       info->inter_clk = inter_clk;
504 +       info->freq_table = freq_table;
505 +
506 +       /*
507 +        * If SRAM regulator is present, software "voltage trace" is needed
508 +        * for this CPU power domain.
509 +        */
510 +       info->need_voltage_trace = !IS_ERR(sram_reg);
511 +
512 +       mtk_cpu_dvfs_info_add(info);
513 +
514 +       return 0;
515 +
516 +out_free_cpumask:
517 +       free_cpumask_var(info->cpus);
518 +
519 +out_free_cpufreq_table:
520 +       dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
521 +
522 +out_free_mtk_cpu_dvfs_info:
523 +       kfree(info);
524 +
525 +out_free_resources:
526 +       if (!IS_ERR(proc_reg))
527 +               regulator_put(proc_reg);
528 +       if (!IS_ERR(sram_reg))
529 +               regulator_put(sram_reg);
530 +       if (!IS_ERR(cpu_clk))
531 +               clk_put(cpu_clk);
532 +       if (!IS_ERR(inter_clk))
533 +               clk_put(inter_clk);
534 +
535 +out_free_opp_table:
536 +       of_free_opp_table(cpu_dev);
537 +
538 +       return ret;
539 +}
540 +
541 +static int mt8173_cpufreq_probe(struct platform_device *pdev)
542 +{
543 +       int cpu, ret;
544 +
545 +       for_each_possible_cpu(cpu) {
546 +               /*
547 +                * If the struct mtk_cpu_dvfs_info for the cpu power domain
548 +                * is already initialized, skip this CPU.
549 +                */
550 +               if (!mtk_cpu_dvfs_info_get(cpu)) {
551 +                       ret = mtk_cpu_dvfs_info_init(cpu);
552 +                       if (ret) {
553 +                               if (ret != -EPROBE_DEFER)
554 +                                       pr_err("%s probe fail\n", __func__);
555 +
556 +                               mtk_cpu_dvfs_info_release();
557 +                               return ret;
558 +                       }
559 +               }
560 +       }
561 +
562 +       ret = cpufreq_register_driver(&mt8173_cpufreq_driver);
563 +       if (ret) {
564 +               pr_err("failed to register mtk cpufreq driver\n");
565 +               mtk_cpu_dvfs_info_release();
566 +       }
567 +
568 +       return ret;
569 +}
570 +
571 +static struct platform_driver mt8173_cpufreq_platdrv = {
572 +       .driver = {
573 +               .name   = "mt8173-cpufreq",
574 +       },
575 +       .probe          = mt8173_cpufreq_probe,
576 +};
577 +module_platform_driver(mt8173_cpufreq_platdrv);
578 +
579 +static int mt8173_cpufreq_driver_init(void)
580 +{
581 +       struct platform_device *pdev;
582 +
583 +       if (!of_machine_is_compatible("mediatek,mt8173"))
584 +               return -ENODEV;
585 +
586 +       pdev = platform_device_register_simple("mt8173-cpufreq", -1, NULL, 0);
587 +       if (IS_ERR(pdev)) {
588 +               pr_err("failed to register mtk-cpufreq platform device\n");
589 +               return PTR_ERR(pdev);
590 +       }
591 +
592 +       return 0;
593 +}
594 +module_init(mt8173_cpufreq_driver_init);