2
0

0033-cpufreq-mediatek-Add-MT8173-cpufreq-driver.patch 16 KB

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