195ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo/* 295ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo * Copyright (C) 2012 Freescale Semiconductor, Inc. 395ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo * 4748c876634870f8e535ddebd76f409f0477d3dd4Viresh Kumar * Copyright (C) 2014 Linaro. 5748c876634870f8e535ddebd76f409f0477d3dd4Viresh Kumar * Viresh Kumar <viresh.kumar@linaro.org> 6748c876634870f8e535ddebd76f409f0477d3dd4Viresh Kumar * 7bbcf071969b20f356877c8067986be0a2dcaa2aaViresh Kumar * The OPP code in function set_target() is reused from 895ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo * drivers/cpufreq/omap-cpufreq.c 995ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo * 1095ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo * This program is free software; you can redistribute it and/or modify 1195ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo * it under the terms of the GNU General Public License version 2 as 1295ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo * published by the Free Software Foundation. 1395ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo */ 1495ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo 1595ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1695ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo 1795ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo#include <linux/clk.h> 18e1825b25309264bf2d1275a8da9c997bca39b0d8Sudeep KarkadaNagesha#include <linux/cpu.h> 1977cff5926a14e80d4545be5841d5938b87b654a4Eduardo Valentin#include <linux/cpu_cooling.h> 2095ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo#include <linux/cpufreq.h> 2134e5a5273d6aa0ee8836bd5d6111b135ffae6931Thomas Petazzoni#include <linux/cpufreq-dt.h> 2277cff5926a14e80d4545be5841d5938b87b654a4Eduardo Valentin#include <linux/cpumask.h> 2395ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo#include <linux/err.h> 2495ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo#include <linux/module.h> 2595ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo#include <linux/of.h> 26e4db1c7439b31993a4886b273bb9235a8eea82bfNishanth Menon#include <linux/pm_opp.h> 275553f9e26f6f49a93ba732fd222eac6973a4cf35Shawn Guo#include <linux/platform_device.h> 2895ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo#include <linux/regulator/consumer.h> 2995ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo#include <linux/slab.h> 3077cff5926a14e80d4545be5841d5938b87b654a4Eduardo Valentin#include <linux/thermal.h> 3195ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo 32d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumarstruct private_data { 33d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar struct device *cpu_dev; 34d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar struct regulator *cpu_reg; 35d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar struct thermal_cooling_device *cdev; 36d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar unsigned int voltage_tolerance; /* in percentage */ 37d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar}; 3895ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo 39bbcf071969b20f356877c8067986be0a2dcaa2aaViresh Kumarstatic int set_target(struct cpufreq_policy *policy, unsigned int index) 4095ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo{ 4147d43ba73eb98d8ba731208735c899129d9849e1Nishanth Menon struct dev_pm_opp *opp; 42d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar struct cpufreq_frequency_table *freq_table = policy->freq_table; 43d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar struct clk *cpu_clk = policy->clk; 44d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar struct private_data *priv = policy->driver_data; 45d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar struct device *cpu_dev = priv->cpu_dev; 46d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar struct regulator *cpu_reg = priv->cpu_reg; 475df6055939f295d723871d9781e73495b131b3d6jhbird.choi@samsung.com unsigned long volt = 0, volt_old = 0, tol = 0; 48d4019f0a92ab802f385cc9c8ad3ab7b5449712cbViresh Kumar unsigned int old_freq, new_freq; 490ca684365547cd5f214b5739568dae3df5d6cec9Guennadi Liakhovetski long freq_Hz, freq_exact; 5095ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo int ret; 5195ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo 5295ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000); 532209b0c964c7c402b07d0df6fcfbecf8ff53db30Paul Walmsley if (freq_Hz <= 0) 5495ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo freq_Hz = freq_table[index].frequency * 1000; 5595ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo 56d4019f0a92ab802f385cc9c8ad3ab7b5449712cbViresh Kumar freq_exact = freq_Hz; 57d4019f0a92ab802f385cc9c8ad3ab7b5449712cbViresh Kumar new_freq = freq_Hz / 1000; 58d4019f0a92ab802f385cc9c8ad3ab7b5449712cbViresh Kumar old_freq = clk_get_rate(cpu_clk) / 1000; 5995ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo 604a511de96d692f2dfa126c10dda4e41636c0ef27Mark Brown if (!IS_ERR(cpu_reg)) { 6178e8eb8feab7d85f4cc215afe1457a228bf4eed9Nishanth Menon rcu_read_lock(); 625d4879cda67b09f086807821cf594ee079d6dfbeNishanth Menon opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_Hz); 6395ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo if (IS_ERR(opp)) { 6478e8eb8feab7d85f4cc215afe1457a228bf4eed9Nishanth Menon rcu_read_unlock(); 65fbd48ca5911b3cd70da57c3313d13004e40aea54Viresh Kumar dev_err(cpu_dev, "failed to find OPP for %ld\n", 66fbd48ca5911b3cd70da57c3313d13004e40aea54Viresh Kumar freq_Hz); 67d4019f0a92ab802f385cc9c8ad3ab7b5449712cbViresh Kumar return PTR_ERR(opp); 6895ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo } 695d4879cda67b09f086807821cf594ee079d6dfbeNishanth Menon volt = dev_pm_opp_get_voltage(opp); 7078e8eb8feab7d85f4cc215afe1457a228bf4eed9Nishanth Menon rcu_read_unlock(); 71d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar tol = volt * priv->voltage_tolerance / 100; 7295ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo volt_old = regulator_get_voltage(cpu_reg); 7395ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo } 7495ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo 75fbd48ca5911b3cd70da57c3313d13004e40aea54Viresh Kumar dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n", 76fbd48ca5911b3cd70da57c3313d13004e40aea54Viresh Kumar old_freq / 1000, volt_old ? volt_old / 1000 : -1, 77fbd48ca5911b3cd70da57c3313d13004e40aea54Viresh Kumar new_freq / 1000, volt ? volt / 1000 : -1); 7895ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo 7995ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo /* scaling up? scale voltage before frequency */ 80d4019f0a92ab802f385cc9c8ad3ab7b5449712cbViresh Kumar if (!IS_ERR(cpu_reg) && new_freq > old_freq) { 8195ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo ret = regulator_set_voltage_tol(cpu_reg, volt, tol); 8295ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo if (ret) { 83fbd48ca5911b3cd70da57c3313d13004e40aea54Viresh Kumar dev_err(cpu_dev, "failed to scale voltage up: %d\n", 84fbd48ca5911b3cd70da57c3313d13004e40aea54Viresh Kumar ret); 85d4019f0a92ab802f385cc9c8ad3ab7b5449712cbViresh Kumar return ret; 8695ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo } 8795ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo } 8895ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo 890ca684365547cd5f214b5739568dae3df5d6cec9Guennadi Liakhovetski ret = clk_set_rate(cpu_clk, freq_exact); 9095ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo if (ret) { 91fbd48ca5911b3cd70da57c3313d13004e40aea54Viresh Kumar dev_err(cpu_dev, "failed to set clock rate: %d\n", ret); 924a511de96d692f2dfa126c10dda4e41636c0ef27Mark Brown if (!IS_ERR(cpu_reg)) 9395ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo regulator_set_voltage_tol(cpu_reg, volt_old, tol); 94d4019f0a92ab802f385cc9c8ad3ab7b5449712cbViresh Kumar return ret; 9595ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo } 9695ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo 9795ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo /* scaling down? scale voltage after frequency */ 98d4019f0a92ab802f385cc9c8ad3ab7b5449712cbViresh Kumar if (!IS_ERR(cpu_reg) && new_freq < old_freq) { 9995ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo ret = regulator_set_voltage_tol(cpu_reg, volt, tol); 10095ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo if (ret) { 101fbd48ca5911b3cd70da57c3313d13004e40aea54Viresh Kumar dev_err(cpu_dev, "failed to scale voltage down: %d\n", 102fbd48ca5911b3cd70da57c3313d13004e40aea54Viresh Kumar ret); 103d4019f0a92ab802f385cc9c8ad3ab7b5449712cbViresh Kumar clk_set_rate(cpu_clk, old_freq * 1000); 10495ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo } 10595ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo } 10695ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo 107fd143b4d6fb763183ef6e46d1ab84a42c59079afViresh Kumar return ret; 10895ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo} 10995ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo 11095b6105835293a910484c5bcdd1599b8588959e9Viresh Kumarstatic int allocate_resources(int cpu, struct device **cdev, 111d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar struct regulator **creg, struct clk **cclk) 11295ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo{ 113d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar struct device *cpu_dev; 114d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar struct regulator *cpu_reg; 115d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar struct clk *cpu_clk; 116d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar int ret = 0; 1172d2c5e0e72546c1b4375ff5820ca8016c7123cbbViresh Kumar char *reg_cpu0 = "cpu0", *reg_cpu = "cpu", *reg; 11895ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo 11995b6105835293a910484c5bcdd1599b8588959e9Viresh Kumar cpu_dev = get_cpu_device(cpu); 120e1825b25309264bf2d1275a8da9c997bca39b0d8Sudeep KarkadaNagesha if (!cpu_dev) { 12195b6105835293a910484c5bcdd1599b8588959e9Viresh Kumar pr_err("failed to get cpu%d device\n", cpu); 122e1825b25309264bf2d1275a8da9c997bca39b0d8Sudeep KarkadaNagesha return -ENODEV; 123e1825b25309264bf2d1275a8da9c997bca39b0d8Sudeep KarkadaNagesha } 1246754f556103be5bd172263b1075ddbb7157afbadMark Langsdorf 1252d2c5e0e72546c1b4375ff5820ca8016c7123cbbViresh Kumar /* Try "cpu0" for older DTs */ 12695b6105835293a910484c5bcdd1599b8588959e9Viresh Kumar if (!cpu) 12795b6105835293a910484c5bcdd1599b8588959e9Viresh Kumar reg = reg_cpu0; 12895b6105835293a910484c5bcdd1599b8588959e9Viresh Kumar else 12995b6105835293a910484c5bcdd1599b8588959e9Viresh Kumar reg = reg_cpu; 1302d2c5e0e72546c1b4375ff5820ca8016c7123cbbViresh Kumar 1312d2c5e0e72546c1b4375ff5820ca8016c7123cbbViresh Kumartry_again: 1322d2c5e0e72546c1b4375ff5820ca8016c7123cbbViresh Kumar cpu_reg = regulator_get_optional(cpu_dev, reg); 133fc31d6f55908759530462998d0464a9f124b1c32Nishanth Menon if (IS_ERR(cpu_reg)) { 134fc31d6f55908759530462998d0464a9f124b1c32Nishanth Menon /* 13595b6105835293a910484c5bcdd1599b8588959e9Viresh Kumar * If cpu's regulator supply node is present, but regulator is 136fc31d6f55908759530462998d0464a9f124b1c32Nishanth Menon * not yet registered, we should try defering probe. 137fc31d6f55908759530462998d0464a9f124b1c32Nishanth Menon */ 138fc31d6f55908759530462998d0464a9f124b1c32Nishanth Menon if (PTR_ERR(cpu_reg) == -EPROBE_DEFER) { 13995b6105835293a910484c5bcdd1599b8588959e9Viresh Kumar dev_dbg(cpu_dev, "cpu%d regulator not ready, retry\n", 14095b6105835293a910484c5bcdd1599b8588959e9Viresh Kumar cpu); 141d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar return -EPROBE_DEFER; 142fc31d6f55908759530462998d0464a9f124b1c32Nishanth Menon } 1432d2c5e0e72546c1b4375ff5820ca8016c7123cbbViresh Kumar 1442d2c5e0e72546c1b4375ff5820ca8016c7123cbbViresh Kumar /* Try with "cpu-supply" */ 1452d2c5e0e72546c1b4375ff5820ca8016c7123cbbViresh Kumar if (reg == reg_cpu0) { 1462d2c5e0e72546c1b4375ff5820ca8016c7123cbbViresh Kumar reg = reg_cpu; 1472d2c5e0e72546c1b4375ff5820ca8016c7123cbbViresh Kumar goto try_again; 1482d2c5e0e72546c1b4375ff5820ca8016c7123cbbViresh Kumar } 1492d2c5e0e72546c1b4375ff5820ca8016c7123cbbViresh Kumar 150a00de1ab21acbd150db341cb56f1897550d6688cThomas Petazzoni dev_dbg(cpu_dev, "no regulator for cpu%d: %ld\n", 151a00de1ab21acbd150db341cb56f1897550d6688cThomas Petazzoni cpu, PTR_ERR(cpu_reg)); 152fc31d6f55908759530462998d0464a9f124b1c32Nishanth Menon } 153fc31d6f55908759530462998d0464a9f124b1c32Nishanth Menon 154e3beb0ac521d50d158a9d253373eae8421ac3998Lucas Stach cpu_clk = clk_get(cpu_dev, NULL); 15595ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo if (IS_ERR(cpu_clk)) { 156d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar /* put regulator */ 157d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar if (!IS_ERR(cpu_reg)) 158d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar regulator_put(cpu_reg); 159d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar 16095ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo ret = PTR_ERR(cpu_clk); 16148a8624b3abe39bd66490e3ab692a74a73b582ebViresh Kumar 16248a8624b3abe39bd66490e3ab692a74a73b582ebViresh Kumar /* 16348a8624b3abe39bd66490e3ab692a74a73b582ebViresh Kumar * If cpu's clk node is present, but clock is not yet 16448a8624b3abe39bd66490e3ab692a74a73b582ebViresh Kumar * registered, we should try defering probe. 16548a8624b3abe39bd66490e3ab692a74a73b582ebViresh Kumar */ 16648a8624b3abe39bd66490e3ab692a74a73b582ebViresh Kumar if (ret == -EPROBE_DEFER) 16795b6105835293a910484c5bcdd1599b8588959e9Viresh Kumar dev_dbg(cpu_dev, "cpu%d clock not ready, retry\n", cpu); 16848a8624b3abe39bd66490e3ab692a74a73b582ebViresh Kumar else 1697179621023011f23f636b3e9fcc97c41aa9d6823Abhilash Kesavan dev_err(cpu_dev, "failed to get cpu%d clock: %d\n", cpu, 1707179621023011f23f636b3e9fcc97c41aa9d6823Abhilash Kesavan ret); 171d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar } else { 172d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar *cdev = cpu_dev; 173d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar *creg = cpu_reg; 174d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar *cclk = cpu_clk; 175d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar } 176d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar 177d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar return ret; 178d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar} 179d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar 180bbcf071969b20f356877c8067986be0a2dcaa2aaViresh Kumarstatic int cpufreq_init(struct cpufreq_policy *policy) 181d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar{ 18234e5a5273d6aa0ee8836bd5d6111b135ffae6931Thomas Petazzoni struct cpufreq_dt_platform_data *pd; 183d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar struct cpufreq_frequency_table *freq_table; 184d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar struct thermal_cooling_device *cdev; 185d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar struct device_node *np; 186d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar struct private_data *priv; 187d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar struct device *cpu_dev; 188d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar struct regulator *cpu_reg; 189d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar struct clk *cpu_clk; 190045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach unsigned long min_uV = ~0, max_uV = 0; 191d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar unsigned int transition_latency; 192d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar int ret; 193d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar 19495b6105835293a910484c5bcdd1599b8588959e9Viresh Kumar ret = allocate_resources(policy->cpu, &cpu_dev, &cpu_reg, &cpu_clk); 195d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar if (ret) { 196d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar pr_err("%s: Failed to allocate resources\n: %d", __func__, ret); 197d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar return ret; 198d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar } 19948a8624b3abe39bd66490e3ab692a74a73b582ebViresh Kumar 200d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar np = of_node_get(cpu_dev->of_node); 201d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar if (!np) { 202d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar dev_err(cpu_dev, "failed to find cpu%d node\n", policy->cpu); 203d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar ret = -ENOENT; 204d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar goto out_put_reg_clk; 20595ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo } 20695ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo 2071bf8cc3d017575a38d4361f56ccc0a670a16bcd9Viresh Kumar /* OPPs might be populated at runtime, don't check for error here */ 2081bf8cc3d017575a38d4361f56ccc0a670a16bcd9Viresh Kumar of_init_opp_table(cpu_dev); 20995ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo 210d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar priv = kzalloc(sizeof(*priv), GFP_KERNEL); 211d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar if (!priv) { 212d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar ret = -ENOMEM; 213045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach goto out_put_node; 21495ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo } 21595ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo 216d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar of_property_read_u32(np, "voltage-tolerance", &priv->voltage_tolerance); 21795ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo 21895ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo if (of_property_read_u32(np, "clock-latency", &transition_latency)) 21995ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo transition_latency = CPUFREQ_ETERNAL; 22095ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo 22143c638e3dd48ff1b1a93ea01c98e258e693880c3Philipp Zabel if (!IS_ERR(cpu_reg)) { 222045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach unsigned long opp_freq = 0; 22395ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo 22495ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo /* 225045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach * Disable any OPPs where the connected regulator isn't able to 226045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach * provide the specified voltage and record minimum and maximum 227045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach * voltage levels. 22895ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo */ 229045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach while (1) { 230045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach struct dev_pm_opp *opp; 231045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach unsigned long opp_uV, tol_uV; 232045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach 233045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach rcu_read_lock(); 234045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach opp = dev_pm_opp_find_freq_ceil(cpu_dev, &opp_freq); 235045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach if (IS_ERR(opp)) { 236045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach rcu_read_unlock(); 237045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach break; 238045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach } 239045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach opp_uV = dev_pm_opp_get_voltage(opp); 240045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach rcu_read_unlock(); 241045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach 242045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach tol_uV = opp_uV * priv->voltage_tolerance / 100; 243045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach if (regulator_is_supported_voltage(cpu_reg, opp_uV, 244045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach opp_uV + tol_uV)) { 245045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach if (opp_uV < min_uV) 246045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach min_uV = opp_uV; 247045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach if (opp_uV > max_uV) 248045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach max_uV = opp_uV; 249045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach } else { 250045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach dev_pm_opp_disable(cpu_dev, opp_freq); 251045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach } 252045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach 253045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach opp_freq++; 254045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach } 255045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach 25695ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo ret = regulator_set_voltage_time(cpu_reg, min_uV, max_uV); 25795ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo if (ret > 0) 25895ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo transition_latency += ret * 1000; 25995ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo } 26095ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo 261045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); 262045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach if (ret) { 263045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach pr_err("failed to init cpufreq table: %d\n", ret); 264045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach goto out_free_priv; 265045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach } 266045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach 26777cff5926a14e80d4545be5841d5938b87b654a4Eduardo Valentin /* 26877cff5926a14e80d4545be5841d5938b87b654a4Eduardo Valentin * For now, just loading the cooling device; 26977cff5926a14e80d4545be5841d5938b87b654a4Eduardo Valentin * thermal DT code takes care of matching them. 27077cff5926a14e80d4545be5841d5938b87b654a4Eduardo Valentin */ 27177cff5926a14e80d4545be5841d5938b87b654a4Eduardo Valentin if (of_find_property(np, "#cooling-cells", NULL)) { 27277cff5926a14e80d4545be5841d5938b87b654a4Eduardo Valentin cdev = of_cpufreq_cooling_register(np, cpu_present_mask); 27377cff5926a14e80d4545be5841d5938b87b654a4Eduardo Valentin if (IS_ERR(cdev)) 274fbd48ca5911b3cd70da57c3313d13004e40aea54Viresh Kumar dev_err(cpu_dev, 275fbd48ca5911b3cd70da57c3313d13004e40aea54Viresh Kumar "running cpufreq without cooling device: %ld\n", 276fbd48ca5911b3cd70da57c3313d13004e40aea54Viresh Kumar PTR_ERR(cdev)); 277d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar else 278d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar priv->cdev = cdev; 27977cff5926a14e80d4545be5841d5938b87b654a4Eduardo Valentin } 280d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar 281d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar priv->cpu_dev = cpu_dev; 282d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar priv->cpu_reg = cpu_reg; 283d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar policy->driver_data = priv; 284d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar 285d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar policy->clk = cpu_clk; 28634e5a5273d6aa0ee8836bd5d6111b135ffae6931Thomas Petazzoni ret = cpufreq_table_validate_and_show(policy, freq_table); 28734e5a5273d6aa0ee8836bd5d6111b135ffae6931Thomas Petazzoni if (ret) { 28834e5a5273d6aa0ee8836bd5d6111b135ffae6931Thomas Petazzoni dev_err(cpu_dev, "%s: invalid frequency table: %d\n", __func__, 28934e5a5273d6aa0ee8836bd5d6111b135ffae6931Thomas Petazzoni ret); 290d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar goto out_cooling_unregister; 29134e5a5273d6aa0ee8836bd5d6111b135ffae6931Thomas Petazzoni } 29234e5a5273d6aa0ee8836bd5d6111b135ffae6931Thomas Petazzoni 29334e5a5273d6aa0ee8836bd5d6111b135ffae6931Thomas Petazzoni policy->cpuinfo.transition_latency = transition_latency; 29434e5a5273d6aa0ee8836bd5d6111b135ffae6931Thomas Petazzoni 29534e5a5273d6aa0ee8836bd5d6111b135ffae6931Thomas Petazzoni pd = cpufreq_get_driver_data(); 296c81407fe573d8ac3c7150f5373475598c59197deGeert Uytterhoeven if (!pd || !pd->independent_clocks) 29734e5a5273d6aa0ee8836bd5d6111b135ffae6931Thomas Petazzoni cpumask_setall(policy->cpus); 298d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar 299f9739d27059d8fd7b64096ea7251608628b5bd30Lucas Stach of_node_put(np); 300f9739d27059d8fd7b64096ea7251608628b5bd30Lucas Stach 30195ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo return 0; 30295ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo 303d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumarout_cooling_unregister: 304d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar cpufreq_cooling_unregister(priv->cdev); 3055d4879cda67b09f086807821cf594ee079d6dfbeNishanth Menon dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); 306045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stachout_free_priv: 307045ee45c4ff2422a6f47e9fad7dd6cb537de940cLucas Stach kfree(priv); 308d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumarout_put_node: 309d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar of_node_put(np); 310d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumarout_put_reg_clk: 311ed4b053cb864f29f57cf5a4c3f3c85cda22edaf1Viresh Kumar clk_put(cpu_clk); 312e3beb0ac521d50d158a9d253373eae8421ac3998Lucas Stach if (!IS_ERR(cpu_reg)) 313e3beb0ac521d50d158a9d253373eae8421ac3998Lucas Stach regulator_put(cpu_reg); 314d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar 315d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar return ret; 316d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar} 317d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar 318bbcf071969b20f356877c8067986be0a2dcaa2aaViresh Kumarstatic int cpufreq_exit(struct cpufreq_policy *policy) 319d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar{ 320d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar struct private_data *priv = policy->driver_data; 321d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar 322d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar cpufreq_cooling_unregister(priv->cdev); 323d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); 324d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar clk_put(policy->clk); 325d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar if (!IS_ERR(priv->cpu_reg)) 326d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar regulator_put(priv->cpu_reg); 327d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar kfree(priv); 328d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar 329d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar return 0; 330d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar} 331d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar 332bbcf071969b20f356877c8067986be0a2dcaa2aaViresh Kumarstatic struct cpufreq_driver dt_cpufreq_driver = { 333d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK, 334d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar .verify = cpufreq_generic_frequency_table_verify, 335bbcf071969b20f356877c8067986be0a2dcaa2aaViresh Kumar .target_index = set_target, 336d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar .get = cpufreq_generic_get, 337bbcf071969b20f356877c8067986be0a2dcaa2aaViresh Kumar .init = cpufreq_init, 338bbcf071969b20f356877c8067986be0a2dcaa2aaViresh Kumar .exit = cpufreq_exit, 339bbcf071969b20f356877c8067986be0a2dcaa2aaViresh Kumar .name = "cpufreq-dt", 340d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar .attr = cpufreq_generic_attr, 341d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar}; 342d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar 343bbcf071969b20f356877c8067986be0a2dcaa2aaViresh Kumarstatic int dt_cpufreq_probe(struct platform_device *pdev) 344d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar{ 345d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar struct device *cpu_dev; 346d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar struct regulator *cpu_reg; 347d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar struct clk *cpu_clk; 348d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar int ret; 349d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar 350d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar /* 351d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar * All per-cluster (CPUs sharing clock/voltages) initialization is done 352d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar * from ->init(). In probe(), we just need to make sure that clk and 353d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar * regulators are available. Else defer probe and retry. 354d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar * 355d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar * FIXME: Is checking this only for CPU0 sufficient ? 356d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar */ 35795b6105835293a910484c5bcdd1599b8588959e9Viresh Kumar ret = allocate_resources(0, &cpu_dev, &cpu_reg, &cpu_clk); 358d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar if (ret) 359d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar return ret; 360d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar 361d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar clk_put(cpu_clk); 362d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar if (!IS_ERR(cpu_reg)) 363d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar regulator_put(cpu_reg); 364d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar 36534e5a5273d6aa0ee8836bd5d6111b135ffae6931Thomas Petazzoni dt_cpufreq_driver.driver_data = dev_get_platdata(&pdev->dev); 36634e5a5273d6aa0ee8836bd5d6111b135ffae6931Thomas Petazzoni 367bbcf071969b20f356877c8067986be0a2dcaa2aaViresh Kumar ret = cpufreq_register_driver(&dt_cpufreq_driver); 368d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar if (ret) 369d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar dev_err(cpu_dev, "failed register driver: %d\n", ret); 370d2f31f1da54f83c4eb2738402284c49cd51798d1Viresh Kumar 37195ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo return ret; 37295ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo} 3735553f9e26f6f49a93ba732fd222eac6973a4cf35Shawn Guo 374bbcf071969b20f356877c8067986be0a2dcaa2aaViresh Kumarstatic int dt_cpufreq_remove(struct platform_device *pdev) 3755553f9e26f6f49a93ba732fd222eac6973a4cf35Shawn Guo{ 376bbcf071969b20f356877c8067986be0a2dcaa2aaViresh Kumar cpufreq_unregister_driver(&dt_cpufreq_driver); 3775553f9e26f6f49a93ba732fd222eac6973a4cf35Shawn Guo return 0; 3785553f9e26f6f49a93ba732fd222eac6973a4cf35Shawn Guo} 3795553f9e26f6f49a93ba732fd222eac6973a4cf35Shawn Guo 380bbcf071969b20f356877c8067986be0a2dcaa2aaViresh Kumarstatic struct platform_driver dt_cpufreq_platdrv = { 3815553f9e26f6f49a93ba732fd222eac6973a4cf35Shawn Guo .driver = { 382bbcf071969b20f356877c8067986be0a2dcaa2aaViresh Kumar .name = "cpufreq-dt", 3835553f9e26f6f49a93ba732fd222eac6973a4cf35Shawn Guo .owner = THIS_MODULE, 3845553f9e26f6f49a93ba732fd222eac6973a4cf35Shawn Guo }, 385bbcf071969b20f356877c8067986be0a2dcaa2aaViresh Kumar .probe = dt_cpufreq_probe, 386bbcf071969b20f356877c8067986be0a2dcaa2aaViresh Kumar .remove = dt_cpufreq_remove, 3875553f9e26f6f49a93ba732fd222eac6973a4cf35Shawn Guo}; 388bbcf071969b20f356877c8067986be0a2dcaa2aaViresh Kumarmodule_platform_driver(dt_cpufreq_platdrv); 38995ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn Guo 390748c876634870f8e535ddebd76f409f0477d3dd4Viresh KumarMODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>"); 39195ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn GuoMODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>"); 392bbcf071969b20f356877c8067986be0a2dcaa2aaViresh KumarMODULE_DESCRIPTION("Generic cpufreq driver"); 39395ceafd46359dfd901f9d3b881b33d3036e4b0ceShawn GuoMODULE_LICENSE("GPL"); 394