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 192a76caf55SØrjan Eide voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */ 1938a31d9d9SViresh Kumar dev_pm_opp_put(opp); 194a76caf55SØrjan Eide 195a76caf55SØrjan Eide if (voltage == 0) { 1968327b830SViresh Kumar dev_err_ratelimited(dev, 197a76caf55SØrjan Eide "Failed to get voltage for frequency %lu: %ld\n", 198a76caf55SØrjan Eide freq, IS_ERR(opp) ? PTR_ERR(opp) : 0); 199a76caf55SØrjan Eide return 0; 200a76caf55SØrjan Eide } 201a76caf55SØrjan Eide 2023aa53743SJavi Merino return dfc->power_ops->get_static_power(df, voltage); 203a76caf55SØrjan Eide } 204a76caf55SØrjan Eide 205a76caf55SØrjan Eide /** 206a76caf55SØrjan Eide * get_dynamic_power - calculate the dynamic power 207a76caf55SØrjan Eide * @dfc: Pointer to devfreq cooling device 208a76caf55SØrjan Eide * @freq: Frequency in Hz 209a76caf55SØrjan Eide * @voltage: Voltage in millivolts 210a76caf55SØrjan Eide * 211a76caf55SØrjan Eide * Calculate the dynamic power in milliwatts consumed by the device at 212a76caf55SØrjan Eide * frequency @freq and voltage @voltage. If the get_dynamic_power() 213a76caf55SØrjan Eide * was supplied as part of the devfreq_cooling_power struct, then that 214a76caf55SØrjan Eide * function is used. Otherwise, a simple power model (Pdyn = Coeff * 215a76caf55SØrjan Eide * Voltage^2 * Frequency) is used. 216a76caf55SØrjan Eide */ 217a76caf55SØrjan Eide static unsigned long 218a76caf55SØrjan Eide get_dynamic_power(struct devfreq_cooling_device *dfc, unsigned long freq, 219a76caf55SØrjan Eide unsigned long voltage) 220a76caf55SØrjan Eide { 22161c8e8aaSJavi Merino u64 power; 222a76caf55SØrjan Eide u32 freq_mhz; 223a76caf55SØrjan Eide struct devfreq_cooling_power *dfc_power = dfc->power_ops; 224a76caf55SØrjan Eide 225a76caf55SØrjan Eide if (dfc_power->get_dynamic_power) 2263aa53743SJavi Merino return dfc_power->get_dynamic_power(dfc->devfreq, freq, 2273aa53743SJavi Merino voltage); 228a76caf55SØrjan Eide 229a76caf55SØrjan Eide freq_mhz = freq / 1000000; 230a76caf55SØrjan Eide power = (u64)dfc_power->dyn_power_coeff * freq_mhz * voltage * voltage; 231a76caf55SØrjan Eide do_div(power, 1000000000); 232a76caf55SØrjan Eide 233a76caf55SØrjan Eide return power; 234a76caf55SØrjan Eide } 235a76caf55SØrjan Eide 236a76caf55SØrjan Eide static int devfreq_cooling_get_requested_power(struct thermal_cooling_device *cdev, 237a76caf55SØrjan Eide struct thermal_zone_device *tz, 238a76caf55SØrjan Eide u32 *power) 239a76caf55SØrjan Eide { 240a76caf55SØrjan Eide struct devfreq_cooling_device *dfc = cdev->devdata; 241a76caf55SØrjan Eide struct devfreq *df = dfc->devfreq; 242a76caf55SØrjan Eide struct devfreq_dev_status *status = &df->last_status; 243a76caf55SØrjan Eide unsigned long state; 244a76caf55SØrjan Eide unsigned long freq = status->current_frequency; 245a76caf55SØrjan Eide u32 dyn_power, static_power; 246a76caf55SØrjan Eide 247a76caf55SØrjan Eide /* Get dynamic power for state */ 248a76caf55SØrjan Eide state = freq_get_state(dfc, freq); 249a76caf55SØrjan Eide if (state == THERMAL_CSTATE_INVALID) 250a76caf55SØrjan Eide return -EAGAIN; 251a76caf55SØrjan Eide 252a76caf55SØrjan Eide dyn_power = dfc->power_table[state]; 253a76caf55SØrjan Eide 254a76caf55SØrjan Eide /* Scale dynamic power for utilization */ 255a76caf55SØrjan Eide dyn_power = (dyn_power * status->busy_time) / status->total_time; 256a76caf55SØrjan Eide 257a76caf55SØrjan Eide /* Get static power */ 258a76caf55SØrjan Eide static_power = get_static_power(dfc, freq); 259a76caf55SØrjan Eide 2609876b1a4SJavi Merino trace_thermal_power_devfreq_get_power(cdev, status, freq, dyn_power, 2619876b1a4SJavi Merino static_power); 2629876b1a4SJavi Merino 263a76caf55SØrjan Eide *power = dyn_power + static_power; 264a76caf55SØrjan Eide 265a76caf55SØrjan Eide return 0; 266a76caf55SØrjan Eide } 267a76caf55SØrjan Eide 268a76caf55SØrjan Eide static int devfreq_cooling_state2power(struct thermal_cooling_device *cdev, 269a76caf55SØrjan Eide struct thermal_zone_device *tz, 270a76caf55SØrjan Eide unsigned long state, 271a76caf55SØrjan Eide u32 *power) 272a76caf55SØrjan Eide { 273a76caf55SØrjan Eide struct devfreq_cooling_device *dfc = cdev->devdata; 274a76caf55SØrjan Eide unsigned long freq; 275a76caf55SØrjan Eide u32 static_power; 276a76caf55SØrjan Eide 277e3da1cbeSShawn Lin if (state >= dfc->freq_table_size) 278a76caf55SØrjan Eide return -EINVAL; 279a76caf55SØrjan Eide 280a76caf55SØrjan Eide freq = dfc->freq_table[state]; 281a76caf55SØrjan Eide static_power = get_static_power(dfc, freq); 282a76caf55SØrjan Eide 283a76caf55SØrjan Eide *power = dfc->power_table[state] + static_power; 284a76caf55SØrjan Eide return 0; 285a76caf55SØrjan Eide } 286a76caf55SØrjan Eide 287a76caf55SØrjan Eide static int devfreq_cooling_power2state(struct thermal_cooling_device *cdev, 288a76caf55SØrjan Eide struct thermal_zone_device *tz, 289a76caf55SØrjan Eide u32 power, unsigned long *state) 290a76caf55SØrjan Eide { 291a76caf55SØrjan Eide struct devfreq_cooling_device *dfc = cdev->devdata; 292a76caf55SØrjan Eide struct devfreq *df = dfc->devfreq; 293a76caf55SØrjan Eide struct devfreq_dev_status *status = &df->last_status; 294a76caf55SØrjan Eide unsigned long freq = status->current_frequency; 295a76caf55SØrjan Eide unsigned long busy_time; 296a76caf55SØrjan Eide s32 dyn_power; 297a76caf55SØrjan Eide u32 static_power; 298a76caf55SØrjan Eide int i; 299a76caf55SØrjan Eide 300a76caf55SØrjan Eide static_power = get_static_power(dfc, freq); 301a76caf55SØrjan Eide 302a76caf55SØrjan Eide dyn_power = power - static_power; 303a76caf55SØrjan Eide dyn_power = dyn_power > 0 ? dyn_power : 0; 304a76caf55SØrjan Eide 305a76caf55SØrjan Eide /* Scale dynamic power for utilization */ 306a76caf55SØrjan Eide busy_time = status->busy_time ?: 1; 307a76caf55SØrjan Eide dyn_power = (dyn_power * status->total_time) / busy_time; 308a76caf55SØrjan Eide 309a76caf55SØrjan Eide /* 310a76caf55SØrjan Eide * Find the first cooling state that is within the power 311a76caf55SØrjan Eide * budget for dynamic power. 312a76caf55SØrjan Eide */ 313a76caf55SØrjan Eide for (i = 0; i < dfc->freq_table_size - 1; i++) 314a76caf55SØrjan Eide if (dyn_power >= dfc->power_table[i]) 315a76caf55SØrjan Eide break; 316a76caf55SØrjan Eide 317a76caf55SØrjan Eide *state = i; 3189876b1a4SJavi Merino trace_thermal_power_devfreq_limit(cdev, freq, *state, power); 319a76caf55SØrjan Eide return 0; 320a76caf55SØrjan Eide } 321a76caf55SØrjan Eide 322a76caf55SØrjan Eide static struct thermal_cooling_device_ops devfreq_cooling_ops = { 323a76caf55SØrjan Eide .get_max_state = devfreq_cooling_get_max_state, 324a76caf55SØrjan Eide .get_cur_state = devfreq_cooling_get_cur_state, 325a76caf55SØrjan Eide .set_cur_state = devfreq_cooling_set_cur_state, 326a76caf55SØrjan Eide }; 327a76caf55SØrjan Eide 328a76caf55SØrjan Eide /** 329a76caf55SØrjan Eide * devfreq_cooling_gen_tables() - Generate power and freq tables. 330a76caf55SØrjan Eide * @dfc: Pointer to devfreq cooling device. 331a76caf55SØrjan Eide * 332a76caf55SØrjan Eide * Generate power and frequency tables: the power table hold the 333a76caf55SØrjan Eide * device's maximum power usage at each cooling state (OPP). The 334a76caf55SØrjan Eide * static and dynamic power using the appropriate voltage and 335a76caf55SØrjan Eide * frequency for the state, is acquired from the struct 336a76caf55SØrjan Eide * devfreq_cooling_power, and summed to make the maximum power draw. 337a76caf55SØrjan Eide * 338a76caf55SØrjan Eide * The frequency table holds the frequencies in descending order. 339a76caf55SØrjan Eide * That way its indexed by cooling device state. 340a76caf55SØrjan Eide * 341a76caf55SØrjan Eide * The tables are malloced, and pointers put in dfc. They must be 342a76caf55SØrjan Eide * freed when unregistering the devfreq cooling device. 343a76caf55SØrjan Eide * 344a76caf55SØrjan Eide * Return: 0 on success, negative error code on failure. 345a76caf55SØrjan Eide */ 346a76caf55SØrjan Eide static int devfreq_cooling_gen_tables(struct devfreq_cooling_device *dfc) 347a76caf55SØrjan Eide { 348a76caf55SØrjan Eide struct devfreq *df = dfc->devfreq; 349a76caf55SØrjan Eide struct device *dev = df->dev.parent; 350a76caf55SØrjan Eide int ret, num_opps; 351a76caf55SØrjan Eide unsigned long freq; 352a76caf55SØrjan Eide u32 *power_table = NULL; 353a76caf55SØrjan Eide u32 *freq_table; 354a76caf55SØrjan Eide int i; 355a76caf55SØrjan Eide 356a76caf55SØrjan Eide num_opps = dev_pm_opp_get_opp_count(dev); 357a76caf55SØrjan Eide 358a76caf55SØrjan Eide if (dfc->power_ops) { 359a76caf55SØrjan Eide power_table = kcalloc(num_opps, sizeof(*power_table), 360a76caf55SØrjan Eide GFP_KERNEL); 361a76caf55SØrjan Eide if (!power_table) 362ce5ee161SDan Carpenter return -ENOMEM; 363a76caf55SØrjan Eide } 364a76caf55SØrjan Eide 365a76caf55SØrjan Eide freq_table = kcalloc(num_opps, sizeof(*freq_table), 366a76caf55SØrjan Eide GFP_KERNEL); 367a76caf55SØrjan Eide if (!freq_table) { 368a76caf55SØrjan Eide ret = -ENOMEM; 369a76caf55SØrjan Eide goto free_power_table; 370a76caf55SØrjan Eide } 371a76caf55SØrjan Eide 372a76caf55SØrjan Eide for (i = 0, freq = ULONG_MAX; i < num_opps; i++, freq--) { 373a76caf55SØrjan Eide unsigned long power_dyn, voltage; 374a76caf55SØrjan Eide struct dev_pm_opp *opp; 375a76caf55SØrjan Eide 376a76caf55SØrjan Eide opp = dev_pm_opp_find_freq_floor(dev, &freq); 377a76caf55SØrjan Eide if (IS_ERR(opp)) { 378a76caf55SØrjan Eide ret = PTR_ERR(opp); 379a76caf55SØrjan Eide goto free_tables; 380a76caf55SØrjan Eide } 381a76caf55SØrjan Eide 382a76caf55SØrjan Eide voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */ 3838a31d9d9SViresh Kumar dev_pm_opp_put(opp); 384a76caf55SØrjan Eide 385a76caf55SØrjan Eide if (dfc->power_ops) { 386a76caf55SØrjan Eide power_dyn = get_dynamic_power(dfc, freq, voltage); 387a76caf55SØrjan Eide 388a76caf55SØrjan Eide dev_dbg(dev, "Dynamic power table: %lu MHz @ %lu mV: %lu = %lu mW\n", 389a76caf55SØrjan Eide freq / 1000000, voltage, power_dyn, power_dyn); 390a76caf55SØrjan Eide 391a76caf55SØrjan Eide power_table[i] = power_dyn; 392a76caf55SØrjan Eide } 393a76caf55SØrjan Eide 394a76caf55SØrjan Eide freq_table[i] = freq; 395a76caf55SØrjan Eide } 396a76caf55SØrjan Eide 397a76caf55SØrjan Eide if (dfc->power_ops) 398a76caf55SØrjan Eide dfc->power_table = power_table; 399a76caf55SØrjan Eide 400a76caf55SØrjan Eide dfc->freq_table = freq_table; 401a76caf55SØrjan Eide dfc->freq_table_size = num_opps; 402a76caf55SØrjan Eide 403a76caf55SØrjan Eide return 0; 404a76caf55SØrjan Eide 405a76caf55SØrjan Eide free_tables: 406a76caf55SØrjan Eide kfree(freq_table); 407a76caf55SØrjan Eide free_power_table: 408a76caf55SØrjan Eide kfree(power_table); 409a76caf55SØrjan Eide 410a76caf55SØrjan Eide return ret; 411a76caf55SØrjan Eide } 412a76caf55SØrjan Eide 413a76caf55SØrjan Eide /** 414a76caf55SØrjan Eide * of_devfreq_cooling_register_power() - Register devfreq cooling device, 415a76caf55SØrjan Eide * with OF and power information. 416a76caf55SØrjan Eide * @np: Pointer to OF device_node. 417a76caf55SØrjan Eide * @df: Pointer to devfreq device. 418a76caf55SØrjan Eide * @dfc_power: Pointer to devfreq_cooling_power. 419a76caf55SØrjan Eide * 420a76caf55SØrjan Eide * Register a devfreq cooling device. The available OPPs must be 421a76caf55SØrjan Eide * registered on the device. 422a76caf55SØrjan Eide * 423a76caf55SØrjan Eide * If @dfc_power is provided, the cooling device is registered with the 424a76caf55SØrjan Eide * power extensions. For the power extensions to work correctly, 425a76caf55SØrjan Eide * devfreq should use the simple_ondemand governor, other governors 426a76caf55SØrjan Eide * are not currently supported. 427a76caf55SØrjan Eide */ 4283c99c2ceSJavi Merino struct thermal_cooling_device * 429a76caf55SØrjan Eide of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df, 430a76caf55SØrjan Eide struct devfreq_cooling_power *dfc_power) 431a76caf55SØrjan Eide { 432a76caf55SØrjan Eide struct thermal_cooling_device *cdev; 433a76caf55SØrjan Eide struct devfreq_cooling_device *dfc; 434a76caf55SØrjan Eide char dev_name[THERMAL_NAME_LENGTH]; 435a76caf55SØrjan Eide int err; 436a76caf55SØrjan Eide 437a76caf55SØrjan Eide dfc = kzalloc(sizeof(*dfc), GFP_KERNEL); 438a76caf55SØrjan Eide if (!dfc) 439a76caf55SØrjan Eide return ERR_PTR(-ENOMEM); 440a76caf55SØrjan Eide 441a76caf55SØrjan Eide dfc->devfreq = df; 442a76caf55SØrjan Eide 443a76caf55SØrjan Eide if (dfc_power) { 444a76caf55SØrjan Eide dfc->power_ops = dfc_power; 445a76caf55SØrjan Eide 446a76caf55SØrjan Eide devfreq_cooling_ops.get_requested_power = 447a76caf55SØrjan Eide devfreq_cooling_get_requested_power; 448a76caf55SØrjan Eide devfreq_cooling_ops.state2power = devfreq_cooling_state2power; 449a76caf55SØrjan Eide devfreq_cooling_ops.power2state = devfreq_cooling_power2state; 450a76caf55SØrjan Eide } 451a76caf55SØrjan Eide 452a76caf55SØrjan Eide err = devfreq_cooling_gen_tables(dfc); 453a76caf55SØrjan Eide if (err) 454a76caf55SØrjan Eide goto free_dfc; 455a76caf55SØrjan Eide 4562f96c035SMatthew Wilcox err = ida_simple_get(&devfreq_ida, 0, 0, GFP_KERNEL); 4572f96c035SMatthew Wilcox if (err < 0) 458a76caf55SØrjan Eide goto free_tables; 4592f96c035SMatthew Wilcox dfc->id = err; 460a76caf55SØrjan Eide 461a76caf55SØrjan Eide snprintf(dev_name, sizeof(dev_name), "thermal-devfreq-%d", dfc->id); 462a76caf55SØrjan Eide 463a76caf55SØrjan Eide cdev = thermal_of_cooling_device_register(np, dev_name, dfc, 464a76caf55SØrjan Eide &devfreq_cooling_ops); 465a76caf55SØrjan Eide if (IS_ERR(cdev)) { 466a76caf55SØrjan Eide err = PTR_ERR(cdev); 467a76caf55SØrjan Eide dev_err(df->dev.parent, 468a76caf55SØrjan Eide "Failed to register devfreq cooling device (%d)\n", 469a76caf55SØrjan Eide err); 4702f96c035SMatthew Wilcox goto release_ida; 471a76caf55SØrjan Eide } 472a76caf55SØrjan Eide 473a76caf55SØrjan Eide dfc->cdev = cdev; 474a76caf55SØrjan Eide 4753c99c2ceSJavi Merino return cdev; 476a76caf55SØrjan Eide 4772f96c035SMatthew Wilcox release_ida: 4782f96c035SMatthew Wilcox ida_simple_remove(&devfreq_ida, dfc->id); 479a76caf55SØrjan Eide free_tables: 480a76caf55SØrjan Eide kfree(dfc->power_table); 481a76caf55SØrjan Eide kfree(dfc->freq_table); 482a76caf55SØrjan Eide free_dfc: 483a76caf55SØrjan Eide kfree(dfc); 484a76caf55SØrjan Eide 485a76caf55SØrjan Eide return ERR_PTR(err); 486a76caf55SØrjan Eide } 487a76caf55SØrjan Eide EXPORT_SYMBOL_GPL(of_devfreq_cooling_register_power); 488a76caf55SØrjan Eide 489a76caf55SØrjan Eide /** 490a76caf55SØrjan Eide * of_devfreq_cooling_register() - Register devfreq cooling device, 491a76caf55SØrjan Eide * with OF information. 492a76caf55SØrjan Eide * @np: Pointer to OF device_node. 493a76caf55SØrjan Eide * @df: Pointer to devfreq device. 494a76caf55SØrjan Eide */ 4953c99c2ceSJavi Merino struct thermal_cooling_device * 496a76caf55SØrjan Eide of_devfreq_cooling_register(struct device_node *np, struct devfreq *df) 497a76caf55SØrjan Eide { 498a76caf55SØrjan Eide return of_devfreq_cooling_register_power(np, df, NULL); 499a76caf55SØrjan Eide } 500a76caf55SØrjan Eide EXPORT_SYMBOL_GPL(of_devfreq_cooling_register); 501a76caf55SØrjan Eide 502a76caf55SØrjan Eide /** 503a76caf55SØrjan Eide * devfreq_cooling_register() - Register devfreq cooling device. 504a76caf55SØrjan Eide * @df: Pointer to devfreq device. 505a76caf55SØrjan Eide */ 5063c99c2ceSJavi Merino struct thermal_cooling_device *devfreq_cooling_register(struct devfreq *df) 507a76caf55SØrjan Eide { 508a76caf55SØrjan Eide return of_devfreq_cooling_register(NULL, df); 509a76caf55SØrjan Eide } 510a76caf55SØrjan Eide EXPORT_SYMBOL_GPL(devfreq_cooling_register); 511a76caf55SØrjan Eide 512a76caf55SØrjan Eide /** 513a76caf55SØrjan Eide * devfreq_cooling_unregister() - Unregister devfreq cooling device. 514a76caf55SØrjan Eide * @dfc: Pointer to devfreq cooling device to unregister. 515a76caf55SØrjan Eide */ 5163c99c2ceSJavi Merino void devfreq_cooling_unregister(struct thermal_cooling_device *cdev) 517a76caf55SØrjan Eide { 5183c99c2ceSJavi Merino struct devfreq_cooling_device *dfc; 5193c99c2ceSJavi Merino 5203c99c2ceSJavi Merino if (!cdev) 521a76caf55SØrjan Eide return; 522a76caf55SØrjan Eide 5233c99c2ceSJavi Merino dfc = cdev->devdata; 5243c99c2ceSJavi Merino 525a76caf55SØrjan Eide thermal_cooling_device_unregister(dfc->cdev); 5262f96c035SMatthew Wilcox ida_simple_remove(&devfreq_ida, dfc->id); 527a76caf55SØrjan Eide kfree(dfc->power_table); 528a76caf55SØrjan Eide kfree(dfc->freq_table); 529a76caf55SØrjan Eide 530a76caf55SØrjan Eide kfree(dfc); 531a76caf55SØrjan Eide } 532a76caf55SØrjan Eide EXPORT_SYMBOL_GPL(devfreq_cooling_unregister); 533