1a76caf55SØrjan Eide /* 2a76caf55SØrjan Eide * devfreq_cooling: Thermal cooling device implementation for devices using 3a76caf55SØrjan Eide * devfreq 4a76caf55SØrjan Eide * 5a76caf55SØrjan Eide * Copyright (C) 2014-2015 ARM Limited 6a76caf55SØrjan Eide * 7a76caf55SØrjan Eide * This program is free software; you can redistribute it and/or modify 8a76caf55SØrjan Eide * it under the terms of the GNU General Public License version 2 as 9a76caf55SØrjan Eide * published by the Free Software Foundation. 10a76caf55SØrjan Eide * 11a76caf55SØrjan Eide * This program is distributed "as is" WITHOUT ANY WARRANTY of any 12a76caf55SØrjan Eide * kind, whether express or implied; without even the implied warranty 13a76caf55SØrjan Eide * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14a76caf55SØrjan Eide * GNU General Public License for more details. 15a76caf55SØrjan Eide * 16a76caf55SØrjan Eide * TODO: 17a76caf55SØrjan Eide * - If OPPs are added or removed after devfreq cooling has 18a76caf55SØrjan Eide * registered, the devfreq cooling won't react to it. 19a76caf55SØrjan Eide */ 20a76caf55SØrjan Eide 21a76caf55SØrjan Eide #include <linux/devfreq.h> 22a76caf55SØrjan Eide #include <linux/devfreq_cooling.h> 23a76caf55SØrjan Eide #include <linux/export.h> 242f96c035SMatthew Wilcox #include <linux/idr.h> 25a76caf55SØrjan Eide #include <linux/slab.h> 26a76caf55SØrjan Eide #include <linux/pm_opp.h> 27a76caf55SØrjan Eide #include <linux/thermal.h> 28a76caf55SØrjan Eide 299876b1a4SJavi Merino #include <trace/events/thermal.h> 309876b1a4SJavi Merino 312f96c035SMatthew Wilcox static DEFINE_IDA(devfreq_ida); 32a76caf55SØrjan Eide 33a76caf55SØrjan Eide /** 34a76caf55SØrjan Eide * struct devfreq_cooling_device - Devfreq cooling device 35a76caf55SØrjan Eide * @id: unique integer value corresponding to each 36a76caf55SØrjan Eide * devfreq_cooling_device registered. 37a76caf55SØrjan Eide * @cdev: Pointer to associated thermal cooling device. 38a76caf55SØrjan Eide * @devfreq: Pointer to associated devfreq device. 39a76caf55SØrjan Eide * @cooling_state: Current cooling state. 40a76caf55SØrjan Eide * @power_table: Pointer to table with maximum power draw for each 41a76caf55SØrjan Eide * cooling state. State is the index into the table, and 42a76caf55SØrjan Eide * the power is in mW. 43a76caf55SØrjan Eide * @freq_table: Pointer to a table with the frequencies sorted in descending 44a76caf55SØrjan Eide * order. You can index the table by cooling device state 45a76caf55SØrjan Eide * @freq_table_size: Size of the @freq_table and @power_table 46a76caf55SØrjan Eide * @power_ops: Pointer to devfreq_cooling_power, used to generate the 47a76caf55SØrjan Eide * @power_table. 48a76caf55SØrjan Eide */ 49a76caf55SØrjan Eide struct devfreq_cooling_device { 50a76caf55SØrjan Eide int id; 51a76caf55SØrjan Eide struct thermal_cooling_device *cdev; 52a76caf55SØrjan Eide struct devfreq *devfreq; 53a76caf55SØrjan Eide unsigned long cooling_state; 54a76caf55SØrjan Eide u32 *power_table; 55a76caf55SØrjan Eide u32 *freq_table; 56a76caf55SØrjan Eide size_t freq_table_size; 57a76caf55SØrjan Eide struct devfreq_cooling_power *power_ops; 58a76caf55SØrjan Eide }; 59a76caf55SØrjan Eide 60a76caf55SØrjan Eide /** 61a76caf55SØrjan Eide * partition_enable_opps() - disable all opps above a given state 62a76caf55SØrjan Eide * @dfc: Pointer to devfreq we are operating on 63a76caf55SØrjan Eide * @cdev_state: cooling device state we're setting 64a76caf55SØrjan Eide * 65a76caf55SØrjan Eide * Go through the OPPs of the device, enabling all OPPs until 66a76caf55SØrjan Eide * @cdev_state and disabling those frequencies above it. 67a76caf55SØrjan Eide */ 68a76caf55SØrjan Eide static int partition_enable_opps(struct devfreq_cooling_device *dfc, 69a76caf55SØrjan Eide unsigned long cdev_state) 70a76caf55SØrjan Eide { 71a76caf55SØrjan Eide int i; 72a76caf55SØrjan Eide struct device *dev = dfc->devfreq->dev.parent; 73a76caf55SØrjan Eide 74a76caf55SØrjan Eide for (i = 0; i < dfc->freq_table_size; i++) { 75a76caf55SØrjan Eide struct dev_pm_opp *opp; 76a76caf55SØrjan Eide int ret = 0; 77a76caf55SØrjan Eide unsigned int freq = dfc->freq_table[i]; 78a76caf55SØrjan Eide bool want_enable = i >= cdev_state ? true : false; 79a76caf55SØrjan Eide 80a76caf55SØrjan Eide opp = dev_pm_opp_find_freq_exact(dev, freq, !want_enable); 81a76caf55SØrjan Eide 82a76caf55SØrjan Eide if (PTR_ERR(opp) == -ERANGE) 83a76caf55SØrjan Eide continue; 84a76caf55SØrjan Eide else if (IS_ERR(opp)) 85a76caf55SØrjan Eide return PTR_ERR(opp); 86a76caf55SØrjan Eide 878a31d9d9SViresh Kumar dev_pm_opp_put(opp); 888a31d9d9SViresh Kumar 89a76caf55SØrjan Eide if (want_enable) 90a76caf55SØrjan Eide ret = dev_pm_opp_enable(dev, freq); 91a76caf55SØrjan Eide else 92a76caf55SØrjan Eide ret = dev_pm_opp_disable(dev, freq); 93a76caf55SØrjan Eide 94a76caf55SØrjan Eide if (ret) 95a76caf55SØrjan Eide return ret; 96a76caf55SØrjan Eide } 97a76caf55SØrjan Eide 98a76caf55SØrjan Eide return 0; 99a76caf55SØrjan Eide } 100a76caf55SØrjan Eide 101a76caf55SØrjan Eide static int devfreq_cooling_get_max_state(struct thermal_cooling_device *cdev, 102a76caf55SØrjan Eide unsigned long *state) 103a76caf55SØrjan Eide { 104a76caf55SØrjan Eide struct devfreq_cooling_device *dfc = cdev->devdata; 105a76caf55SØrjan Eide 106a76caf55SØrjan Eide *state = dfc->freq_table_size - 1; 107a76caf55SØrjan Eide 108a76caf55SØrjan Eide return 0; 109a76caf55SØrjan Eide } 110a76caf55SØrjan Eide 111a76caf55SØrjan Eide static int devfreq_cooling_get_cur_state(struct thermal_cooling_device *cdev, 112a76caf55SØrjan Eide unsigned long *state) 113a76caf55SØrjan Eide { 114a76caf55SØrjan Eide struct devfreq_cooling_device *dfc = cdev->devdata; 115a76caf55SØrjan Eide 116a76caf55SØrjan Eide *state = dfc->cooling_state; 117a76caf55SØrjan Eide 118a76caf55SØrjan Eide return 0; 119a76caf55SØrjan Eide } 120a76caf55SØrjan Eide 121a76caf55SØrjan Eide static int devfreq_cooling_set_cur_state(struct thermal_cooling_device *cdev, 122a76caf55SØrjan Eide unsigned long state) 123a76caf55SØrjan Eide { 124a76caf55SØrjan Eide struct devfreq_cooling_device *dfc = cdev->devdata; 125a76caf55SØrjan Eide struct devfreq *df = dfc->devfreq; 126a76caf55SØrjan Eide struct device *dev = df->dev.parent; 127a76caf55SØrjan Eide int ret; 128a76caf55SØrjan Eide 129a76caf55SØrjan Eide if (state == dfc->cooling_state) 130a76caf55SØrjan Eide return 0; 131a76caf55SØrjan Eide 132a76caf55SØrjan Eide dev_dbg(dev, "Setting cooling state %lu\n", state); 133a76caf55SØrjan Eide 134a76caf55SØrjan Eide if (state >= dfc->freq_table_size) 135a76caf55SØrjan Eide return -EINVAL; 136a76caf55SØrjan Eide 137a76caf55SØrjan Eide ret = partition_enable_opps(dfc, state); 138a76caf55SØrjan Eide if (ret) 139a76caf55SØrjan Eide return ret; 140a76caf55SØrjan Eide 141a76caf55SØrjan Eide dfc->cooling_state = state; 142a76caf55SØrjan Eide 143a76caf55SØrjan Eide return 0; 144a76caf55SØrjan Eide } 145a76caf55SØrjan Eide 146a76caf55SØrjan Eide /** 147a76caf55SØrjan Eide * freq_get_state() - get the cooling state corresponding to a frequency 148a76caf55SØrjan Eide * @dfc: Pointer to devfreq cooling device 149a76caf55SØrjan Eide * @freq: frequency in Hz 150a76caf55SØrjan Eide * 151a76caf55SØrjan Eide * Return: the cooling state associated with the @freq, or 152a76caf55SØrjan Eide * THERMAL_CSTATE_INVALID if it wasn't found. 153a76caf55SØrjan Eide */ 154a76caf55SØrjan Eide static unsigned long 155a76caf55SØrjan Eide freq_get_state(struct devfreq_cooling_device *dfc, unsigned long freq) 156a76caf55SØrjan Eide { 157a76caf55SØrjan Eide int i; 158a76caf55SØrjan Eide 159a76caf55SØrjan Eide for (i = 0; i < dfc->freq_table_size; i++) { 160a76caf55SØrjan Eide if (dfc->freq_table[i] == freq) 161a76caf55SØrjan Eide return i; 162a76caf55SØrjan Eide } 163a76caf55SØrjan Eide 164a76caf55SØrjan Eide return THERMAL_CSTATE_INVALID; 165a76caf55SØrjan Eide } 166a76caf55SØrjan Eide 167a76caf55SØrjan Eide /** 168a76caf55SØrjan Eide * get_static_power() - calculate the static power 169a76caf55SØrjan Eide * @dfc: Pointer to devfreq cooling device 170a76caf55SØrjan Eide * @freq: Frequency in Hz 171a76caf55SØrjan Eide * 172a76caf55SØrjan Eide * Calculate the static power in milliwatts using the supplied 173a76caf55SØrjan Eide * get_static_power(). The current voltage is calculated using the 174a76caf55SØrjan Eide * OPP library. If no get_static_power() was supplied, assume the 175a76caf55SØrjan Eide * static power is negligible. 176a76caf55SØrjan Eide */ 177a76caf55SØrjan Eide static unsigned long 178a76caf55SØrjan Eide get_static_power(struct devfreq_cooling_device *dfc, unsigned long freq) 179a76caf55SØrjan Eide { 180a76caf55SØrjan Eide struct devfreq *df = dfc->devfreq; 181a76caf55SØrjan Eide struct device *dev = df->dev.parent; 182a76caf55SØrjan Eide unsigned long voltage; 183a76caf55SØrjan Eide struct dev_pm_opp *opp; 184a76caf55SØrjan Eide 185a76caf55SØrjan Eide if (!dfc->power_ops->get_static_power) 186a76caf55SØrjan Eide return 0; 187a76caf55SØrjan Eide 188a76caf55SØrjan Eide opp = dev_pm_opp_find_freq_exact(dev, freq, true); 189a4e49c9bSViresh Kumar if (PTR_ERR(opp) == -ERANGE) 190a76caf55SØrjan Eide opp = dev_pm_opp_find_freq_exact(dev, freq, false); 191a76caf55SØrjan Eide 192afd1f4e0SViresh Kumar if (IS_ERR(opp)) { 193afd1f4e0SViresh Kumar dev_err_ratelimited(dev, "Failed to find OPP for frequency %lu: %ld\n", 194afd1f4e0SViresh Kumar freq, PTR_ERR(opp)); 195afd1f4e0SViresh Kumar return 0; 196afd1f4e0SViresh Kumar } 197afd1f4e0SViresh Kumar 198a76caf55SØrjan Eide voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */ 1998a31d9d9SViresh Kumar dev_pm_opp_put(opp); 200a76caf55SØrjan Eide 201a76caf55SØrjan Eide if (voltage == 0) { 2028327b830SViresh Kumar dev_err_ratelimited(dev, 203afd1f4e0SViresh Kumar "Failed to get voltage for frequency %lu\n", 204afd1f4e0SViresh Kumar freq); 205a76caf55SØrjan Eide return 0; 206a76caf55SØrjan Eide } 207a76caf55SØrjan Eide 2083aa53743SJavi Merino return dfc->power_ops->get_static_power(df, voltage); 209a76caf55SØrjan Eide } 210a76caf55SØrjan Eide 211a76caf55SØrjan Eide /** 212a76caf55SØrjan Eide * get_dynamic_power - calculate the dynamic power 213a76caf55SØrjan Eide * @dfc: Pointer to devfreq cooling device 214a76caf55SØrjan Eide * @freq: Frequency in Hz 215a76caf55SØrjan Eide * @voltage: Voltage in millivolts 216a76caf55SØrjan Eide * 217a76caf55SØrjan Eide * Calculate the dynamic power in milliwatts consumed by the device at 218a76caf55SØrjan Eide * frequency @freq and voltage @voltage. If the get_dynamic_power() 219a76caf55SØrjan Eide * was supplied as part of the devfreq_cooling_power struct, then that 220a76caf55SØrjan Eide * function is used. Otherwise, a simple power model (Pdyn = Coeff * 221a76caf55SØrjan Eide * Voltage^2 * Frequency) is used. 222a76caf55SØrjan Eide */ 223a76caf55SØrjan Eide static unsigned long 224a76caf55SØrjan Eide get_dynamic_power(struct devfreq_cooling_device *dfc, unsigned long freq, 225a76caf55SØrjan Eide unsigned long voltage) 226a76caf55SØrjan Eide { 22761c8e8aaSJavi Merino u64 power; 228a76caf55SØrjan Eide u32 freq_mhz; 229a76caf55SØrjan Eide struct devfreq_cooling_power *dfc_power = dfc->power_ops; 230a76caf55SØrjan Eide 231a76caf55SØrjan Eide if (dfc_power->get_dynamic_power) 2323aa53743SJavi Merino return dfc_power->get_dynamic_power(dfc->devfreq, freq, 2333aa53743SJavi Merino voltage); 234a76caf55SØrjan Eide 235a76caf55SØrjan Eide freq_mhz = freq / 1000000; 236a76caf55SØrjan Eide power = (u64)dfc_power->dyn_power_coeff * freq_mhz * voltage * voltage; 237a76caf55SØrjan Eide do_div(power, 1000000000); 238a76caf55SØrjan Eide 239a76caf55SØrjan Eide return power; 240a76caf55SØrjan Eide } 241a76caf55SØrjan Eide 242a76caf55SØrjan Eide static int devfreq_cooling_get_requested_power(struct thermal_cooling_device *cdev, 243a76caf55SØrjan Eide struct thermal_zone_device *tz, 244a76caf55SØrjan Eide u32 *power) 245a76caf55SØrjan Eide { 246a76caf55SØrjan Eide struct devfreq_cooling_device *dfc = cdev->devdata; 247a76caf55SØrjan Eide struct devfreq *df = dfc->devfreq; 248a76caf55SØrjan Eide struct devfreq_dev_status *status = &df->last_status; 249a76caf55SØrjan Eide unsigned long state; 250a76caf55SØrjan Eide unsigned long freq = status->current_frequency; 251a76caf55SØrjan Eide u32 dyn_power, static_power; 252a76caf55SØrjan Eide 253a76caf55SØrjan Eide /* Get dynamic power for state */ 254a76caf55SØrjan Eide state = freq_get_state(dfc, freq); 255a76caf55SØrjan Eide if (state == THERMAL_CSTATE_INVALID) 256a76caf55SØrjan Eide return -EAGAIN; 257a76caf55SØrjan Eide 258a76caf55SØrjan Eide dyn_power = dfc->power_table[state]; 259a76caf55SØrjan Eide 260a76caf55SØrjan Eide /* Scale dynamic power for utilization */ 261a76caf55SØrjan Eide dyn_power = (dyn_power * status->busy_time) / status->total_time; 262a76caf55SØrjan Eide 263a76caf55SØrjan Eide /* Get static power */ 264a76caf55SØrjan Eide static_power = get_static_power(dfc, freq); 265a76caf55SØrjan Eide 2669876b1a4SJavi Merino trace_thermal_power_devfreq_get_power(cdev, status, freq, dyn_power, 2679876b1a4SJavi Merino static_power); 2689876b1a4SJavi Merino 269a76caf55SØrjan Eide *power = dyn_power + static_power; 270a76caf55SØrjan Eide 271a76caf55SØrjan Eide return 0; 272a76caf55SØrjan Eide } 273a76caf55SØrjan Eide 274a76caf55SØrjan Eide static int devfreq_cooling_state2power(struct thermal_cooling_device *cdev, 275a76caf55SØrjan Eide struct thermal_zone_device *tz, 276a76caf55SØrjan Eide unsigned long state, 277a76caf55SØrjan Eide u32 *power) 278a76caf55SØrjan Eide { 279a76caf55SØrjan Eide struct devfreq_cooling_device *dfc = cdev->devdata; 280a76caf55SØrjan Eide unsigned long freq; 281a76caf55SØrjan Eide u32 static_power; 282a76caf55SØrjan Eide 283e3da1cbeSShawn Lin if (state >= dfc->freq_table_size) 284a76caf55SØrjan Eide return -EINVAL; 285a76caf55SØrjan Eide 286a76caf55SØrjan Eide freq = dfc->freq_table[state]; 287a76caf55SØrjan Eide static_power = get_static_power(dfc, freq); 288a76caf55SØrjan Eide 289a76caf55SØrjan Eide *power = dfc->power_table[state] + static_power; 290a76caf55SØrjan Eide return 0; 291a76caf55SØrjan Eide } 292a76caf55SØrjan Eide 293a76caf55SØrjan Eide static int devfreq_cooling_power2state(struct thermal_cooling_device *cdev, 294a76caf55SØrjan Eide struct thermal_zone_device *tz, 295a76caf55SØrjan Eide u32 power, unsigned long *state) 296a76caf55SØrjan Eide { 297a76caf55SØrjan Eide struct devfreq_cooling_device *dfc = cdev->devdata; 298a76caf55SØrjan Eide struct devfreq *df = dfc->devfreq; 299a76caf55SØrjan Eide struct devfreq_dev_status *status = &df->last_status; 300a76caf55SØrjan Eide unsigned long freq = status->current_frequency; 301a76caf55SØrjan Eide unsigned long busy_time; 302a76caf55SØrjan Eide s32 dyn_power; 303a76caf55SØrjan Eide u32 static_power; 304a76caf55SØrjan Eide int i; 305a76caf55SØrjan Eide 306a76caf55SØrjan Eide static_power = get_static_power(dfc, freq); 307a76caf55SØrjan Eide 308a76caf55SØrjan Eide dyn_power = power - static_power; 309a76caf55SØrjan Eide dyn_power = dyn_power > 0 ? dyn_power : 0; 310a76caf55SØrjan Eide 311a76caf55SØrjan Eide /* Scale dynamic power for utilization */ 312a76caf55SØrjan Eide busy_time = status->busy_time ?: 1; 313a76caf55SØrjan Eide dyn_power = (dyn_power * status->total_time) / busy_time; 314a76caf55SØrjan Eide 315a76caf55SØrjan Eide /* 316a76caf55SØrjan Eide * Find the first cooling state that is within the power 317a76caf55SØrjan Eide * budget for dynamic power. 318a76caf55SØrjan Eide */ 319a76caf55SØrjan Eide for (i = 0; i < dfc->freq_table_size - 1; i++) 320a76caf55SØrjan Eide if (dyn_power >= dfc->power_table[i]) 321a76caf55SØrjan Eide break; 322a76caf55SØrjan Eide 323a76caf55SØrjan Eide *state = i; 3249876b1a4SJavi Merino trace_thermal_power_devfreq_limit(cdev, freq, *state, power); 325a76caf55SØrjan Eide return 0; 326a76caf55SØrjan Eide } 327a76caf55SØrjan Eide 328a76caf55SØrjan Eide static struct thermal_cooling_device_ops devfreq_cooling_ops = { 329a76caf55SØrjan Eide .get_max_state = devfreq_cooling_get_max_state, 330a76caf55SØrjan Eide .get_cur_state = devfreq_cooling_get_cur_state, 331a76caf55SØrjan Eide .set_cur_state = devfreq_cooling_set_cur_state, 332a76caf55SØrjan Eide }; 333a76caf55SØrjan Eide 334a76caf55SØrjan Eide /** 335a76caf55SØrjan Eide * devfreq_cooling_gen_tables() - Generate power and freq tables. 336a76caf55SØrjan Eide * @dfc: Pointer to devfreq cooling device. 337a76caf55SØrjan Eide * 338a76caf55SØrjan Eide * Generate power and frequency tables: the power table hold the 339a76caf55SØrjan Eide * device's maximum power usage at each cooling state (OPP). The 340a76caf55SØrjan Eide * static and dynamic power using the appropriate voltage and 341a76caf55SØrjan Eide * frequency for the state, is acquired from the struct 342a76caf55SØrjan Eide * devfreq_cooling_power, and summed to make the maximum power draw. 343a76caf55SØrjan Eide * 344a76caf55SØrjan Eide * The frequency table holds the frequencies in descending order. 345a76caf55SØrjan Eide * That way its indexed by cooling device state. 346a76caf55SØrjan Eide * 347a76caf55SØrjan Eide * The tables are malloced, and pointers put in dfc. They must be 348a76caf55SØrjan Eide * freed when unregistering the devfreq cooling device. 349a76caf55SØrjan Eide * 350a76caf55SØrjan Eide * Return: 0 on success, negative error code on failure. 351a76caf55SØrjan Eide */ 352a76caf55SØrjan Eide static int devfreq_cooling_gen_tables(struct devfreq_cooling_device *dfc) 353a76caf55SØrjan Eide { 354a76caf55SØrjan Eide struct devfreq *df = dfc->devfreq; 355a76caf55SØrjan Eide struct device *dev = df->dev.parent; 356a76caf55SØrjan Eide int ret, num_opps; 357a76caf55SØrjan Eide unsigned long freq; 358a76caf55SØrjan Eide u32 *power_table = NULL; 359a76caf55SØrjan Eide u32 *freq_table; 360a76caf55SØrjan Eide int i; 361a76caf55SØrjan Eide 362a76caf55SØrjan Eide num_opps = dev_pm_opp_get_opp_count(dev); 363a76caf55SØrjan Eide 364a76caf55SØrjan Eide if (dfc->power_ops) { 365a76caf55SØrjan Eide power_table = kcalloc(num_opps, sizeof(*power_table), 366a76caf55SØrjan Eide GFP_KERNEL); 367a76caf55SØrjan Eide if (!power_table) 368ce5ee161SDan Carpenter return -ENOMEM; 369a76caf55SØrjan Eide } 370a76caf55SØrjan Eide 371a76caf55SØrjan Eide freq_table = kcalloc(num_opps, sizeof(*freq_table), 372a76caf55SØrjan Eide GFP_KERNEL); 373a76caf55SØrjan Eide if (!freq_table) { 374a76caf55SØrjan Eide ret = -ENOMEM; 375a76caf55SØrjan Eide goto free_power_table; 376a76caf55SØrjan Eide } 377a76caf55SØrjan Eide 378a76caf55SØrjan Eide for (i = 0, freq = ULONG_MAX; i < num_opps; i++, freq--) { 379a76caf55SØrjan Eide unsigned long power_dyn, voltage; 380a76caf55SØrjan Eide struct dev_pm_opp *opp; 381a76caf55SØrjan Eide 382a76caf55SØrjan Eide opp = dev_pm_opp_find_freq_floor(dev, &freq); 383a76caf55SØrjan Eide if (IS_ERR(opp)) { 384a76caf55SØrjan Eide ret = PTR_ERR(opp); 385a76caf55SØrjan Eide goto free_tables; 386a76caf55SØrjan Eide } 387a76caf55SØrjan Eide 388a76caf55SØrjan Eide voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */ 3898a31d9d9SViresh Kumar dev_pm_opp_put(opp); 390a76caf55SØrjan Eide 391a76caf55SØrjan Eide if (dfc->power_ops) { 392a76caf55SØrjan Eide power_dyn = get_dynamic_power(dfc, freq, voltage); 393a76caf55SØrjan Eide 394a76caf55SØrjan Eide dev_dbg(dev, "Dynamic power table: %lu MHz @ %lu mV: %lu = %lu mW\n", 395a76caf55SØrjan Eide freq / 1000000, voltage, power_dyn, power_dyn); 396a76caf55SØrjan Eide 397a76caf55SØrjan Eide power_table[i] = power_dyn; 398a76caf55SØrjan Eide } 399a76caf55SØrjan Eide 400a76caf55SØrjan Eide freq_table[i] = freq; 401a76caf55SØrjan Eide } 402a76caf55SØrjan Eide 403a76caf55SØrjan Eide if (dfc->power_ops) 404a76caf55SØrjan Eide dfc->power_table = power_table; 405a76caf55SØrjan Eide 406a76caf55SØrjan Eide dfc->freq_table = freq_table; 407a76caf55SØrjan Eide dfc->freq_table_size = num_opps; 408a76caf55SØrjan Eide 409a76caf55SØrjan Eide return 0; 410a76caf55SØrjan Eide 411a76caf55SØrjan Eide free_tables: 412a76caf55SØrjan Eide kfree(freq_table); 413a76caf55SØrjan Eide free_power_table: 414a76caf55SØrjan Eide kfree(power_table); 415a76caf55SØrjan Eide 416a76caf55SØrjan Eide return ret; 417a76caf55SØrjan Eide } 418a76caf55SØrjan Eide 419a76caf55SØrjan Eide /** 420a76caf55SØrjan Eide * of_devfreq_cooling_register_power() - Register devfreq cooling device, 421a76caf55SØrjan Eide * with OF and power information. 422a76caf55SØrjan Eide * @np: Pointer to OF device_node. 423a76caf55SØrjan Eide * @df: Pointer to devfreq device. 424a76caf55SØrjan Eide * @dfc_power: Pointer to devfreq_cooling_power. 425a76caf55SØrjan Eide * 426a76caf55SØrjan Eide * Register a devfreq cooling device. The available OPPs must be 427a76caf55SØrjan Eide * registered on the device. 428a76caf55SØrjan Eide * 429a76caf55SØrjan Eide * If @dfc_power is provided, the cooling device is registered with the 430a76caf55SØrjan Eide * power extensions. For the power extensions to work correctly, 431a76caf55SØrjan Eide * devfreq should use the simple_ondemand governor, other governors 432a76caf55SØrjan Eide * are not currently supported. 433a76caf55SØrjan Eide */ 4343c99c2ceSJavi Merino struct thermal_cooling_device * 435a76caf55SØrjan Eide of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df, 436a76caf55SØrjan Eide struct devfreq_cooling_power *dfc_power) 437a76caf55SØrjan Eide { 438a76caf55SØrjan Eide struct thermal_cooling_device *cdev; 439a76caf55SØrjan Eide struct devfreq_cooling_device *dfc; 440a76caf55SØrjan Eide char dev_name[THERMAL_NAME_LENGTH]; 441a76caf55SØrjan Eide int err; 442a76caf55SØrjan Eide 443a76caf55SØrjan Eide dfc = kzalloc(sizeof(*dfc), GFP_KERNEL); 444a76caf55SØrjan Eide if (!dfc) 445a76caf55SØrjan Eide return ERR_PTR(-ENOMEM); 446a76caf55SØrjan Eide 447a76caf55SØrjan Eide dfc->devfreq = df; 448a76caf55SØrjan Eide 449a76caf55SØrjan Eide if (dfc_power) { 450a76caf55SØrjan Eide dfc->power_ops = dfc_power; 451a76caf55SØrjan Eide 452a76caf55SØrjan Eide devfreq_cooling_ops.get_requested_power = 453a76caf55SØrjan Eide devfreq_cooling_get_requested_power; 454a76caf55SØrjan Eide devfreq_cooling_ops.state2power = devfreq_cooling_state2power; 455a76caf55SØrjan Eide devfreq_cooling_ops.power2state = devfreq_cooling_power2state; 456a76caf55SØrjan Eide } 457a76caf55SØrjan Eide 458a76caf55SØrjan Eide err = devfreq_cooling_gen_tables(dfc); 459a76caf55SØrjan Eide if (err) 460a76caf55SØrjan Eide goto free_dfc; 461a76caf55SØrjan Eide 4622f96c035SMatthew Wilcox err = ida_simple_get(&devfreq_ida, 0, 0, GFP_KERNEL); 4632f96c035SMatthew Wilcox if (err < 0) 464a76caf55SØrjan Eide goto free_tables; 4652f96c035SMatthew Wilcox dfc->id = err; 466a76caf55SØrjan Eide 467a76caf55SØrjan Eide snprintf(dev_name, sizeof(dev_name), "thermal-devfreq-%d", dfc->id); 468a76caf55SØrjan Eide 469a76caf55SØrjan Eide cdev = thermal_of_cooling_device_register(np, dev_name, dfc, 470a76caf55SØrjan Eide &devfreq_cooling_ops); 471a76caf55SØrjan Eide if (IS_ERR(cdev)) { 472a76caf55SØrjan Eide err = PTR_ERR(cdev); 473a76caf55SØrjan Eide dev_err(df->dev.parent, 474a76caf55SØrjan Eide "Failed to register devfreq cooling device (%d)\n", 475a76caf55SØrjan Eide err); 4762f96c035SMatthew Wilcox goto release_ida; 477a76caf55SØrjan Eide } 478a76caf55SØrjan Eide 479a76caf55SØrjan Eide dfc->cdev = cdev; 480a76caf55SØrjan Eide 4813c99c2ceSJavi Merino return cdev; 482a76caf55SØrjan Eide 4832f96c035SMatthew Wilcox release_ida: 4842f96c035SMatthew Wilcox ida_simple_remove(&devfreq_ida, dfc->id); 485a76caf55SØrjan Eide free_tables: 486a76caf55SØrjan Eide kfree(dfc->power_table); 487a76caf55SØrjan Eide kfree(dfc->freq_table); 488a76caf55SØrjan Eide free_dfc: 489a76caf55SØrjan Eide kfree(dfc); 490a76caf55SØrjan Eide 491a76caf55SØrjan Eide return ERR_PTR(err); 492a76caf55SØrjan Eide } 493a76caf55SØrjan Eide EXPORT_SYMBOL_GPL(of_devfreq_cooling_register_power); 494a76caf55SØrjan Eide 495a76caf55SØrjan Eide /** 496a76caf55SØrjan Eide * of_devfreq_cooling_register() - Register devfreq cooling device, 497a76caf55SØrjan Eide * with OF information. 498a76caf55SØrjan Eide * @np: Pointer to OF device_node. 499a76caf55SØrjan Eide * @df: Pointer to devfreq device. 500a76caf55SØrjan Eide */ 5013c99c2ceSJavi Merino struct thermal_cooling_device * 502a76caf55SØrjan Eide of_devfreq_cooling_register(struct device_node *np, struct devfreq *df) 503a76caf55SØrjan Eide { 504a76caf55SØrjan Eide return of_devfreq_cooling_register_power(np, df, NULL); 505a76caf55SØrjan Eide } 506a76caf55SØrjan Eide EXPORT_SYMBOL_GPL(of_devfreq_cooling_register); 507a76caf55SØrjan Eide 508a76caf55SØrjan Eide /** 509a76caf55SØrjan Eide * devfreq_cooling_register() - Register devfreq cooling device. 510a76caf55SØrjan Eide * @df: Pointer to devfreq device. 511a76caf55SØrjan Eide */ 5123c99c2ceSJavi Merino struct thermal_cooling_device *devfreq_cooling_register(struct devfreq *df) 513a76caf55SØrjan Eide { 514a76caf55SØrjan Eide return of_devfreq_cooling_register(NULL, df); 515a76caf55SØrjan Eide } 516a76caf55SØrjan Eide EXPORT_SYMBOL_GPL(devfreq_cooling_register); 517a76caf55SØrjan Eide 518a76caf55SØrjan Eide /** 519a76caf55SØrjan Eide * devfreq_cooling_unregister() - Unregister devfreq cooling device. 520a76caf55SØrjan Eide * @dfc: Pointer to devfreq cooling device to unregister. 521a76caf55SØrjan Eide */ 5223c99c2ceSJavi Merino void devfreq_cooling_unregister(struct thermal_cooling_device *cdev) 523a76caf55SØrjan Eide { 5243c99c2ceSJavi Merino struct devfreq_cooling_device *dfc; 5253c99c2ceSJavi Merino 5263c99c2ceSJavi Merino if (!cdev) 527a76caf55SØrjan Eide return; 528a76caf55SØrjan Eide 5293c99c2ceSJavi Merino dfc = cdev->devdata; 5303c99c2ceSJavi Merino 531a76caf55SØrjan Eide thermal_cooling_device_unregister(dfc->cdev); 5322f96c035SMatthew Wilcox ida_simple_remove(&devfreq_ida, dfc->id); 533a76caf55SØrjan Eide kfree(dfc->power_table); 534a76caf55SØrjan Eide kfree(dfc->freq_table); 535a76caf55SØrjan Eide 536a76caf55SØrjan Eide kfree(dfc); 537a76caf55SØrjan Eide } 538a76caf55SØrjan Eide EXPORT_SYMBOL_GPL(devfreq_cooling_unregister); 539